Skip to content

Instantly share code, notes, and snippets.

@viperadnan-git
Created February 1, 2026 21:26
Show Gist options
  • Select an option

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

Select an option

Save viperadnan-git/b27193df91f18d4e262aca8d168b4eb5 to your computer and use it in GitHub Desktop.
GitHub Actions Cache Cleanup - Delete old cache entries (3+ days) with filtering by repo/branch/key. Includes dry-run mode, auto repo detection, and size reporting. Requires: gh CLI, jq
#!/usr/bin/env bash
set -euo pipefail
# Default values
DAYS=3
REPO=""
BRANCH=""
KEY_PATTERN=""
DRY_RUN=false
VERBOSE=false
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
usage() {
cat << EOF
Usage: $(basename "$0") [OPTIONS]
Delete GitHub Actions cache entries older than specified days.
OPTIONS:
-r, --repo REPO Repository (owner/name format, default: current repo)
-d, --days DAYS Delete cache older than DAYS (default: 3)
-b, --branch BRANCH Filter by branch name
-k, --key PATTERN Filter by cache key pattern
-n, --dry-run Show what would be deleted without deleting
-v, --verbose Verbose output
-h, --help Show this help message
EXAMPLES:
# Delete cache older than 3 days from current repo
$(basename "$0")
# Delete cache older than 7 days from specific repo
$(basename "$0") -r owner/repo -d 7
# Delete cache for main branch only
$(basename "$0") -b main -d 5
# Delete cache matching key pattern
$(basename "$0") -k "Linux-" -d 1
# Dry run to see what would be deleted
$(basename "$0") -d 3 --dry-run
EOF
exit 0
}
log() {
echo -e "${GREEN}[INFO]${NC} $*"
}
warn() {
echo -e "${YELLOW}[WARN]${NC} $*"
}
error() {
echo -e "${RED}[ERROR]${NC} $*" >&2
exit 1
}
verbose() {
if [[ "$VERBOSE" == true ]]; then
echo -e "${NC}[DEBUG]${NC} $*"
fi
}
check_dependencies() {
if ! command -v gh &> /dev/null; then
error "gh CLI is not installed. Install from: https://cli.github.com/"
fi
if ! command -v jq &> /dev/null; then
error "jq is not installed. Install with: apt/brew install jq"
fi
# Check gh authentication
if ! gh auth status &> /dev/null; then
error "Not authenticated with gh. Run: gh auth login"
fi
}
get_repo() {
if [[ -n "$REPO" ]]; then
echo "$REPO"
return
fi
# Try to get repo from git remote
if git rev-parse --git-dir &> /dev/null; then
local remote_url
remote_url=$(git config --get remote.origin.url || echo "")
if [[ -n "$remote_url" ]]; then
# Extract owner/repo from various URL formats
echo "$remote_url" | sed -E 's#.*github\.com[:/](.+/.+?)(\.git)?$#\1#'
return
fi
fi
error "Could not determine repository. Use -r flag to specify."
}
parse_args() {
while [[ $# -gt 0 ]]; do
case $1 in
-r|--repo)
REPO="$2"
shift 2
;;
-d|--days)
DAYS="$2"
shift 2
;;
-b|--branch)
BRANCH="$2"
shift 2
;;
-k|--key)
KEY_PATTERN="$2"
shift 2
;;
-n|--dry-run)
DRY_RUN=true
shift
;;
-v|--verbose)
VERBOSE=true
shift
;;
-h|--help)
usage
;;
*)
error "Unknown option: $1"
;;
esac
done
}
delete_cache() {
local repo
repo=$(get_repo)
log "Repository: $repo"
log "Delete cache older than: $DAYS days"
# Calculate cutoff date
local cutoff_date
if [[ "$OSTYPE" == "darwin"* ]]; then
cutoff_date=$(date -u -v-"${DAYS}"d +"%Y-%m-%dT%H:%M:%SZ")
else
cutoff_date=$(date -u -d "$DAYS days ago" +"%Y-%m-%dT%H:%M:%SZ")
fi
verbose "Cutoff date: $cutoff_date"
# Fetch all cache entries
log "Fetching cache entries..."
local cache_list
cache_list=$(gh api -X GET "/repos/$repo/actions/caches" --paginate \
--jq '.actions_caches[]')
if [[ -z "$cache_list" ]]; then
log "No cache entries found."
exit 0
fi
local total_count=0
local deleted_count=0
local total_size=0
# Process each cache entry
while IFS= read -r cache; do
local id key ref created_at size_bytes
id=$(echo "$cache" | jq -r '.id')
key=$(echo "$cache" | jq -r '.key')
ref=$(echo "$cache" | jq -r '.ref')
created_at=$(echo "$cache" | jq -r '.created_at')
size_bytes=$(echo "$cache" | jq -r '.size_in_bytes')
total_count=$((total_count + 1))
# Apply filters
if [[ -n "$BRANCH" ]] && [[ "$ref" != *"$BRANCH"* ]]; then
verbose "Skipping (branch filter): $key"
continue
fi
if [[ -n "$KEY_PATTERN" ]] && [[ "$key" != *"$KEY_PATTERN"* ]]; then
verbose "Skipping (key filter): $key"
continue
fi
# Check if older than cutoff
if [[ "$created_at" < "$cutoff_date" ]]; then
deleted_count=$((deleted_count + 1))
total_size=$((total_size + size_bytes))
local size_mb
size_mb=$(echo "scale=2; $size_bytes / 1048576" | bc)
if [[ "$DRY_RUN" == true ]]; then
echo -e "${YELLOW}[DRY-RUN]${NC} Would delete: $key (${size_mb}MB, created: $created_at)"
else
verbose "Deleting: $key (${size_mb}MB, created: $created_at)"
if gh api -X DELETE "/repos/$repo/actions/caches/$id" &> /dev/null; then
echo -e "${GREEN}${NC} Deleted: $key (${size_mb}MB)"
else
warn "Failed to delete: $key"
fi
fi
else
verbose "Keeping (newer): $key (created: $created_at)"
fi
done < <(echo "$cache_list")
# Summary
local total_size_mb
total_size_mb=$(echo "scale=2; $total_size / 1048576" | bc)
echo ""
log "Summary:"
echo " Total cache entries: $total_count"
echo " Entries to delete: $deleted_count"
echo " Total size: ${total_size_mb}MB"
if [[ "$DRY_RUN" == true ]]; then
warn "DRY RUN - No cache was actually deleted. Remove --dry-run to delete."
fi
}
main() {
parse_args "$@"
check_dependencies
delete_cache
}
main "$@"
@viperadnan-git
Copy link
Author

