Skip to content

Commit 7b09361

Browse files
committed
Add pull_request_target trigger support to release-post-comment workflow
This implements a hybrid trigger approach to enable PR comment posting for both fork and non-fork PRs: - For non-fork PRs: workflow_run trigger works as before (elegant, no polling) - For fork PRs: pull_request_target trigger with polling (new capability) GitHub's workflow_run trigger does not fire for fork PRs due to security restrictions. This change adds pull_request_target as a fallback trigger that polls/waits for the release workflow to complete. Changes: 1. Added pull_request_target trigger for opened/synchronize events 2. Added wait-for-release job that polls for release completion (60 min timeout) 3. Updated check-release-exists job to handle both trigger types 4. Updated find-wstest JavaScript to use optional chaining for context 5. Updated workflow_run_url construction to handle both trigger contexts The polling approach mirrors the old implementation (commit 1c989ee) but is now used ONLY for fork PRs, while non-fork PRs continue to use the more efficient workflow_run trigger without polling.
1 parent bd54b7d commit 7b09361

File tree

1 file changed

+117
-4
lines changed

1 file changed

+117
-4
lines changed

.github/workflows/release-post-comment.yml

Lines changed: 117 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,16 @@ name: release-post-comment
33
on:
44
# Trigger after release workflow completes (ensures all 4 base workflows finished)
55
# release.yml waits for: wheels, wheels-docker, wstest, main
6+
# NOTE: workflow_run does NOT trigger for fork PRs (GitHub security restriction)
67
workflow_run:
78
workflows: ["release"]
89
types: [completed]
910

11+
# Fallback trigger for fork PRs (workflow_run doesn't fire for these)
12+
# Will poll/wait for release to be ready before posting comment
13+
pull_request_target:
14+
types: [opened, synchronize]
15+
1016
# Manual dispatch for debugging
1117
workflow_dispatch:
1218
inputs:
@@ -35,9 +41,102 @@ jobs:
3541
# IMPORTANT: we still need .cicd as a Git submodule in the using repo though!
3642
# because e.g. identifiers.yml wants to access scripts/sanitize.sh !
3743

