From fda098a33fdf1066969940d3b2234c9162d72529 Mon Sep 17 00:00:00 2001 From: Gregory Haddow <93638800+ankorstore-haddowg@users.noreply.github.com> Date: Thu, 30 Mar 2023 12:36:46 +0100 Subject: [PATCH] feat: add cancel-redundant-workflows command (#28) --- src/commands/cancel-redundant-workflows.yml | 12 ++++++ src/scripts/cancel-redundant-workflows.sh | 42 +++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 src/commands/cancel-redundant-workflows.yml create mode 100755 src/scripts/cancel-redundant-workflows.sh diff --git a/src/commands/cancel-redundant-workflows.yml b/src/commands/cancel-redundant-workflows.yml new file mode 100644 index 0000000..27c0dad --- /dev/null +++ b/src/commands/cancel-redundant-workflows.yml @@ -0,0 +1,12 @@ +description: > + Cancels any previous running or on-hold workflows for the same branch. + + CircleCI can do this automatically when this feature is enabled in project settings for all branches EXCEPT the default branch. + There is however no way to filter what branches are affected or to include the default branch. + This command can be used with an appropriate `when` step to do this. + + This command requires a CIRCLE_TOKEN env var to be set with a valid CircleCi API Token. +steps: + - run: + name: Cancelling redundant workflows + command: << include(scripts/cancel-redundant-workflows.sh) >> diff --git a/src/scripts/cancel-redundant-workflows.sh b/src/scripts/cancel-redundant-workflows.sh new file mode 100755 index 0000000..e864709 --- /dev/null +++ b/src/scripts/cancel-redundant-workflows.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +if [ -z "$BASH" ]; then + echo "Bash not installed. Aborting." + exit 1 +fi +hash curl 2>/dev/null || { echo >&2 "curl is not installed. Aborting."; exit 1; } +if [ -z "$CIRCLE_TOKEN" ]; then + echo "CIRCLE_TOKEN env not set. Please set a valid CircleCi API Token in the env var CIRCLE_TOKEN"; + exit 1; +fi + +# Get the name of the workflow and the related pipeline number +CURRENT_WORKFLOW_URL="https://circleci.com/api/v2/workflow/${CIRCLE_WORKFLOW_ID}?circle-token=$CIRCLE_TOKEN" +curl -f -s --retry 3 --retry-all-errors "$CURRENT_WORKFLOW_URL" > /tmp/aks/current_wf.json +WORKFLOW_NAME="$(jq -r '.name' /tmp/aks/current_wf.json)" +CURRENT_PIPELINE_NUM="$(jq -r '.pipeline_number' /tmp/aks/current_wf.json)" + +# Get the IDs of pipelines created for the same branch. (Only consider pipelines that have a pipeline number smaller than the current pipeline) +PIPELINES_URL="https://circleci.com/api/v2/project/gh/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME/pipeline?circle-token=$CIRCLE_TOKEN&branch=$CIRCLE_BRANCH" +curl -f -s --retry 3 --retry-all-errors "$PIPELINES_URL" >> /tmp/aks/pipelines.json +PIPELINE_IDS=$(jq -r --argjson CURRENT_PIPELINE_NUM "$CURRENT_PIPELINE_NUM" '.items[]|select(.state == "created")|select(.number < $CURRENT_PIPELINE_NUM)|.id | values') + +## Get the IDs of currently running/on_hold workflows that have the same name as the current workflow, in all previously created pipelines. +if [ -n "$PIPELINE_IDS" ]; then + for PIPELINE_ID in $PIPELINE_IDS + do + curl -f -s --retry 3 --retry-all-errors "https://circleci.com/api/v2/pipeline/${PIPELINE_ID}/workflow?circle-token=$CIRCLE_TOKEN" | jq -r --arg workflow_name "${WORKFLOW_NAME}" '.items[] | select(.status == "on_hold" or .status == "running") | select(.name == $workflow_name) | .id | values' >> /tmp/aks/wf_to_cancel + done +fi + +## Cancel any currently running/on_hold workflow with the same name +if [ -s /tmp/aks/wf_to_cancel ]; then + echo "Cancelling the following redundant workflow(s):" + cat /tmp/aks/wf_to_cancel + while read -r WORKFLOW_ID; + do + curl -f -s --retry 3 --retry-all-errors --header "Circle-Token: $CIRCLE_TOKEN" --request POST "https://circleci.com/api/v2/workflow/$WORKFLOW_ID/cancel" + done < /tmp/aks/wf_to_cancel + else + echo "Nothing to cancel" +fi