Enforcing style in CI for Rust Projects
This article isn’t a new addition to that debate. Instead, this article will attempt to help you avoid the debate entirely, at least in your Rust projects, by explaining how you can use the
rustfmt tool to enforce style guidelines using CI. We’ll start with a brief introduction to
rustfmt, so feel free to skip the next section if you are already familiar.
rustfmt is a tool for Rust projects that helps enforce style. It runs a set of lints against your code and will fail if any of the checks don’t pass.
rustfmt you first must add the component, via
rustup component add rustfmt-preview
Then, to run it:
It’s worth noting that when you run
cargo fmt it will change your code formatting. It will only fail if it cannot safely change your code. It’s quite smart though, and generally can take care of most of the problems for you, leaving just a few for you to solve on your own.
You can configure the default lints if you would like. For more on that, read this. Generally speaking, I don’t recommend configuring a tool like this, but I know that some folks really like to.
The rest of this article will discuss using
rustfmt in CI. We’ll use Travis CI for our examples, but you can use whichever CI provider you’d like without any significant edits.
Stable or Nightly
When testing on CI, one of the first decisions you need to make is which versions of Rust to test on. You’ll need to pick which channel is best to test your code on- and this is likely enforced by the dependencies your project uses.
rustfmt is in the mix, there’s a few more things to consider. As it currently stands,
rustfmt is slightly different on
nightly channels. If you are able to pick just one channel, the examples below should be very useful for you. We’ll discuss how to handle projects with multi-channel support in the next section.
On stable, your
.travis.yml should use
--write-mode diff. This feature will be deprecated in favor of
--check, which is currently on
beta and will land in the next release in early August (~1 month).
Nightly: use check
On nightly, your
.travis.yml, should use
--check. Long-term, this is the strategy you should use, and it should be stabilized in a little less than a month.
Style across Nightly and Stable
Many projects, especially libraries, support both nightly and stable channels. This poses a unique problem for testing style because
rustfmt has different checks in each channel’s version. This is because
rustfmt is still in preview mode.
As a result, it’s best to pick one channel to enforce style.
Nightly style, stable code features
If you so desire, you can use
rustfmt on the nightly channel, even if you only want to test your project on stable. It’s worth noting that you can’t do the inverse.
You’ll note that the Rust channel is set to
stable but we pass
--toolchain nightly when we add the
rustfmt-preview component, and then also use
+nightly when we call
Communicate to your contributors
When deciding which channel to pick, you should pay attention to the channel your project’s contributors generally work on. I would recommend adding a section in your project’s
CONTRIBUTING.md explains the need to choose one to enforce on. You can use this as a starting point (pulled from the
A Moving Target
rustfmt works towards stabilization, another thing to be aware of is that the style checks in both stable and nightly will change. This can definitely be frustrating!
If you are running into an issue with a contributor where style checks pass locally, but not on CI, it’s likely that the contributor has an older version of
rustfmt. To update, run:
Participate in the Discussion
If you are curious about what is in store for when
rustfmt is stablized, or just want to see what lints might change, you should check out the following links:
And there you have it! Some best practices on using
rustfmt to enforce style on your Rust projects in CI. Perhaps one day the whole developer community can relish, as I do, in the relief of leaving style enforcement energy to computers.