Files
Georgi Gerganov 985b14912b ci : apply ccache-clear with older/min/dry-run to all ccache jobs (#27602)
* ci : apply ccache-clear with older/min/dry-run to all ccache jobs

Assisted-by: llama.cpp:DeepSeek-v4-Flash-0731

* ci : install gh in ccache-clear if missing (container jobs)

The ccache-clear action relies on the gh CLI, which is not present in
container-based jobs. Install it on demand so those jobs can clear caches.

Assisted-by: llama.cpp:DeepSeek-v4-Flash-0731

* ci : install gh via apt repo in ccache-clear

The install.sh script used previously is no longer served (404). Switch to
the official GitHub CLI apt repository, which is still available.

Assisted-by: llama.cpp:DeepSeek-v4-Flash-0731

* ci : pass --repo to gh cache commands in ccache-clear

In container jobs gh cannot auto-detect the repository from git, so
gh cache list/delete fail with 'failed to run git: not a git repository'.
Pass the repository explicitly via --repo using GITHUB_REPOSITORY.

Assisted-by: llama.cpp:DeepSeek-v4-Flash-0731

* ci : drop -new suffix from vulkan ccache key

The -new suffix was only needed to force a fresh cache. With
ccache-clear now evicting stale caches, the original key can be used
again. The old ccache-vulkan-ubuntu-24.04-arm-new entries still match
the ccache-clear key prefix and are cleaned up automatically.

Assisted-by: llama.cpp:DeepSeek-v4-Flash-0731

* ci : fix ccache-clear date parsing on macOS (BSD date)

macOS ships BSD date, which has no -d option. The older cutoff check
was silently disabled there: 'date: illegal option -- d' errors in the
log and the loop was only stopped by the min limit, risking deletion
of caches not older than the cutoff (e.g. saved by a concurrent job).

Parse the ISO-8601 timestamps with GNU date when available and fall
back to BSD date otherwise (TZ=UTC, fractional seconds dropped).

Assisted-by: llama.cpp:DeepSeek-v4-Flash-0731

* ci : extract ccache-clear logic into scripts/ccache-clear.sh

The composite action now consists of a dedicated step that installs the
GitHub CLI when missing (e.g. in container jobs) and a thin step that
calls the new script. The script follows the make-release-checks.sh
conventions (usage/env header, set -euo pipefail, CLI flags) and only
checks that gh is available. The action inputs are unchanged, so the
workflow steps are untouched.

Assisted-by: llama.cpp:DeepSeek-v4-Flash-0731

* ci : remove unused apple ccaches
2026-08-24 10:49:20 +03:00

106 lines
3.8 KiB
Bash
Executable File

#!/bin/bash
# Delete GitHub Actions caches matching a key prefix, oldest first.
#
# Usage: ccache-clear.sh --key KEY [--older DURATION] [--min N] [--dry-run]
# --key: cache key prefix to match and delete (without the ccache- prefix)
# --older: only delete caches created more than DURATION ago (e.g. 5m, 1h, 1d);
# by default all matching caches are deleted
# --min: stop deleting if fewer than N caches would remain (default: 0)
# --dry-run: only print the caches that would be deleted, without deleting them
#
# Env (when running in GitHub Actions):
# GH_TOKEN: token for the gh CLI
# GITHUB_REPOSITORY: owner/repo of the caches to manage
set -euo pipefail
KEY=""
OLDER=""
MIN=0
DRY_RUN=false
while [[ $# -gt 0 ]]; do
case "$1" in
--key) [[ $# -ge 2 ]] || { echo "Missing value for $1" >&2; exit 1; }; KEY="$2"; shift 2 ;;
--older) [[ $# -ge 2 ]] || { echo "Missing value for $1" >&2; exit 1; }; OLDER="$2"; shift 2 ;;
--min) [[ $# -ge 2 ]] || { echo "Missing value for $1" >&2; exit 1; }; MIN="$2"; shift 2 ;;
--dry-run) DRY_RUN=true; shift ;;
*) echo "Unknown argument: $1"; exit 1 ;;
esac
done
command -v gh >/dev/null 2>&1 || { echo "Error: GitHub CLI (gh) is required" >&2; exit 1; }
[[ -n "${GITHUB_REPOSITORY:-}" ]] || { echo "Error: GITHUB_REPOSITORY not set" >&2; exit 1; }
[[ -n "$KEY" ]] || { echo "Error: --key is required" >&2; exit 1; }
[[ "$MIN" =~ ^[0-9]+$ ]] || { echo "Invalid min value: $MIN" >&2; exit 1; }
# Convert a duration (e.g. 90m, 1h, 1d, plain seconds) to seconds
to_seconds() {
local val="$1"
[[ "$val" =~ ^[0-9]+$ ]] && { echo "$val"; return 0; }
local num="${val%?}" unit="${val: -1}" mult
[[ "$num" =~ ^[0-9]+$ ]] || return 1
case "$unit" in
s) mult=1 ;;
m) mult=60 ;;
h) mult=3600 ;;
d) mult=86400 ;;
*) return 1 ;;
esac
echo $((num * mult))
}
# Convert an ISO-8601 UTC timestamp (e.g. 2026-08-23T16:51:23.313693Z) to epoch seconds
to_epoch() {
local val="$1" out
# GNU date (e.g. Linux)
if out=$(date -d "$val" +%s 2>/dev/null) && [[ "$out" =~ ^[0-9]+$ ]]; then
echo "$out"
return 0
fi
# BSD date (e.g. macOS); fractional seconds are not needed, TZ forces UTC
out=$(TZ=UTC date -j -f "%Y-%m-%dT%H:%M:%S" "${val:0:19}" +%s 2>/dev/null) || return 1
[[ "$out" =~ ^[0-9]+$ ]] || return 1
echo "$out"
}
CACHES=$(gh cache list --repo "$GITHUB_REPOSITORY" --key "ccache-$KEY" --json id,key,createdAt --jq '.[] | [.createdAt, .id, .key] | @tsv' | LC_ALL=C sort)
if [[ -z "$CACHES" ]]; then
echo "No caches found with key prefix: $KEY"
exit 0
fi
TOTAL=$(( $(wc -l <<< "$CACHES") ))
echo "Found $TOTAL cache(s) with key prefix: $KEY (oldest first):"
while IFS=$'\t' read -r CREATED ID CACHE_KEY; do
printf ' %s %s %s\n' "$CREATED" "$ID" "$CACHE_KEY"
done <<< "$CACHES"
CUTOFF=""
if [[ -n "$OLDER" ]]; then
OLDER_SECONDS=$(to_seconds "$OLDER") || { echo "Invalid older value: $OLDER (expected e.g. 90m, 1h, 1d)" >&2; exit 1; }
CUTOFF=$(( $(date +%s) - OLDER_SECONDS ))
fi
# Caches are sorted oldest first
DELETED=0
while IFS=$'\t' read -r CREATED ID CACHE_KEY; do
if [[ -n "$CUTOFF" ]]; then
CREATED_SECONDS=$(to_epoch "$CREATED") || { echo "Failed to parse date: $CREATED" >&2; exit 1; }
if [[ "$CREATED_SECONDS" -ge "$CUTOFF" ]]; then
echo "Rest are not older than $OLDER, stopping"
break
fi
fi
if (( TOTAL - DELETED - 1 < MIN )); then
echo "Keeping at least $MIN cache(s), stopping"
break
fi
if [[ "$DRY_RUN" == "true" ]]; then
echo "Would delete cache: $ID ($CACHE_KEY)"
else
echo "Deleting cache: $ID ($CACHE_KEY)"
gh cache delete --repo "$GITHUB_REPOSITORY" "$ID"
fi
DELETED=$((DELETED + 1))
done <<< "$CACHES"