From 103d2bf1a8a006d7f3244f5ca06baec2c82c62fa Mon Sep 17 00:00:00 2001 From: Shantur Rathore Date: Fri, 20 Mar 2026 07:40:59 +0000 Subject: [PATCH] ci: comment PR artifacts from validation run --- .github/workflows/comment-pr-artifacts.yml | 112 --------------------- .github/workflows/pr-build.yml | 75 ++++++++++++++ 2 files changed, 75 insertions(+), 112 deletions(-) delete mode 100644 .github/workflows/comment-pr-artifacts.yml diff --git a/.github/workflows/comment-pr-artifacts.yml b/.github/workflows/comment-pr-artifacts.yml deleted file mode 100644 index 38ee7e72..00000000 --- a/.github/workflows/comment-pr-artifacts.yml +++ /dev/null @@ -1,112 +0,0 @@ -name: Comment PR Artifacts - -on: - workflow_run: - workflows: - - PR Build Validation - types: - - completed - -permissions: - actions: read - pull-requests: write - issues: write - -jobs: - comment: - # Only runs for PR Build Validation runs triggered by PRs. - if: ${{ github.event.workflow_run.event == 'pull_request' }} - runs-on: ubuntu-latest - steps: - - name: Comment with artifact download link - uses: actions/github-script@v7 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const run = context.payload.workflow_run; - const owner = context.repo.owner; - const repo = context.repo.repo; - - let prNumber = run.pull_requests?.[0]?.number; - - // `workflow_run` payload does not reliably include pull request numbers. - // Ask the Actions API for the triggering run itself and use that as source of truth. - if (!prNumber) { - const runDetails = await github.rest.actions.getWorkflowRun({ - owner, - repo, - run_id: run.id, - }); - prNumber = runDetails.data.pull_requests?.[0]?.number; - } - - if (!prNumber) { - core.info(`No PR number found on workflow run ${run.id}; skipping.`); - return; - } - - // Only comment when the PR build job actually ran (i.e. authorization passed). - // Unauthorized PRs targeting non-dev will skip the `build` job. - const jobs = await github.paginate( - github.rest.actions.listJobsForWorkflowRun, - { owner, repo, run_id: run.id, per_page: 100 } - ); - const buildJob = jobs.find((j) => j.name === 'build'); - if (!buildJob) { - core.info('No `build` job found on this run; skipping.'); - return; - } - if (buildJob.conclusion === 'skipped') { - core.info('`build` job was skipped; skipping comment.'); - return; - } - - // List artifacts from the run. If none exist (e.g. build failed before packaging), - // still comment with the run link so testers can see logs. - const artifacts = await github.paginate( - github.rest.actions.listWorkflowRunArtifacts, - { owner, repo, run_id: run.id, per_page: 100 } - ); - const active = artifacts.filter((a) => !a.expired); - - const marker = ''; - const runUrl = `https://github.com/${owner}/${repo}/actions/runs/${run.id}`; - const retentionDays = 7; - - const artifactsBlock = active.length - ? ['Artifacts:', ...active.map((a) => `- ${a.name}`)].join('\n') - : 'Artifacts: (none found on this run)'; - - const body = [ - marker, - 'PR builds are available as GitHub Actions artifacts:', - '', - runUrl, - '', - `Artifacts expire in ${retentionDays} days.`, - artifactsBlock, - ].join('\n'); - - const comments = await github.paginate( - github.rest.issues.listComments, - { owner, repo, issue_number: prNumber, per_page: 100 } - ); - const existing = comments.find((c) => (c.body || '').includes(marker)); - - if (existing) { - await github.rest.issues.updateComment({ - owner, - repo, - comment_id: existing.id, - body, - }); - core.info(`Updated existing artifacts comment: ${existing.html_url}`); - } else { - const created = await github.rest.issues.createComment({ - owner, - repo, - issue_number: prNumber, - body, - }); - core.info(`Created artifacts comment: ${created.data.html_url}`); - } diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml index 1f780ffc..c0646aa3 100644 --- a/.github/workflows/pr-build.yml +++ b/.github/workflows/pr-build.yml @@ -10,6 +10,8 @@ on: permissions: contents: read actions: write + issues: write + pull-requests: write concurrency: group: pr-build-${{ github.event.pull_request.number }} @@ -54,3 +56,76 @@ jobs: actions_artifacts_retention_days: 7 actions_artifacts_name_prefix: pr-${{ github.event.pull_request.number }}-${{ github.event.pull_request.head.sha }}- set_versions: false + + comment-artifacts: + needs: + - authorize + - build + if: ${{ always() && needs.authorize.outputs.allowed == 'true' }} + runs-on: ubuntu-latest + steps: + - name: Get PR number + id: get-pr + uses: bcgov/action-get-pr@v0.1.1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Comment with artifact download link + uses: actions/github-script@v8 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const owner = context.repo.owner; + const repo = context.repo.repo; + const prNumber = Number('${{ steps.get-pr.outputs.pr }}'); + if (!prNumber) { + core.setFailed('Failed to resolve PR number.'); + return; + } + + const artifacts = await github.paginate( + github.rest.actions.listWorkflowRunArtifacts, + { owner, repo, run_id: context.runId, per_page: 100 } + ); + const active = artifacts.filter((a) => !a.expired); + + const marker = ''; + const runUrl = `https://github.com/${owner}/${repo}/actions/runs/${context.runId}`; + const retentionDays = 7; + const artifactsBlock = active.length + ? ['Artifacts:', ...active.map((a) => `- ${a.name}`)].join('\n') + : 'Artifacts: (none found on this run)'; + + const body = [ + marker, + 'PR builds are available as GitHub Actions artifacts:', + '', + runUrl, + '', + `Artifacts expire in ${retentionDays} days.`, + artifactsBlock, + ].join('\n'); + + const comments = await github.paginate( + github.rest.issues.listComments, + { owner, repo, issue_number: prNumber, per_page: 100 } + ); + const existing = comments.find((c) => (c.body || '').includes(marker)); + + if (existing) { + await github.rest.issues.updateComment({ + owner, + repo, + comment_id: existing.id, + body, + }); + core.info(`Updated existing artifacts comment: ${existing.html_url}`); + } else { + const created = await github.rest.issues.createComment({ + owner, + repo, + issue_number: prNumber, + body, + }); + core.info(`Created artifacts comment: ${created.data.html_url}`); + }