I finally got to reading this and just loved it. I read the headline a couple times and thought “that’s simple just ignore them” … and of course that’s a nice simple and wrong answer. Good work here, if/when I ever maintain a public crate I’ll be using this for sure.
Thanks for checking out the post and for the kind words!
cargo-semver-checks development is just full of “oh wow the ‘obvious’ solution is just completely wrong for fascinating reasons” moments :) If you’re looking for another example of non-obvious things being necessary, a good one is “we have to get rustdoc data on private items in order to determine what’s in the public API” from this blog post: https://predr.ag/blog/breaking-semver-in-rust-by-adding-private-type-or-import/
We’ve had problems with (what was supposed to be) a minor upgrade in a library crate. Its generics and traits had type bounds that required traits from another library crate dependency. Updating that dependency across a major version didn’t show up as a problem in cargo-semver-checks because no interfaces were changed, except for the bounds which broke semver. In retrospect obviously doing major dependency updates in a minor update is a no-no.
Yes, but not anytime soon unless the project gets a lot more funding. Getting there requires multiple engineer-years’ worth of work. I’d be thrilled to do the work, but unfortunately despite continually asking for GitHub sponsorships, cargo-semver-checks generates “family dinner” money and not rent money each month. That severely restricts how much time I can dedicate to it. I’d love your help with that!
The first obstacle is supporting cross-crate analysis. Right now, cargo-semver-checks sees only one crate’s rustdoc JSON at a time, due to some limitations in rustc metadata and the rustdoc format itself that make it challenging to resolve cross-crate items.
The next obstacle is modeling generics and type bounds in the Trustfall schema that cargo-semver-checks uses (schema — try querying it in our playground!) This is again doable but requires a few engineer-months of work since it’ll require some new features in Trustfall first.
The final obstacle is trait resolution itself. Rustdoc shows raw information, but does not provide any facility for checking if a concrete type Example<SomeType> satisfies the bounds on some trait impl and ends up implementing the trait. It’s even worse for generic types. I already had to reimplement rustc’s visibility resolution and name resolution rules in cargo-semver-checks to handle edge cases like the ones described in this post, and I suspect trait resolution would require something similar.
To summarize: plans, yes. Timeline, no. Limiting factor: funding, because I can’t afford to work on cargo-semver-checks full-time when it doesn’t pay the bills.
Since your employer seems to be getting some value out of cargo-semver-checks, I’d love it if you could help get them onboard as a sponsor of the project — even small donations add up: https://github.com/sponsors/obi1kenobi
Go has a rule where packages in a directory called /internal/ are only allowed to be imported by other packages in the same project. Is there a way to do this in Rust, or do you just use doc(hidden)?
There has been some discussion of a pub(workspace) visibility level that would be analogous to the Go rule, but it hasn’t been implemented yet. Currently AFAIK it has to be public, but can be prevented or discouraged from use via doc(hidden) or by putting it in an unpublished internal crate that is always used as a path dependency.
I finally got to reading this and just loved it. I read the headline a couple times and thought “that’s simple just ignore them” … and of course that’s a nice simple and wrong answer. Good work here, if/when I ever maintain a public crate I’ll be using this for sure.
Thanks for checking out the post and for the kind words!
cargo-semver-checks
development is just full of “oh wow the ‘obvious’ solution is just completely wrong for fascinating reasons” moments :) If you’re looking for another example of non-obvious things being necessary, a good one is “we have to get rustdoc data on private items in order to determine what’s in the public API” from this blog post: https://predr.ag/blog/breaking-semver-in-rust-by-adding-private-type-or-import/We’ve had problems with (what was supposed to be) a minor upgrade in a library crate. Its generics and traits had type bounds that required traits from another library crate dependency. Updating that dependency across a major version didn’t show up as a problem in cargo-semver-checks because no interfaces were changed, except for the bounds which broke semver. In retrospect obviously doing major dependency updates in a minor update is a no-no.
Any plan to tackle this kind of issues?
Yes, but not anytime soon unless the project gets a lot more funding. Getting there requires multiple engineer-years’ worth of work. I’d be thrilled to do the work, but unfortunately despite continually asking for GitHub sponsorships,
cargo-semver-checks
generates “family dinner” money and not rent money each month. That severely restricts how much time I can dedicate to it. I’d love your help with that!The first obstacle is supporting cross-crate analysis. Right now, cargo-semver-checks sees only one crate’s rustdoc JSON at a time, due to some limitations in rustc metadata and the rustdoc format itself that make it challenging to resolve cross-crate items.
The next obstacle is modeling generics and type bounds in the Trustfall schema that
cargo-semver-checks
uses (schema — try querying it in our playground!) This is again doable but requires a few engineer-months of work since it’ll require some new features in Trustfall first.The final obstacle is trait resolution itself. Rustdoc shows raw information, but does not provide any facility for checking if a concrete type
Example<SomeType>
satisfies the bounds on some trait impl and ends up implementing the trait. It’s even worse for generic types. I already had to reimplement rustc’s visibility resolution and name resolution rules incargo-semver-checks
to handle edge cases like the ones described in this post, and I suspect trait resolution would require something similar.To summarize: plans, yes. Timeline, no. Limiting factor: funding, because I can’t afford to work on
cargo-semver-checks
full-time when it doesn’t pay the bills.Since your employer seems to be getting some value out of
cargo-semver-checks
, I’d love it if you could help get them onboard as a sponsor of the project — even small donations add up: https://github.com/sponsors/obi1kenobiGo has a rule where packages in a directory called /internal/ are only allowed to be imported by other packages in the same project. Is there a way to do this in Rust, or do you just use doc(hidden)?
There has been some discussion of a
pub(workspace)
visibility level that would be analogous to the Go rule, but it hasn’t been implemented yet. Currently AFAIK it has to be public, but can be prevented or discouraged from use viadoc(hidden)
or by putting it in an unpublished internal crate that is always used as a path dependency.