name: PR Build Validation on: pull_request: types: - opened - synchronize - reopened permissions: contents: read actions: write issues: write pull-requests: write concurrency: group: pr-build-${{ github.event.pull_request.number }} cancel-in-progress: true jobs: authorize: runs-on: ubuntu-latest outputs: allowed: ${{ steps.auth.outputs.allowed }} env: ALLOWED_ACTORS: ${{ vars.ALLOWED_NON_DEV_PR_ACTORS }} ACTOR: ${{ github.actor }} BASE_REF: ${{ github.event.pull_request.base.ref }} steps: - name: Check PR authorization id: auth shell: bash run: | set -euo pipefail if [ "$BASE_REF" = "dev" ]; then echo "allowed=true" >> "$GITHUB_OUTPUT" exit 0 fi normalized=",${ALLOWED_ACTORS}," if [[ "$normalized" == *",${ACTOR},"* ]]; then echo "allowed=true" >> "$GITHUB_OUTPUT" else echo "allowed=false" >> "$GITHUB_OUTPUT" echo "Skipping builds for unauthorized PR targeting $BASE_REF" >&2 fi build: needs: authorize if: ${{ needs.authorize.outputs.allowed == 'true' }} uses: ./.github/workflows/build-and-upload.yml with: ref: ${{ github.event.pull_request.head.sha }} upload: false upload_actions_artifacts: true 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}`); }