From 2a7f4f361e8bb91368c7bf1005d46c5f6929ea38 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Thu, 7 May 2026 22:00:03 +0100 Subject: [PATCH] ci: trigger PackageDistro from PR comments Add an issue_comment workflow for pull requests that accepts the exact bot command, checks collaborator permissions, and dispatches the PackageDistro workflow for the PR head. The workflow also keeps a bot comment on the PR up to date so rejected requests get a clear reply and accepted requests are replaced by the later PackageDistro result. AI assistance: Codex implemented the workflow and verification updates. Co-authored-by: Codex --- .github/workflows/package-distro-trigger.yml | 171 +++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 .github/workflows/package-distro-trigger.yml diff --git a/.github/workflows/package-distro-trigger.yml b/.github/workflows/package-distro-trigger.yml new file mode 100644 index 0000000000..ed38770508 --- /dev/null +++ b/.github/workflows/package-distro-trigger.yml @@ -0,0 +1,171 @@ +name: PackageDistro PR trigger + +on: + issue_comment: + types: [created] + +permissions: + contents: read + issues: write + pull-requests: read + +concurrency: + group: ${{ github.workflow }}-${{ github.event.issue.number }} + cancel-in-progress: false + +jobs: + dispatch-package-distro: + name: Dispatch PackageDistro test + if: ${{ github.event.issue.pull_request != null }} + runs-on: ubuntu-latest + steps: + - name: Check command + id: command + env: + COMMENT_BODY: ${{ github.event.comment.body }} + run: | + expected='@gap-package-distribution-bot test' + if [[ "${COMMENT_BODY}" == "${expected}" ]]; then + echo "matches=true" >> "$GITHUB_OUTPUT" + else + echo "matches=false" >> "$GITHUB_OUTPUT" + fi + + - uses: actions/create-github-app-token@v3 + id: gap-token + if: ${{ steps.command.outputs.matches == 'true' }} + with: + client-id: ${{ secrets.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + owner: gap-system + repositories: gap + + - name: Check commenter permission + id: permission + if: ${{ steps.command.outputs.matches == 'true' }} + env: + GH_TOKEN: ${{ steps.gap-token.outputs.token }} + REPO: ${{ github.repository }} + ACTOR: ${{ github.event.comment.user.login }} + run: | + api_url="https://api.github.com/repos/${REPO}/collaborators/${ACTOR}/permission" + http_code=$( + curl -sSL \ + -H "Authorization: Bearer ${GH_TOKEN}" \ + -H "Accept: application/vnd.github+json" \ + -o permission.json \ + -w '%{http_code}' \ + "${api_url}" + ) + if [[ "${http_code}" == "200" ]]; then + permission=$(jq -r '.permission // "none"' permission.json) + else + permission="none" + fi + echo "permission=${permission}" >> "$GITHUB_OUTPUT" + case "${permission}" in + admin|maintain|write|triage) + echo "authorized=true" >> "$GITHUB_OUTPUT" + ;; + *) + echo "authorized=false" >> "$GITHUB_OUTPUT" + ;; + esac + + - name: Find prior bot comment + id: find-comment + if: ${{ steps.command.outputs.matches == 'true' }} + uses: peter-evans/find-comment@v4 + with: + token: ${{ steps.gap-token.outputs.token }} + issue-number: ${{ github.event.issue.number }} + body-includes: "" + + - name: Reply to unauthorized request + if: >- + ${{ + steps.command.outputs.matches == 'true' && + steps.permission.outputs.authorized != 'true' + }} + uses: peter-evans/create-or-update-comment@v5 + with: + token: ${{ steps.gap-token.outputs.token }} + comment-id: ${{ steps.find-comment.outputs.comment-id }} + issue-number: ${{ github.event.issue.number }} + edit-mode: replace + body: | + + `@gap-package-distribution-bot test` may only be used by GAP collaborators with at least triage access. + + - uses: actions/create-github-app-token@v3 + id: pkgdistro-token + if: >- + ${{ + steps.command.outputs.matches == 'true' && + steps.permission.outputs.authorized == 'true' + }} + with: + client-id: ${{ secrets.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + owner: gap-system + repositories: PackageDistro + + - name: Dispatch PackageDistro workflow + if: >- + ${{ + steps.command.outputs.matches == 'true' && + steps.permission.outputs.authorized == 'true' + }} + env: + GH_TOKEN: ${{ steps.pkgdistro-token.outputs.token }} + PR_URL: ${{ github.event.issue.html_url }} + COMMENT_ID: ${{ steps.find-comment.outputs.comment-id }} + REQUESTER: ${{ github.event.comment.user.login }} + COMMAND: ${{ github.event.comment.body }} + run: | + comment_id_json=null + if [[ -n "${COMMENT_ID}" ]]; then + comment_id_json=${COMMENT_ID} + fi + jq -n \ + --arg ref main \ + --arg pr_url "${PR_URL}" \ + --arg requester "${REQUESTER}" \ + --arg command "${COMMAND}" \ + --arg callback_repo "${GITHUB_REPOSITORY}" \ + --arg callback_pr_number "${{ github.event.issue.number }}" \ + --argjson callback_comment_id "${comment_id_json}" \ + '{ + ref: $ref, + inputs: { + "gap-pr-url": $pr_url, + "callback-repo": $callback_repo, + "callback-pr-number": $callback_pr_number, + requester: $requester, + command: $command + } + (if $callback_comment_id == null then {} else {"callback-comment-id": ($callback_comment_id | tostring)} end) + }' > payload.json + curl -fsSL \ + -X POST \ + -H "Authorization: Bearer ${GH_TOKEN}" \ + -H "Accept: application/vnd.github+json" \ + https://api.github.com/repos/gap-system/PackageDistro/actions/workflows/test-gap-pr.yml/dispatches \ + -d @payload.json + + - name: Acknowledge accepted request + if: >- + ${{ + steps.command.outputs.matches == 'true' && + steps.permission.outputs.authorized == 'true' + }} + uses: peter-evans/create-or-update-comment@v5 + with: + token: ${{ steps.gap-token.outputs.token }} + comment-id: ${{ steps.find-comment.outputs.comment-id }} + issue-number: ${{ github.event.issue.number }} + edit-mode: replace + body: | + + Accepted `@gap-package-distribution-bot test`. + + PackageDistro was asked to run the full package test suite against the current head of this pull request. This comment will be updated with the result.