Skip to content

Commit a14791c

Browse files
authored
feat: skip publish=false pkg when publishing entire workspace (#15525)
### What does this PR try to resolve? Fixes #15006 This changes how cargo-publish works with the unstable `-Zpackage-workspace` feature. Before this, when publishing the entire workspace, like `cargo publish --workspace`, if there is a package with `package.pulibsh=false, it'll fail the entire publish process. After this, when `--workspace` is passed, or when publishing the virtual workspace, the intent is more like “publish all publishable in this workspace”, so skip `publish=false` packages and proceed to publish others. The new overall behavior looks like this: * `cargo publish` (inside a `package.publish = false` package): error * `cargo publish -p publishable -p unpublishable`: error * `cargo publish --workspace`: skips `package.publish = false See #15006 (comment) ### How should we test and review this PR? * `workspace_flag_with_unpublishable_packages` was added to ensure `--workspace` work with non-virtual workspace. * `unpublishable_package_as_versioned_dev_dep` was added to ensure versioned dev-dependencies won't be skipped and still fail cargo-publish, as they are required to be published. There is a new scenario that nothing is going to publish. I went with a warning instead of hard error because missing publish for the entire worspace should be a fairly visible. However, this is open for future to configure via Cargo lint system.
2 parents 966229a + 090dcfe commit a14791c

File tree

2 files changed

+307
-32
lines changed

2 files changed

+307
-32
lines changed

src/cargo/ops/registry/publish.rs

+40-13
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,46 @@ pub fn publish(ws: &Workspace<'_>, opts: &PublishOpts<'_>) -> CargoResult<()> {
9393
.filter(|(m, _)| specs.iter().any(|spec| spec.matches(m.package_id())))
9494
.collect();
9595

96+
let (unpublishable, pkgs): (Vec<_>, Vec<_>) = pkgs
97+
.into_iter()
98+
.partition(|(pkg, _)| pkg.publish() == &Some(vec![]));
99+
// If `--workspace` is passed,
100+
// the intent is more like "publish all publisable packages in this workspace",
101+
// so skip `publish=false` packages.
102+
let allow_unpublishable = multi_package_mode
103+
&& match &opts.to_publish {
104+
Packages::Default => ws.is_virtual(),
105+
Packages::All(_) => true,
106+
Packages::OptOut(_) => true,
107+
Packages::Packages(_) => false,
108+
};
109+
if !unpublishable.is_empty() && !allow_unpublishable {
110+
bail!(
111+
"{} cannot be published.\n\
112+
`package.publish` must be set to `true` or a non-empty list in Cargo.toml to publish.",
113+
unpublishable
114+
.iter()
115+
.map(|(pkg, _)| format!("`{}`", pkg.name()))
116+
.join(", "),
117+
);
118+
}
119+
120+
if pkgs.is_empty() {
121+
if allow_unpublishable {
122+
let n = unpublishable.len();
123+
let plural = if n == 1 { "" } else { "s" };
124+
ws.gctx().shell().warn(format_args!(
125+
"nothing to publish, but found {n} unpublishable package{plural}"
126+
))?;
127+
ws.gctx().shell().note(format_args!(
128+
"to publish packages, set `package.publish` to `true` or a non-empty list"
129+
))?;
130+
return Ok(());
131+
} else {
132+
unreachable!("must have at least one publishable package");
133+
}
134+
}
135+
96136
let just_pkgs: Vec<_> = pkgs.iter().map(|p| p.0).collect();
97137
let reg_or_index = match opts.reg_or_index.clone() {
98138
Some(r) => {
@@ -705,19 +745,6 @@ fn package_list(pkgs: impl IntoIterator<Item = PackageId>, final_sep: &str) -> S
705745
}
706746

707747
fn validate_registry(pkgs: &[&Package], reg_or_index: Option<&RegistryOrIndex>) -> CargoResult<()> {
708-
let unpublishable = pkgs
709-
.iter()
710-
.filter(|pkg| pkg.publish() == &Some(Vec::new()))
711-
.map(|pkg| format!("`{}`", pkg.name()))
712-
.collect::<Vec<_>>();
713-
if !unpublishable.is_empty() {
714-
bail!(
715-
"{} cannot be published.\n\
716-
`package.publish` must be set to `true` or a non-empty list in Cargo.toml to publish.",
717-
unpublishable.join(", ")
718-
);
719-
}
720-
721748
let reg_name = match reg_or_index {
722749
Some(RegistryOrIndex::Registry(r)) => Some(r.as_str()),
723750
None => Some(CRATES_IO_REGISTRY),

0 commit comments

Comments
 (0)