Skip to content

Instantly share code, notes, and snippets.

@Fleshgrinder
Last active October 6, 2022 14:45
Show Gist options
  • Save Fleshgrinder/3a1f00b2d10e8ca8612d70a0b5b453a7 to your computer and use it in GitHub Desktop.
Save Fleshgrinder/3a1f00b2d10e8ca8612d70a0b5b453a7 to your computer and use it in GitHub Desktop.
Deletes a GitHub Workflow by deleting all its Runs.

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.

#!/usr/bin/env bash
set -Eeuo pipefail
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_path[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