44+
wait-for-release:
45+
name: Wait for release (pull_request_target only)
46+
needs: identifiers
47+
# Only run when triggered by pull_request_target (fork PRs)
48+
if: github.event_name == 'pull_request_target'
49+
runs-on: ubuntu-latest
50+
51+
steps:
52+
- name: Wait for release workflow to complete
53+
uses: actions/github-script@v7
54+
with:
55+
script: |
56+
const maxWaitMinutes = 60; // Maximum wait time
57+
const pollIntervalSeconds = 30; // Check every 30 seconds
58+
const maxAttempts = (maxWaitMinutes * 60) / pollIntervalSeconds;
59+
60+
const commitSha = context.payload.pull_request.head.sha;
61+
console.log(`Waiting for release workflow to complete for commit: ${commitSha}`);
62+
console.log(`Max wait: ${maxWaitMinutes} minutes, polling every ${pollIntervalSeconds} seconds`);
63+
64+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
65+
console.log(`\nAttempt ${attempt}/${maxAttempts} - Checking for release workflow...`);
66+
67+
// Check if release workflow has completed for this commit
68+
const { data: runs } = await github.rest.actions.listWorkflowRunsForRepo({
69+
owner: context.repo.owner,
70+
repo: context.repo.repo,
71+
workflow_id: 'release.yml',
72+
head_sha: commitSha,
73+
per_page: 10
74+
});
75+
76+
const releaseRun = runs.workflow_runs.find(run =>
77+
run.head_sha === commitSha &&
78+
run.status === 'completed'
79+
);
80+
81+
if (releaseRun) {
82+
console.log(`✅ Release workflow completed with status: ${releaseRun.conclusion}`);
83+
console.log(` Run URL: ${releaseRun.html_url}`);
84+
85+
if (releaseRun.conclusion === 'success') {
86+
console.log('Release workflow succeeded - proceeding with comment posting');
87+
return;
88+
} else {
89+
core.setFailed(`Release workflow completed with conclusion: ${releaseRun.conclusion}`);
90+
return;
91+
}
92+
}
93+
94+
// Check if any base workflows are still running
95+
const baseWorkflows = ['main', 'wheels', 'wheels-docker', 'wstest'];
96+
const runningWorkflows = [];
97+
98+
for (const workflowName of baseWorkflows) {
99+
const { data: workflowRuns } = await github.rest.actions.listWorkflowRunsForRepo({
100+
owner: context.repo.owner,
101+
repo: context.repo.repo,
102+
workflow_id: `${workflowName}.yml`,
103+
head_sha: commitSha,
104+
per_page: 5
105+
});
106+
107+
const workflowRun = workflowRuns.workflow_runs.find(run => run.head_sha === commitSha);
108+
if (workflowRun && workflowRun.status !== 'completed') {
109+
runningWorkflows.push(`${workflowName} (${workflowRun.status})`);
110+
}
111+
}
112+
113+
if (runningWorkflows.length > 0) {
114+
console.log(`⏳ Base workflows still running: ${runningWorkflows.join(', ')}`);
115+
} else {
116+
console.log('⏳ All base workflows completed, waiting for release workflow...');
117+
}
118+
119+
if (attempt < maxAttempts) {
120+
console.log(`Sleeping ${pollIntervalSeconds} seconds before next check...`);
121+
await new Promise(resolve => setTimeout(resolve, pollIntervalSeconds * 1000));
122+
}
123+
}
124+
125+
core.setFailed(`Timeout: Release workflow did not complete within ${maxWaitMinutes} minutes`);
126+
127+
38128
check-release-exists:
39129
name: Check if release created (Early Exit Pattern)
40-
needs: identifiers
130+
needs: [identifiers, wait-for-release]
131+
# For pull_request_target: wait-for-release must succeed
132+
# For workflow_run: proceed immediately (release already completed)
133+
# For workflow_dispatch: proceed immediately (manual trigger)
134+
if: |
135+
always() &&
136+
needs.identifiers.result == 'success' &&
137+
(github.event_name == 'workflow_run' ||
138+
github.event_name == 'workflow_dispatch' ||
139+
(github.event_name == 'pull_request_target' && needs.wait-for-release.result == 'success'))
41140
runs-on: ubuntu-latest
42141
outputs:
43142
should_process: ${{ steps.check.outputs.should_process }}
@@ -266,8 +365,12 @@ jobs:
266365
uses: actions/github-script@v7
267366
with:
268367
script: |
269-
const commitSha = context.payload.workflow_run.head_sha;
368+
// Handle both workflow_run and pull_request_target triggers
369+
const commitSha = context.payload.workflow_run?.head_sha ||
370+
context.payload.pull_request?.head.sha ||
371+
context.sha;
270372
console.log(`Finding wstest workflow for commit: ${commitSha}`);
373+
console.log(`Triggered by: ${context.eventName}`);
271374
272375
const { data: runs } = await github.rest.actions.listWorkflowRunsForRepo({
273376
owner: context.repo.owner,
@@ -367,7 +470,13 @@ jobs:
367470
fi
368471
fi
369472
370-
WORKFLOW_RUN_URL="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${{ github.event.workflow_run.id }}"
473+
# Construct workflow run URL (handle both workflow_run and pull_request_target triggers)
474+
if [ "${{ github.event_name }}" = "workflow_run" ]; then
475+
WORKFLOW_RUN_URL="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${{ github.event.workflow_run.id }}"
476+
else
477+
# For pull_request_target or workflow_dispatch, link to current run
478+
WORKFLOW_RUN_URL="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${{ github.run_id }}"
479+
fi
371480
372481
# Read release notes (already fetched)
373482
RELEASE_NOTES=$(cat release-notes.md)
@@ -444,8 +553,12 @@ jobs:
444553
uses: actions/github-script@v7
445554
with:
446555
script: |
447-
const commitSha = context.payload.workflow_run.head_sha;
556+
// Handle both workflow_run and pull_request_target triggers
557+
const commitSha = context.payload.workflow_run?.head_sha ||
558+
context.payload.pull_request?.head.sha ||
559+
context.sha;
448560
console.log(`Finding wstest workflow for commit: ${commitSha}`);
561+
console.log(`Triggered by: ${context.eventName}`);
449562
450563
const { data: runs } = await github.rest.actions.listWorkflowRunsForRepo({
451564
owner: context.repo.owner,

0 commit comments

Comments
 (0)