mirror of
https://github.com/moonrepo/setup-rust.git
synced 2025-05-01 22:30:04 +00:00
Compare commits
5 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
52e0bc3392 | ||
![]() |
2d9112aa0c | ||
![]() |
1670d14080 | ||
![]() |
dcab3dcf9f | ||
![]() |
c91b4202a2 |
11 changed files with 2412 additions and 1774 deletions
30
.github/workflows/ci.yml
vendored
30
.github/workflows/ci.yml
vendored
|
@ -9,24 +9,42 @@ jobs:
|
|||
name: 'CI'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
- 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/setup-node@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
- 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@v4
|
||||
- run: npm install -g pnpm
|
||||
- run: pnpm install
|
||||
- run: pnpm run build
|
||||
- uses: ./ # self
|
||||
with:
|
||||
cache-base: master
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
4
.github/workflows/publish.yml
vendored
4
.github/workflows/publish.yml
vendored
|
@ -6,10 +6,10 @@ 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
|
||||
- uses: actions/setup-node@v4
|
||||
- run: npm install -g pnpm
|
||||
- run: pnpm install
|
||||
- run: pnpm run build
|
||||
|
|
22
CHANGELOG.md
22
CHANGELOG.md
|
@ -1,3 +1,25 @@
|
|||
# 1.2.2
|
||||
|
||||
- Updated dependencies.
|
||||
|
||||
# 1.2.1
|
||||
|
||||
- Pinned the `cargo-binstall` version to v1.8 to work around the 404 errors in CI.
|
||||
- Added support for the `CARGO_BINSTALL_VERSION` environment variable.
|
||||
|
||||
# 1.2.0
|
||||
|
||||
- Added a `target-dirs` input, allowing the target folders to be specified. Can now cache multiple
|
||||
target folders.
|
||||
- Updated to skip caching a directory if it does not exist, instead of failing.
|
||||
- Updated dependencies.
|
||||
|
||||
# 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.
|
||||
|
|
21
README.md
21
README.md
|
@ -22,12 +22,16 @@ 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.
|
||||
- `inherit-toolchain` - Inherit all toolchain settings from the `rust-toolchain.toml` file. Defaults
|
||||
to `false`.
|
||||
- `targets` - Comma-separated list of additional targets to install.
|
||||
- `target-dirs` - Comma-separated list of target folder paths, relative from the repository root.
|
||||
Defaults to `target`.
|
||||
- `profile` - Profile to install. Defaults to `minimal`.
|
||||
|
||||
## Configuring the Rust toolchain
|
||||
|
@ -135,6 +139,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/*`
|
||||
|
|
10
action.yml
10
action.yml
|
@ -8,7 +8,10 @@ inputs:
|
|||
description: 'Comma-separated list of global binaries to install into Cargo.'
|
||||
cache:
|
||||
description: 'Toggle caching of ~/.cargo/registry and /target/<cache-target> directories.'
|
||||
default: true
|
||||
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'
|
||||
|
@ -18,9 +21,12 @@ inputs:
|
|||
description: 'Comma-separated list of additional components to install.'
|
||||
inherit-toolchain:
|
||||
description: 'Inherit all toolchain settings from the rust-toolchain.toml file.'
|
||||
default: false
|
||||
default: 'false'
|
||||
targets:
|
||||
description: 'Comma-separated list of additional targets to install.'
|
||||
target-dirs:
|
||||
description: 'Comma-separated list of target folder paths, relative from the repository root.'
|
||||
default: 'target'
|
||||
profile:
|
||||
description: 'Profile to install. Defaults to "minimal".'
|
||||
outputs:
|
||||
|
|
3
index.ts
3
index.ts
|
@ -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() {
|
||||
|
|
14
package.json
14
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@moonrepo/setup-rust",
|
||||
"version": "1.0.3",
|
||||
"version": "1.2.2",
|
||||
"description": "A GitHub action for setting up Rust and Cargo.",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
|
@ -16,24 +16,24 @@
|
|||
"author": "Miles Johnson",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/cache": "^3.2.2",
|
||||
"@actions/cache": "^4.0.0",
|
||||
"@actions/core": "^1.10.1",
|
||||
"@actions/exec": "^1.1.1",
|
||||
"@actions/glob": "^0.4.0",
|
||||
"@actions/glob": "^0.5.0",
|
||||
"@actions/io": "^1.1.3",
|
||||
"@actions/tool-cache": "^2.0.1",
|
||||
"@ltd/j-toml": "^1.38.0",
|
||||
"detect-libc": "^2.0.2"
|
||||
"detect-libc": "^2.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.9.0",
|
||||
"@types/node": "^20.13.4",
|
||||
"@vercel/ncc": "^0.38.1",
|
||||
"eslint": "^8.53.0",
|
||||
"eslint-config-moon": "^2.0.11",
|
||||
"prettier": "^3.0.3",
|
||||
"prettier": "^3.2.5",
|
||||
"prettier-config-moon": "^1.1.2",
|
||||
"tsconfig-moon": "^1.3.0",
|
||||
"typescript": "^5.2.2"
|
||||
"typescript": "^5.4.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
|
|
3785
pnpm-lock.yaml
generated
3785
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
7
post.ts
7
post.ts
|
@ -3,7 +3,14 @@ import { saveCache } from './src/cargo';
|
|||
|
||||
async function run() {
|
||||
try {
|
||||
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);
|
||||
}
|
||||
|
|
102
src/cache.ts
Normal file
102
src/cache.ts
Normal file
|
@ -0,0 +1,102 @@
|
|||
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 getTargetPaths(): string[] {
|
||||
const profile = getCacheTarget();
|
||||
const dirs = core.getInput('target-dirs', { required: true }).split(',');
|
||||
|
||||
return dirs
|
||||
.map((dir) => dir.trim())
|
||||
.filter(Boolean)
|
||||
.map((dir) => path.join(WORKSPACE_ROOT, dir, profile));
|
||||
}
|
||||
|
||||
export function getCachePaths(): string[] {
|
||||
return [
|
||||
// ~/.cargo/registry
|
||||
path.join(CARGO_HOME, 'registry'),
|
||||
// /workspace/target/debug
|
||||
...getTargetPaths(),
|
||||
];
|
||||
}
|
||||
|
||||
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')}`;
|
||||
}
|
118
src/cargo.ts
118
src/cargo.ts
|
@ -1,6 +1,4 @@
|
|||
import crypto from 'node:crypto';
|
||||
import fs from 'node:fs';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { family } from 'detect-libc';
|
||||
import * as cache from '@actions/cache';
|
||||
|
@ -8,15 +6,18 @@ import * as core from '@actions/core';
|
|||
import * as exec from '@actions/exec';
|
||||
import * as glob from '@actions/glob';
|
||||
import * as tc from '@actions/tool-cache';
|
||||
import {
|
||||
CARGO_HOME,
|
||||
getCachePaths,
|
||||
getCachePrefixes,
|
||||
getCacheTarget,
|
||||
getPrimaryCacheKey,
|
||||
isCacheEnabled,
|
||||
WORKSPACE_ROOT,
|
||||
} from './cache';
|
||||
import { rmrf } from './fs';
|
||||
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 const CACHE_ENABLED = core.getBooleanInput('cache') && cache.isFeatureAvailable();
|
||||
|
||||
// eslint-disable-next-line complexity
|
||||
export async function downloadAndInstallBinstall(binDir: string) {
|
||||
core.info('cargo-binstall does not exist, attempting to install');
|
||||
|
||||
|
@ -62,7 +63,11 @@ export async function downloadAndInstallBinstall(binDir: string) {
|
|||
throw new Error(`Unsupported platform: ${process.platform}`);
|
||||
}
|
||||
|
||||
const url = `https://github.com/cargo-bins/cargo-binstall/releases/latest/download/cargo-binstall-${file}`;
|
||||
// https://github.com/cargo-bins/cargo-binstall/issues/1864
|
||||
const version = process.env.CARGO_BINSTALL_VERSION ?? 'v1.8.0';
|
||||
const url = version === 'latest'
|
||||
? `https://github.com/cargo-bins/cargo-binstall/releases/latest/download/cargo-binstall-${file}`
|
||||
: `https://github.com/cargo-bins/cargo-binstall/releases/download/${version}/cargo-binstall-${file}`;
|
||||
const dlPath = await tc.downloadTool(url);
|
||||
|
||||
if (url.endsWith('.zip')) {
|
||||
|
@ -79,7 +84,7 @@ export async function installBins() {
|
|||
.map((bin) => bin.trim())
|
||||
.filter(Boolean);
|
||||
|
||||
if (CACHE_ENABLED) {
|
||||
if (isCacheEnabled()) {
|
||||
bins.push('cargo-cache');
|
||||
}
|
||||
|
||||
|
@ -98,61 +103,6 @@ export async function installBins() {
|
|||
await exec.exec('cargo', ['binstall', '--no-confirm', '--log-level', 'info', ...bins]);
|
||||
}
|
||||
|
||||
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 lockHash = await glob.hashFiles('Cargo.lock');
|
||||
|
||||
core.debug(`Hashing Cargo.lock = ${lockHash}`);
|
||||
hasher.update(lockHash);
|
||||
|
||||
const cacheTarget = getCacheTarget();
|
||||
|
||||
core.debug(`Hashing target profile = ${cacheTarget}`);
|
||||
hasher.update(cacheTarget);
|
||||
|
||||
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')}`;
|
||||
}
|
||||
|
||||
export async function cleanCargoRegistry() {
|
||||
core.info('Cleaning ~/.cargo before saving');
|
||||
|
||||
|
@ -208,7 +158,7 @@ export async function cleanTargetProfile() {
|
|||
}
|
||||
|
||||
export async function saveCache() {
|
||||
if (!CACHE_ENABLED) {
|
||||
if (!isCacheEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -220,22 +170,52 @@ export async function saveCache() {
|
|||
return;
|
||||
}
|
||||
|
||||
const cachePaths = getCachePaths().filter((cachePath) => {
|
||||
if (!fs.existsSync(cachePath)) {
|
||||
core.info(`Cache path ${cachePath} does not exist, skipping`);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
if (cachePaths.length === 0) {
|
||||
core.info('No paths to cache, skipping save entirely');
|
||||
return;
|
||||
}
|
||||
|
||||
await cleanCargoRegistry();
|
||||
await cleanTargetProfile();
|
||||
|
||||
core.info(`Saving cache with key ${primaryKey}`);
|
||||
|
||||
await cache.saveCache(getCachePaths(), primaryKey);
|
||||
core.debug(`Cache key: ${primaryKey}`);
|
||||
core.debug('Cache paths:');
|
||||
|
||||
for (const cachePath of cachePaths) {
|
||||
core.debug(`- ${cachePath}`);
|
||||
}
|
||||
|
||||
await cache.saveCache(cachePaths, primaryKey);
|
||||
}
|
||||
|
||||
export async function restoreCache() {
|
||||
if (!CACHE_ENABLED) {
|
||||
if (!isCacheEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
core.info('Attempting to restore cache');
|
||||
|
||||
const primaryKey = await getPrimaryCacheKey();
|
||||
const cachePaths = getCachePaths();
|
||||
|
||||
core.debug(`Cache key: ${primaryKey}`);
|
||||
core.debug('Cache paths:');
|
||||
|
||||
for (const cachePath of cachePaths) {
|
||||
core.debug(`- ${cachePath}`);
|
||||
}
|
||||
|
||||
const cacheKey = await cache.restoreCache(getCachePaths(), primaryKey, getCachePrefixes());
|
||||
|
||||
if (cacheKey) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue