Skip to content

Commit c547a97

Browse files
author
刘威
committed
ci: cache build tool downloads and prune stale caches
1 parent 6c0c659 commit c547a97

2 files changed

Lines changed: 114 additions & 2 deletions

File tree

.github/workflows/build.yml

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,15 @@ jobs:
8080
hash=$(node -e "const crypto = require('crypto'); const fs = require('fs'); const lock = JSON.parse(fs.readFileSync('package-lock.json', 'utf8')); const normalizedPackages = Object.fromEntries(Object.entries(lock.packages || {}).map(([name, pkg]) => [name, { version: pkg.version, resolved: pkg.resolved, integrity: pkg.integrity, dependencies: pkg.dependencies, optionalDependencies: pkg.optionalDependencies, cpu: pkg.cpu, os: pkg.os, engines: pkg.engines, hasInstallScript: pkg.hasInstallScript }])); const normalizedLock = { lockfileVersion: lock.lockfileVersion, requires: lock.requires, packages: normalizedPackages, dependencies: lock.dependencies }; process.stdout.write(crypto.createHash('sha256').update(JSON.stringify(normalizedLock)).digest('hex'));")
8181
echo "value=$hash" >> "$GITHUB_OUTPUT"
8282
83+
- name: Resolve build tool versions
84+
id: build-tool-versions
85+
shell: bash
86+
run: |
87+
versions=$(node -e "const lock = require('./package-lock.json'); const packages = lock.packages || {}; const values = { electron: packages['node_modules/electron']?.version || 'unknown', electron_builder: packages['node_modules/electron-builder']?.version || 'unknown' }; for (const [key, value] of Object.entries(values)) { console.log(key + '=' + value); }")
88+
while IFS= read -r line; do
89+
echo "$line" >> "$GITHUB_OUTPUT"
90+
done <<< "$versions"
91+
8392
- name: Get npm cache directory
8493
shell: bash
8594
id: npm-cache-dir
@@ -100,8 +109,9 @@ jobs:
100109
path: |
101110
~\AppData\Local\electron\Cache
102111
~\AppData\Local\electron-builder\Cache
103-
key: ${{ runner.os }}-electron-${{ steps.dep-cache-key.outputs.value }}
112+
key: ${{ runner.os }}-electron-${{ steps.build-tool-versions.outputs.electron }}-${{ steps.build-tool-versions.outputs.electron_builder }}
104113
restore-keys: |
114+
${{ runner.os }}-electron-${{ steps.build-tool-versions.outputs.electron }}-
105115
${{ runner.os }}-electron-
106116
107117
- name: Cache Electron binaries (Unix)
@@ -113,8 +123,9 @@ jobs:
113123
~/.cache/electron-builder
114124
~/Library/Caches/electron
115125
~/Library/Caches/electron-builder
116-
key: ${{ runner.os }}-electron-${{ steps.dep-cache-key.outputs.value }}
126+
key: ${{ runner.os }}-electron-${{ steps.build-tool-versions.outputs.electron }}-${{ steps.build-tool-versions.outputs.electron_builder }}
117127
restore-keys: |
128+
${{ runner.os }}-electron-${{ steps.build-tool-versions.outputs.electron }}-
118129
${{ runner.os }}-electron-
119130
120131
- name: Cache node-gyp (Windows)
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
name: Cache Maintenance
2+
3+
on:
4+
schedule:
5+
- cron: '30 3 * * 0'
6+
workflow_dispatch:
7+
inputs:
8+
keep_per_key:
9+
description: How many recent caches to keep for each normalized key
10+
type: choice
11+
default: '2'
12+
options:
13+
- '1'
14+
- '2'
15+
16+
permissions:
17+
actions: write
18+
contents: read
19+
20+
jobs:
21+
prune-caches:
22+
runs-on: ubuntu-latest
23+
env:
24+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
25+
KEEP_PER_KEY: ${{ inputs.keep_per_key || '2' }}
26+
27+
steps:
28+
- name: List caches
29+
run: gh cache list --limit 1000 --json createdAt,id,key,lastAccessedAt,ref,sizeInBytes > caches.json
30+
31+
- name: Select stale caches
32+
shell: bash
33+
run: |
34+
node <<'NODE'
35+
const fs = require('fs');
36+
37+
const keepCount = Number(process.env.KEEP_PER_KEY || '2');
38+
const caches = JSON.parse(fs.readFileSync('caches.json', 'utf8'));
39+
const groups = new Map();
40+
41+
const normalizeKey = (key) => key.replace(/-[0-9a-f]{32,}$/i, '');
42+
const score = (cache) => new Date(cache.lastAccessedAt || cache.createdAt || 0).getTime();
43+
44+
for (const cache of caches) {
45+
const groupKey = normalizeKey(cache.key);
46+
if (!groups.has(groupKey)) {
47+
groups.set(groupKey, []);
48+
}
49+
groups.get(groupKey).push(cache);
50+
}
51+
52+
const stale = [];
53+
const summary = [];
54+
55+
for (const [groupKey, items] of groups.entries()) {
56+
items.sort((a, b) => score(b) - score(a));
57+
const keep = items.slice(0, keepCount);
58+
const remove = items.slice(keepCount);
59+
60+
summary.push(
61+
`${groupKey}: keep ${keep.length}, delete ${remove.length}, total ${items.length}`,
62+
);
63+
64+
stale.push(...remove);
65+
}
66+
67+
fs.writeFileSync('stale-cache-ids.txt', stale.map((cache) => String(cache.id)).join('\n'));
68+
fs.writeFileSync(
69+
process.env.GITHUB_STEP_SUMMARY,
70+
[
71+
'# Cache Maintenance',
72+
'',
73+
`Keep per normalized key: ${keepCount}`,
74+
'Normalized key rule: strip trailing hex hash like `-f27f...`',
75+
'',
76+
`Total caches scanned: ${caches.length}`,
77+
`Caches selected for deletion: ${stale.length}`,
78+
'',
79+
'## Groups',
80+
...summary.map((line) => `- ${line}`),
81+
].join('\n'),
82+
);
83+
84+
console.log(`Caches scanned: ${caches.length}`);
85+
console.log(`Caches selected for deletion: ${stale.length}`);
86+
NODE
87+
88+
- name: Delete stale caches
89+
shell: bash
90+
run: |
91+
if [ ! -s stale-cache-ids.txt ]; then
92+
echo "No stale caches to delete"
93+
exit 0
94+
fi
95+
96+
while IFS= read -r cache_id; do
97+
if [ -n "$cache_id" ]; then
98+
echo "Deleting cache $cache_id"
99+
gh cache delete "$cache_id"
100+
fi
101+
done < stale-cache-ids.txt

0 commit comments

Comments
 (0)