fix: cancel running CI workflow before re-triggering and allow trusted GitHub Apps (#26461)
* fix: cancel running CI workflow before re-triggering and allow trusted bots Co-Authored-By: keith@cal.com <keithwillcode@gmail.com> * fix: remove hardcoded bot allowlist, keep only cancel-and-rerun improvement Co-Authored-By: keith@cal.com <keithwillcode@gmail.com> * fix: add app_id verification for trusted GitHub Apps (Graphite) Co-Authored-By: keith@cal.com <keithwillcode@gmail.com> * fix: simplify trusted bot check to use sender type, login, and installation context Co-Authored-By: keith@cal.com <keithwillcode@gmail.com> * chore: remove unnecessary comments Co-Authored-By: keith@cal.com <keithwillcode@gmail.com> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
0109427d04
commit
3ab6d9096e
1 file changed
+64
-14
@@ -19,21 +19,32 @@ jobs:
|
||||
with:
|
||||
script: |
|
||||
const adder = context.payload.sender.login;
|
||||
const senderType = context.payload.sender.type;
|
||||
const pr = context.payload.pull_request;
|
||||
const installation = context.payload.installation;
|
||||
|
||||
// Verify label adder has write access
|
||||
const { data: perm } = await github.rest.repos.getCollaboratorPermissionLevel({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
username: adder,
|
||||
});
|
||||
const trustedBotLogins = ['graphite-app[bot]'];
|
||||
let isAuthorized = false;
|
||||
|
||||
if (!['admin', 'maintain', 'write'].includes(perm.permission)) {
|
||||
core.setFailed(`${adder} does not have write access`);
|
||||
return;
|
||||
if (senderType === 'Bot' && installation && trustedBotLogins.includes(adder)) {
|
||||
console.log(`Label added by trusted GitHub App: ${adder}`);
|
||||
isAuthorized = true;
|
||||
}
|
||||
|
||||
console.log(`Label added by ${adder} (${perm.permission})`);
|
||||
if (!isAuthorized) {
|
||||
const { data: perm } = await github.rest.repos.getCollaboratorPermissionLevel({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
username: adder,
|
||||
});
|
||||
|
||||
if (!['admin', 'maintain', 'write'].includes(perm.permission)) {
|
||||
core.setFailed(`${adder} does not have write access`);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`Label added by ${adder} (${perm.permission})`);
|
||||
}
|
||||
|
||||
// Find the latest pr.yml run for this PR's head SHA
|
||||
const { data: runs } = await github.rest.actions.listWorkflowRuns({
|
||||
@@ -56,13 +67,52 @@ jobs:
|
||||
|
||||
const latestRun = matchingRuns[0];
|
||||
|
||||
// Check if workflow is still running - can't re-run in-progress workflows
|
||||
// If workflow is still running, cancel it first then re-run
|
||||
if (latestRun.status === 'in_progress' || latestRun.status === 'queued') {
|
||||
core.setFailed(`Workflow is still running (status: ${latestRun.status}). Wait for it to complete or cancel it first.`);
|
||||
return;
|
||||
console.log(`Workflow is running (status: ${latestRun.status}). Cancelling it first...`);
|
||||
|
||||
await github.rest.actions.cancelWorkflowRun({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
run_id: latestRun.id,
|
||||
});
|
||||
|
||||
// Wait for the workflow to be cancelled (poll with timeout)
|
||||
const maxWaitTime = 60000; // 60 seconds
|
||||
const pollInterval = 2000; // 2 seconds
|
||||
const startTime = Date.now();
|
||||
|
||||
while (Date.now() - startTime < maxWaitTime) {
|
||||
await new Promise(resolve => setTimeout(resolve, pollInterval));
|
||||
|
||||
const { data: updatedRun } = await github.rest.actions.getWorkflowRun({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
run_id: latestRun.id,
|
||||
});
|
||||
|
||||
if (updatedRun.status === 'completed') {
|
||||
console.log(`Workflow cancelled successfully (conclusion: ${updatedRun.conclusion})`);
|
||||
break;
|
||||
}
|
||||
|
||||
console.log(`Waiting for workflow to cancel... (status: ${updatedRun.status})`);
|
||||
}
|
||||
|
||||
// Check final status
|
||||
const { data: finalRun } = await github.rest.actions.getWorkflowRun({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
run_id: latestRun.id,
|
||||
});
|
||||
|
||||
if (finalRun.status !== 'completed') {
|
||||
core.setFailed(`Timed out waiting for workflow to cancel (status: ${finalRun.status})`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`Re-running workflow ${latestRun.id} (was: ${latestRun.conclusion})`);
|
||||
console.log(`Re-running workflow ${latestRun.id} (was: ${latestRun.conclusion || latestRun.status})`);
|
||||
|
||||
// Re-run preserves original context (PR, SHA, etc.)
|
||||
await github.rest.actions.reRunWorkflow({
|
||||
|
||||
Reference in new issue
Block a user