-
Notifications
You must be signed in to change notification settings - Fork 41
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add built-in caching via inputs
- Loading branch information
Showing
7 changed files
with
164 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -79,6 +79,41 @@ jobs: | |
- name: Check binary exists | ||
run: deno_foo -V | ||
|
||
test-setup-cache: | ||
runs-on: ${{ matrix.os }} | ||
strategy: | ||
matrix: | ||
os: [ubuntu-latest, windows-latest, macos-latest] | ||
steps: | ||
- uses: actions/checkout@v4 | ||
|
||
- name: Setup Deno | ||
uses: ./ | ||
with: | ||
cache: true | ||
cache-hash: bar-${{ hashFiles('**/package-lock.json') }} | ||
|
||
- name: Download dependencies for cache | ||
run: deno install --global npm:[email protected] | ||
|
||
test-cache: | ||
needs: test-setup-cache | ||
runs-on: ${{ matrix.os }} | ||
strategy: | ||
matrix: | ||
os: [ubuntu-latest, windows-latest, macos-latest] | ||
steps: | ||
- uses: actions/checkout@v4 | ||
|
||
- name: Setup Deno | ||
uses: ./ | ||
with: | ||
cache: true | ||
cache-hash: ${{ hashFiles('**/package-lock.json') }} | ||
|
||
- name: Run with cached dependencies | ||
run: deno run --cached-only -RE npm:[email protected] "It works!" | ||
|
||
lint: | ||
runs-on: ubuntu-latest | ||
steps: | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import process from "node:process"; | ||
import core from "@actions/core"; | ||
import { saveCache } from "./src/cache.mjs"; | ||
|
||
async function main() { | ||
try { | ||
await saveCache(); | ||
} catch (err) { | ||
core.setFailed((err instanceof Error) ? err : String(err)); | ||
process.exit(); | ||
} | ||
} | ||
|
||
main(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import process from "node:process"; | ||
import cache from "@actions/cache"; | ||
import core from "@actions/core"; | ||
|
||
const state = { | ||
DENO_DIR: "DENO_DIR", | ||
CACHE_HIT: "CACHE_HIT", | ||
CACHE_SAVE: "CACHE_SAVE", | ||
}; | ||
|
||
export async function saveCache() { | ||
if (!cache.isFeatureAvailable()) { | ||
core.warning("Caching is not available. Caching is skipped."); | ||
return; | ||
} | ||
|
||
const denoDir = core.getState(state.DENO_DIR); | ||
const saveKey = core.getState(state.CACHE_SAVE); | ||
if (!denoDir || !saveKey) { | ||
core.info("Caching is not enabled. Caching is skipped."); | ||
return; | ||
} else if (core.getState(state.CACHE_HIT) === "true") { | ||
core.info( | ||
`Cache hit occurred on the primary key "${saveKey}", not saving cache.`, | ||
); | ||
return; | ||
} | ||
|
||
await cache.saveCache([denoDir], saveKey); | ||
core.info(`Cache saved with key: "${saveKey}".`); | ||
} | ||
|
||
/** | ||
* @param {string} cacheHash Should be a hash of any lockfiles or similar. | ||
*/ | ||
export async function restoreCache(cacheHash) { | ||
try { | ||
const denoDir = await resolveDenoDir(); | ||
core.saveState(state.DENO_DIR, denoDir); | ||
|
||
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. | ||
const primaryKey = `${restoreKey}-${GITHUB_JOB}-${cacheHash}`; | ||
core.saveState(state.CACHE_SAVE, primaryKey); | ||
|
||
const loadedCacheKey = await cache.restoreCache([denoDir], primaryKey, [ | ||
restoreKey, | ||
]); | ||
const cacheHit = primaryKey === loadedCacheKey; | ||
core.setOutput("cache-hit", cacheHit); | ||
core.saveState(state.CACHE_HIT, cacheHit); | ||
|
||
const message = loadedCacheKey | ||
? `Cache key used: "${loadedCacheKey}".` | ||
: `No cache found for restore key: "${restoreKey}".`; | ||
core.info(message); | ||
} catch (err) { | ||
core.warning( | ||
new Error("Failed to restore cache. Continuing without cache.", { | ||
cause: err, | ||
}), | ||
); | ||
} | ||
} | ||
|
||
/** | ||
* @returns {Promise<string>} | ||
*/ | ||
async function resolveDenoDir() { | ||
const { DENO_DIR } = process.env; | ||
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((res, rej) => { | ||
exec("deno info --json", (err, stdout) => err ? rej(err) : res(stdout)); | ||
}); | ||
return JSON.parse(output).denoDir; | ||
} |