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
cargo
andrustup
available (might be missing at some CI services) - Install the toolchain needed (
stable
,nightly
or some specific version, and maybe a MSRV version too) - Run the
cargo check
,cargo test
and so on - Run
cargo clippy
andcargo fmt
too
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
cargo
executable. - It checks if
cargo
is 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 therustup
first (see the next section).
Here is an example:
- uses: actions-rs/cargo@v1
with:
command: build
arguments: --release --all-features
Sure, it is pretty much redundant and can be replaced with that one:
- run: cargo build --release --all-features
But 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-gnueabihf
Okay, 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: true
Which is basically the same as:
$ rustup toolchain install stable
$ rustup override set stable
Now, 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: true
And it is equal to these commands:
$ rustup toolchain install stable
$ rustup target add --toolchain stable armv7-unknown-linux-gnueabihf
$ rustup override set stable
As 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 warnings
And 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!