Like with cargo-add, I'm interested in merging cargo upgrade into cargo. There are some open questions on the design and, with how successful the cargo-add thread was, I'm hopeful we can have a productive brainstorming session on resolving them to finalize the design for merging into cargo. I especially want to call attention to the first point of concern below as its the most critical, undefined, and yet could have the biggest repercussions.
Background
cargo upgrade
performs bulk edits to a Cargo.toml's version requirements.
Example run on cargo
Notes
- It preserves existing version requirement precision, where possible
- By default, it deals with breaking changes only. To instead upgrade minimum versions, pass
--to-lockfile
- By default it ignores dependencies that are most likely pinned, requiring
--pinned
to upgrade them also. Besides the version requirement itself (e.g. using=
), we assume renamed dependencies are pinned dependencies since a common use case is to have multiple incompatible versions of a depednency - Output is formatted into a table modeled after
cargo outdated
but summarizes "uninteresting" cases. The goal is to (1) build trust that its working by communicating why we made a choice, (2) show information for users to make decisions, while (3) not overwhelming the user especially in large crates or workspaces - When selecting dependencies to upgrade (
cargo upgrade serde
), it accepts the renamed version of that dependency (cargo upgrade tokio_01
) to avoid selecting items intentionally held back (which is somewhat redundant with not upgrading pinned by default
Known Points of Concern
1. Distinction between cargo update
and cargo upgrade
may be confusing
The verbs "update" and "upgrade" can be synonymous to users. How can we clarify this?
Tools available
- Naming of the commands
- Finding a way to merge the commands, reconciling
-
upgrade
deals with breaking changes whileupdate
deals with compatible changes -
upgrade
deals with direct dependencies whileupdate
deals with direct and transitive dependencies -
upgrade
selects dependencies by their key (ie if renamed) whileupdate
selects dependencies by their crate name and optionally version -
upgrade
interacts with workspace members (manifests) whileupdate
interacts with the workspace itself (lock file)
-
- Cross-linking commands (e.g.
cargo upgrade
could suggest runningcargo update
if a direct dependency in the lockfile is stale) - Learn from prior art. I've not found another build system that deals with these concepts. Extending out to linux package managers,
apt
hasupdate
andupgrade
. Maybe people have experience with what they do to help clarify these or how other distributions avoid the problem.
Proposal Merge cargo upgrade
into cargo update
- Add
--save
flag to update direct dependencies to corresponding lockfile versions - Add
--incompatible
that forces the lockfile to upgrade across incompatible versions for unpinned version requirements- Error if this mismatches with manifest (ie
--save
is not passed in)
- Error if this mismatches with manifest (ie
- Add
--pinned
flag to update unpinned version requirements - Provide summary table at the end for direct dependencies
- Add
-Z minimal-direct-versions
that causes the resolver to update all transitive dependencies to latest but direct dependencies to the earliest version. This will help with libs that want to leave their version requirements low - Consider we mimicking
poetry
andgo get
by supportingcargo add <pkg>@latest
- Hack this behavior into
cargo upgrade
so we can collect feedback on whether there are workflows this is leaving behind
Comparing this with commands today:
-
cargo update
: same as today -
cargo update --save
: likecargo update && cargo upgrade --workspace --to-lockfile
-
cargo update --incompatible
: error if we try to upgrade to an incompatible version, suggesting adding--save
-
cargo update --incompatible --save
: likecargo upgrade --workspace && cargo update && cargo upgrade --workspace --to-lockfile
-
--pinned
would still exist but require--incompatible
to be present (i.e. we'd start updating pinned version reqs to the lock file) - Provide the direct dependency summary table at the end
2. How to select packages to upgrade vs dependencies within packages
Normally in cargo commands --workspace
, --package <PKGID>
, and --exclude <PKGID>
are used to select which packages to operate on.
cargo upgrade
has two dimensions to operate on
- Manifests to modify
- Dependencies within those manifests
Currently, we mix up the flags between these cases
-
--workspace
and--package <PKGID>
select manifests to modify -
<DEP_ID>
(a positional argument) and--exclude <DEP_ID>
select which dependencies within those manifests to modify
Proposal Rely on cargo update
s behavior
3. How do we represent "upgrade minimum compatible versions" vs "error if upgrades needed"
Currently
- Upgrade compatible minimums:
--to-lockfile
- Error if upgrades needed:
--locked
--locked
generally means "avoid or error if something will modify the lock file" which might match "Upgrade minimums" but we then need a way to fail if upgrades are needed.
There is --dry-run
but there are multiple, valid, approaches to error reporting for that
- Error only if a non-
dry-run
will fail - Error if the
--dry-run
was prevented from doing something - Always error
A more out there alternative to --to-lockfile
is we actually prompt the user for each upgrade and have a --choice <none|locked|latest>
to bypass the prompts with a specific choice.
Proposal Rely on cargo update
s behavior
4. Should we require require the repo to be clean, like cargo publish
or cargo fix
Proposal No change
-
cargo update
already doesn't do this and would be weird to have--save
only care - This is also consistent with
cargo add
andcargo rm
- Like the above commands, the developer might iterate on what is happening and requiring
--allow-dirty
would be disruptive
Prior Art
Prior art
-
(Python) poetry add
- Upgrade individual dependency via
poetry add <name>@latest
- No bulk upgrade, see Suggestion: new command to bump versions of dependencies in `pyproject.toml` · Issue #461 · python-poetry/poetry · GitHub
- Upgrade individual dependency via
-
(Javascript) yarn/pnpm ?
- Unclear how much behavior is like
cargo update
vscargo upgrade
- Unclear how much behavior is like
-
(Go)
go get
- Upgrade individual dependency via
go get <dep>@latest
- No bulk upgrade
- Upgrade individual dependency via
- ... Julia, Ruby, or Dart: ?
- Couldn't find any equivalents
Status Updates
(As of 8/1/2022)
- Updated proposal to merge cargo-update / cargo-upgrade