feat: include a hash of deno.lock files in the cache key automatically (#98)

This commit is contained in:
David Sherret
2025-05-13 12:53:56 -04:00
committed by GitHub
parent fd6b0ad149
commit 3169cf993b
12 changed files with 1993 additions and 830 deletions

View File

@@ -92,7 +92,6 @@ jobs:
uses: ./
with:
cache: true
cache-hash: ${{ hashFiles('**/deno.lock') }}
- name: Download dependencies for cache
run: deno install --global --no-config npm:cowsay@1.6.0
@@ -110,7 +109,6 @@ jobs:
uses: ./
with:
cache: true
cache-hash: ${{ hashFiles('**/deno.lock') }}
- name: Run with cached dependencies
run: deno run --cached-only --no-config -RE npm:cowsay@1.6.0 "It works!"

View File

@@ -144,20 +144,38 @@ number.
### Caching dependencies downloaded by Deno automatically
Dependencies installed by Deno can be cached automatically, which is similar to
the [`cache` option in `setup-node`](https://github.com/actions/setup-node).
Dependencies installed by Deno can be cached automatically between workflow
runs. This helps make your GH action run faster by not repeating caching work
and network requests done by a previous run.
To enable the cache, use `cache: true`. It's recommended to also add the
`cache-hash` property, to scope caches based on lockfile changes.
To enable the cache, use `cache: true`.
```yaml
- uses: denoland/setup-deno@v2
with:
cache: true
cache-hash: ${{ hashFiles('**/deno.lock') }}
```
> [!WARNING]
> If an environment variable `DENO_DIR` is set for steps that run/download
> dependencies, then `DENO_DIR` must also be set for the `denoland/setup-deno`
> action, for the caching to work as intended.
By default, the cache is automatically keyed by:
- the github
[job_id](https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_id)
- the runner os and architecture
- a hash of the `deno.lock` files in the project
It is possible to customize the default hash
(`${{ hashFiles('**/deno.lock') }}`) used as part of the cache key via the
`cache-hash` input.
```yaml
- uses: denoland/setup-deno@v2
with:
# setting `cache-hash` implies `cache: true` and will replace
# the default cache-hash of `${{ hashFiles('**/deno.lock') }}`
cache-hash: ${{ hashFiles('**/deno.json') }}
```

View File

@@ -17,7 +17,7 @@ inputs:
description: Cache downloaded modules & packages automatically in GitHub Actions cache.
default: "false"
cache-hash:
description: A hash used as part of the cache key. Use e.g. `$\{{ hashFiles('**/deno.lock') }}` to cache based on the lockfile contents.
description: A hash used as part of the cache key, which defaults to a hash of the deno.lock files.
outputs:
cache-hit:
description: A boolean indicating whether the cache was hit.

View File

@@ -16,6 +16,7 @@
"imports": {
"@actions/cache": "npm:@actions/cache@^4.0.3",
"@actions/core": "npm:@actions/core@^1.11.1",
"@actions/glob": "npm:@actions/glob@^0.5.0",
"@actions/tool-cache": "npm:@actions/tool-cache@^2.0.2",
"@types/node": "npm:@types/node@^22.15.0",
"@types/semver": "npm:@types/semver@^7.7.0",

11
deno.lock generated
View File

@@ -3,6 +3,7 @@
"specifiers": {
"npm:@actions/cache@^4.0.3": "4.0.3",
"npm:@actions/core@^1.11.1": "1.11.1",
"npm:@actions/glob@0.5": "0.5.0",
"npm:@actions/tool-cache@^2.0.2": "2.0.2",
"npm:@types/node@*": "22.15.15",
"npm:@types/node@^22.15.0": "22.15.17",
@@ -17,7 +18,7 @@
"dependencies": [
"@actions/core",
"@actions/exec",
"@actions/glob",
"@actions/glob@0.1.2",
"@actions/http-client",
"@actions/io",
"@azure/abort-controller@1.1.0",
@@ -47,6 +48,13 @@
"minimatch"
]
},
"@actions/glob@0.5.0": {
"integrity": "sha512-tST2rjPvJLRZLuT9NMUtyBjvj9Yo0MiJS3ow004slMvm8GFM+Zv9HvMJ7HWzfUyJnGrJvDsYkWBaaG3YKXRtCw==",
"dependencies": [
"@actions/core",
"minimatch"
]
},
"@actions/http-client@2.2.3": {
"integrity": "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==",
"dependencies": [
@@ -1083,6 +1091,7 @@
"dependencies": [
"npm:@actions/cache@^4.0.3",
"npm:@actions/core@^1.11.1",
"npm:@actions/glob@0.5",
"npm:@actions/tool-cache@^2.0.2",
"npm:@types/node@^22.15.0",
"npm:@types/semver@^7.7.0",

View File

@@ -1,4 +0,0 @@
import "./semver-DmxAwBYV.mjs";
import { restoreCache, saveCache } from "./cache-DzONlZ-I.mjs";
export { restoreCache };

4
dist/cache-D7LLZXo3.mjs vendored Normal file
View File

@@ -0,0 +1,4 @@
import "./semver-DmxAwBYV.mjs";
import { restoreCache, saveCache } from "./cache-zjpbixka.mjs";
export { restoreCache };

File diff suppressed because it is too large Load Diff

7
dist/main.mjs vendored
View File

@@ -20318,6 +20318,9 @@ function exit(message) {
import_core.setFailed(message);
process$1.exit();
}
function isCachingEnabled() {
return import_core.getInput("cache") === "true" || import_core.getInput("cache-hash").length > 0;
}
async function main() {
try {
const denoVersionFile = import_core.getInput("deno-version-file");
@@ -20331,8 +20334,8 @@ async function main() {
import_core.setOutput("deno-version", version.version);
import_core.setOutput("release-channel", version.kind);
import_core.info("Installation complete.");
if (import_core.getInput("cache") === "true") {
const { restoreCache } = await import("./cache-ByPW8-iO.mjs");
if (isCachingEnabled()) {
const { restoreCache } = await import("./cache-D7LLZXo3.mjs");
await restoreCache(import_core.getInput("cache-hash"));
}
} catch (err) {

2
dist/post.mjs vendored
View File

@@ -1,5 +1,5 @@
import { import_core } from "./semver-DmxAwBYV.mjs";
import { saveCache } from "./cache-DzONlZ-I.mjs";
import { saveCache } from "./cache-zjpbixka.mjs";
import process from "node:process";
//#region src/post.ts

View File

@@ -1,6 +1,7 @@
import process from "node:process";
import cache from "@actions/cache";
import core from "@actions/core";
import { hashFiles } from "@actions/glob";
const state = {
DENO_DIR: "DENO_DIR",
@@ -35,6 +36,10 @@ export async function restoreCache(cacheHash: string) {
const denoDir = await resolveDenoDir();
core.saveState(state.DENO_DIR, denoDir);
if (cacheHash.length === 0) {
cacheHash = await resolveDefaultCacheKey();
}
const { GITHUB_JOB, RUNNER_OS, RUNNER_ARCH } = process.env;
const restoreKey = `deno-cache-${RUNNER_OS}-${RUNNER_ARCH}`;
// CI jobs often download different dependencies, so include Job ID in the cache key.
@@ -54,22 +59,28 @@ export async function restoreCache(cacheHash: string) {
core.info(message);
} catch (err) {
core.warning(
new Error("Failed to restore cache. Continuing without cache.", {
cause: err,
}),
new Error("Failed to restore cache. Continuing without cache."),
);
// core.warning doesn't log error causes, so explicititly log the error
core.warning(err as Error);
}
}
function resolveDefaultCacheKey(): Promise<string> {
return hashFiles(
"**/deno.lock",
process.env.GITHUB_WORKSPACE,
);
}
async function resolveDenoDir(): Promise<string> {
const { DENO_DIR } = process.env;
if (DENO_DIR) return DENO_DIR;
if (DENO_DIR) {
return DENO_DIR;
}
// Retrieve the DENO_DIR from `deno info --json`
const { exec } = await import("node:child_process");
const output = await new Promise<string>((res, rej) => {
exec("deno info --json", (err, stdout) => err ? rej(err) : res(stdout));
});
const output = await exec("deno info --json");
const info = JSON.parse(output);
if (typeof info.denoDir !== "string") {
throw new Error(
@@ -79,3 +90,10 @@ async function resolveDenoDir(): Promise<string> {
}
return info.denoDir;
}
async function exec(command: string) {
const { exec } = await import("node:child_process");
return await new Promise<string>((res, rej) => {
exec(command, (err, stdout) => err ? rej(err) : res(stdout));
});
}

View File

@@ -20,6 +20,11 @@ function exit(message: string): never {
process.exit();
}
function isCachingEnabled() {
return core.getInput("cache") === "true" ||
core.getInput("cache-hash").length > 0;
}
async function main() {
try {
const denoVersionFile = core.getInput("deno-version-file");
@@ -57,7 +62,7 @@ async function main() {
core.info("Installation complete.");
if (core.getInput("cache") === "true") {
if (isCachingEnabled()) {
const { restoreCache } = await import("./cache.ts");
await restoreCache(core.getInput("cache-hash"));
}