I've created a comprehensive bash script for cleaning up GitHub Actions cache. Here's what it does:

Features:

  • Delete cache entries older than N days (default: 3)
  • Filter by repository, branch, or cache key pattern
  • Dry-run mode to preview deletions
  • Verbose logging
  • Auto-detects current repo from git remote
  • Color-coded output
  • Size reporting in MB

Quick Install:

curl -fsSL https://gist.githubusercontent.com/viperadnan-git/b27193df91f18d4e262aca8d168b4eb5/raw/gh-cache-cleanup.sh | bash -s -- [OPTIONS]

Or download and make executable:

curl -fsSL https://gist.githubusercontent.com/viperadnan-git/b27193df91f18d4e262aca8d168b4eb5/raw/gh-cache-cleanup.sh -o gh-cache-cleanup.sh
chmod +x gh-cache-cleanup.sh
./gh-cache-cleanup.sh [OPTIONS]

Usage Examples:

# Delete cache older than 3 days from current repo
./gh-cache-cleanup.sh

# Delete cache older than 7 days from specific repo
./gh-cache-cleanup.sh -r owner/repo -d 7

# Delete cache for main branch only
./gh-cache-cleanup.sh -b main -d 5

# Delete cache matching key pattern (e.g., "Linux-")
./gh-cache-cleanup.sh -k "Linux-" -d 1

# Dry run to preview
./gh-cache-cleanup.sh -d 3 --dry-run -v

# Direct curl execution with options
curl -fsSL https://gist.githubusercontent.com/viperadnan-git/b27193df91f18d4e262aca8d168b4eb5/raw/gh-cache-cleanup.sh | bash -s -- -d 7 --dry-run

Requirements:

  • gh CLI (authenticated)
  • jq for JSON parsing
  • bc for calculations (usually pre-installed)

The script handles pagination automatically and provides a detailed summary of deleted entries and space freed.

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