-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
added curlable script to cancel circleci workflows
- Loading branch information
1 parent
34bdac7
commit 5ced9a9
Showing
1 changed file
with
158 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
#!/usr/bin/env bash | ||
# vim: et sr sw=4 ts=4 smartindent: | ||
# Cancels redundant PR builds on circleci pipelines. | ||
# Expected to be run from Github Actions. | ||
# | ||
# This only works for PR branches as it relies on | ||
# env var GITHUB_HEAD_REF which only exists for PRs | ||
# in github actions. | ||
# | ||
# This is by design - generally we don't want to cancel | ||
# builds of commits on release or main branches as sometimes | ||
# we need to deploy different commits sequentially rather than | ||
# bundled. However commits on a PR generally should get squashed | ||
# as they are all part of the same feature or bugfix and we only | ||
# need to built the HEAD of it. | ||
|
||
REQUIRED_VARS=" | ||
CIRCLE_TOKEN | ||
CCI_ORG_NAME | ||
GH_BRANCH | ||
GITHUB_HEAD_REF | ||
GITHUB_REPOSITORY | ||
" | ||
|
||
CCI_GITHUB_APP="${CCI_GITHUB_APP:-}" # set to true if you access CircleCi with Github App | ||
CCI_API="https://circleci.com/api/v2" | ||
|
||
# If you access circleci with github app and not oauth | ||
# set CCI_ORG_NAME to your Circleci org id (see your org settings) | ||
if [[ -n "$CCI_GITHUB_APP" ]]; then | ||
if [[ -z "$CCI_ORG_NAME" ]]; then | ||
echo >&2 "ERROR: using CCI_GITHUB_APP: set env var CCI_ORG_NAME to your CircleCI org ID" | ||
exit 1 | ||
fi | ||
CCI_VCS_SLUG="circleci" | ||
else | ||
# defaults when using CircleCI oauth, not github app | ||
CCI_VCS_SLUG="gh" | ||
CCI_ORG_NAME="${GITHUB_REPOSITORY}" | ||
fi | ||
|
||
declare -a WORKFLOWS_TO_CANCEL=() | ||
|
||
set_GH_BRANCH() { | ||
GH_BRANCH="" | ||
case "${GITHUB_EVENT_NAME:-}" in | ||
pull_request*) GH_BRANCH="$GITHUB_HEAD_REF" ;; | ||
*) GH_BRANCH="$GITHUB_REF_NAME" ;; | ||
esac | ||
|
||
if [[ -z "$GH_BRANCH" ]]; then | ||
echo >&2 "ERROR: couldn't set GH_BRANCH based on trigger event [${GITHUB_EVENT_NAME:-}]" | ||
return 1 | ||
fi | ||
|
||
export GH_BRANCH | ||
return 0 | ||
} | ||
|
||
required_vars() { | ||
local rc=0 | ||
local required_vars="$1" | ||
local this_var="" | ||
for this_var in $required_vars; do | ||
if ! check_var_defined $this_var | ||
then | ||
failed="${failed}\$$this_var " | ||
rc=1 | ||
fi | ||
done | ||
[[ $rc -ne 0 ]] && echo >&2 "ERROR: following vars must be set in env:\n$failed" | ||
return $rc | ||
} | ||
|
||
check_var_defined() { [[ ! -z "${!1}" ]] ; } | ||
|
||
pipelines_for_branch() { | ||
local o="" | ||
o=$( | ||
curl -sS --request GET \ | ||
--url "$CCI_API/project/${CCI_VCS_SLUG}/${CCI_ORG_NAME}/pipeline?branch=$GH_BRANCH" \ | ||
--header "Circle-Token: ${CIRCLE_TOKEN}" \ | ||
| jq -r '.items[].id' | ||
) | ||
|
||
if [[ $? -ne 0 ]] || [[ -z "${o:-}" ]]; then | ||
echo >&2 "ERROR: failed to get pipelines for branch $GH_BRANCH" | ||
return 1 | ||
else | ||
echo "$o" | ||
return 0 | ||
fi | ||
} | ||
|
||
cancel_workflows() { | ||
local rc=0 | ||
for id in ${WORKFLOWS_TO_CANCEL[@]}; do | ||
echo "INFO: attempting to cancel workflow id $id" | ||
curl --request POST \ | ||
--url "$CCI_API/workflow/$id/cancel" \ | ||
--header "Circle-Token: ${CIRCLE_TOKEN}" \ | ||
|| rc=1 | ||
done | ||
|
||
return $rc | ||
} | ||
|
||
workflow_for_pipeline() { | ||
local pipeline_id="$1" | ||
local o="" | ||
o=$( | ||
curl -sS --request GET \ | ||
--url "${CCI_API}/pipeline/${pipeline_id}/workflow" \ | ||
--header "Circle-Token: ${CIRCLE_TOKEN}" \ | ||
| jq -r '.items[] | select(.status | test("running|failing|on_hold")) | .id' | ||
) | ||
if [[ $? -ne 0 ]]; then | ||
echo >&2 "ERROR: failed to get single workflow for pipeline $pipeline_id" | ||
return 1 | ||
else | ||
echo "$o" | ||
return 0 | ||
fi | ||
} | ||
|
||
main() { | ||
set_GH_BRANCH || return 1 | ||
required_vars "$REQUIRED_VARS" || return 1 | ||
|
||
echo "INFO: Getting pipelines for branch $GH_BRANCH" | ||
pipeline_ids=$(pipelines_for_branch) || return 1 | ||
|
||
local rc=0 | ||
for pipeline_id in $pipeline_ids; do | ||
! workflow_id=$(workflow_for_pipeline "$pipeline_id") && rc=1 && continue | ||
[[ -n "$workflow_id" ]] && WORKFLOWS_TO_CANCEL+=("$workflow_id") | ||
done | ||
|
||
if [[ ${#WORKFLOWS_TO_CANCEL[@]} -lt 1 ]]; then | ||
echo "INFO: found no active workflows to cancel." | ||
return 0 | ||
fi | ||
|
||
echo "INFO: will cancel these workflow ids:" ${WORKFLOWS_TO_CANCEL[*]} | ||
if cancel_workflows | ||
then | ||
echo "INFO: all currently running workflows cancelled successfully" | ||
return 0 | ||
else | ||
echo "INFO: Didn't kill all workflows successfully." | ||
echo "INFO: Please clean them up manually via the circleci dashboard" | ||
return 1 | ||
fi | ||
|
||
} | ||
|
||
main | ||
exit 0 |