Skip to content

Instantly share code, notes, and snippets.

@viperadnan-git
Last active March 3, 2026 23:23
Show Gist options
  • Select an option

  • Save viperadnan-git/5968c1dc3756427c83c69a8a71a41a2a to your computer and use it in GitHub Desktop.

Select an option

Save viperadnan-git/5968c1dc3756427c83c69a8a71a41a2a to your computer and use it in GitHub Desktop.
GitHub Actions Cleanup Script
#!/bin/bash
# GitHub Actions Cleanup Script
# Cancels running workflows and deletes ALL runs (including cancelled ones)
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
# Check if gh is installed
if ! command -v gh &> /dev/null; then
echo -e "${RED}Error: gh CLI is not installed. Install it from https://cli.github.com/${NC}"
exit 1
fi
# Check if jq is installed
if ! command -v jq &> /dev/null; then
echo -e "${RED}Error: jq is not installed. Install it with 'apt install jq' or 'brew install jq'${NC}"
exit 1
fi
# Check if authenticated
if ! gh auth status &> /dev/null; then
echo -e "${RED}Error: Not authenticated with gh. Run 'gh auth login' first.${NC}"
exit 1
fi
# Get repository (use current repo or specify one)
REPO="${1:-}"
REPO_FLAG=""
if [ -n "$REPO" ]; then
REPO_FLAG="--repo $REPO"
echo -e "${BLUE}Working on repository: $REPO${NC}"
else
echo -e "${BLUE}Working on current repository${NC}"
fi
echo ""
iteration=1
# Process runs in batches until none remain
while true; do
echo -e "${CYAN}=== Iteration $iteration ===${NC}"
# Fetch batch of runs (max 1000 per request)
runs=$(gh run list $REPO_FLAG --limit 1000 --json databaseId,status,conclusion,displayTitle,workflowName 2>/dev/null)
if [ -z "$runs" ] || [ "$runs" == "[]" ]; then
echo -e "${GREEN}No more workflow runs found.${NC}"
break
fi
batch_count=$(echo "$runs" | jq length)
echo -e "${BLUE}Found $batch_count workflow runs in this batch${NC}"
echo "----------------------------------------"
# Process each run
echo "$runs" | jq -c '.[]' | while read -r run; do
run_id=$(echo "$run" | jq -r '.databaseId')
status=$(echo "$run" | jq -r '.status')
conclusion=$(echo "$run" | jq -r '.conclusion')
title=$(echo "$run" | jq -r '.displayTitle')
workflow=$(echo "$run" | jq -r '.workflowName')
# Truncate title if too long
if [ ${#title} -gt 40 ]; then
title="${title:0:37}..."
fi
echo -ne "Run #$run_id [$workflow] \"$title\" - "
# Check if running (in_progress, queued, waiting, pending, requested)
if [[ "$status" == "in_progress" || "$status" == "queued" || "$status" == "waiting" || "$status" == "pending" || "$status" == "requested" ]]; then
echo -ne "${YELLOW}$status${NC} -> "
# Cancel first
if gh run cancel "$run_id" $REPO_FLAG 2>/dev/null; then
echo -ne "${GREEN}CANCELLED${NC} -> "
# Wait a moment for the cancellation to process
sleep 1
# Then delete
if gh run delete "$run_id" $REPO_FLAG 2>/dev/null; then
echo -e "${GREEN}DELETED${NC}"
else
echo -e "${YELLOW}DELETE PENDING (will retry)${NC}"
fi
else
echo -e "${RED}CANCEL FAILED${NC}"
fi
else
# Run is completed, just delete it
echo -ne "${BLUE}$status${NC}"
[ -n "$conclusion" ] && [ "$conclusion" != "null" ] && echo -ne " ($conclusion)"
echo -ne " -> "
if gh run delete "$run_id" $REPO_FLAG 2>/dev/null; then
echo -e "${GREEN}DELETED${NC}"
else
echo -e "${RED}DELETE FAILED${NC}"
fi
fi
done
echo ""
((iteration++))
# Small delay between iterations to avoid rate limiting
sleep 2
done
echo ""
echo "========================================"
echo -e "${GREEN}Cleanup complete!${NC}"
echo "========================================"
@viperadnan-git
Copy link
Author

GitHub Actions Cleanup Script

A bash script to bulk cancel and delete all GitHub Actions workflow runs from a repository.

What it does

  • Running/queued/pending workflows → Cancels them, then deletes
  • Completed workflows (success, failure, cancelled, skipped) → Deletes immediately
  • Recursive processing → Continues until all workflow runs are removed

Prerequisites

Installation

macOS:

brew install gh jq

Ubuntu/Debian:

sudo apt install gh jq

Authenticate with GitHub:

gh auth login

Usage

# Make executable
chmod +x cleanup-gh-actions.sh

# Run in current git repository
./cleanup-gh-actions.sh

# Run for a specific repository
./cleanup-gh-actions.sh owner/repo-name

Example Output

Working on repository: myorg/my-repo

=== Iteration 1 ===
Found 150 workflow runs in this batch
----------------------------------------
Run #12345678 [CI] "feat: add new feature" - in_progress -> CANCELLED -> DELETED
Run #12345677 [CI] "fix: bug fix" - completed (success) -> DELETED
Run #12345676 [Deploy] "chore: update deps" - completed (cancelled) -> DELETED
...

=== Iteration 2 ===
No more workflow runs found.

========================================
Cleanup complete!
========================================

How it works

  1. Fetches up to 1000 workflow runs per iteration
  2. For each run:
    • If running/queued/pending: cancels first, waits 1 second, then deletes
    • If completed: deletes immediately
  3. Repeats until no runs remain
  4. Includes 2-second delay between iterations to avoid API rate limiting

Notes

  • The script requires write access to the repository's Actions
  • Rate limiting: GitHub API has rate limits; the script includes delays to mitigate this
  • Large repositories with thousands of runs may take several minutes to fully clean

@viperadnan-git
Copy link
Author

Or run directly using curl

curl -fsSL "https://gist.githubusercontent.com/viperadnan-git/5968c1dc3756427c83c69a8a71a41a2a/raw/cleanup-gh-actions.sh" | bash -s -- user/repo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment