From a865dac30b28c52543cd3fce17b13cae6ec04b61 Mon Sep 17 00:00:00 2001 From: Thom Wiggers Date: Tue, 8 Sep 2020 09:55:37 +0200 Subject: [PATCH 1/4] Cancel all workflows but the latest --- action.yml | 6 +++++- src/index.ts | 38 +++++++++++++++++++++++++++----------- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/action.yml b/action.yml index f3c505bd..b9dc2c9a 100644 --- a/action.yml +++ b/action.yml @@ -2,7 +2,7 @@ name: 'Cancel Workflow Action' description: 'This Action will cancel any previous runs that are not `completed` for a given workflow.' author: styfle branding: - icon: 'stop-circle' + icon: 'stop-circle' color: 'white' inputs: workflow_id: @@ -15,6 +15,10 @@ inputs: access_token: description: 'Your GitHub Access Token, defaults to: {{ github.token }}' default: '${{ github.token }}' + required: true + all_but_latest: + description: "Cancel all actions but the last one" + required: false runs: using: 'node12' main: 'dist/index.js' diff --git a/src/index.ts b/src/index.ts index 1c9b2a27..6a11a383 100644 --- a/src/index.ts +++ b/src/index.ts @@ -27,6 +27,7 @@ async function main() { const token = core.getInput('access_token', { required: true }); const workflow_id = core.getInput('workflow_id', { required: false }); const ignore_sha = core.getInput('ignore_sha', { required: false }) === 'true'; + const all_but_latest = core.getInput('all_but_latest', { required: false }); console.log(`Found token: ${token ? 'yes' : 'no'}`); const workflow_ids: string[] = []; const octokit = github.getOctokit(token); @@ -58,20 +59,35 @@ async function main() { workflow_id, branch, }); + console.log(`Found ${data.total_count} runs total.`); - const branchWorkflows = data.workflow_runs.filter(run => run.head_branch === branch); - console.log(`Found ${branchWorkflows.length} runs for workflow ${workflow_id} on branch ${branch}`); - console.log(branchWorkflows.map(run => `- ${run.html_url}`).join('\n')); + let cancel_before; + if (all_but_latest) { + cancel_before = new Date(data.workflow_runs.reduce((a, b) => Math.max(a.created_at, b.created_at))); + } else { + cancel_before = new Date(current_run.created_at); + } - const runningWorkflows = branchWorkflows.filter(run => - (ignore_sha || run.head_sha !== headSha) && - run.status !== 'completed' && - new Date(run.created_at) < new Date(current_run.created_at) + const runningWorkflows = data.workflow_runs.filter( + run => run.head_branch === branch && (ignore_sha || run.head_sha !== headSha) && run.status !== 'completed' && + run != current_run && + new Date(run.created_at) < cancel_before ); - console.log(`with ${runningWorkflows.length} runs to cancel.`); - - for (const {id, head_sha, status, html_url} of runningWorkflows) { - console.log('Canceling run: ', {id, head_sha, status, html_url}); + console.log(`Found ${runningWorkflows.length} runs to cancel.`); + for (const {id, head_sha, status} of runningWorkflows) { + console.log('Cancelling another run: ', {id, head_sha, status}); + const res = await octokit.actions.cancelWorkflowRun({ + owner, + repo, + run_id: id + }); + console.log(`Cancel run ${id} responded with status ${res.status}`); + } + // Make sure we cancel this run itself if it's out-of-date. + // We postponed canceling this run because otherwise we couldn't cancel the rest. + if (all_but_latest && new Date(current_run.created_at) < cancel_before) { + // FIXME actions/core doesn't support cancelling, so we need to do it through the API + const id = current_run.id; const res = await octokit.actions.cancelWorkflowRun({ owner, repo, From e12516c96b762532b85ccc7d4770b6fb0481ab1d Mon Sep 17 00:00:00 2001 From: Thom Wiggers Date: Tue, 8 Sep 2020 10:00:19 +0200 Subject: [PATCH 2/4] Update README and fix #34 --- README.md | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index dc1de619..23ce227a 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ This includes runs with a [status](https://docs.github.com/en/rest/reference/che ## How does it work? -When you `git push`, this GitHub Action will capture the current Branch and SHA. It will query GitHub's API to find previous workflow runs that match the Branch but do not match the SHA. These in-progress runs will be canceled leaving only the latest run. +When you `git push`, this GitHub Action will capture the current Branch and SHA. It will query GitHub's API to find previous workflow runs that match the Branch but do not match the SHA. These in-progress runs will be cancelled leaving only this run. Read more about the [Workflow Runs API](https://docs.github.com/en/rest/reference/actions#workflow-runs). @@ -100,6 +100,28 @@ jobs: workflow_id: 479426 ``` +## Advanced: Cancel more recent workflows + +Because this action can only cancel workflows if it is actually being run, it only helps if the pipeline isn't saturated and there are still runners available to schedule the workflow. +By default, this action does not cancel any workflows older than itself. The optional flag ``all_but_latest`` switches to a mode where the action also cancels itself and all later-scheduled workflows but the last one. + +```yml +name: Cancel +on: [push] +jobs: + cancel: + name: 'Cancel Previous Runs' + runs-on: ubuntu-latest + timeout-minutes: 3 + steps: + - uses: styfle/cancel-workflow-action@0.8.0 + with: + all_but_latest: true + access_token: ${{ github.token }} +``` + +At the time of writing `0.8.0` is the latest release but you can select any [release](https://github.com/styfle/cancel-workflow-action/releases). + ## Contributing - Clone this repo From a7eadb6f3809d6ae84fa62ee7bd8538e289cb9a4 Mon Sep 17 00:00:00 2001 From: Thom Wiggers Date: Tue, 16 Feb 2021 11:36:28 +0100 Subject: [PATCH 3/4] remove fixme --- src/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 6a11a383..e2c250df 100644 --- a/src/index.ts +++ b/src/index.ts @@ -86,7 +86,6 @@ async function main() { // Make sure we cancel this run itself if it's out-of-date. // We postponed canceling this run because otherwise we couldn't cancel the rest. if (all_but_latest && new Date(current_run.created_at) < cancel_before) { - // FIXME actions/core doesn't support cancelling, so we need to do it through the API const id = current_run.id; const res = await octokit.actions.cancelWorkflowRun({ owner, From 33102daca210322241825dd61b991041a7796311 Mon Sep 17 00:00:00 2001 From: Steven Date: Sat, 10 Apr 2021 21:17:28 -0400 Subject: [PATCH 4/4] Double "L" to single "L" --- README.md | 2 +- src/index.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 23ce227a..0b204e7d 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ This includes runs with a [status](https://docs.github.com/en/rest/reference/che ## How does it work? -When you `git push`, this GitHub Action will capture the current Branch and SHA. It will query GitHub's API to find previous workflow runs that match the Branch but do not match the SHA. These in-progress runs will be cancelled leaving only this run. +When you `git push`, this GitHub Action will capture the current Branch and SHA. It will query GitHub's API to find previous workflow runs that match the Branch but do not match the SHA. These in-progress runs will be canceled leaving only this run. Read more about the [Workflow Runs API](https://docs.github.com/en/rest/reference/actions#workflow-runs). diff --git a/src/index.ts b/src/index.ts index e2c250df..fd06deba 100644 --- a/src/index.ts +++ b/src/index.ts @@ -75,7 +75,7 @@ async function main() { ); console.log(`Found ${runningWorkflows.length} runs to cancel.`); for (const {id, head_sha, status} of runningWorkflows) { - console.log('Cancelling another run: ', {id, head_sha, status}); + console.log('Canceling run: ', {id, head_sha, status, html_url}); const res = await octokit.actions.cancelWorkflowRun({ owner, repo,