diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0686e3f..a2d5ed9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,66 +1,106 @@ - name: CI on: - push: + push: { branches: [main] } pull_request: schedule: [cron: "40 1 * * *"] jobs: install: - name: Rust ${{matrix.rust}} ${{matrix.os}} + name: Rust ${{matrix.rust || '(default)'}} (toolchain-file=${{matrix.write-toolchain-file}}) (${{matrix.os}}) runs-on: ${{matrix.os}} strategy: fail-fast: false + max-parallel: 5 matrix: - rust: [ - # Test with toolchain file override - "1.60", + os: + - ubuntu-latest + - windows-latest + - macos-latest + write-toolchain-file: + - false + - true + rust: + # use stable toolchain as default + - null + # Test that the sparse registry check works. # 1.66 and 1.67 don't support stable sparse registry. - "1.66", - "nightly", - "beta", - "stable", - ] - os: [ - "ubuntu-latest", - "windows-latest", - "macos-latest", - ] + - "1.66" + + - "nightly" + - "beta" + - "stable" steps: - uses: actions/checkout@v4 + # Test toolchain file support - name: Write rust-toolchain.toml + if: matrix.write-toolchain-file + shell: bash run: | cat <>rust-toolchain.toml [toolchain] - channel = "nightly-2022-09-10" + channel = "nightly-2024-01-10" components = [ "rustfmt", "rustc-dev" ] targets = [ "wasm32-unknown-unknown", "thumbv7m-none-eabi" ] profile = "minimal" EOF - shell: bash - if: matrix.rust == '1.60' - - uses: ./ - name: Run actions-rust-lang/setup-rust-toolchain ${{matrix.rust}} - id: toolchain + - id: toolchain + name: Run actions-rust-lang/setup-rust-toolchain ${{matrix.rust || 'on toolchain file'}} + uses: ./ with: toolchain: ${{matrix.rust}} components: clippy + - name: Check ${{'${{steps.toolchain.outputs.rustc-version}}'}} run: echo '${{steps.toolchain.outputs.rustc-version}}' + - name: Check ${{'${{steps.toolchain.outputs.cargo-version}}'}} run: echo '${{steps.toolchain.outputs.cargo-version}}' + - name: Check ${{'${{steps.toolchain.outputs.rustup-version}}'}} run: echo '${{steps.toolchain.outputs.rustup-version}}' - - run: rustc --version && cargo --version + + - name: Check lack of toolchain input or file results in stable + if: matrix.write-toolchain-file == false && matrix.rust == null + shell: bash + run: |- + rustcv="$(rustc --version)" + [[ "$rustcv" != *"nightly"* && "$rustcv" != *"beta"* ]] + + - name: Check toolchain file is being overridden + if: matrix.write-toolchain-file shell: bash + run: |- + rustcv="$(rustc --version)" + [[ ! ( "$rustcv" == *"nightly"* && "$rustcv" == *"2024-01-10"* ) ]] + + - shell: bash + run: rustc --version && cargo --version # Test with creating a small project - run: cargo init . --bin --name ci + # Add tiny empty crate. # This checks that registry access works. - run: cargo add serde_as + - run: cargo clippy + + cache: + name: Cache + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install Rust + uses: ./ + with: + components: clippy + cache: true + cache-workspaces: |- + ./test-workspace + + - run: cargo clippy --manifest-path=./test-workspace/Cargo.toml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..ba2a6f4 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,18 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.6.0 + hooks: + - id: check-case-conflict + - id: check-executables-have-shebangs + - id: check-merge-conflict + - id: check-json + - id: check-yaml + - id: end-of-file-fixer + - id: trailing-whitespace + args: [--markdown-linebreak-ext=md] + - repo: https://github.com/python-jsonschema/check-jsonschema + rev: 0.29.2 + hooks: + - id: check-dependabot + - id: check-github-actions + - id: check-github-workflows diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e580c5..a637784 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,46 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.12.0] - 2025-04-23 + +* Add support for installing rustup on Windows (#58 by @maennchen) + This adds support for using Rust on the GitHub provided Windows ARM runners. + +## [1.11.0] - 2025-02-24 + +* Add new parameter `cache-bin` that is propagated to `Swatinem/rust-cache` as `cache-bin` (#51 by @enkhjile) +* Add new parameter `cache-shared-key` that is propagated to `Swatinem/rust-cache` as `shared-key` (#52 by @skanehira) + +## [1.10.1] - 2024-10-01 + +* Fix problem matcher for rustfmt output. + The format has changed since https://github.com/rust-lang/rustfmt/pull/5971 and now follows the form "filename:line". + Thanks to @0xcypher02 for pointing out the problem. + +## [1.10.0] - 2024-09-23 + +* Add new parameter `cache-directories` that is propagated to `Swatinem/rust-cache` (#44 by @pranc1ngpegasus) +* Add new parameter `cache-key` that is propagated to `Swatinem/rust-cache` as `key` (#41 by @iainlane) +* Make rustup toolchain installation more robust in light of planned changes https://github.com/rust-lang/rustup/issues/3635 and https://github.com/rust-lang/rustup/pull/3985 +* Allow installing multiple Rust toolchains by specifying multiple versions in the `toolchain` input parameter. +* Configure the `rustup override` behavior via the new `override` input. (#38) + +## [1.9.0] - 2024-06-08 + +* Add extra argument `cache-on-failure` and forward it to `Swatinem/rust-cache`. (#39 by @samuelhnrq) + Set the default the value to true. + This will result in more caching than previously. + This helps when large dependencies are compiled only for testing to fail. + +## [1.8.0] - 2024-01-13 + +* Allow specifying subdirectories for cache. +* Fix toolchain file overriding. + +## [1.7.0] - 2024-01-11 + +* Allow overriding the toolchain file with explicit `toolchain` input. (#26) + ## [1.6.0] - 2023-12-04 ### Added diff --git a/README.md b/README.md index 2c1eef8..6f8a15c 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions-rust-lang/setup-rust-toolchain@v1 - run: cargo test --all-features - + # Check formatting with rustfmt formatting: name: cargo fmt @@ -42,18 +42,29 @@ jobs: ## Inputs All inputs are optional. -If a [toolchain file](https://rust-lang.github.io/rustup/overrides.html#the-toolchain-file) (i.e., `rust-toolchain` or `rust-toolchain.toml`) is found in the root of the repository, its `toolchain` value takes precedence. +If a [toolchain file](https://rust-lang.github.io/rustup/overrides.html#the-toolchain-file) (i.e., `rust-toolchain` or `rust-toolchain.toml`) is found in the root of the repository and no `toolchain` value is provided, all items specified in the toolchain file will be installed. +If a `toolchain` value is provided, the toolchain file will be ignored. +If no `toolchain` value or toolchain file is present, it will default to `stable`. First, all items specified in the toolchain file are installed. Afterward, the `components` and `target` specified via inputs are installed in addition to the items from the toolchain file. -| Name | Description | Default | -| ------------ | -------------------------------------------------------------------------------------- | ------------- | -| `toolchain` | Rustup toolchain specifier e.g. `stable`, `nightly`, `1.42.0`. | stable | -| `target` | Additional target support to install e.g. `wasm32-unknown-unknown` | | -| `components` | Comma-separated string of additional components to install e.g. `clippy, rustfmt` | | -| `cache` | Automatically configure Rust cache (using `Swatinem/rust-cache`) | true | -| `matcher` | Enable problem matcher to surface build messages and formatting issues | true | -| `rustflags` | Set the value of `RUSTFLAGS` (set to empty string to avoid overwriting existing flags) | "-D warnings" | +| Name | Description | Default | +| ------------------- | ------------------------------------------------------------------------------------------------------------------------ | ------------- | +| `toolchain` | Comma-separated list of Rustup toolchain specifier e.g. `stable`, `nightly`, `1.42.0`. The last version is the default. | stable | +| `target` | Additional target support to install e.g. `wasm32-unknown-unknown` | | +| `components` | Comma-separated string of additional components to install e.g. `clippy, rustfmt` | | +| `cache` | Automatically configure Rust cache (using [`Swatinem/rust-cache`]) | true | +| `cache-directories` | Propagates the value to [`Swatinem/rust-cache`] | | +| `cache-workspaces` | Propagates the value to [`Swatinem/rust-cache`] | | +| `cache-on-failure` | Propagates the value to [`Swatinem/rust-cache`] | true | +| `cache-key` | Propagates the value to [`Swatinem/rust-cache`] as `key` | | +| `cache-shared-key` | Propagates the value to [`Swatinem/rust-cache`] as `shared-key` | | +| `cache-bin` | Propagates the value to [`Swatinem/rust-cache`] as `cache-bin` | true | +| `matcher` | Enable problem matcher to surface build messages and formatting issues | true | +| `rustflags` | Set the value of `RUSTFLAGS` (set to empty string to avoid overwriting existing flags) | "-D warnings" | +| `override` | Setup the last installed toolchain as the default via `rustup override` | true | + +[`Swatinem/rust-cache`]: https://github.com/Swatinem/rust-cache ### RUSTFLAGS @@ -79,6 +90,16 @@ You can read more rustflags, and their load order, in the [Cargo reference]. | `rustup-version` | Version as reported by `rustup --version` | | `cachekey` | A short hash of the installed rustc version | +## Dependencies + +The action works best on the GitHub-hosted runners, but can work on self-hosted ones too, provided the necessary dependencies are available. +PRs to add support for more environments are welcome. + +* bash 5 +* brew (macOS only) +* rustup or curl +* using other node actions + ## License The scripts and documentation in this project are released under the [MIT diff --git a/action.yml b/action.yml index 500341b..ca44c3d 100644 --- a/action.yml +++ b/action.yml @@ -13,9 +13,8 @@ branding: # The action is heavily inspired by https://github.com/dtolnay/rust-toolchain inputs: toolchain: - description: "Rust toolchain specification -- see https://rust-lang.github.io/rustup/concepts/toolchains.html#toolchain-specification" + description: "Comma-separated list of Rust toolchain specifications. Last version becomes the default. -- see https://rust-lang.github.io/rustup/concepts/toolchains.html#toolchain-specification" required: false - default: "stable" target: description: "Target triple to install for this toolchain" required: false @@ -26,6 +25,26 @@ inputs: description: "Automatically configure Rust cache" required: false default: "true" + cache-workspaces: + description: "Paths to multiple Cargo workspaces and their target directories, separated by newlines." + required: false + cache-directories: + description: "Additional non workspace directories to be cached, separated by newlines." + required: false + cache-on-failure: + description: "Also cache on workflow failures" + default: "true" + required: false + cache-key: + description: "An additional cache key that is added alongside the automatic `job`-based cache key and can be used to further differentiate jobs." + required: false + cache-shared-key: + description: "A cache key that is used instead of the automatic `job`-based key, and is stable over multiple jobs." + required: false + cache-bin: + description: "Determines whether to cache ${CARGO_HOME}/bin." + required: false + default: "true" matcher: description: "Enable the Rust problem matcher" required: false @@ -34,6 +53,10 @@ inputs: description: "set RUSTFLAGS environment variable, set to empty string to avoid overwriting build.rustflags" required: false default: "-D warnings" + override: + description: "Setup the last installed toolchain as the default via `rustup override`" + required: false + default: "true" outputs: rustc-version: @@ -60,17 +83,21 @@ runs: shell: bash - id: flags + env: + targets: ${{inputs.target}} + components: ${{inputs.components}} + shell: bash run: | : construct rustup command line echo "targets=$(for t in ${targets//,/ }; do echo -n ' --target' $t; done)" >> $GITHUB_OUTPUT echo "components=$(for c in ${components//,/ }; do echo -n ' --component' $c; done)" >> $GITHUB_OUTPUT - echo "downgrade=${{inputs.toolchain == 'nightly' && inputs.components && ' --allow-downgrade' || ''}}" >> $GITHUB_OUTPUT + echo "downgrade=${{contains(inputs.toolchain, 'nightly') && inputs.components && ' --allow-downgrade' || ''}}" >> $GITHUB_OUTPUT + + # The environment variables always need to be set before the caching action + - name: Setting Environment Variables env: - targets: ${{inputs.target}} - components: ${{inputs.components}} + NEW_RUSTFLAGS: ${{inputs.rustflags}} shell: bash - # The environment variables always need to be set before the caching action - - name: "Setting Environment Variables" run: | if [[ ! -v CARGO_INCREMENTAL ]]; then echo "CARGO_INCREMENTAL=0" >> $GITHUB_ENV @@ -96,29 +123,43 @@ runs: if [[ ! -v CARGO_REGISTRIES_CRATES_IO_PROTOCOL ]]; then echo "CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse" >> $GITHUB_ENV fi - shell: bash - env: - NEW_RUSTFLAGS: ${{inputs.rustflags}} - - name: "Install Rust Problem Matcher" + + - name: Install Rust Problem Matcher if: inputs.matcher == 'true' - run: echo "::add-matcher::${{ github.action_path }}/rust.json" shell: bash + run: echo "::add-matcher::${{ github.action_path }}/rust.json" - name: Install rustup, if needed + shell: bash run: | if ! command -v rustup &> /dev/null ; then curl --proto '=https' --tlsv1.2 --retry 10 --retry-connrefused -fsSL "https://sh.rustup.rs" | sh -s -- --default-toolchain none -y - echo "${CARGO_HOME:-$HOME/.cargo}/bin" >> $GITHUB_PATH + + # Resolve the correct CARGO_HOME path depending on OS + if [[ "$RUNNER_OS" == "Windows" ]]; then + echo "${CARGO_HOME:-$USERPROFILE/.cargo}/bin" | sed 's|/|\\|g' >> $GITHUB_PATH + else + echo "${CARGO_HOME:-$HOME/.cargo}/bin" >> $GITHUB_PATH + fi fi - if: runner.os != 'Windows' + env: + RUNNER_OS: "${{ runner.os }}" + + - name: rustup toolchain install ${{inputs.toolchain || 'stable'}} + env: + toolchain: ${{inputs.toolchain}} + targets: ${{inputs.target}} + components: ${{inputs.components}} + override: ${{inputs.override}} shell: bash - - name: rustup toolchain install ${{inputs.toolchain}} run: | - if [[ -f "rust-toolchain" || -f "rust-toolchain.toml" ]] + if [[ -z "$toolchain" && ( -f "rust-toolchain" || -f "rust-toolchain.toml" ) ]] then # Install the toolchain as specified in the file - # Might break at some point: https://github.com/rust-lang/rustup/issues/1397 - rustup show + # rustup show is the old way that implicitly installed a toolchain + # rustup toolchain install is the new explicit way + # https://github.com/rust-lang/rustup/issues/3635#issuecomment-2343511297 + rustup show active-toolchain || rustup toolchain install if [[ -n $components ]]; then rustup component add ${components//,/ } fi @@ -126,16 +167,21 @@ runs: rustup target add ${targets//,/ } fi else - rustup toolchain install ${{inputs.toolchain}}${{steps.flags.outputs.targets}}${{steps.flags.outputs.components}} --profile minimal${{steps.flags.outputs.downgrade}} --no-self-update - rustup default ${{inputs.toolchain}} + if [[ -z "$toolchain" ]] + then + toolchain=stable + fi + rustup toolchain install ${toolchain//,/ } ${{steps.flags.outputs.targets}}${{steps.flags.outputs.components}} --profile minimal${{steps.flags.outputs.downgrade}} --no-self-update + # Take the last element from the list + if [[ "$override" == "true" ]] + then + rustup override set ${toolchain//*,/ } + fi fi - env: - targets: ${{inputs.target}} - components: ${{inputs.components}} - shell: bash - - name: Print installed versions - id: versions + - id: versions + name: Print installed versions + shell: bash run: | echo "rustc-version=$(rustc --version)" >> $GITHUB_OUTPUT rustc --version --verbose @@ -147,9 +193,9 @@ runs: DATE=$(rustc --version --verbose | sed -ne 's/^commit-date: \(20[0-9][0-9]\)-\([01][0-9]\)-\([0-3][0-9]\)$/\1\2\3/p') HASH=$(rustc --version --verbose | sed -ne 's/^commit-hash: //p') echo "cachekey=$(echo $DATE$HASH | head -c12)" >> $GITHUB_OUTPUT - shell: bash - - name: "Downgrade registry access protocol when needed" + - name: Downgrade registry access protocol when needed + shell: bash run: | # Not all versions support setting CARGO_REGISTRIES_CRATES_IO_PROTOCOL # On versions 1.66, 1.67, and 1.68.0-nightly the value "sparse" is still unstable. @@ -159,8 +205,14 @@ runs: echo "Downgrade cargo registry protocol to git" echo "CARGO_REGISTRIES_CRATES_IO_PROTOCOL=git" >> $GITHUB_ENV fi - shell: bash - - name: "Setup Rust Caching" + - name: Setup Rust Caching if: inputs.cache == 'true' uses: Swatinem/rust-cache@v2 + with: + workspaces: ${{inputs.cache-workspaces}} + cache-directories: ${{inputs.cache-directories}} + cache-on-failure: ${{inputs.cache-on-failure}} + cache-bin: ${{inputs.cache-bin}} + key: ${{inputs.cache-key}} + shared-key: ${{inputs.cache-shared-key}} diff --git a/rust.json b/rust.json index ddaa1b0..c407391 100644 --- a/rust.json +++ b/rust.json @@ -5,7 +5,7 @@ "severity": "warning", "pattern": [ { - "regexp": "^(Diff in (.+)) at line (\\d+):$", + "regexp": "^(Diff in (.+))(?: at line |:)(\\d+):$", "message": 1, "file": 2, "line": 3 diff --git a/test-workspace/Cargo.lock b/test-workspace/Cargo.lock new file mode 100644 index 0000000..f0ff31f --- /dev/null +++ b/test-workspace/Cargo.lock @@ -0,0 +1,16 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ci" +version = "0.1.0" +dependencies = [ + "serde_as", +] + +[[package]] +name = "serde_as" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee4afe4c5c3b69699c4267ae42b838e911466d7ca0005046adc93ac95bb16dd" diff --git a/test-workspace/Cargo.toml b/test-workspace/Cargo.toml new file mode 100644 index 0000000..431b03d --- /dev/null +++ b/test-workspace/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "ci" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +serde_as = "0.0.1" diff --git a/test-workspace/src/main.rs b/test-workspace/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/test-workspace/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +}