Skip to content

Commit 6e0989c

Browse files
authored
Resolve PR by head SHA in coverage-comment workflow (#847)
Two issues with the previous "Resolve PR number" step: 1. Inline `${{ toJson(github.event) }}` interpolation inside `'...'` shell quoting could be broken by any single quote in the payload (e.g. an apostrophe in a commit message), producing the notorious `syntax error near unexpected token "else"`. 2. `workflow_run.pull_requests[]` is *always empty* for PRs whose head ref lives in a fork. By GitHub design, the default-branch `workflow_run` handler (which holds the write token) does not receive cross-repo PR linkage. The first PR through the new coverage workflow happened to come from a fork, so the comment was posted to the tracking issue instead of the PR. Replace the bash step with a github-script step: - reads `github.event` via an environment variable, immune to payload-quoting issues; - first tries `workflow_run.pull_requests[0]` for the same-repo branch case; - falls back to `GET /repos/{owner}/{repo}/commits/{sha}/pulls` (the "pull requests associated with commit" API), which is the only way to recover a PR number from a fork `workflow_run` payload; - prefers an open PR but tolerates a closed one if there's a squash-merge race between the build and this comment job; - falls through to the tracking-issue path only when neither source produces a PR. The downstream "Comment on PR" step is unchanged — it consumes the same `steps.pr.outputs.pr` it always did.
1 parent 34c9d32 commit 6e0989c

1 file changed

Lines changed: 45 additions & 23 deletions

File tree

.github/workflows/coverage-comment.yml

Lines changed: 45 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -119,31 +119,53 @@ jobs:
119119
120120
- name: Resolve PR number
121121
id: pr
122+
uses: actions/github-script@v7
122123
env:
123-
# Pass the event JSON via the environment rather than
124-
# interpolating it directly into the shell script. The
125-
# `${{ toJson(...) }}` expansion happens *before* bash
126-
# parses the script, so any single quote inside the JSON
127-
# (e.g. an apostrophe in a commit message or branch
128-
# name) would terminate the surrounding `'...'` quoting
129-
# and corrupt the rest of the step — manifesting as a
130-
# bewildering syntax error like
131-
# "syntax error near unexpected token `else`" several
132-
# commands later.
124+
# Pass the event JSON via the environment, not via inline
125+
# `${{ toJson(...) }}` interpolation. Actions resolves
126+
# `${{ ... }}` *before* the shell parses the script, so a
127+
# single quote anywhere in the payload (e.g. an apostrophe
128+
# in a commit message or branch name) would close the
129+
# surrounding `'...'` quoting and corrupt the rest of the
130+
# script.
133131
EVENT_JSON: ${{ toJson(github.event) }}
134-
run: |
135-
set -euo pipefail
136-
# workflow_run.pull_requests[] is empty for fork PRs and
137-
# for default-branch schedule/push runs. Empty == no PR
138-
# to comment on; fall through to the tracking-issue path.
139-
pr=$(jq -r '.workflow_run.pull_requests[0].number // empty' \
140-
<<<"$EVENT_JSON")
141-
echo "pr=$pr" >> "$GITHUB_OUTPUT"
142-
if [ -n "$pr" ]; then
143-
echo "Will comment on PR #$pr"
144-
else
145-
echo "No PR in workflow_run payload; will update tracking issue"
146-
fi
132+
with:
133+
github-token: ${{ secrets.GITHUB_TOKEN }}
134+
# Two-stage resolution:
135+
# 1. workflow_run.pull_requests[] — populated for PRs
136+
# from branches in the same repository.
137+
# 2. GET /repos/{owner}/{repo}/commits/{sha}/pulls —
138+
# works for fork PRs too, because GitHub indexes the
139+
# PR by the merge head SHA regardless of which repo
140+
# the head ref lives in. This is the only reliable
141+
# way to recover the PR number for a fork-originated
142+
# `workflow_run` payload, since `pull_requests[]` is
143+
# always empty in that case.
144+
# If both fail, fall through to the tracking-issue path.
145+
script: |
146+
const ev = JSON.parse(process.env.EVENT_JSON);
147+
const wr = ev.workflow_run;
148+
let pr = (wr.pull_requests && wr.pull_requests.length)
149+
? wr.pull_requests[0].number : 0;
150+
if (!pr) {
151+
core.info(
152+
`pull_requests[] empty (likely fork PR); ` +
153+
`looking up by head SHA ${wr.head_sha}`);
154+
const resp = await github.rest.repos.listPullRequestsAssociatedWithCommit({
155+
owner: context.repo.owner,
156+
repo: context.repo.repo,
157+
commit_sha: wr.head_sha,
158+
});
159+
// Prefer an open PR; fall back to any PR if only
160+
// closed ones match (e.g. squash-merged race).
161+
const open = resp.data.find(p => p.state === 'open');
162+
const any = resp.data[0];
163+
if (open) pr = open.number;
164+
else if (any) pr = any.number;
165+
}
166+
if (pr) core.info(`Will comment on PR #${pr}`);
167+
else core.info('No PR resolved; will update tracking issue');
168+
core.setOutput('pr', pr ? String(pr) : '');
147169
148170
# ------------------------------------------------------------
149171
# PR path: find-or-create the bot comment, dual-marker check.

0 commit comments

Comments
 (0)