Skip to content

Commit fbb345b

Browse files
committed
feat(sfw): cache the sfw binary via @actions/cache
Saves ~130 MB and ~5-15s per run, and gives us a fallback when the GitHub releases CDN flakes (we've hit that class of incident before for the vp install scripts in #67). Implementation: - restoreCache at the start of installSfw with key sfw-${SFW_VERSION}-${platform}-${arch}-${libc} No restoreKeys: we never accept a different version's binary as a fallback. The version is in the key so a Renovate bump to SFW_VERSION naturally evicts stale entries (GHA also auto-evicts after 7 days). - On cache hit: chmod+addPath and return — skip the download entirely. - On cache miss: existing download/retry path runs, then saveCache publishes to GHA cache for future runs. - All cache calls wrapped in try/catch so any cache-service failure (network blip, 5xx, ReserveCacheError on duplicate key) falls through cleanly to the download path; cache is never load-bearing. - The composition path (socketdev/action@<sha>) is untouched — findSfwOnPath() still wins and we don't double-cache what @actions/tool-cache (which socketdev/action uses) already manages. CI: existing test-sfw matrix exercises both the cache-miss (first push on a branch) and cache-hit (subsequent pushes) paths; no new job needed.
1 parent 18c1cc4 commit fbb345b

2 files changed

Lines changed: 73 additions & 35 deletions

File tree

dist/index.mjs

Lines changed: 35 additions & 35 deletions
Large diffs are not rendered by default.

src/install-sfw.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { restoreCache, saveCache } from "@actions/cache";
12
import { info, warning, addPath } from "@actions/core";
23
import { exec } from "@actions/exec";
34
import { execFileSync } from "node:child_process";
@@ -86,6 +87,30 @@ export async function installSfw(): Promise<void> {
8687
mkdirSync(binDir, { recursive: true });
8788
const binPath = join(binDir, process.platform === "win32" ? "sfw.exe" : "sfw");
8889

90+
// Try the GHA cache first so we don't redownload ~130 MB on every run and
91+
// we get a fallback when the GitHub releases CDN flakes. Key includes the
92+
// pinned version + platform + arch + libc; no restoreKeys, so we never
93+
// accept a different version's binary as a fallback. All cache calls are
94+
// best-effort: any failure falls through to the download path.
95+
const cacheKey = `sfw-${SFW_VERSION}-${process.platform}-${process.arch}-${isMuslLinux() ? "musl" : "glibc"}`;
96+
let cacheHit = false;
97+
try {
98+
const matchedKey = await restoreCache([binDir], cacheKey);
99+
if (matchedKey && existsSync(binPath)) {
100+
if (process.platform !== "win32") {
101+
chmodSync(binPath, 0o755);
102+
}
103+
addPath(binDir);
104+
info(`sfw restored from cache: ${matchedKey}`);
105+
cacheHit = true;
106+
return;
107+
}
108+
} catch (error) {
109+
warning(
110+
`sfw cache restore failed (${error instanceof Error ? error.message : String(error)}); falling through to download.`,
111+
);
112+
}
113+
89114
info(`Installing sfw from ${url}...`);
90115

91116
const maxAttempts = INSTALL_MAX_ROUNDS;
@@ -99,6 +124,19 @@ export async function installSfw(): Promise<void> {
99124
}
100125
addPath(binDir);
101126
info(`sfw installed at ${binPath}`);
127+
// Save to cache for future runs. Skipped on cache-hit branch (return
128+
// above). On a re-key collision @actions/cache throws
129+
// ReserveCacheError — swallow it like any other cache failure.
130+
if (!cacheHit) {
131+
try {
132+
await saveCache([binDir], cacheKey);
133+
info(`sfw cached under key: ${cacheKey}`);
134+
} catch (error) {
135+
warning(
136+
`sfw cache save failed (${error instanceof Error ? error.message : String(error)}); continuing.`,
137+
);
138+
}
139+
}
102140
return;
103141
}
104142
failureReason = `exit code ${exitCode}`;

0 commit comments

Comments
 (0)