mirror of
https://github.com/moonrepo/setup-rust.git
synced 2025-05-02 14:50:02 +00:00
Compare commits
16 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
52e0bc3392 | ||
![]() |
2d9112aa0c | ||
![]() |
1670d14080 | ||
![]() |
dcab3dcf9f | ||
![]() |
c91b4202a2 | ||
![]() |
c15c42022b | ||
![]() |
9c00f9cafd | ||
![]() |
393c8c7871 | ||
![]() |
7a64551755 | ||
![]() |
deec13b3d0 | ||
![]() |
889bf1db60 | ||
![]() |
711a320c49 | ||
![]() |
7229efd154 | ||
![]() |
b07b2e2e9e | ||
![]() |
28b46eda6c | ||
![]() |
cef1bc3f53 |
14 changed files with 3096 additions and 2118 deletions
|
@ -7,4 +7,7 @@ module.exports = {
|
||||||
project: 'tsconfig.json',
|
project: 'tsconfig.json',
|
||||||
tsconfigRootDir: __dirname,
|
tsconfigRootDir: __dirname,
|
||||||
},
|
},
|
||||||
|
rules: {
|
||||||
|
'unicorn/prefer-top-level-await': 'off',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
38
.github/workflows/ci.yml
vendored
38
.github/workflows/ci.yml
vendored
|
@ -9,8 +9,42 @@ jobs:
|
||||||
name: 'CI'
|
name: 'CI'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v4
|
||||||
- run: npm install -g pnpm
|
- run: npm install -g pnpm
|
||||||
- run: pnpm install
|
- run: pnpm install
|
||||||
- run: pnpm run check
|
- run: pnpm run check
|
||||||
|
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@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:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.event.release.tag_name }}
|
ref: ${{ github.event.release.tag_name }}
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v4
|
||||||
- run: npm install -g pnpm
|
- run: npm install -g pnpm
|
||||||
- run: pnpm install
|
- run: pnpm install
|
||||||
- run: pnpm run build
|
- run: pnpm run build
|
||||||
|
|
46
CHANGELOG.md
46
CHANGELOG.md
|
@ -1,3 +1,49 @@
|
||||||
|
# 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.
|
||||||
|
- Updated dependencies.
|
||||||
|
|
||||||
|
# 1.0.2
|
||||||
|
|
||||||
|
- Switch to Node.js v20.
|
||||||
|
|
||||||
|
# 1.0.1
|
||||||
|
|
||||||
|
- Fixed an issue where a module was missing from the build.
|
||||||
|
|
||||||
|
# 1.0.0
|
||||||
|
|
||||||
|
- Will now install `rustup` if it does not exist in the environment.
|
||||||
|
- Added musl support to `cargo-binstall`.
|
||||||
|
|
||||||
|
# 0.6.0
|
||||||
|
|
||||||
|
- Breaking: Cargo `bins` must provide the `cargo-` crate prefix manually. This change allows
|
||||||
|
non-crate globals to be installed.
|
||||||
|
- Added a `cache-target` input, to customize which target profile is cached. Defaults to `debug`.
|
||||||
|
|
||||||
# 0.5.0
|
# 0.5.0
|
||||||
|
|
||||||
- Added `inherit-toolchain` input to inherit all settings from `rust-toolchain.toml`, and not just
|
- Added `inherit-toolchain` input to inherit all settings from `rust-toolchain.toml`, and not just
|
||||||
|
|
82
README.md
82
README.md
|
@ -11,10 +11,29 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
# ...
|
# ...
|
||||||
- uses: moonrepo/setup-rust@v0
|
- uses: moonrepo/setup-rust@v1
|
||||||
- run: cargo test
|
- run: cargo test
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
The following inputs are available for the action, and can be passed via `with`. All inputs are
|
||||||
|
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
|
## Configuring the Rust toolchain
|
||||||
|
|
||||||
This action will automatically install the appropriate toolchain with `rustup` by inspecting the
|
This action will automatically install the appropriate toolchain with `rustup` by inspecting the
|
||||||
|
@ -36,18 +55,19 @@ The toolchain/channel can also be explicitly configured with the `channel` input
|
||||||
highest precedence.
|
highest precedence.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: moonrepo/setup-rust@v0
|
- uses: moonrepo/setup-rust@v1
|
||||||
with:
|
with:
|
||||||
channel: '1.65.0'
|
channel: '1.65.0'
|
||||||
```
|
```
|
||||||
|
|
||||||
### Profile and components
|
### Profile, components, and targets
|
||||||
|
|
||||||
Furthermore, this action supports rustup profiles and components, which can be configured with the
|
Furthermore, this action supports rustup profiles, components, and targets, which can be configured
|
||||||
`profile` and `components` inputs respectively. When not defined, profile defaults to `minimal`.
|
with the `profile`, `components`, and `targets` inputs respectively. When not defined, profile
|
||||||
|
defaults to `minimal`.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: moonrepo/setup-rust@v0
|
- uses: moonrepo/setup-rust@v1
|
||||||
with:
|
with:
|
||||||
profile: complete
|
profile: complete
|
||||||
```
|
```
|
||||||
|
@ -55,36 +75,48 @@ Furthermore, this action supports rustup profiles and components, which can be c
|
||||||
When using components, the input requires a comma separated list of component names.
|
When using components, the input requires a comma separated list of component names.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: moonrepo/setup-rust@v0
|
- uses: moonrepo/setup-rust@v1
|
||||||
with:
|
with:
|
||||||
components: clippy
|
components: clippy
|
||||||
- run: cargo clippy --workspace
|
- run: cargo clippy --workspace
|
||||||
```
|
```
|
||||||
|
|
||||||
|
When using targets, the input requires a comma separated list of target triples.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- uses: moonrepo/setup-rust@v1
|
||||||
|
with:
|
||||||
|
targets: 'x86_64-pc-windows-msvc,x86_64-pc-windows-gnu'
|
||||||
|
```
|
||||||
|
|
||||||
## Installing Cargo binaries
|
## Installing Cargo binaries
|
||||||
|
|
||||||
If you require `cargo-make`, `cargo-nextest`, or other global binaries, this action supports
|
If you require `cargo-make`, `cargo-nextest`, or other global binaries, this action supports
|
||||||
installing Cargo binaries through the `bins` input, which requires a comma-separated list of crate
|
installing Cargo binaries through the `bins` input, which requires a comma-separated list of crate
|
||||||
names (`cargo-` prefix optional).
|
names.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: moonrepo/setup-rust@v0
|
- uses: moonrepo/setup-rust@v1
|
||||||
with:
|
with:
|
||||||
bins: nextest, cargo-insta@1.28.0
|
bins: cargo-nextest, cargo-insta@1.28.0
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
```
|
```
|
||||||
|
|
||||||
> Binaries are installed with [`cargo-binstall`](https://crates.io/crates/cargo-binstall) under the
|
> Binaries are installed with [`cargo-binstall`](https://crates.io/crates/cargo-binstall) under the
|
||||||
> hood.
|
> hood. We suggest setting `GITHUB_TOKEN` to avoid rate limiting.
|
||||||
|
|
||||||
## Caching in CI
|
## Caching in CI
|
||||||
|
|
||||||
By default this action will cache the `~/.cargo/registry` and `/target/debug` directories to improve
|
By default this action will cache the `~/.cargo/registry` and `/target/debug` directories to improve
|
||||||
CI times. To disable caching, set the `cache` input to `false`.
|
CI times. To disable caching, set the `cache` input to `false`. Furthermore, the target profile can
|
||||||
|
be changed with the `cache-target` input, which defaults to `debug`.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: moonrepo/setup-rust@v0
|
- uses: moonrepo/setup-rust@v1
|
||||||
with:
|
with:
|
||||||
cache: false
|
cache: false
|
||||||
|
cache-target: release
|
||||||
```
|
```
|
||||||
|
|
||||||
The following optimizations and considerations are taken into account when caching:
|
The following optimizations and considerations are taken into account when caching:
|
||||||
|
@ -98,7 +130,7 @@ The following optimizations and considerations are taken into account when cachi
|
||||||
`.cache`, and any other unnecessary files.
|
`.cache`, and any other unnecessary files.
|
||||||
- `/target`
|
- `/target`
|
||||||
- Only the `/debug` profile is cached, as this profile is typically used for formatting, linting,
|
- Only the `/debug` profile is cached, as this profile is typically used for formatting, linting,
|
||||||
and testing.
|
and testing. This can be changed with the `cache-target` input.
|
||||||
- The `/examples` and `/incremental` sub-directories are not cached as they are not necessary for
|
- The `/examples` and `/incremental` sub-directories are not cached as they are not necessary for
|
||||||
CI.
|
CI.
|
||||||
- All dep-info (`*.d`) files are removed, as they're meant for build systems and signaling
|
- All dep-info (`*.d`) files are removed, as they're meant for build systems and signaling
|
||||||
|
@ -107,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
|
> The following sources are hashed for the generated cache key: `$GITHUB_JOB`, `Cargo.lock`, Rust
|
||||||
> version, Rust commit hash, and OS.
|
> 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
|
## Compared to
|
||||||
|
|
||||||
### `actions-rs/*`
|
### `actions-rs/*`
|
||||||
|
@ -121,11 +170,6 @@ Outside of being evergreen, this action also supports the following features:
|
||||||
- Assumes `rustup`, `cargo`, and other commands are available globally. This allows you to use them
|
- Assumes `rustup`, `cargo`, and other commands are available globally. This allows you to use them
|
||||||
directly in a `run` command, without having to use `actions-rs/cargo`.
|
directly in a `run` command, without having to use `actions-rs/cargo`.
|
||||||
|
|
||||||
However, this action _does not_:
|
|
||||||
|
|
||||||
- Install `rustup` if it does not exist, while `actions-rs` will. This is typically fine if using
|
|
||||||
GitHub provided runners as all Rust tooling comes pre-installed.
|
|
||||||
|
|
||||||
### `dtolnay/rust-toolchain`
|
### `dtolnay/rust-toolchain`
|
||||||
|
|
||||||
Our action is very similar to theirs, which was a great implementation reference, but our action
|
Our action is very similar to theirs, which was a great implementation reference, but our action
|
||||||
|
|
27
action.yml
27
action.yml
|
@ -7,19 +7,28 @@ inputs:
|
||||||
bins:
|
bins:
|
||||||
description: 'Comma-separated list of global binaries to install into Cargo.'
|
description: 'Comma-separated list of global binaries to install into Cargo.'
|
||||||
cache:
|
cache:
|
||||||
description: 'Toggle caching of ~/.cargo/registry and /target/debug directories.'
|
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'
|
||||||
channel:
|
channel:
|
||||||
description: 'Toolchain specification/channel to install.'
|
description: 'Toolchain specification/channel to explicitly install.'
|
||||||
components:
|
components:
|
||||||
description: 'Comma-separated list of additional components to install.'
|
description: 'Comma-separated list of additional components to install.'
|
||||||
targets:
|
|
||||||
description: 'Comma-separated list of additional targets to install.'
|
|
||||||
profile:
|
|
||||||
description: 'Profile to install. Defaults to "minimal".'
|
|
||||||
inherit-toolchain:
|
inherit-toolchain:
|
||||||
description: 'Inherit all toolchain settings from the rust-toolchain.toml file.'
|
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:
|
outputs:
|
||||||
cache-key:
|
cache-key:
|
||||||
description: 'The generated cache key used.'
|
description: 'The generated cache key used.'
|
||||||
|
@ -30,7 +39,7 @@ outputs:
|
||||||
rust-hash:
|
rust-hash:
|
||||||
description: 'Commit hash of the installed rustc.'
|
description: 'Commit hash of the installed rustc.'
|
||||||
runs:
|
runs:
|
||||||
using: 'node16'
|
using: 'node20'
|
||||||
main: 'dist/index.js'
|
main: 'dist/index.js'
|
||||||
post: 'dist/post/index.js'
|
post: 'dist/post/index.js'
|
||||||
branding:
|
branding:
|
||||||
|
|
36
index.ts
36
index.ts
|
@ -1,8 +1,39 @@
|
||||||
import path from 'path';
|
import fs from 'node:fs';
|
||||||
|
import os from 'node:os';
|
||||||
|
import path from 'node:path';
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import { CARGO_HOME, installBins, restoreCache } from './src/cargo';
|
import * as exec from '@actions/exec';
|
||||||
|
import * as io from '@actions/io';
|
||||||
|
import * as tc from '@actions/tool-cache';
|
||||||
|
import { CARGO_HOME } from './src/cache';
|
||||||
|
import { installBins, restoreCache } from './src/cargo';
|
||||||
import { installToolchain } from './src/rust';
|
import { installToolchain } from './src/rust';
|
||||||
|
|
||||||
|
export async function installRustup() {
|
||||||
|
try {
|
||||||
|
await io.which('rustup', true);
|
||||||
|
return;
|
||||||
|
} catch {
|
||||||
|
// Doesn't exist
|
||||||
|
}
|
||||||
|
|
||||||
|
core.info('rustup does not exist, attempting to install');
|
||||||
|
|
||||||
|
const script = await tc.downloadTool(
|
||||||
|
process.platform === 'win32' ? 'https://win.rustup.rs' : 'https://sh.rustup.rs',
|
||||||
|
path.join(os.tmpdir(), 'rustup-init'),
|
||||||
|
);
|
||||||
|
|
||||||
|
core.info(`Downloaded installation script to ${script}`);
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-magic-numbers
|
||||||
|
await fs.promises.chmod(script, 0o755);
|
||||||
|
|
||||||
|
await exec.exec(script, ['--default-toolchain', 'none', '-y']);
|
||||||
|
|
||||||
|
core.info('Installed rustup');
|
||||||
|
}
|
||||||
|
|
||||||
async function run() {
|
async function run() {
|
||||||
core.info('Setting cargo environment variables');
|
core.info('Setting cargo environment variables');
|
||||||
|
|
||||||
|
@ -14,6 +45,7 @@ async function run() {
|
||||||
core.addPath(path.join(CARGO_HOME, 'bin'));
|
core.addPath(path.join(CARGO_HOME, 'bin'));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
await installRustup();
|
||||||
await installToolchain();
|
await installToolchain();
|
||||||
await installBins();
|
await installBins();
|
||||||
|
|
||||||
|
|
26
package.json
26
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@moonrepo/setup-rust",
|
"name": "@moonrepo/setup-rust",
|
||||||
"version": "0.5.0",
|
"version": "1.2.2",
|
||||||
"description": "A GitHub action for setting up Rust and Cargo.",
|
"description": "A GitHub action for setting up Rust and Cargo.",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -16,22 +16,26 @@
|
||||||
"author": "Miles Johnson",
|
"author": "Miles Johnson",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/cache": "^3.2.1",
|
"@actions/cache": "^4.0.0",
|
||||||
"@actions/core": "^1.10.0",
|
"@actions/core": "^1.10.1",
|
||||||
"@actions/exec": "^1.1.1",
|
"@actions/exec": "^1.1.1",
|
||||||
"@actions/glob": "^0.4.0",
|
"@actions/glob": "^0.5.0",
|
||||||
"@actions/io": "^1.1.3",
|
"@actions/io": "^1.1.3",
|
||||||
"@actions/tool-cache": "^2.0.1",
|
"@actions/tool-cache": "^2.0.1",
|
||||||
"@ltd/j-toml": "^1.38.0"
|
"@ltd/j-toml": "^1.38.0",
|
||||||
|
"detect-libc": "^2.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^18.15.11",
|
"@types/node": "^20.13.4",
|
||||||
"@vercel/ncc": "^0.36.1",
|
"@vercel/ncc": "^0.38.1",
|
||||||
"eslint": "^8.38.0",
|
"eslint": "^8.53.0",
|
||||||
"eslint-config-moon": "^2.0.2",
|
"eslint-config-moon": "^2.0.11",
|
||||||
"prettier": "^2.8.7",
|
"prettier": "^3.2.5",
|
||||||
"prettier-config-moon": "^1.1.2",
|
"prettier-config-moon": "^1.1.2",
|
||||||
"tsconfig-moon": "^1.3.0",
|
"tsconfig-moon": "^1.3.0",
|
||||||
"typescript": "^5.0.4"
|
"typescript": "^5.4.5"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
4695
pnpm-lock.yaml
generated
4695
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
9
post.ts
9
post.ts
|
@ -3,7 +3,14 @@ import { saveCache } from './src/cargo';
|
||||||
|
|
||||||
async function run() {
|
async function run() {
|
||||||
try {
|
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) {
|
} catch (error: unknown) {
|
||||||
core.setFailed((error as Error).message);
|
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')}`;
|
||||||
|
}
|
140
src/cargo.ts
140
src/cargo.ts
|
@ -1,21 +1,23 @@
|
||||||
import crypto from 'crypto';
|
import fs from 'node:fs';
|
||||||
import fs from 'fs';
|
import path from 'node:path';
|
||||||
import os from 'os';
|
import { family } from 'detect-libc';
|
||||||
import path from 'path';
|
|
||||||
import * as cache from '@actions/cache';
|
import * as cache from '@actions/cache';
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import * as exec from '@actions/exec';
|
import * as exec from '@actions/exec';
|
||||||
import * as glob from '@actions/glob';
|
import * as glob from '@actions/glob';
|
||||||
import * as tc from '@actions/tool-cache';
|
import * as tc from '@actions/tool-cache';
|
||||||
|
import {
|
||||||
|
CARGO_HOME,
|
||||||
|
getCachePaths,
|
||||||
|
getCachePrefixes,
|
||||||
|
getCacheTarget,
|
||||||
|
getPrimaryCacheKey,
|
||||||
|
isCacheEnabled,
|
||||||
|
WORKSPACE_ROOT,
|
||||||
|
} from './cache';
|
||||||
import { rmrf } from './fs';
|
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) {
|
export async function downloadAndInstallBinstall(binDir: string) {
|
||||||
core.info('cargo-binstall does not exist, attempting to install');
|
core.info('cargo-binstall does not exist, attempting to install');
|
||||||
|
|
||||||
|
@ -26,6 +28,9 @@ export async function downloadAndInstallBinstall(binDir: string) {
|
||||||
case 'x64':
|
case 'x64':
|
||||||
arch = 'x86_64';
|
arch = 'x86_64';
|
||||||
break;
|
break;
|
||||||
|
case 'arm':
|
||||||
|
arch = 'armv7';
|
||||||
|
break;
|
||||||
case 'arm64':
|
case 'arm64':
|
||||||
arch = 'aarch64';
|
arch = 'aarch64';
|
||||||
break;
|
break;
|
||||||
|
@ -34,9 +39,20 @@ export async function downloadAndInstallBinstall(binDir: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (process.platform) {
|
switch (process.platform) {
|
||||||
case 'linux':
|
case 'linux': {
|
||||||
file = `${arch}-unknown-linux-gnu.tgz`;
|
let lib = 'gnu';
|
||||||
|
|
||||||
|
if ((await family()) === 'musl') {
|
||||||
|
lib = 'musl';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.arch === 'arm') {
|
||||||
|
lib += 'eabihf';
|
||||||
|
}
|
||||||
|
|
||||||
|
file = `${arch}-unknown-linux-${lib}.tgz`;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case 'darwin':
|
case 'darwin':
|
||||||
file = `${arch}-apple-darwin.zip`;
|
file = `${arch}-apple-darwin.zip`;
|
||||||
break;
|
break;
|
||||||
|
@ -47,7 +63,11 @@ export async function downloadAndInstallBinstall(binDir: string) {
|
||||||
throw new Error(`Unsupported platform: ${process.platform}`);
|
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);
|
const dlPath = await tc.downloadTool(url);
|
||||||
|
|
||||||
if (url.endsWith('.zip')) {
|
if (url.endsWith('.zip')) {
|
||||||
|
@ -62,10 +82,9 @@ export async function installBins() {
|
||||||
.getInput('bins')
|
.getInput('bins')
|
||||||
.split(',')
|
.split(',')
|
||||||
.map((bin) => bin.trim())
|
.map((bin) => bin.trim())
|
||||||
.filter(Boolean)
|
.filter(Boolean);
|
||||||
.map((bin) => (bin.startsWith('cargo-') ? bin : `cargo-${bin}`));
|
|
||||||
|
|
||||||
if (CACHE_ENABLED) {
|
if (isCacheEnabled()) {
|
||||||
bins.push('cargo-cache');
|
bins.push('cargo-cache');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,45 +103,6 @@ export async function installBins() {
|
||||||
await exec.exec('cargo', ['binstall', '--no-confirm', '--log-level', 'info', ...bins]);
|
await exec.exec('cargo', ['binstall', '--no-confirm', '--log-level', 'info', ...bins]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getCachePaths(): string[] {
|
|
||||||
return [
|
|
||||||
// ~/.cargo/registry
|
|
||||||
path.join(CARGO_HOME, 'registry'),
|
|
||||||
// /workspace/target/debug
|
|
||||||
path.join(WORKSPACE_ROOT, 'target/debug'),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
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 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() {
|
export async function cleanCargoRegistry() {
|
||||||
core.info('Cleaning ~/.cargo before saving');
|
core.info('Cleaning ~/.cargo before saving');
|
||||||
|
|
||||||
|
@ -149,11 +129,13 @@ export async function cleanCargoRegistry() {
|
||||||
|
|
||||||
// https://doc.rust-lang.org/cargo/guide/build-cache.html
|
// https://doc.rust-lang.org/cargo/guide/build-cache.html
|
||||||
export async function cleanTargetProfile() {
|
export async function cleanTargetProfile() {
|
||||||
core.info('Cleaning target/debug before saving');
|
const targetProfile = getCacheTarget();
|
||||||
|
|
||||||
const targetDir = path.join(WORKSPACE_ROOT, 'target/debug');
|
core.info(`Cleaning target/${targetProfile} before saving`);
|
||||||
|
|
||||||
// target/debug/{examples,incremental} - Not required in CI
|
const targetDir = path.join(WORKSPACE_ROOT, 'target', targetProfile);
|
||||||
|
|
||||||
|
// target/*/{examples,incremental} - Not required in CI
|
||||||
core.info('Removing examples and incremental directories');
|
core.info('Removing examples and incremental directories');
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
|
@ -166,7 +148,7 @@ export async function cleanTargetProfile() {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
// target/debug/**/*.d - Not required in CI?
|
// target/**/*.d - Not required in CI?
|
||||||
core.info('Removing dep-info files (*.d)');
|
core.info('Removing dep-info files (*.d)');
|
||||||
|
|
||||||
const globber = await glob.create(path.join(targetDir, '**/*.d'));
|
const globber = await glob.create(path.join(targetDir, '**/*.d'));
|
||||||
|
@ -176,7 +158,7 @@ export async function cleanTargetProfile() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function saveCache() {
|
export async function saveCache() {
|
||||||
if (!CACHE_ENABLED) {
|
if (!isCacheEnabled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,29 +170,59 @@ export async function saveCache() {
|
||||||
return;
|
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 cleanCargoRegistry();
|
||||||
await cleanTargetProfile();
|
await cleanTargetProfile();
|
||||||
|
|
||||||
core.info(`Saving cache with key ${primaryKey}`);
|
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() {
|
export async function restoreCache() {
|
||||||
if (!CACHE_ENABLED) {
|
if (!isCacheEnabled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
core.info('Attempting to restore cache');
|
core.info('Attempting to restore cache');
|
||||||
|
|
||||||
const primaryKey = await getPrimaryCacheKey();
|
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());
|
const cacheKey = await cache.restoreCache(getCachePaths(), primaryKey, getCachePrefixes());
|
||||||
|
|
||||||
if (cacheKey) {
|
if (cacheKey) {
|
||||||
core.saveState('cache-hit-key', cacheKey);
|
core.saveState('cache-hit-key', cacheKey);
|
||||||
core.info(`Cache restored using key ${primaryKey}`);
|
core.info(`Cache restored using key ${primaryKey}`);
|
||||||
} else {
|
} else {
|
||||||
core.warning(`Cache does not exist using key ${primaryKey}`);
|
core.info(`Cache does not exist using key ${primaryKey}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
core.setOutput('cache-key', cacheKey ?? primaryKey);
|
core.setOutput('cache-key', cacheKey ?? primaryKey);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* eslint-disable import/no-mutable-exports */
|
/* eslint-disable import/no-mutable-exports */
|
||||||
|
|
||||||
import fs from 'fs';
|
import fs from 'node:fs';
|
||||||
import path from 'path';
|
import path from 'node:path';
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import * as exec from '@actions/exec';
|
import * as exec from '@actions/exec';
|
||||||
import TOML from '@ltd/j-toml';
|
import TOML from '@ltd/j-toml';
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"extends": "tsconfig-moon/tsconfig.json",
|
"extends": "tsconfig-moon/tsconfig.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"module": "Node16",
|
"module": "NodeNext",
|
||||||
"moduleResolution": "NodeNext",
|
"moduleResolution": "NodeNext",
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"verbatimModuleSyntax": false
|
"verbatimModuleSyntax": false
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue