A utility script for managing GitHub Actions workflow runs. Provides flexible options for bulk deletion of workflow runs with safety features.
- Delete all workflow runs in a repository
- Delete workflow runs with a specific name
- Keep N most recent workflow runs and delete the rest
- Dry run mode to preview deletions
- Progress tracking and feedback
- Smart workflow name display
- Install Homebrew (if not already installed):
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
- Install GitHub CLI and jq:
brew install gh jq
- Authenticate GitHub CLI:
gh auth login
Follow the interactive prompts to complete authentication.
- Verify installations:
gh --version
jq --version
gh auth status
- Create script directory and file:
mkdir -p ~/bin
touch ~/bin/gh-workflow-delete
chmod +x ~/bin/gh-workflow-delete
- Add the bin directory to PATH (if not already there):
if ! grep -q 'if \[ -d "$HOME/bin" \]' ~/.zshrc; then echo 'if [ -d "$HOME/bin" ]; then export PATH="$HOME/bin:$PATH"; fi' >> ~/.zshrc; fi
- Reload shell configuration:
source ~/.zshrc
- Add the script content to
~/bin/gh-workflow-delete
:
#!/bin/bash
function gh_bulk_delete_workflow_runs() {
local repo=$1
local strategy=$2
local value=$3
local dry_run=$4
# Fetch workflow runs
echo "Fetching workflow runs..."
local runs=$(gh api repos/$repo/actions/runs --paginate | jq -r '.workflow_runs[] | "\(.id)|\(.name)|\(.display_title)|\(.head_branch)"')
echo "Processing runs..."
case "$strategy" in
"all")
echo "Deleting all workflow runs..."
;;
"byName")
echo "Deleting all workflow runs with name: $value"
runs=$(echo "$runs" | grep "^[0-9]*|$value|")
;;
"keepRecent")
echo "Keeping $value most recent workflow runs..."
runs=$(echo "$runs" | sort -t'|' -k1,1r | tail -n +$((value + 1)))
;;
*)
echo "Invalid strategy: $strategy"
return 1
;;
esac
local total=0
while IFS='|' read -r id name display_title branch; do
if [[ -n "$id" ]]; then
# Format the workflow title based on whether name and display_title are the same
local workflow_title
if [[ "$name" == "$display_title" ]]; then
workflow_title="$name"
else
workflow_title="$name: $display_title"
fi
if [[ "$dry_run" == "true" ]]; then
echo "[DRY RUN] Would delete run Workflow: $workflow_title ($id)..."
else
echo "Deleting run Workflow: $workflow_title ($id)..."
gh api -X DELETE "repos/$repo/actions/runs/$id" --silent
fi
((total++))
fi
done <<< "$runs"
if [[ "$dry_run" == "true" ]]; then
echo "[DRY RUN] Would delete $total workflow runs from $repo"
else
echo "Deleted $total workflow runs from $repo"
fi
}
# Parse command line arguments
parse_args() {
local repo=$1
local dry_run=false
shift
if [[ -z "$repo" ]]; then
echo "Usage: gh-workflow-delete <owner/repo> [--name <workflow-name> | --keep <count>] [--dry-run]" >&2
return 1
fi
# Check for --dry-run flag anywhere in the arguments
if [[ "$@" =~ "--dry-run" ]]; then
dry_run=true
# Remove --dry-run from arguments
set -- "${@/--dry-run/}"
fi
case "$1" in
--name)
if [[ -z "$2" ]]; then
echo "--name requires a workflow name" >&2
return 1
fi
gh_bulk_delete_workflow_runs "$repo" "byName" "$2" "$dry_run"
;;
--keep)
if [[ ! "$2" =~ ^[0-9]+$ ]]; then
echo "--keep requires a non-negative number" >&2
return 1
fi
gh_bulk_delete_workflow_runs "$repo" "keepRecent" "$2" "$dry_run"
;;
"")
gh_bulk_delete_workflow_runs "$repo" "all" "" "$dry_run"
;;
*)
echo "Invalid option. Use --name <workflow-name> or --keep <count>" >&2
return 1
;;
esac
}
# Execute with provided arguments
parse_args "$@"
gh-workflow-delete username/repository
gh-workflow-delete username/repository --name "CI/CD Pipeline"
gh-workflow-delete username/repository --keep 5
To preview deletions without actually deleting:
gh-workflow-delete username/repository --dry-run
gh-workflow-delete username/repository --name "CI/CD Pipeline" --dry-run
gh-workflow-delete username/repository --keep 5 --dry-run
The script provides informative output about each workflow run:
- When workflow name and display title are the same:
Workflow: Update Vercel Badge (1234567)...
- When workflow name and display title differ:
Workflow: CI: Build and Test (1234567)...
-
If the script isn't found:
- Verify ~/bin is in your PATH:
echo $PATH
- Check script permissions:
ls -l ~/bin/gh-workflow-delete
- Reload shell configuration:
source ~/.zshrc
- Verify ~/bin is in your PATH:
-
Permission errors:
- Verify GitHub CLI authentication:
gh auth status
- Check repository permissions
- Ensure script is executable:
chmod +x ~/bin/gh-workflow-delete
- Verify GitHub CLI authentication:
-
No workflows found:
- Verify repository name is correct
- Check if repository has workflow runs
- Verify GitHub CLI authentication
- Use --dry-run to preview deletions before executing
- Deletions are permanent and cannot be undone
- Consider keeping recent workflow history with --keep
- Double-check repository names before execution
- The script processes workflows in batches for better performance