Skip to content

Instantly share code, notes, and snippets.

@gearsandcode
Last active February 15, 2025 10:04
Show Gist options
  • Save gearsandcode/a73a2ad3737089fc0a598058e739c2cd to your computer and use it in GitHub Desktop.
Save gearsandcode/a73a2ad3737089fc0a598058e739c2cd to your computer and use it in GitHub Desktop.
Delete GitHub Action runs with options

GitHub Workflow Run Deletion Guide

A utility script for managing GitHub Actions workflow runs. Provides flexible options for bulk deletion of workflow runs with safety features.

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

Prerequisites

Installing Dependencies on macOS

  1. Install Homebrew (if not already installed):
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
  1. Install GitHub CLI and jq:
brew install gh jq
  1. Authenticate GitHub CLI:
gh auth login

Follow the interactive prompts to complete authentication.

  1. Verify installations:
gh --version
jq --version
gh auth status

Installation

  1. Create script directory and file:
mkdir -p ~/bin
touch ~/bin/gh-workflow-delete
chmod +x ~/bin/gh-workflow-delete
  1. 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
  1. Reload shell configuration:
source ~/.zshrc
  1. 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 "$@"

Usage

Delete All Workflow Runs

gh-workflow-delete username/repository

Delete Specific Workflow Runs

gh-workflow-delete username/repository --name "CI/CD Pipeline"

Keep Recent Workflow Runs

gh-workflow-delete username/repository --keep 5

Dry Run Mode

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

Output Format

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)...

Troubleshooting

  1. 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
  2. Permission errors:

    • Verify GitHub CLI authentication: gh auth status
    • Check repository permissions
    • Ensure script is executable: chmod +x ~/bin/gh-workflow-delete
  3. No workflows found:

    • Verify repository name is correct
    • Check if repository has workflow runs
    • Verify GitHub CLI authentication

Safety Notes

  • 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment