Skip to content

Commit 312e586

Browse files
authored
[build] prune old codeql caches (#17570)
* [build] prune old codeql caches * bump limit to 1000
1 parent 32edfbe commit 312e586

2 files changed

Lines changed: 111 additions & 0 deletions

File tree

.github/workflows/prune-caches.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: Prune CodeQL caches
2+
3+
on:
4+
workflow_run:
5+
workflows: ["CodeQL"]
6+
types: [completed]
7+
branches: [trunk]
8+
workflow_dispatch:
9+
10+
concurrency:
11+
group: prune-codeql-caches
12+
cancel-in-progress: true
13+
14+
permissions:
15+
contents: read
16+
actions: write
17+
18+
jobs:
19+
prune:
20+
name: Prune
21+
runs-on: ubuntu-latest
22+
steps:
23+
- uses: actions/checkout@v6
24+
- name: Prune stale CodeQL caches
25+
env:
26+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
27+
run: ./scripts/github-actions/prune-codeql-caches.sh --delete
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#!/usr/bin/env bash
2+
#
3+
# Prune stale CodeQL Actions caches, keeping only the most recently created
4+
# entry per cache "group". CodeQL's default setup creates a new
5+
# overlay-base-database cache per commit and never reaps the old ones, which
6+
# pushes the repo over the 10 GiB per-repo cache budget.
7+
#
8+
# Grouping:
9+
# codeql-overlay-base-database-* -> strip trailing "-<sha>-<runid>-1"
10+
# codeql-dependencies-* -> exact key (GH allows duplicate keys)
11+
#
12+
# Requires GH_TOKEN with `actions: write`. Default is dry-run; pass --delete
13+
# to actually remove caches. Safe to run concurrently from multiple jobs: a
14+
# delete that races with another job just returns "not found", which is
15+
# treated as success.
16+
17+
set -euo pipefail
18+
19+
DELETE=0
20+
if [[ "${1:-}" == "--delete" ]]; then
21+
DELETE=1
22+
fi
23+
24+
mapfile -t rows < <(
25+
gh cache list --key "codeql" --limit 1000 \
26+
--json id,key,createdAt \
27+
--jq '.[] | [.id, .key, .createdAt] | @tsv'
28+
)
29+
30+
declare -A newest_id newest_time
31+
32+
for row in "${rows[@]}"; do
33+
IFS=$'\t' read -r id key created <<<"$row"
34+
35+
if [[ "$key" == codeql-overlay-base-database-* ]]; then
36+
group=$(printf '%s' "$key" | sed -E 's/-[0-9a-f]{40}-[0-9]+-1$//')
37+
else
38+
group="$key"
39+
fi
40+
41+
# ISO8601 sorts lexicographically; keep the newest per group.
42+
if [[ -z "${newest_time[$group]:-}" || "$created" > "${newest_time[$group]}" ]]; then
43+
newest_time[$group]="$created"
44+
newest_id[$group]="$id"
45+
fi
46+
done
47+
48+
echo "Groups found: ${#newest_id[@]}"
49+
for g in "${!newest_id[@]}"; do
50+
echo " keep id=${newest_id[$g]} @ ${newest_time[$g]} ($g)"
51+
done
52+
echo
53+
54+
deleted=0
55+
for row in "${rows[@]}"; do
56+
IFS=$'\t' read -r id key created <<<"$row"
57+
58+
if [[ "$key" == codeql-overlay-base-database-* ]]; then
59+
group=$(printf '%s' "$key" | sed -E 's/-[0-9a-f]{40}-[0-9]+-1$//')
60+
else
61+
group="$key"
62+
fi
63+
64+
[[ "$id" == "${newest_id[$group]}" ]] && continue
65+
66+
if (( DELETE )); then
67+
# Tolerate races: another concurrent job may have already deleted it.
68+
if out=$(gh cache delete "$id" 2>&1); then
69+
echo "deleted id=$id key=$key"
70+
elif printf '%s' "$out" | grep -qi 'not found\|HTTP 404'; then
71+
echo "already gone id=$id key=$key"
72+
else
73+
echo "::warning::failed to delete id=$id: $out"
74+
continue
75+
fi
76+
else
77+
echo "would delete id=$id key=$key"
78+
fi
79+
deleted=$((deleted + 1))
80+
done
81+
82+
echo
83+
echo "Total $( (( DELETE )) && echo removed || echo to remove ): $deleted"
84+
(( DELETE )) || echo "(dry run — re-run with --delete to apply)"

0 commit comments

Comments
 (0)