There are a few tests that's running locally but not on Github workflows. I've spent quite some time but not able to debug and fix them. For now, I want to ignore them on ci/cd but run them locally. Since, Github provides a handy environment variable CI, which always remains true, can I use that to ignore test?
I don't want to wrap the whole function code under if(env::var("CI").is_ok()). Is there any better way?
One way you could go about doing this is by adding a feature to your Cargo.toml file, like ci or something similar. And then have your GitHub action compile with that feature enabled, and have a conditional compilation attribute on the tests in question.
To do this, you would first add a new feature to your Cargo.toml file:
[features]
ci = []
Then in your Rust code on a test you could write something like this:
#[test]
#[cfg_attr(feature = "ci", ignore)]
fn test_some_code() {
println!("This is a test");
}
Now locally if you run cargo test you will see the test run, but if you run cargo test --features ci you will see the test shows ignored, like below:
Now you just have to change your GitHub action to compile with this feature. If your action looks something like this:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout#v2
- name: Build
run: cargo build --verbose
- name: Run tests
run: cargo test --verbose
Then add --features ci to the end of both the cargo build and cargo test commands.
For more information on conditional compilation, this is in the Rust book: https://doc.rust-lang.org/reference/conditional-compilation.html
For more information on features in Cargo, this is in the Cargo book: https://doc.rust-lang.org/cargo/reference/features.html
To add to pokeyOne's answer, you can include a build script that checks for the CI environment variable and enables a ci feature when it's present. To do this, you would add this build.rs to your project root:
fn main() {
if std::env::var("CI").is_ok() {
println!("cargo:rustc-cfg=feature=\"ci\"");
}
}
Note that build scripts are only run on clean builds, so to test this locally you'll need to run cargo clean between runs (this won't be an issue on CI since you're doing a clean build there).
$ cargo test # run all tests
$ cargo clean # make sure build.rs is re-run...
$ CI=1 cargo test # skip CI tests
Features are a special type of --cfg flag, used for conditional compilation. Instead of using a feature, you could instead use a single identifier --cfg flag, like so:
// build.rs
fn main() {
if std::env::var("CI").is_ok() {
println!("cargo:rustc-cfg=ci");
}
}
// src/main.rs
#[cfg(test)]
mod tests {
// ..(snip)..
#[test]
#[cfg(not(ci))]
fn breaks_on_ci() { ... }
}
This build.rs is equivalent to running
$ RUSTFLAGS="--cfg ci" cargo test
You can read more about build scripts, --cfg flags, and conditional compilation in the Rust book here.
Related
If I build my project with
cargo build --verbose --target=i686-linux-android
where build.rs looks like this
fn main() {
#[cfg(target_os = "linux")]
{
panic!("target_os is linux!!!!!!!!!!!!!");
}
I get the panic at panic!("target_os is linux!!!!!!!!!!!!!");, but the target is android.
Why?
The build.rs script is compiled and run locally and thus its #[cfg(...)] attributes will reflect the local system. If you want to know the operating system that you're ultimately building for, use the CARGO_CFG_TARGET_OS environment variable.
Others can be seen in Environment variables Cargo sets for build scripts in the Rust Reference.
I'm trying to learn rust by writing CLI but i can't do cargo run with features passed and i don't understand why. I read docs / stack and i still don't see why this is happening. It feels like it should work this way https://doc.rust-lang.org/cargo/commands/cargo-run.html
I'm trying to run this code
https://github.com/clap-rs/clap/blob/master/examples/17_yaml.rs
with command cargo run --features=yaml or cargo run --features yaml. I tried many combinations, none of them worked.
My Cargo.toml looks like that:
[dependencies.clap]
version = "*"
default-features = false
features = ["yaml"]
When i run i have error:
:!cargo run --features=yaml
error: Package `fun v0.1.0 (/Users/XXX/Projekty/rust/fun)` does not have these fe
atures: `yaml`
shell returned 101
What am i doing wrong?
Their code expects you to have cloned the clap repository, changed into its directory, and then run cargo run --features yaml --example 17_yaml from there. You can read more about how the cargo examples feature works here.
If you’re planning on copying their code, as noted in that example code, you have to remove this conditional compilation attribute:
// Note: If you're using clap as a dependency and don't have a feature for your users called
// "yaml", you'll need to remove the #[cfg(feature = "yaml")] conditional compilation attribute
#[cfg(feature = "yaml")]
fn main() {
Otherwise it will load this other main implementation and emit that error:
#[cfg(not(feature = "yaml"))]
fn main() {
// As stated above, if clap is not compiled with the YAML feature, it is disabled.
println!("YAML feature is disabled.");
println!("Pass --features yaml to cargo when trying this example.");
}
You don’t actually need to pass --features on the command line unless you are running their example within their crate as described above. You should also remove this whole function if you’re copying their code! It is only relevant when run as an example.
I'm trying to build and test my Rust code with a CI, and I'm wondering whether cargo clippy (potentially with options) covers everything that cargo check does. Do I only need to run cargo clippy, or do I need to run both?
clippy itself runs cargo check.
I'm trying to run the example code from this project. Following the instructions on the Cargo docs, I did the following:
git clone https://github.com/basiliscos/rust-procol-ftp-client
cd rust-procol-ftp-client
cargo run
cargo test
cargo test should also have compiled the example according to the Rust docs.
Although cargo test executes successfully, when I change into the target/debug directory, I don't find an executable for ftp-get (which is the example code). The target/debug/examples directory is also empty.
What is the best way to go about running this example?
You can run a specific example with:
cargo run --example name_of_example
where name_of_example is the base filename (without .rs)
or to run it in release mode:
cargo run --release --example name_of_example
To pass arguments to the example:
cargo run --example name_of_example -- arguments go here
cargo run will automatically build (or rebuild) the program first if it's out of date.
Try the following:
cd rust-procol-ftp-client
cargo build --examples
./target/debug/examples/ftp-get
In a Cargo project, I can easily run clippy on my src code using this command:
rustup run nightly cargo clippy
However, if I'm using a build script, I'd like to run clippy on that as well. For instance, if my build.rs file looks like this:
fn main() {
let foo = "Hello, world!";
println!("{}", foo);
}
I'd like to see this when I run clippy:
warning: use of a blacklisted/placeholder name `foo`, #[warn(blacklisted_name)] on by default
--> build.rs:2:9
|
2 | let foo = "Hello, world!";
| ^^^
|
= help: for further information visit https://github.com/Manishearth/rust-clippy/wiki#blacklisted_name
The only way I can think of to run clippy on my build script is to copy it into a cargo new temporary project, run clippy, make my changes there, and copy back, but this is horribly inconvenient and quickly becomes infeasible when build dependencies and the like are added to the mix.
Is there a simpler way to analyze my build script with clippy?
Note: This solution no longer works. The clippy plugin feature has been removed (source).
There are two ways to use Clippy: the cargo clippy command and the clippy compiler plugin. cargo clippy detects the build script as a dependency of the main project, so it doesn't load the compiler plugin.
Therefore, the other option is to use the compiler plugin directly. The instructions for doing this are in clippy's README. We need to make a few adaptations for using it on the build script, though.
First, we need to add clippy as a build dependency:
[build-dependencies]
clippy = { version = "*", optional = true }
[features]
default = []
Adding it to [dependencies] instead will not work (the result is error[E0463]: can't find crate for `clippy`), as Cargo will not pass the path to dependencies to the compiler when building the build script.
Then, we need to add this at the top of build.rs:
#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]
Finally, we need to build with the clippy feature enabled:
$ cargo build --features clippy
If you want to run clippy on both the build script and on the main project when you use the command above, add the same clippy dependency to [dependencies], then add the cfg_attr attributes to the crate root(s) (lib.rs, main.rs, etc.).