-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Seamless upgrade from 0.x to 1.0 #14460
Comments
I might be misunderstanding something, but this seems to assume that crates don't upgrade their dependencies between incompatible versions (including 0.x.y to 1.0.0). If this were true, I would argue this is the problem that needs fixing. Not upgrading between major versions is a sign of an unmaintained crate and an open door to transitive security vulnerabilities. Crates should not be afraid to release the exact same code from a 0.x.y version to a 1.0.0 version (although it is good practice to provide a migration guide between incompatible versions in the crate documentation, which in the case of the exact same code could be something like "smooth migration, no breaking changes"). |
Because Rust has safe code, it is not the case that all code can be sources of security vulnerabilities. Many algorithms are unlikely to have security-relevant bugs even with arbitrary input and even if they do contain bugs.
Doing so will create completely unnecessary incompatibilities that may have a very large cost. For example, if Even without the particular trouble of static state, breaking changes are still tedious any time you have a foundational library and dependents which build upon its types and traits. Not every library has this class of problem, but many can. Of course, this is all a one-time cost in this case, since there is exactly one 1.0, but I think you under-weight the cost of incompatible upgrades in general. And, the point of this issue is that, empirically, 1.0 releases are uncommon, and making them easier would make them more common. |
I'm just going to ignore this comment because it is an invalid argument. It is of the type: You can't argue against A by saying "A sometimes implies B (which is bad)" because "A doesn't always implies B" (where A is not using the latest major version of direct dependencies and B is making it harder for your dependents to apply security fixes when available). It's like arguing that we don't need safety belts because not all cars end up having a deadly accidents (where A is not using safety belts and B is having a deadly accident).
Again, similar issue as above. This is a corner case which should not alter the decision for the general case more than its actual proportion. If this proportion is big (of crates with global state that needs to be unique across the dependency tree), then we have an ecosystem issue. For those corner cases, it is acceptable to do the trick such that the ecosystem can be incrementally updated to the latest major version.
Again, same issue as above. Except that it's also mixing breaking changes (as in incompatible API change) and incompatible versions (as in different major versions). I'm not asking for breaking changes, I'm asking to not be afraid of incompatible versions when it actually doesn't break anything. In particular, users of #12425 won't even notice (as stated above, I believe crates should regularly use
And I think you don't make the distinction between incompatible upgrades and incompatible changes.
I'll restate what you're trying to say but correctly: The point of this issue is that there are crates with both a stable API and a major version of zero (this is in violation of SemVer item 4). The issue claims that those crates are afraid of bumping the major version number because it requires a manual update for their users (and implicitly that maintained crates won't do this manual update). The problem in your version is that you're missing the part where the crate has a stable API. It's expected that a lot of crates are 0.x.y because a lot of software is unstable. You won't magically make software stable. You also won't magically make software maintained. And trying to camouflage or not break unmaintained crates is a bad idea. Unmaintained crates should eventually be purged from the ecosystem so increasing the cost of their usage is a good thing. |
In hindsight, I should not have brought up In these terms, I think the place where we disagree is in how many dependencies are public dependencies. I think that there are enough chains of public dependencies that they are not a “corner case” and it is important to help them out.
Sorry, I used the wrong words. I meant to say incompatible versions.
I'm not claiming that having more incompatible versions will “break” anything. I'm claiming that that having a higher rate of incompatible versions gives maintainers more problems where they, collectively, have to pursue a sequence of incompatible version bumps, and there will be periods where they cannot perform those bumps. For example, suppose we have the following dependency graph (where all involved packages have different maintainers, and all packages make use of types from
Then, when Concretely, if we suppose that The deeper one’s dependency graph, the longer the delay from these cascades is. When one avoids a incompatible version bump that is not technically necessary, one avoids creating these periods of delay for one’s dependents. So, even given the premise that all transitive dependencies must be kept up to date (which I disagree with), it is desirable to have fewer incompatible versions, and therefore it is particularly likely that package authors will not bother to release an incompatible 1.0 just for “we are stable” documentation purposes.
Yes. The cases of interest are those where the API is in practice stable, but the maintainers don't want to release an incompatible version and fork the ecosystem of dependents, when it is not technically necessary to do so. The easier it is made for them to release 1.0 without creating such a fork, the more likely they will release a 1.0 when stable. It might be that those cases are too few for it to be worth adding a special seamless upgrade feature to Cargo, though. |
Majority of the top most used most dependent on crates are at 0.x. Why isn't libc at 1.0? Why isn't pkg-config 1.0? Why is Unicode-width for ten years at 0.1? |
Yes and more precisely the impact of public dependencies. I agree public dependencies have a negative impact on incompatible versions. However, I don't think this should cascade. Authors of crates with public dependencies have the responsibility to reduce the negative impact by specifying dependencies with a range of major versions that are actually compatible as exposed (and used) by that crate. This solution is officially recommended even though it currently has caveats. This will ultimately be properly handled when
This example (I'm assuming the
That said, I totally agree that overdoing incompatible versions without purpose is a bad idea. There's some trade-off to be found.
Yes, I think we agree on those points:
With infinite energy, I guess we could have such feature. But with infinite energy, we could also have maintainers use multiple version requirements and semver-trick. It's a trade-off and my personal opinion is that such feature should not be considered for cargo because it has a net negative impact (although it comes from good intentions). |
I'm facing this problem with my RGB crate. It provides a shared type for interoperability, but bumping it to 1.0 is going to ruin the interoperability. |
Because of missing education materials? Those crates should take the measure needed to go to 1.0. Those could be the semver-trick, providing a migration guide (including how to use multiple version requirements and which ones such that dependents can copy/paste), or a combination of both.
Why don't you use the semver-trick? Why don't you help your dependents migrate and propagate the migration? Should the work be on cargo instead of the ecosystem? |
Who needs to be educated? The crates I listed were created by some of the old time contributors to Rust and Cargo. Why should it be in Cargo? Because it can be implemented in one place for the benefit of the entire ecosystem. |
Just an aside but libc is already planning a 1,0 release but it is going to be a breaking release so the proposed Cargo feature won't help. |
Some recent examples of crates matching the problematic type (i.e. largely used with re-exported types) that went stable:
Note however that those were not only an incompatible version but also an incompatible change. So this issue wouldn't even have helped. |
The cargo team talked about this today and decided to close/postpone this for now. We acknowledge that this can be a friction for updating past 0.x, but were uncertain about how strong of a reason this particularly point is. There are quite a few complexities involved with this, such as impact on the resolver (which is already quite complex), modifications to the index, how this metadata gets added, etc. Something that could help is gathering survey information about reasons why maintainers stay with 0.x to better understand how common various reasons are. |
Problem
Release of 1.0.0 is a semver-incompatible change, which is inconvenient when a crate has already established a stable API and a userbase on a 0.x version.
Crates usually start from 0.1.0 and evolve their API while releasing 0.x versions. Once the crate reaches maturity and becomes de-facto stable while still in a 0.x version, there's no easy way to call it 1.0.0 and move the library and its users to v1. Versions 0.x and 1.0 are semver-incompatible, requiring manual upgrades. This fragments the userbase, causes churn, and can cause incompatibilities between crates unless a semver-trick is used.
During development it's hard to predict which semver-major breaking change will be the last breaking change needed (at least for a while), and therefore hard to predict when to commit to releasing 1.0.0. This becomes obvious in retrospect after the latest release stays stable for a while.
Having to use the "semver trick" to move 0.x users to 1.0.0 is far from perfect. It's a trick. It's not obvious. Needs care to forward Cargo features. If the new version is re-exporting the old one, it's also a breaking change to remove the re-export.
The Rust ecosystem has many de-facto stable and widely-used crates in v0.x. Out of the top 250 Rust crates with most downloads and/or rev deps, the majority (143) is still on v0.x. Being able to bless the last 0.x version as 1.0.0 without migration headaches could help at least some of the crates to move out of "unstable" 0.x versions. I'm hoping this would include
libc
, which in v0.2 is one of the most used stable Rust crates.Proposed Solution
There could be a mechanism that lets Cargo automatically unify selected semver-major versions of a crate, the same way it unifies minor and patch versions.
or maybe the other way:
Either way the expected behavior would be that
0.12
and1.0.0
would be treated as a compatible range, and all uses of0.12
were replaced by1.0.0
, the same way that av1.0.1234
would be unified and bumped tov1.1.0
.Notes
No response
The text was updated successfully, but these errors were encountered: