diff --git a/src/cargo/ops/cargo_package/mod.rs b/src/cargo/ops/cargo_package/mod.rs index 71d43bc0198..fe750adb9f7 100644 --- a/src/cargo/ops/cargo_package/mod.rs +++ b/src/cargo/ops/cargo_package/mod.rs @@ -239,18 +239,17 @@ fn do_package<'a>( let deps = local_deps(pkgs.iter().map(|(p, f)| ((*p).clone(), f.clone()))); let just_pkgs: Vec<_> = pkgs.iter().map(|p| p.0).collect(); - // The publish registry doesn't matter unless there are local dependencies, - // so only try to get one if we need it. If they explicitly passed a - // registry on the CLI, we check it no matter what. - let sid = if deps.has_no_dependencies() && opts.reg_or_index.is_none() { - None - } else { - let sid = get_registry(ws.gctx(), &just_pkgs, opts.reg_or_index.clone())?; - debug!("packaging for registry {}", sid); - Some(sid) - }; - let mut local_reg = if ws.gctx().cli_unstable().package_workspace { + // The publish registry doesn't matter unless there are local dependencies, + // so only try to get one if we need it. If they explicitly passed a + // registry on the CLI, we check it no matter what. + let sid = if deps.has_no_dependencies() && opts.reg_or_index.is_none() { + None + } else { + let sid = get_registry(ws.gctx(), &just_pkgs, opts.reg_or_index.clone())?; + debug!("packaging for registry {}", sid); + Some(sid) + }; let reg_dir = ws.build_dir().join("package").join("tmp-registry"); sid.map(|sid| TmpRegistry::new(ws.gctx(), reg_dir, sid)) .transpose()? @@ -407,9 +406,14 @@ fn local_deps(packages: impl Iterator) -> LocalDependenc for (pkg, _payload) in packages.values() { graph.add(pkg.package_id()); for dep in pkg.dependencies() { - // Ignore local dev-dependencies because they aren't needed for intra-workspace - // lockfile generation or verification as they get stripped on publish. - if dep.kind() == DepKind::Development || !dep.source_id().is_path() { + // We're only interested in local (i.e. living in this workspace) dependencies. + if !dep.source_id().is_path() { + continue; + } + + // If local dev-dependencies don't have a version specified, they get stripped + // on publish so we should ignore them. + if dep.kind() == DepKind::Development && !dep.specified_req() { continue; }; diff --git a/tests/testsuite/package.rs b/tests/testsuite/package.rs index ed12768cf1e..e519fa18bcf 100644 --- a/tests/testsuite/package.rs +++ b/tests/testsuite/package.rs @@ -5806,6 +5806,77 @@ features = ["foo"] ); } +#[cargo_test] +fn workspace_with_local_dev_deps() { + let crates_io = registry::init(); + let p = project() + .file( + "Cargo.toml", + r#" + [workspace] + members = ["main", "dev_dep"] + resolver = "3" + + [workspace.dependencies] + dev_dep = { path = "dev_dep", version = "0.0.1" } + "#, + ) + .file( + "main/Cargo.toml", + r#" + [package] + name = "main" + version = "0.0.1" + edition = "2024" + authors = [] + license = "MIT" + description = "main" + + [dev-dependencies] + dev_dep.workspace = true + "#, + ) + .file( + "dev_dep/Cargo.toml", + r#" + [package] + name = "dev_dep" + version = "0.0.1" + edition = "2024" + authors = [] + license = "MIT" + description = "main" + "#, + ) + .file("main/src/lib.rs", "") + .file("dev_dep/src/lib.rs", "") + .build(); + + p.cargo("package -Zpackage-workspace") + .masquerade_as_nightly_cargo(&["package-workspace"]) + .replace_crates_io(crates_io.index_url()) + .with_stdout_data("") + .with_stderr_data(str![[r#" +[WARNING] manifest has no documentation, homepage or repository. +See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. +[PACKAGING] dev_dep v0.0.1 ([ROOT]/foo/dev_dep) +[PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) +[WARNING] manifest has no documentation, homepage or repository. +See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. +[PACKAGING] main v0.0.1 ([ROOT]/foo/main) +[UPDATING] crates.io index +[PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) +[VERIFYING] dev_dep v0.0.1 ([ROOT]/foo/dev_dep) +[COMPILING] dev_dep v0.0.1 ([ROOT]/foo/target/package/dev_dep-0.0.1) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s +[VERIFYING] main v0.0.1 ([ROOT]/foo/main) +[COMPILING] main v0.0.1 ([ROOT]/foo/target/package/main-0.0.1) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s + +"#]]) + .run(); +} + fn workspace_with_local_deps_packaging_one_fails_project() -> Project { project() .file(