Skip to content

Commit

Permalink
new: Add cache base warmup strategy. (#16)
Browse files Browse the repository at this point in the history
  • Loading branch information
milesj authored Nov 17, 2023
1 parent c15c420 commit c91b420
Show file tree
Hide file tree
Showing 11 changed files with 177 additions and 86 deletions.
26 changes: 22 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,42 @@ jobs:
name: 'CI'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
- run: npm install -g pnpm
- run: pnpm install
- run: pnpm run check
action:
name: 'Action'
action-default:
name: 'Action - Default'
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
fail-fast: false
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
- run: npm install -g pnpm
- run: pnpm install
- run: pnpm run build
- uses: ./ # self
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
action-warmup:
name: 'Action - Cache warmup'
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
- run: npm install -g pnpm
- run: pnpm install
- run: pnpm run build
- uses: ./ # self
with:
cache-base: master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
ref: ${{ github.event.release.tag_name }}
- uses: actions/setup-node@v3
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# 1.1.0

- Added a `cache-base` input. When provided, will only save cache on this branch/ref, but will
restore cache on all branches/refs.
- Updated dependencies.

# 1.0.3

- Include `GITHUB_WORKFLOW` in cache key.
Expand Down
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ optional.

- `bins` - Comma-separated list of global binaries to install into Cargo.
- `cache` - Toggle caching of directories. Defaults to `true`.
- `cache-base` - Base branch/ref to save a warmup cache on. Other branches/refs will restore from
this base.
- `cache-target` - Name of the target profile to cache. Defaults to `debug`.
- `channel` - Toolchain specification/channel to explicitly install.
- `components` - Comma-separated list of additional components to install.
Expand Down Expand Up @@ -135,6 +137,23 @@ The following optimizations and considerations are taken into account when cachi
> The following sources are hashed for the generated cache key: `$GITHUB_JOB`, `Cargo.lock`, Rust
> version, Rust commit hash, and OS.

### Warmup strategy

Another strategy that we support is called a warmup cache, where a base branch/ref is used to
generate and save the cache (like master), and all other branches/refs will _only_ restore this
cache (and not save).

This can be enabled with the `cache-base` input, which requires a branch/ref name. This input also
supports regex.

```yaml
- uses: moonrepo/setup-rust@v1
with:
cache-base: master
# With regex
cache-base: (master|main|develop)
```

## Compared to

### `actions-rs/*`
Expand Down
3 changes: 3 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ inputs:
cache:
description: 'Toggle caching of ~/.cargo/registry and /target/<cache-target> directories.'
default: true
cache-base:
description:
'Base branch/ref to save a warmup cache on. Other branches/refs will restore from this base.'
cache-target:
description: 'Name of the target profile to cache.'
default: 'debug'
Expand Down
3 changes: 2 additions & 1 deletion index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import * as core from '@actions/core';
import * as exec from '@actions/exec';
import * as io from '@actions/io';
import * as tc from '@actions/tool-cache';
import { CARGO_HOME, installBins, restoreCache } from './src/cargo';
import { CARGO_HOME } from './src/cache';
import { installBins, restoreCache } from './src/cargo';
import { installToolchain } from './src/rust';

export async function installRustup() {
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@
"detect-libc": "^2.0.2"
},
"devDependencies": {
"@types/node": "^20.9.0",
"@types/node": "^20.9.1",
"@vercel/ncc": "^0.38.1",
"eslint": "^8.53.0",
"eslint-config-moon": "^2.0.11",
"prettier": "^3.0.3",
"prettier": "^3.1.0",
"prettier-config-moon": "^1.1.2",
"tsconfig-moon": "^1.3.0",
"typescript": "^5.2.2"
Expand Down
20 changes: 10 additions & 10 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@ import { saveCache } from './src/cargo';

async function run() {
try {
await saveCache();
const base = core.getInput('cache-base');

// Only save the cache for the following 2 scenarios:
// - If not using the base warmup strategy.
// - If using the base warmup strategy, and the current ref matches.
if (!base || (base && !!(process.env.GITHUB_REF_NAME ?? '').match(base))) {
await saveCache();
}
} catch (error: unknown) {
core.setFailed((error as Error).message);
}
Expand Down
92 changes: 92 additions & 0 deletions src/cache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import crypto from 'node:crypto';
import os from 'node:os';
import path from 'node:path';
import * as cache from '@actions/cache';
import * as core from '@actions/core';
import * as glob from '@actions/glob';
import { RUST_HASH, RUST_VERSION } from './rust';

export const CARGO_HOME = process.env.CARGO_HOME ?? path.join(os.homedir(), '.cargo');

export const WORKSPACE_ROOT = process.env.GITHUB_WORKSPACE ?? process.cwd();

export function isCacheEnabled(): boolean {
return core.getBooleanInput('cache') && cache.isFeatureAvailable();
}

export function getCacheTarget(): string {
return core.getInput('cache-target') || 'debug';
}

export function getCachePaths(): string[] {
return [
// ~/.cargo/registry
path.join(CARGO_HOME, 'registry'),
// /workspace/target/debug
path.join(WORKSPACE_ROOT, 'target', getCacheTarget()),
];
}

export function getCachePrefixes(): string[] {
return [`setup-rustcargo-v1-${process.platform}`, 'setup-rustcargo-v1'];
}

export async function getPrimaryCacheKey() {
const hasher = crypto.createHash('sha1');

core.info('Generating cache key');

core.debug(`Hashing Rust version = ${RUST_VERSION}`);
hasher.update(RUST_VERSION);

core.debug(`Hashing Rust commit hash = ${RUST_HASH}`);
hasher.update(RUST_HASH);

const cacheTarget = getCacheTarget();

core.debug(`Hashing target profile = ${cacheTarget}`);
hasher.update(cacheTarget);

// When warming up, loosen the cache key to allow for more cache hits
if (core.getInput('cache-base')) {
core.debug('Using warmup strategy, not hashing Cargo.lock, GITHUB_WORKFLOW, or GITHUB_JOB');
hasher.update('warmup');

const baseRef = process.env.GITHUB_BASE_REF ?? '';

if (
baseRef === 'master' ||
baseRef === 'main' ||
baseRef === 'trunk' ||
baseRef.startsWith('develop') ||
baseRef.startsWith('release')
) {
core.debug(`Hashing GITHUB_BASE_REF = ${baseRef}`);
hasher.update(baseRef);
}
}

// Otherwise, these add far too much granularity to the cache key
else {
const lockHash = await glob.hashFiles('Cargo.lock');

core.debug(`Hashing Cargo.lock = ${lockHash}`);
hasher.update(lockHash);

const workflow = process.env.GITHUB_WORKFLOW;

if (workflow) {
core.debug(`Hashing GITHUB_WORKFLOW = ${workflow}`);
hasher.update(workflow);
}

const job = process.env.GITHUB_JOB;

if (job) {
core.debug(`Hashing GITHUB_JOB = ${job}`);
hasher.update(job);
}
}

return `${getCachePrefixes()[0]}-${hasher.digest('hex')}`;
}
Loading

0 comments on commit c91b420

Please sign in to comment.