cargo-semver-checks icon indicating copy to clipboard operation
cargo-semver-checks copied to clipboard

False negative: moving traits behind a non-default feature flag

Open adamchalmers opened this issue 1 year ago • 4 comments

Steps to reproduce the bug with the above code

  1. Clone the repo https://github.com/KittyCAD/modeling-api and check out the branch achalmers/remove-one-enum
  2. Notice that the PR adds a new Cargo feature "diesel", which is not a default feature. It also moves a lot of Diesel trait implementations behind the --features diesel flag, which should be a breaking change.

Actual Behaviour

Cargo semver-checks reports no semver violations

Expected Behaviour

Cargo semver-checks should report a semver violation

Generated System Information

Software version

cargo-semver-checks 0.25.0

Operating system

macOS 13.4.1 (Darwin 22.5.0)

Command-line

/Users/adamchalmers/.cargo/bin/cargo-semver-checks semver-checks --bugreport 

cargo version

> cargo -V 
cargo 1.74.1 (ecb9851af 2023-10-18)

Compile time information

  • Profile: release
  • Target triple: aarch64-apple-darwin
  • Family: unix
  • OS: macos
  • Architecture: aarch64
  • Pointer width: 64
  • Endian: little
  • CPU features: aes,crc,dit,dotprod,dpb,dpb2,fcma,fhm,flagm,fp16,frintts,jsconv,lor,lse,neon,paca,pacg,pan,pmuv3,ras,rcpc,rcpc2,rdm,sb,sha2,sha3,ssbs,vh
  • Host: aarch64-apple-darwin

Build Configuration

No response

Additional Context

No response

adamchalmers avatar Dec 12 '23 17:12 adamchalmers

Thanks for the report! This feels more like a shortcoming in our docs / FAQ / GitHub Action than anything else — I'd love your help in resolving it!

When checking, cargo-semver-checks has to choose a combination of features to build rustdoc with. Rustdoc doesn't currently support any way to build JSON that describes which pieces of code are visible under what combination of features, so we can't do a "single pass" check for all feature combinations.

We also cannot afford to check every combination of features by default, since that's 2^n combinations which would rapidly become impractical.

By default, cargo-semver-checks uses a heuristic to enable all features that "don't look private" in order to try to test as much code as possible: https://github.com/obi1kenobi/cargo-semver-checks#what-features-does-cargo-semver-checks-enable-in-the-tested-crates

But as you point out, this is also not a perfect choice since it will miss breakage that happens when only a subset of features is enabled. This is why it allows choosing other feature combinations: cargo semver-checks --default-features should catch the issue you point out.

My question to you is: how can we make this situation better for the next person?

Would you change something in the README / FAQ to convey this better? Perhaps suggest that users whose packages have non-default features run cargo-semver-checks both with only default features and with our heuristic for "all public features"?

obi1kenobi avatar Dec 12 '23 17:12 obi1kenobi

Thanks for explaining! I think ideally I'd like semver-checks to build and analyze Rustdoc twice: once with the current behaviour (all features that don't look private) and once with just the default features. I think a lot of Rust programmers use crates with just the default features.

That way, you'd catch the common problem of "this struct used to be visible by default, but now it's only visible if I enable a new Cargo feature for the crate". In my experience this is a common problem for semver in the Rust ecosystem :)

adamchalmers avatar Dec 12 '23 18:12 adamchalmers

Yeah, totally fair.

The reasons we haven't implemented this yet are questions of ergonomics and UX:

  • Because most crates don't have any features (default or otherwise), we don't want to run it twice for everyone. Checking for non-default features can be implemented, but it's a bit tricky around edge cases — e.g. what should happen if the "current" and "baseline" versions don't have the same answer for "does the crate have non-default features" ?
  • The "default features" and the current behavior scans are completely independent, and could run in parallel in separate jobs. The rustdoc build is the "long pole" in our performance profile, and sequentially building it twice would probably be a non-starter for some of the bigger crates and workspaces that use cargo-semver-checks. So perhaps the right answer is to implement this in our GitHub Action? That of course makes the feature detection I described above even more complex...

What do you think?

Btw, I'd love to have KittyCAD as a GitHub sponsor of cargo-semver-checks — and I'd be happy to make solving this problem a top priority if it would push you over the activation energy barrier for that :)

obi1kenobi avatar Dec 12 '23 18:12 obi1kenobi

Checking for non-default features can be implemented, but it's a bit tricky around edge cases

Agreed. A good first step might be to only run the check once if the [features] table in Cargo.toml is totally absent -- this would hit most of the crates without features, which is most crates as you say :)

We like sponsoring the open-source tech we rely on! I'm still only experimenting with semver-checks, right now I just run it for curiosity because I'm not actually using semver yet (just publishing some things on crates.io for ease of deployment). But if in the future it becomes part of our workflow, we'll sponsor you :)

adamchalmers avatar Dec 13 '23 03:12 adamchalmers