mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2026-07-28 14:29:57 +00:00
* ci: post Build & analyze report on fork PRs via workflow_run The Comment PR report step in pr-build.yml fails with 403 "Resource not accessible by integration" on fork PRs: GitHub gives `pull_request` runs from forks a read-only GITHUB_TOKEN (they build untrusted code), so issues.createComment is forbidden and the whole f7 build check goes red even though the firmware built fine. Split delivery from analysis: - pr-build.yml keeps all build/size/API analysis on the fork's code with the read-only token, but instead of commenting it uploads the assembled report + PR number as the `pr-report` artifact. Drops pull-requests:write. - pr-comment.yml (new) is triggered on workflow_run when the build completes. It runs from the default branch in the base-repo context, so it gets a read-write token even for fork-triggered builds, downloads the artifact, and posts/updates the comment. It never checks out or runs PR code. The PR number travels via the artifact because workflow_run.pull_requests is empty for fork PRs. Same-repo PRs keep working; fork PRs now get the report comment a few seconds later, and the build check is no longer falsely red. Closes #1026 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * ci: harden fork-PR comment workflow after review Review + simplify pass on the workflow_run split: - pr-comment.yml: add `actions: read` — an explicit permissions block sets unlisted scopes to none, and a cross-run download-artifact needs it; without it the download 403s, continue-on-error swallows it, and the comment silently never posts. This is the fix that makes the feature actually work on forks. - pr-comment.yml: skip cancelled/skipped builds in the job `if`, and warn (job annotation) when the artifact can't be downloaded, so a genuine failure isn't a green check with no comment and no signal. - pr-comment.yml: add a concurrency group (keyed on the build run id, since workflow_run.pull_requests is empty for forks) so a re-run can't race the find-or-create into duplicate comments; log incomplete artifact at warning, not info; per_page:100 on listComments to cut pagination round-trips. - pr-build.yml: mark the report upload continue-on-error so a transient upload hiccup can't redden an otherwise-green build (the point of the split); fix two comment overstatements (push/dispatch summary omits the PR-only API section; concurrency also covers pushes to dev). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
89 lines
4.1 KiB
YAML
89 lines
4.1 KiB
YAML
# Post the "Build & analyze" report as a PR comment — including on fork PRs.
|
|
#
|
|
# The build workflow (pr-build.yml) runs on `pull_request`; for fork PRs GitHub hands it
|
|
# a read-only token, so it cannot comment itself. It instead uploads the assembled report
|
|
# as the `pr-report` artifact. This workflow is triggered by `workflow_run` when that build
|
|
# completes: because `workflow_run` always runs the copy of this file on the DEFAULT BRANCH,
|
|
# in the base-repo context, its requested write permissions are actually granted (unlike the
|
|
# fork's read-only `pull_request` token). It downloads the artifact and posts the comment.
|
|
#
|
|
# Security: this job must NOT check out or execute the PR's code. Its only untrusted input
|
|
# is the report artifact, which it treats strictly as text to post.
|
|
#
|
|
# Note: `workflow_run` workflows only ever run from the default branch, so changes here take
|
|
# effect once merged to dev and can't be exercised from a PR branch.
|
|
|
|
name: PR report comment
|
|
|
|
on:
|
|
workflow_run:
|
|
workflows: ["Build & analyze"] # must match pr-build.yml's `name:`
|
|
types: [completed]
|
|
|
|
# Cross-run artifact download needs `actions: read`; posting the comment needs
|
|
# `pull-requests: write`. An explicit block sets every unlisted scope to `none`.
|
|
permissions:
|
|
actions: read
|
|
pull-requests: write # honored here: this runs in the base-repo context, not the fork's
|
|
|
|
# Serialize comment runs for the same build so a re-run can't race the find-or-create
|
|
# below into duplicate comments. workflow_run.pull_requests is empty for fork PRs, so key
|
|
# on the run id (unique per triggering build) rather than the PR number.
|
|
concurrency:
|
|
group: pr-comment-${{ github.event.workflow_run.id }}
|
|
cancel-in-progress: false
|
|
|
|
jobs:
|
|
comment:
|
|
name: Post report comment
|
|
runs-on: ubuntu-latest
|
|
# Only PR builds that actually produced a report: skip push/dispatch (no PR) and
|
|
# cancelled/skipped builds (no artifact — would otherwise warn spuriously below).
|
|
if: >-
|
|
github.event.workflow_run.event == 'pull_request' &&
|
|
github.event.workflow_run.conclusion != 'cancelled' &&
|
|
github.event.workflow_run.conclusion != 'skipped'
|
|
steps:
|
|
# Cross-run: pulls the artifact from the build's run, not this workflow's.
|
|
# continue-on-error so a missing/expired artifact doesn't fail the job; the next
|
|
# step surfaces it as a warning instead of silently dropping the comment.
|
|
- name: Download report artifact
|
|
id: dl
|
|
continue-on-error: true
|
|
uses: actions/download-artifact@v7
|
|
with:
|
|
name: pr-report
|
|
run-id: ${{ github.event.workflow_run.id }}
|
|
github-token: ${{ github.token }}
|
|
|
|
- name: Warn if report unavailable
|
|
if: steps.dl.outcome != 'success'
|
|
run: echo "::warning::pr-report artifact could not be downloaded (outcome=${{ steps.dl.outcome }}); no PR comment posted."
|
|
|
|
- name: Post or update comment
|
|
if: steps.dl.outcome == 'success'
|
|
uses: actions/github-script@v9
|
|
with:
|
|
script: |
|
|
const fs = require('fs');
|
|
if (!fs.existsSync('pr_report.md') || !fs.existsSync('pr_number.txt')) {
|
|
core.warning('Report artifact incomplete; nothing to post.');
|
|
return;
|
|
}
|
|
const marker = '<!-- unleashed-pr-report -->';
|
|
const body = fs.readFileSync('pr_report.md', 'utf8');
|
|
const issue_number = parseInt(fs.readFileSync('pr_number.txt', 'utf8').trim(), 10);
|
|
if (!Number.isInteger(issue_number)) {
|
|
core.setFailed('Invalid PR number in artifact.');
|
|
return;
|
|
}
|
|
const { owner, repo } = context.repo;
|
|
const comments = await github.paginate(github.rest.issues.listComments,
|
|
{ owner, repo, issue_number, per_page: 100 });
|
|
const existing = comments.find(c => c.body && c.body.includes(marker));
|
|
if (existing) {
|
|
await github.rest.issues.updateComment({ owner, repo, comment_id: existing.id, body });
|
|
} else {
|
|
await github.rest.issues.createComment({ owner, repo, issue_number, body });
|
|
}
|