From e7ffab26602daf5a533135efe772809c4f66abf4 Mon Sep 17 00:00:00 2001 From: Eric Lunde Date: Mon, 12 Oct 2026 15:50:27 -0400 Subject: [PATCH 1/2] ci: add PR lifecycle automation and on-demand Copilot dispatch workflows --- .../workflows/copilot-ci-failure-handler.yml | 36 ++++++++++++++ .github/workflows/copilot-review-handler.yml | 27 +++++++++++ .github/workflows/pr-automation.yml | 48 +++++++++++++++++++ .github/workflows/ready-for-review.yml | 35 -------------- 4 files changed, 111 insertions(+), 35 deletions(-) create mode 100644 .github/workflows/copilot-ci-failure-handler.yml create mode 100644 .github/workflows/copilot-review-handler.yml create mode 100644 .github/workflows/pr-automation.yml delete mode 100644 .github/workflows/ready-for-review.yml diff --git a/.github/workflows/copilot-ci-failure-handler.yml b/.github/workflows/copilot-ci-failure-handler.yml new file mode 100644 index 0000000..1ce135b --- /dev/null +++ b/.github/workflows/copilot-ci-failure-handler.yml @@ -0,0 +1,36 @@ +name: "Auto-summon Copilot on CI Failure" + +on: + workflow_run: + workflows: + - "CI" + - "CodeQL Analysis" + - "SonarCloud Analysis" + types: + - completed + +jobs: + notify-copilot-ci: + name: Notify Copilot on Build Failure + runs-on: ubuntu-latest + if: github.event.workflow_run.conclusion == 'failure' && github.event.workflow_run.event == 'pull_request' + permissions: + pull-requests: write + issues: write + + steps: + - name: Comment on PR to Summon Copilot + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + WORKFLOW_NAME: ${{ github.event.workflow_run.name }} + RUN_URL: ${{ github.event.workflow_run.html_url }} + run: | + # Fetch the associated PR number from the workflow run payload + PR_NUMBER="${{ github.event.workflow_run.pull_requests[0].number }}" + if [ -n "$PR_NUMBER" ] && [ "$PR_NUMBER" != "null" ]; then + echo "CI workflow '${WORKFLOW_NAME}' failed for PR #${PR_NUMBER}." + gh pr comment "${PR_NUMBER}" \ + --body "@copilot The workflow **${WORKFLOW_NAME}** failed on this pull request. Please inspect the build failure logs at ${RUN_URL}, fix the issue, and commit the update." + else + echo "No associated pull request found for this workflow run." + fi diff --git a/.github/workflows/copilot-review-handler.yml b/.github/workflows/copilot-review-handler.yml new file mode 100644 index 0000000..7721506 --- /dev/null +++ b/.github/workflows/copilot-review-handler.yml @@ -0,0 +1,27 @@ +name: "Auto-summon Copilot on Review Changes Requested" + +on: + pull_request_review: + types: + - submitted + +jobs: + dispatch-copilot: + name: Notify Copilot of Review Feedback + runs-on: ubuntu-latest + # Only trigger when a review requests changes or comments from a reviewer bot/human + if: github.event.review.state == 'changes_requested' + permissions: + pull-requests: write + issues: write + + steps: + - name: Comment on PR to Summon Copilot + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ github.event.pull_request.number }} + REVIEWER: ${{ github.event.review.user.login }} + run: | + echo "Review submitted requesting changes by @${REVIEWER} on PR #${PR_NUMBER}." + gh pr comment "${PR_NUMBER}" \ + --body "@copilot Changes were requested on this pull request by @${REVIEWER}. Please review the feedback, implement the necessary corrections, and push an update." diff --git a/.github/workflows/pr-automation.yml b/.github/workflows/pr-automation.yml new file mode 100644 index 0000000..0b53e7e --- /dev/null +++ b/.github/workflows/pr-automation.yml @@ -0,0 +1,48 @@ +name: "PR Lifecycle Automation" + +on: + pull_request_target: + types: + - opened + - converted_to_draft + - edited + - labeled + +jobs: + manage-pr: + name: Manage PR State & Auto-merge + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + + steps: + # 1. Undraft: If PR is a draft and doesn't start with [WIP], mark it as ready for review + - name: Mark Draft as Ready for Review + if: github.event.pull_request.draft == true && !startsWith(github.event.pull_request.title, '[WIP]') + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NODE_ID: ${{ github.event.pull_request.node_id }} + PR_NUMBER: ${{ github.event.pull_request.number }} + run: | + echo "Marking PR #${PR_NUMBER} as ready for review..." + gh api graphql -f query=' + mutation($id: ID!) { + markPullRequestReadyForReview(input: {pullRequestId: $id}) { + pullRequest { + id + isDraft + } + } + } + ' -f id="${PR_NODE_ID}" + + # 2. Auto-merge: If PR is open, not draft, not WIP, enable auto-merge (squash) + - name: Enable Auto-Merge + if: github.event.pull_request.state == 'open' && !startsWith(github.event.pull_request.title, '[WIP]') + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ github.event.pull_request.number }} + run: | + echo "Enabling auto-merge for PR #${PR_NUMBER}..." + gh pr merge "${PR_NUMBER}" --auto --squash || echo "Auto-merge could not be enabled (may already be enabled or repo settings require manual merge)." diff --git a/.github/workflows/ready-for-review.yml b/.github/workflows/ready-for-review.yml deleted file mode 100644 index 878f5a1..0000000 --- a/.github/workflows/ready-for-review.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: "Ready for Review" - -on: - pull_request_target: - types: - - opened - - converted_to_draft - - edited - -jobs: - mark-ready: - name: Mark Draft as Ready for Review - runs-on: ubuntu-latest - if: github.event.pull_request.draft == true && !startsWith(github.event.pull_request.title, '[WIP]') - permissions: - pull-requests: write - - steps: - - name: Mark PR as Ready for Review - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR_NODE_ID: ${{ github.event.pull_request.node_id }} - PR_NUMBER: ${{ github.event.pull_request.number }} - run: | - echo "Marking PR #${PR_NUMBER} as ready for review..." - gh api graphql -f query=' - mutation($id: ID!) { - markPullRequestReadyForReview(input: {pullRequestId: $id}) { - pullRequest { - id - isDraft - } - } - } - ' -f id="${PR_NODE_ID}" From 2b0d62e74a28cf553ea71979b2a2a4ecef5eefde Mon Sep 17 00:00:00 2001 From: Eric Lunde Date: Mon, 12 Oct 2026 15:57:11 -0400 Subject: [PATCH 2/2] chore: address review findings on auto-merge permissions and env var pass --- .github/workflows/copilot-ci-failure-handler.yml | 3 +-- .github/workflows/copilot-review-handler.yml | 2 +- .github/workflows/pr-automation.yml | 7 +++++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/copilot-ci-failure-handler.yml b/.github/workflows/copilot-ci-failure-handler.yml index 1ce135b..565d574 100644 --- a/.github/workflows/copilot-ci-failure-handler.yml +++ b/.github/workflows/copilot-ci-failure-handler.yml @@ -24,9 +24,8 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} WORKFLOW_NAME: ${{ github.event.workflow_run.name }} RUN_URL: ${{ github.event.workflow_run.html_url }} + PR_NUMBER: ${{ github.event.workflow_run.pull_requests[0].number }} run: | - # Fetch the associated PR number from the workflow run payload - PR_NUMBER="${{ github.event.workflow_run.pull_requests[0].number }}" if [ -n "$PR_NUMBER" ] && [ "$PR_NUMBER" != "null" ]; then echo "CI workflow '${WORKFLOW_NAME}' failed for PR #${PR_NUMBER}." gh pr comment "${PR_NUMBER}" \ diff --git a/.github/workflows/copilot-review-handler.yml b/.github/workflows/copilot-review-handler.yml index 7721506..8a39861 100644 --- a/.github/workflows/copilot-review-handler.yml +++ b/.github/workflows/copilot-review-handler.yml @@ -9,7 +9,7 @@ jobs: dispatch-copilot: name: Notify Copilot of Review Feedback runs-on: ubuntu-latest - # Only trigger when a review requests changes or comments from a reviewer bot/human + # Only trigger when a review explicitly requests changes if: github.event.review.state == 'changes_requested' permissions: pull-requests: write diff --git a/.github/workflows/pr-automation.yml b/.github/workflows/pr-automation.yml index 0b53e7e..2c42484 100644 --- a/.github/workflows/pr-automation.yml +++ b/.github/workflows/pr-automation.yml @@ -37,9 +37,12 @@ jobs: } ' -f id="${PR_NODE_ID}" - # 2. Auto-merge: If PR is open, not draft, not WIP, enable auto-merge (squash) + # 2. Auto-merge: If PR is open, not draft, not WIP, and authored by repo member/collaborator/owner, enable auto-merge (squash) - name: Enable Auto-Merge - if: github.event.pull_request.state == 'open' && !startsWith(github.event.pull_request.title, '[WIP]') + if: | + github.event.pull_request.state == 'open' && + !startsWith(github.event.pull_request.title, '[WIP]') && + contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.pull_request.author_association) env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} PR_NUMBER: ${{ github.event.pull_request.number }}