GitHub Actions for Rust
A few weeks ago I got beta access to the GitHub CI/CD platform called Actions. For my own Rust projects I was using Travis CI mostly before and had started migrating to the Azure Pipelines recently, but now I’m considering moving to the Actions instead.
Configuration syntax is a bit nicer comparing to Azure one, there are Linux, macOS and Windows environments available (pretty much as everywhere now) and integration with other GitHub parts is just amazing. But the most important thing there for me is a possibility to create “Actions” — custom tasks to be executed in the CI workflow. So, about that.
What does usual Rust CI looks alike
In order to make a decent CI workflow for a Rust project there are few things you might want to do:
- Check that there are
cargoandrustupavailable (might be missing at some CI services) - Install the toolchain needed (
stable,nightlyor some specific version, and maybe a MSRV version too) - Run the
cargo check,cargo testand so on - Run
cargo clippyandcargo fmttoo
Also, I prefer to use the nightly version of clippy, as it is fancier than stable one,
but it might not be available in the latest nightly toolchain,
so either I’m left with a broken build for a whole day
or I should permanently mark that job as an “okay to fail“
and check the output manually each time.
At first, I found myself copying all the same scripts from Azure Pipelines configurations, but then I thought that it would be great to share them somehow between my projects, got carried away a little and now I’m excited to present GitHub Actions for Rust — basic blocks to build a CI workflows for Rust projects without worries.
cargo
This Action is needed when you want to call cargo.
It is pretty much the same as - run: cargo build line in the job steps,
but it can do two additional things:
- If you are using cross-platform compilation,
it can install cross automatically on demand,
and call it instead of the
cargoexecutable. - It checks if
cargois available at all. As for 2019-09-15, Rust is not installed for a macOS environment by default, so this Action shows a nice error message, which suggests to install therustupfirst (see the next section).
Here is an example:
- uses: actions-rs/cargo@v1
with:
command: build
arguments: --release --all-featuresSure, it is pretty much redundant and can be replaced with that one:
- run: cargo build --release --all-featuresBut the following example will install cross automatically for you and call it instead. Cool, right?
- uses: actions-rs/cargo@v1
with:
use-cross: true
command: build
args: --target armv7-unknown-linux-gnueabihfOkay, yes, but where does armv7-unknown-linux-gnueabihf target come from?
toolchain
This one Action, as you might have guessed, can install the Rust toolchain and, if needed, specific compilation target for it.
In a simplest form, it looks like this:
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: trueWhich is basically the same as:
$ rustup toolchain install stable
$ rustup override set stableNow, let’s add the target input to make that armv7 example from above to compile:
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: armv7-unknown-linux-gnueabihf
override: trueAnd it is equal to these commands:
$ rustup toolchain install stable
$ rustup target add --toolchain stable armv7-unknown-linux-gnueabihf
$ rustup override set stableAs I’ve mentioned before, cargo executable might not be available
for all environments and rustup might be missing too.
This Action will automatically install the rustup on a first call if needed,
no more headaches, yay!
components-nightly
Third one Action helps with a missing clippy and rustfmt components for nightly builds;
when executed, it finds the most recent toolchain with the requested component available.
Combine it with the toolchain Action from above
and you can fall back to the specific nightly build instead of breaking a CI job.
For example, clippy is missing for nightly-x86_64-unknown-linux-gnu-2019-09-16,
..-2019-09-15 and ..-2019-09-14 builds, but available for nightly-..-2019-09-13.
We can use the components-nightly output to install the specific nightly version and use its clippy:
- id: component
uses: actions-rs/components-nightly@v1
with:
target: x86_64-unknown-linux-gnu
component: clippy
- uses: actions-rs/toolchain@v1
with:
toolchain: ${{ steps.component.outputs.toolchain }}
override: true
- uses: actions-rs/cargo@v1
with:
command: clippy
args: -- -D warningsAnd you can do the same thing for rustfmt, miri
or any other rustup component if you want too.
Conclusion
So far that’s pretty much it.
I like an idea of hiding up the setup complexity
and making the workflow configuration totally declarative,
GitHub Actions looks like a great thing to help with that.
Check out the @actions-rs organization for sources, examples and some workflow recipes and let me know what are you thinking!