Last active
October 6, 2022 14:45
-
-
Save Fleshgrinder/3a1f00b2d10e8ca8612d70a0b5b453a7 to your computer and use it in GitHub Desktop.
Deletes a GitHub Workflow by deleting all its Runs.
This file contains hidden or 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
#!/usr/bin/env bash | |
set -Eeuo pipefail | |
# There is no button in the interface of GitHub (and as it seems also no API) with which workflows can be deleted. | |
# They are eventually removed automatically, but in case you want to clean up your Actions UI it is sometimes nice | |
# to have the possibility to get rid of workflows that are not required anymore. This interactive script allows you | |
# to achieve exactly that by deleting each individual run of a workflow, after which GitHub deletes the workflow. | |
declare -ir CONCURRENCY=${CONCURRENCY:-8} | |
# region https://no-color.org/ | |
if [[ "${NO_COLOR:-}" == '' ]]; then | |
readonly RESET='\033[0m' | |
readonly DIM='\033[2m' | |
readonly RESET_DIM='\033[22m' | |
readonly BOLD='\033[1m' | |
readonly RESET_BOLD='\033[22m' | |
readonly CYAN='\033[36m' | |
readonly RED='\033[31m' | |
readonly GREEN='\033[32m' | |
else | |
readonly RESET= | |
readonly DIM= | |
readonly RESET_DIM= | |
readonly BOLD= | |
readonly RESET_BOLD= | |
readonly CYAN= | |
readonly RED= | |
readonly GREEN= | |
fi | |
# endregion | |
dry_run=false | |
yes=false | |
while (($# > 0)); do | |
case "$1" in | |
-d | --dry-run) | |
dry_run=true | |
;; | |
-h | --help) | |
cat <<HELP | |
Delete GitHub Actions Workflows from this repository. | |
Usage: gh-delete-workflow [option]... | |
Options: | |
-d --dry-run Print what would be deleted, but do not delete anything. | |
-h --help Show this help and exit. | |
-y --yes I know what I am doing, stop asking me questions! | |
Environment: | |
CONCURRENCY=$CONCURRENCY Sets the concurrency level for requests. | |
HELP | |
exit 0 | |
;; | |
-y | --yes) | |
yes=true | |
;; | |
--) | |
break | |
;; | |
-*) | |
printf -- '%bUnknown option: %s%b\n' "$RED" "$1" "$RESET" | |
;; | |
*) | |
break | |
;; | |
esac | |
shift | |
done | |
readonly dry_run yes | |
if ! command -v gh &>/dev/null; then | |
printf -- '%bCould not find gh in PATH, make sure it is available: https://cli.github.com/%b\n' "$RED" "$RESET" >&2 | |
exit 1 | |
fi | |
workflow_names=() | |
workflow_paths=() | |
workflow_ids=() | |
while read -r workflow; do | |
eval "$workflow" | |
done < <(gh api '/repos/{owner}/{repo}/actions/workflows' --jq '.workflows |= sort_by(.name) | .workflows[] | "workflow_names+=('"'"'\(.name)'"'"');workflow_paths+=('"'"'\(.path)'"'"');workflow_ids+=(\(.id))"') | |
case ${#workflow_names[@]} in | |
0) | |
echo 'Nothing to delete, this repository does not have any workflows.' | |
exit 0 | |
;; | |
1) | |
readonly workflow_name=${workflow_names[0]} | |
readonly workflow_path=${workflow_paths[0]} | |
readonly workflow_id=${workflow_ids[0]} | |
printf 'There is only one workflow %b%s %b(%s)%b...\n' "$CYAN" "$workflow_name" "$DIM" "$workflow_id" "$RESET" | |
;; | |
*) | |
for ((i = 0; i < ${#workflow_names[@]}; i++)); do | |
printf -- '%b[%i]%b %s %b%s (%s)%b\n' "$CYAN" $((i + 1)) "$RESET" "${workflow_names[$i]}" "$DIM" "${workflow_paths[$i]}" "${workflow_ids[$i]}" "$RESET_DIM" | |
done | |
while :; do | |
printf -- '%bWhich workflow [1..%i]? ' "$CYAN" ${#workflow_names[@]} | |
read -r selection | |
if ((1 <= selection && selection <= ${#workflow_names[@]})); then | |
printf -- "%b" "$RESET" | |
((selection--)) | |
readonly selection | |
break | |
else | |
# shellcheck disable=SC2016 | |
printf -- '%bSelection `%s` is invalid, %bMUST%b be one of [1..%i], try again...%b\n' "$RED" "$selection" "$BOLD" "$RESET_BOLD" "${#workflow_names[@]}" "$RESET" >&2 | |
fi | |
done | |
readonly workflow_name=${workflow_names[$selection]} | |
readonly workflow_path=${workflow_paths[$selection]} | |
readonly workflow_id=${workflow_ids[$selection]} | |
;; | |
esac | |
unset workflow_names workflow_ids | |
if [[ "$dry_run" == false && "$yes" == false ]]; then | |
# shellcheck disable=SC2016 | |
printf -- 'Are you sure you want to delete workflow %b%s %b%s (%s)%b? %bYou cannot recover from this!%b [y/n] ' "$CYAN" "$workflow_name" "$DIM" "$workflow_path" "$workflow_id" "$RESET" "$RED" "$RESET" | |
read -rN1 reply | |
if [[ "$reply" != y ]]; then | |
case "$reply" in | |
n) response='\nOK' ;; | |
$'\n') response='You did not enter anything' ;; | |
*) response='\nAssuming you meant n' ;; | |
esac | |
printf -- '%b%b, aborting...%b\n' "$RED" "$response" "$RESET" | |
exit 0 | |
fi | |
unset reply | |
echo | |
fi | |
i=0 | |
while read -r run_id; do | |
if [[ "$dry_run" == true ]]; then | |
printf -- '%b💀 run %s%b\n' "$RED" "$run_id" "$RESET" | |
else | |
gh api -X DELETE "/repos/{owner}/{repo}/actions/runs/$run_id" & | |
fi | |
if ((++i == CONCURRENCY)); then | |
i=0 | |
wait | |
fi | |
done < <(gh api --paginate "/repos/{owner}/{repo}/actions/workflows/$workflow_id/runs" --jq '.workflow_runs[] | .id') | |
wait | |
printf -- '%bDone%b\n' "$GREEN" "$RESET" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment