Description
Current behavior 😯
Some crates appear twice in the dependency tree. These are the crates that are part of the workspace and also depended on by gix-testtools
, either directly or transitively. For those crates, cargo
commands that specify a crate name with -p
do not easily work, due to the ambiguity of which crate is intended. For example, gix-date
is a transitive dependency of gix-testtools
, so this does not work:
ek in 🌐 catenary in gitoxide on main is 📦 v0.44.0 via 🦀 v1.86.0
❯ cargo nextest run -p gix-date
error: There are multiple `gix-date` packages in your project, and the specification `gix-date` is ambiguous.
Please re-run this command with one of the following specifications:
path+file:///home/ek/repos/gitoxide/gix-date#0.10.1
registry+https://github.com/rust-lang/crates.io-index#[email protected]
error: command `/home/ek/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin/cargo test --no-run --message-format json-render-diagnostics --package gix-date` exited with code 101
They can be made to work by giving cargo
enough information to select the correct crate, but this is cumbersome, it is not always obvious how to do this, and it seems to vary across different commands, and possibly even sometimes not to be feasible.
For commands run manually or through a script in this project that contains the command, this problem is only a minor inconvenience. This is because the command can be run without -p
in a subdirectory. For example, I can run cargo nextest
on gix-date
like this:
ek in 🌐 catenary in gitoxide on main is 📦 v0.44.0 via 🦀 v1.86.0 took 7s
❯ (cd gix-date; cargo nextest run)
Finished `test` profile [unoptimized + debuginfo] target(s) in 0.16s
────────────
Nextest run ID f978e57c-afa3-4b4c-9989-ad1240a49829 with nextest profile: default
Starting 31 tests across 2 binaries
PASS [ 0.003s] gix-date parse::relative::tests::two_weeks_ago
PASS [ 0.003s] gix-date::date time::format::iso8601_strict
...
This is long-standing. In a number of places in ci.yml
and the justfile
, where we would prefer to use <cmd> -p <crate>
and may even previously have done so (before <crate>
made its way into the gix-testtools
dependency tree by being added as a dependency of something it dpeends on), this workaround is used already. That is, we already have a number of uses of (cd <crate-dir>; <cmd>)
, or a variant such as (cd <crate-dir> && <cmd>)
. This approach is fully general.
The limitation of this workaround, though, is that sometimes we do not write the command. If the command is in an external script that we do not control, or if it is synthesized by an editor/IDE, then there is no easy workaround. The latter case is a practical problem, because VS Code with rust-analyzer composes commands that attempt but fail to run tests. Running tests through VS Code is something that would be convenient to do. The more important functionality, however, is to debug tests through VS Code, since then the editor integration really helps. Both are broken for tests of crates that are present in the workspace and also depended on directly or transitively by gix-testtools
.
For example, this shows an attempt to run the fuzz::invalid_but_does_not_cause_panic
test in the gix-date
test suite in the debugger in VS Code:
The message is analogous to the one shown above:
2025-05-04 18:30:19.625 [error] error: There are multiple `gix-date` packages in your project, and the specification `[email protected]` is ambiguous.
Please re-run this command with one of the following specifications:
path+file:///home/ek/repos/gitoxide/gix-date#0.10.1
registry+https://github.com/rust-lang/crates.io-index#[email protected]
2025-05-04 18:30:19.628 [error] Cargo invocation has failed: Error: exit code: 101.
Arguably this is a bug in the rust-analyzer
extension or some other component used in VS Code. A workaround is to debug the test in RustRover instead.
However, this will happen anytime -p <crate>
is used in a command that is not easily modified, either because it is not clear how to modify it (in practice, applying those "specifications" is not always as straightforward as the error message makes it sound), or because the command is synthesized by software and hard or impossible to customize.
Expected behavior 🤔
Commonly used techniques for running tests in a crate within a workspace should be allowed to work as expected, if at all possible.
If it is reasonable to deduplicate the crates in the workspace dependency tree, then that would fix this. I had long assumed that this was the only possible fix, and thus not gotten around to reporting this before. After all, gix-testtools
very intentionally depended on older SemVer-breaking versions of its gix-*
dependencies. However, since gix-testtools
v0.16.1, the versions are now intentionally the same (#1972).
Assuming we are able to keep it that way, it opens the option of depending not only on the same version, but also on the same code. The distinction between what version is used and what code is used is irrelevant outside of the gitoxide
workspace. That is, it is irrelevant for project that are separate from gitoxide and that use gix-testtools
from crates.io. But this distinction is relevant in crates developed here. When path =
is not specified in Cargo.toml
, the code from the workspace is not used, even if the versions would match.
Furthermore, it looks like this may--even separately from this issue--be intended. The commit message in 9b12d50, which appears in the v0.16.1 changelog, summarizes the change with the phrase "unify the dependency graph by choosing the right versions". But this actually does not unify the dependency graph. It unifies the versions, but the dependency is still duplicated due to the distinction between the published crate and the workspace crate.
If I understand correctly, the current behavior is that gix-testtools
depends on gix-*
crates as code published at crates.io, without including changes in the workspace versions (i.e. changes committed to the repository) since then. Assuming that is the case, truly unifying them by adding path = "../../gix-X"
in the gix-testtools
manifest for each gix-X
dependency gix-testtools
would have some other advantages besides fixing this issue, but also may have some disadvantages.
I will open a PR that makes this change, to demonstrate that it does actually work, which can then either be merged if the change is suitable, or closed without merging if not. Although there are other tradeoffs to consider, which I'll try to cover in the PR, the main concern I have about this relates to #1972 (comment): would this change further complicate things in the event that cargo-smart-release
is not adapted to allow releasing to proceed without extra steps?
Git behavior
Not applicable.
Steps to reproduce 🕹
See "Current behavior" above for details.
The quick reproducer is to see if cargo nextest run -p gix-date
works when run from the workspace root.