Skip to content

Commit 19b915b

Browse files
Scope E2E workflow cancellation to the triggering PR branch.
Cross-PR pushes were cancelling unrelated in-flight Electron Playwright Tests runs because cancelActiveE2ERuns aborted every active workflow. Match runs by head_branch so only the same PR's stale runs are stopped. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 6d81908 commit 19b915b

3 files changed

Lines changed: 65 additions & 15 deletions

File tree

.github/workflows/e2e-functional.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,4 +388,5 @@ jobs:
388388
with:
389389
name: policy-test-results-${{ runner.os }}
390390
path: e2e/playwright-report
391+
if-no-files-found: ignore
391392
retention-days: 7

.github/workflows/e2e-pr-trigger.yml

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,9 @@ name: E2E PR Trigger
99
# opened/synchronize events do not add E2E/Run, and applying the override label
1010
# strips E2E/Run and cancels in-flight E2E runs.
1111
#
12-
# On synchronize: in-progress Electron Playwright Tests runs are cancelled before
13-
# re-adding the label so stale runs for the old commit don't block the new one.
14-
# Matterwick dispatches e2e-functional.yml via workflow_dispatch using the default
15-
# branch as the ref (so all E2E runs show head_branch: master). This makes it
16-
# impossible to distinguish runs by PR branch, so all in-progress E2E runs are
17-
# cancelled — which is correct behaviour since only one labelled PR triggers tests
18-
# at a time in this project.
12+
# On synchronize: in-progress Electron Playwright Tests runs for this PR are
13+
# cancelled before re-adding the label so stale runs for the old commit do not
14+
# block the new one. Runs on other PR branches are left running.
1915
#
2016
# The concurrency group ensures rapid pushes to the same PR don't queue multiple
2117
# label operations: only the most recent push proceeds.
@@ -87,7 +83,12 @@ jobs:
8783
}
8884
}
8985
90-
await cancelActiveE2ERuns({ github, context });
86+
await cancelActiveE2ERuns({
87+
github,
88+
context,
89+
prNumber: issue_number,
90+
headBranch: pr.head.ref,
91+
});
9192
await markE2EStatusesCancelled({
9293
github,
9394
context,
@@ -97,7 +98,12 @@ jobs:
9798
return;
9899
}
99100
100-
await cancelActiveE2ERuns({ github, context });
101+
await cancelActiveE2ERuns({
102+
github,
103+
context,
104+
prNumber: issue_number,
105+
headBranch: pr.head.ref,
106+
});
101107
102108
try {
103109
await github.rest.issues.removeLabel({
@@ -151,7 +157,12 @@ jobs:
151157
}
152158
}
153159
154-
await cancelActiveE2ERuns({ github, context });
160+
await cancelActiveE2ERuns({
161+
github,
162+
context,
163+
prNumber: issue_number,
164+
headBranch: pr.head.ref,
165+
});
155166
await markE2EStatusesCancelled({
156167
github,
157168
context,

e2e/utils/github-actions.js

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -152,12 +152,45 @@ async function markE2EStatusesCancelled({github, context, sha, reason = CANCELLE
152152
}
153153

154154
/**
155-
* Cancel all active Electron Playwright Tests workflow runs.
156-
* Matterwick dispatches via workflow_dispatch on the default branch, so runs
157-
* cannot be filtered reliably by PR branch — cancel every active run instead.
155+
* Return true when a workflow run belongs to the given PR.
156+
* Matterwick dispatches with version_name set to the PR head branch, so
157+
* head_branch on the run matches pull_request.head.ref.
158158
*/
159-
async function cancelActiveE2ERuns({github, context}) {
159+
function runBelongsToPr(run, headBranch) {
160+
return Boolean(headBranch && run.head_branch === headBranch);
161+
}
162+
163+
async function resolvePrHeadBranch({github, context, prNumber, headBranch}) {
164+
if (headBranch) {
165+
return headBranch;
166+
}
167+
168+
if (!prNumber) {
169+
return null;
170+
}
171+
172+
const {data: pr} = await github.rest.pulls.get({
173+
owner: context.repo.owner,
174+
repo: context.repo.repo,
175+
pull_number: prNumber,
176+
});
177+
return pr.head.ref;
178+
}
179+
180+
/**
181+
* Cancel active Electron Playwright Tests runs for a single PR.
182+
* Only runs whose head_branch matches the PR branch are cancelled so concurrent
183+
* E2E runs on other PRs are not interrupted.
184+
*/
185+
async function cancelActiveE2ERuns({github, context, prNumber, headBranch}) {
160186
const {owner, repo} = context.repo;
187+
const branch = await resolvePrHeadBranch({github, context, prNumber, headBranch});
188+
189+
if (!branch) {
190+
console.log('cancelActiveE2ERuns: no PR branch resolved — skipping cancellation');
191+
return 0;
192+
}
193+
161194
const {data: {workflows}} = await github.rest.actions.listRepoWorkflows({owner, repo});
162195
const e2eWorkflow = workflows.find((workflow) => workflow.name === E2E_WORKFLOW_NAME);
163196

@@ -178,9 +211,14 @@ async function cancelActiveE2ERuns({github, context}) {
178211
});
179212

180213
for (const run of workflowRuns) {
214+
if (!runBelongsToPr(run, branch)) {
215+
console.log(`Skipping E2E run ${run.id} (branch ${run.head_branch ?? 'unknown'} != ${branch})`);
216+
continue;
217+
}
218+
181219
try {
182220
await github.rest.actions.cancelWorkflowRun({owner, repo, run_id: run.id});
183-
console.log(`Cancelled E2E run ${run.id} (status: ${status})`);
221+
console.log(`Cancelled E2E run ${run.id} for branch ${branch} (status: ${status})`);
184222
cancelled += 1;
185223
} catch (error) {
186224
console.log(`Could not cancel run ${run.id}: ${error.message}`);

0 commit comments

Comments
 (0)