| name: PR Comment |
| |
| on: |
| workflow_run: |
| workflows: ["Build"] |
| types: |
| - completed |
| |
| jobs: |
| # Resolve the PR number from trusted workflow_run metadata, NOT from build artifacts: a forked PR |
| # controls its own Build run and could plant any number, which the privileged jobs below would |
| # then post to. Same-repo PRs populate workflow_run.pull_requests; for forks it is empty, so look |
| # the PR up by the trusted head SHA. |
| pr_number: |
| if: github.event.workflow_run.event == 'pull_request' |
| runs-on: ubuntu-latest |
| permissions: |
| contents: read |
| pull-requests: read |
| outputs: |
| number: ${{ steps.resolve.outputs.number }} |
| steps: |
| - name: Resolve PR number |
| id: resolve |
| env: |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| REPO: ${{ github.repository }} |
| HEAD_SHA: ${{ github.event.workflow_run.head_sha }} |
| HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }} |
| HEAD_REPO: ${{ github.event.workflow_run.head_repository.full_name }} |
| PRS_JSON: ${{ toJSON(github.event.workflow_run.pull_requests) }} |
| run: | |
| # Every lookup is best-effort: on any miss the number stays empty and the comment jobs |
| # below simply skip (never a failed check). |
| # Same-repo PRs: workflow_run.pull_requests is populated. |
| num=$(printf '%s' "$PRS_JSON" | jq -r '.[0].number // empty') |
| # Fork PRs: pull_requests is empty. Find the open PR by its trusted head ref and confirm |
| # its head SHA matches the built commit. |
| if [ -z "$num" ] && [ -n "$HEAD_BRANCH" ] && [ -n "$HEAD_REPO" ]; then |
| num=$(gh api --method GET "repos/$REPO/pulls" \ |
| -f state=open -f head="${HEAD_REPO%%/*}:$HEAD_BRANCH" \ |
| --jq '[.[] | select(.head.sha == env.HEAD_SHA)][0].number // empty' 2>/dev/null || true) |
| fi |
| echo "number=$num" >> "$GITHUB_OUTPUT" |
| |
| # --------------------------------------- |
| # Combine the rigs' HIL reports into one sticky PR comment (one table per rig). |
| # Runs here (workflow_run / base-repo context) rather than in build.yml so it also works on |
| # forked PRs, whose build-side GITHUB_TOKEN is read-only and cannot post comments. Posts even |
| # on build/HIL failure (when the report matters most); skips only on cancellation. |
| # --------------------------------------- |
| hil-comment: |
| needs: pr_number |
| if: > |
| github.event.workflow_run.conclusion != 'cancelled' && |
| needs.pr_number.outputs.number != '' |
| runs-on: ubuntu-latest |
| permissions: |
| actions: read |
| pull-requests: write |
| steps: |
| - name: Download HIL reports |
| uses: actions/download-artifact@v5 |
| with: |
| run-id: ${{ github.event.workflow_run.id }} |
| github-token: ${{ secrets.GITHUB_TOKEN }} |
| pattern: hil-report-* |
| path: hil-reports |
| continue-on-error: true |
| |
| - name: Combine rig reports (one table per rig) |
| id: combine |
| run: | |
| shopt -s nullglob |
| dirs=(hil-reports/hil-report-*) |
| if [ ${#dirs[@]} -eq 0 ]; then |
| # No rig produced a report: PR selection matched no board anywhere, or the |
| # HIL jobs did not run at all. Post it rather than exiting, so a table from |
| # an earlier push is replaced instead of being left to look current. |
| echo "No HIL reports found" |
| { |
| echo "## Hardware-in-the-loop (HIL) Test Report" |
| echo |
| echo "_No HIL run for this push (no affected boards, or hardware testing did not run)._" |
| } > hil_combined.md |
| echo "found=true" >> "$GITHUB_OUTPUT" |
| exit 0 |
| fi |
| { |
| echo "## Hardware-in-the-loop (HIL) Test Report" |
| echo |
| for d in "${dirs[@]}"; do |
| [ -d "$d" ] || continue |
| echo "### ${d#hil-reports/hil-report-}" |
| echo |
| cat "$d/hil_report.md" 2>/dev/null || echo "_no report produced_" |
| echo |
| done |
| } > hil_combined.md |
| # Fork PRs can influence report content and this job posts in base-repo context, so |
| # neutralize @-mentions (insert a zero-width space) to prevent notification abuse. |
| zwsp=$(printf '\342\200\213') |
| sed -i -E "s/@([A-Za-z0-9_-])/@${zwsp}\1/g" hil_combined.md |
| cat hil_combined.md |
| echo "found=true" >> "$GITHUB_OUTPUT" |
| |
| - name: Post HIL report as sticky PR comment |
| if: steps.combine.outputs.found == 'true' |
| uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 # v2.9.4 |
| with: |
| header: hil-report |
| path: hil_combined.md |
| number: ${{ needs.pr_number.outputs.number }} |
| |
| # --------------------------------------- |
| # Code size of the PR's CI-pinned boards against the master push run of the commit it was |
| # built against (code_size_ci.py baseline): no base build, only the snapshots both Build |
| # runs uploaded. Artifacts are PR-built data, parsed only by the default branch's scripts |
| # and rendered escaped. Report only: this job never fails the PR. |
| # --------------------------------------- |
| code-size-comment: |
| needs: pr_number |
| if: > |
| github.event.workflow_run.conclusion != 'cancelled' && |
| needs.pr_number.outputs.number != '' |
| runs-on: ubuntu-latest |
| continue-on-error: true |
| permissions: |
| contents: read |
| actions: read |
| pull-requests: write |
| env: |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| REPO: ${{ github.repository }} |
| steps: |
| - name: Checkout default branch scripts |
| uses: actions/checkout@v6 |
| with: |
| persist-credentials: false |
| |
| # every step up to the freshness check must succeed, even with nothing to compare: |
| # a failed one would skip the post and leave an earlier push's table looking current |
| - name: Download code size snapshots |
| continue-on-error: true |
| uses: actions/download-artifact@v5 |
| with: |
| run-id: ${{ github.event.workflow_run.id }} |
| github-token: ${{ secrets.GITHUB_TOKEN }} |
| pattern: code-size-* |
| path: ${{ runner.temp }}/code-size/current |
| |
| - name: Find the baseline |
| id: baseline |
| run: | |
| CS="$RUNNER_TEMP/code-size" |
| mkdir -p "$CS/current" "$CS/out" |
| # it reports its own failures in the info; a crash still must not skip the post |
| python3 .github/scripts/code_size_ci.py baseline --repo "$REPO" --current "$CS/current" \ |
| --info "$CS/baseline.json" || echo "::warning::code_size_ci.py baseline crashed" |
| echo "run_id=$(jq -r '.run_id // empty' "$CS/baseline.json")" >> "$GITHUB_OUTPUT" |
| |
| - name: Download baseline snapshots |
| if: steps.baseline.outputs.run_id != '' |
| continue-on-error: true |
| uses: actions/download-artifact@v5 |
| with: |
| run-id: ${{ steps.baseline.outputs.run_id }} |
| github-token: ${{ secrets.GITHUB_TOKEN }} |
| pattern: code-size-* |
| path: ${{ runner.temp }}/code-size/base |
| |
| - name: Compare against the baseline |
| env: |
| RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} |
| run: | |
| CS="$RUNNER_TEMP/code-size" |
| if ! python3 tools/code_size.py compare "$CS/current" "$CS/base" -o "$CS/out" --symbols \ |
| --baseline-info "$CS/baseline.json"; then |
| printf '## Code size\n\n_The comparison failed._\n' > "$CS/out/comment.md" |
| fi |
| echo "_[Full report]($RUN_URL)_" >> "$CS/out/comment.md" |
| # the job summary caps at 1 MiB |
| if [ -f "$CS/out/code-size.md" ]; then head -c 1000000 "$CS/out/code-size.md" >> "$GITHUB_STEP_SUMMARY"; fi |
| |
| - name: Upload full report |
| continue-on-error: true |
| uses: actions/upload-artifact@v7 |
| with: |
| name: code-size-report |
| path: ${{ runner.temp }}/code-size/out/code-size.* |
| |
| - name: Skip a superseded run |
| id: current |
| env: |
| PR: ${{ needs.pr_number.outputs.number }} |
| RUN_ID: ${{ github.event.workflow_run.id }} |
| ATTEMPT: ${{ github.event.workflow_run.run_attempt }} |
| HEAD_SHA: ${{ github.event.workflow_run.head_sha }} |
| run: | |
| if python3 .github/scripts/code_size_ci.py is-current --repo "$REPO" --pr "$PR" \ |
| --run-id "$RUN_ID" --attempt "$ATTEMPT" --head-sha "$HEAD_SHA"; then |
| echo "post=true" >> "$GITHUB_OUTPUT" |
| fi |
| |
| - name: Post code size as sticky PR comment |
| if: steps.current.outputs.post == 'true' |
| uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 # v2.9.4 |
| with: |
| header: code-size |
| path: ${{ runner.temp }}/code-size/out/comment.md |
| number: ${{ needs.pr_number.outputs.number }} |