Skip to content

Commit 53d9920

Browse files
authored
feat(cargo-mono): always forward --no-verify on publish (#348)
## Summary - always pass `--no-verify` to delegated `cargo publish` calls, including dry-run mode - update publish error context, CLI help text, and cargo-mono docs to describe the new contract - extend integration coverage to assert forwarded cargo publish flags in execute and dry-run flows ## Testing - cargo test -p cargo-mono - cargo test
1 parent e443276 commit 53d9920

7 files changed

Lines changed: 99 additions & 3 deletions

File tree

crates/AGENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
- Keep command identifiers stable and documented in `docs/project-cargo-mono.md` and `docs/crates-cargo-mono-foundation.md`.
3636
- Preserve `cargo mono` subcommand compatibility (`cargo-mono` binary naming contract).
3737
- Keep release-tag responsibility split: `bump` must not create tags, and `publish` may create tags only for packages listed in `[workspace.metadata.cargo-mono.publish.tag].packages`.
38+
- Keep `publish` delegation aligned with the documented contract: `cargo mono publish` must invoke `cargo publish --no-verify` in both execute and dry-run modes.
3839
- Ensure release automation (`bump`, `publish`) logs include structured operational context.
3940
- Keep runtime error output on the fixed `Summary/Context/Hint` three-line contract and include only safe debugging context values.
4041

crates/cargo-mono/README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ cargo mono bump [--all|--changed|--package <name>] --level <major|minor|patch|pr
1111
cargo mono publish [--all|--changed|--package <name>] [--dry-run]
1212
```
1313

14+
`cargo mono publish` always delegates to `cargo publish --no-verify`, including `--dry-run`
15+
execution.
16+
1417
## Publish Tag Configuration
1518

1619
`cargo mono publish` can create local Git tags for published crates when opt-in allowlist
@@ -40,7 +43,7 @@ Coverage highlights:
4043
- `list`: workspace discovery and publishability reporting.
4144
- `changed`: base override, include/exclude filters, invalid glob rejection, direct-only vs dependent expansion, include-uncommitted behavior, and global-impact file handling.
4245
- `bump`: clean-tree preflight, non-publishable skip behavior, manifest/version/dependency updates, dependent patch propagation, and release commit creation (no tag creation).
43-
- `publish`: clean-tree preflight, non-publishable skip behavior, unknown package validation, and allowlist-based publish tag creation.
46+
- `publish`: clean-tree preflight, fixed `--no-verify` delegation (including dry-run), unknown package validation, and allowlist-based publish tag creation.
4447
- Cargo external-subcommand mode compatibility (`cargo mono ...`) and top-level help/version behavior outside workspaces.
4548

4649
## Local Validation

crates/cargo-mono/src/cli.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,8 @@ pub struct PublishArgs {
144144
pub target: TargetArgs,
145145
#[command(flatten)]
146146
pub changed: ChangedArgs,
147-
/// Validate publish without uploading artifacts.
147+
/// Run the publish flow without uploading artifacts; delegated Cargo
148+
/// verification remains disabled.
148149
#[arg(long)]
149150
pub dry_run: bool,
150151
/// Allow execution with a dirty working tree.

crates/cargo-mono/src/commands/publish.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pub(super) const PUBLISH_PREFETCH_CONCURRENCY_ENV: &str = "CARGO_MONO_PUBLISH_PR
3030
const DEFAULT_PREFETCH_CONCURRENCY: usize = 16;
3131
const MAX_PREFETCH_CONCURRENCY: usize = 64;
3232
const PREFETCH_HTTP_TIMEOUT: Duration = Duration::from_secs(15);
33+
const PUBLISH_NO_VERIFY: bool = true;
3334

3435
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3536
enum PublishFailureKind {
@@ -264,6 +265,7 @@ pub fn execute(args: &PublishArgs, output: OutputSettings, app: &CargoMonoApp) -
264265
outcome = "attempt",
265266
retry_attempt = attempts,
266267
mode = mode.as_str(),
268+
no_verify = PUBLISH_NO_VERIFY,
267269
"Publishing package"
268270
);
269271

@@ -956,7 +958,11 @@ fn merge_prefetch_lookup_results(
956958

957959
fn run_publish_command(package: &str, dry_run: bool, registry: Option<&str>) -> Result<Output> {
958960
let mut command = Command::new("cargo");
959-
command.arg("publish").arg("-p").arg(package);
961+
command
962+
.arg("publish")
963+
.arg("-p")
964+
.arg(package)
965+
.arg("--no-verify");
960966

961967
if dry_run {
962968
command.arg("--dry-run");
@@ -973,6 +979,7 @@ fn run_publish_command(package: &str, dry_run: bool, registry: Option<&str>) ->
973979
vec![
974980
("package", package.to_string()),
975981
("dry_run", dry_run.to_string()),
982+
("no_verify", PUBLISH_NO_VERIFY.to_string()),
976983
("registry", registry.unwrap_or("default").to_string()),
977984
("error", error.to_string()),
978985
],
@@ -996,6 +1003,7 @@ fn format_publish_failure(
9961003
("attempt", attempts.to_string()),
9971004
("status", status.to_string()),
9981005
("dry_run", dry_run.to_string()),
1006+
("no_verify", PUBLISH_NO_VERIFY.to_string()),
9991007
("registry", registry.unwrap_or("default").to_string()),
10001008
];
10011009
if !details.is_empty() {
@@ -1034,6 +1042,7 @@ fn format_publish_retry_limit_failure(
10341042
("attempts", attempts.to_string()),
10351043
("max_attempts", MAX_PUBLISH_ATTEMPTS.to_string()),
10361044
("dry_run", dry_run.to_string()),
1045+
("no_verify", PUBLISH_NO_VERIFY.to_string()),
10371046
("registry", registry.unwrap_or("default").to_string()),
10381047
],
10391048
"Wait for index propagation or rate limits to clear, then rerun publish.",
@@ -1214,6 +1223,7 @@ mod tests {
12141223
assert!(message.contains("package=alpha"));
12151224
assert!(message.contains("attempt=1"));
12161225
assert!(message.contains("status=exit status: 101"));
1226+
assert!(message.contains("no_verify=true"));
12171227
assert!(message.contains("Hint: "));
12181228
}
12191229

@@ -1229,6 +1239,7 @@ mod tests {
12291239
);
12301240
assert!(message.contains("details_excerpt=error: network timeout"));
12311241
assert!(message.contains("dry_run=true"));
1242+
assert!(message.contains("no_verify=true"));
12321243
assert!(message.contains("registry=default"));
12331244
assert!(message.contains("Hint: "));
12341245
}
@@ -1263,6 +1274,7 @@ mod tests {
12631274
);
12641275
assert!(message.contains("attempts=3"));
12651276
assert!(message.contains("max_attempts=3"));
1277+
assert!(message.contains("no_verify=true"));
12661278
assert!(message.contains("registry=internal"));
12671279
assert!(message.contains("Hint: "));
12681280
}

crates/cargo-mono/tests/cli.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -766,6 +766,67 @@ fn publish_dry_run_does_not_create_tags_even_with_allowlist() {
766766
assert_eq!(result["published"][0]["name"], json!("alpha"));
767767
assert_eq!(result["tags"], json!([]));
768768
assert!(git_tags(temp_dir.path()).is_empty());
769+
assert_eq!(
770+
read_fake_publish_args(temp_dir.path()),
771+
vec![
772+
"publish".to_string(),
773+
"-p".to_string(),
774+
"alpha".to_string(),
775+
"--no-verify".to_string(),
776+
"--dry-run".to_string(),
777+
]
778+
);
779+
}
780+
781+
#[test]
782+
fn publish_exec_forwards_no_verify_to_cargo_publish() {
783+
let temp_dir = init_mixed_publishability_workspace();
784+
785+
let mut command = cargo_mono_command_with_fake_publish(temp_dir.path());
786+
command
787+
.current_dir(temp_dir.path())
788+
.args(["publish", "--allow-dirty", "--package", "alpha"])
789+
.assert()
790+
.success();
791+
792+
assert_eq!(
793+
read_fake_publish_args(temp_dir.path()),
794+
vec![
795+
"publish".to_string(),
796+
"-p".to_string(),
797+
"alpha".to_string(),
798+
"--no-verify".to_string(),
799+
]
800+
);
801+
}
802+
803+
#[test]
804+
fn publish_dry_run_forwards_no_verify_to_cargo_publish() {
805+
let temp_dir = init_mixed_publishability_workspace();
806+
807+
let mut command = cargo_mono_command_with_fake_publish(temp_dir.path());
808+
command
809+
.current_dir(temp_dir.path())
810+
.args([
811+
"publish",
812+
"--dry-run",
813+
"--allow-dirty",
814+
"--package",
815+
"alpha",
816+
])
817+
.assert()
818+
.success();
819+
820+
assert_eq!(
821+
read_fake_publish_args(temp_dir.path()),
822+
vec![
823+
"publish".to_string(),
824+
"-p".to_string(),
825+
"alpha".to_string(),
826+
"--no-verify".to_string(),
827+
"--dry-run".to_string(),
828+
]
829+
);
769830
}
770831

771832
#[test]
@@ -863,6 +924,8 @@ fn cargo_mono_command_with_fake_publish(working_dir: &Path) -> Command {
863924
set -euo pipefail
864925
865926
if [ "${1-}" = "publish" ]; then
927+
: "${FAKE_CARGO_PUBLISH_ARGS_FILE:?}"
928+
printf '%s\n' "$@" > "${FAKE_CARGO_PUBLISH_ARGS_FILE}"
866929
exit 0
867930
fi
868931
@@ -883,10 +946,24 @@ exec "${REAL_CARGO:?}" "$@"
883946

884947
let mut command = cargo_mono_command();
885948
command.env("REAL_CARGO", env!("CARGO"));
949+
command.env(
950+
"FAKE_CARGO_PUBLISH_ARGS_FILE",
951+
fake_publish_args_path(working_dir),
952+
);
886953
command.env("PATH", path_with_prepend(&fake_bin_directory));
887954
command
888955
}
889956

957+
fn fake_publish_args_path(working_dir: &Path) -> PathBuf {
958+
working_dir.join(".fake-publish-args")
959+
}
960+
961+
fn read_fake_publish_args(working_dir: &Path) -> Vec<String> {
962+
let raw = fs::read_to_string(fake_publish_args_path(working_dir))
963+
.expect("failed to read fake cargo publish args");
964+
raw.lines().map(str::to_string).collect()
965+
}
966+
890967
fn path_with_prepend(prefix: &Path) -> OsString {
891968
let mut paths = Vec::from([PathBuf::from(prefix)]);
892969
if let Some(current_path) = std::env::var_os("PATH") {

docs/crates-cargo-mono-foundation.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
- Publish and bump workflows must preserve scriptable output contracts for automation.
2020
- `bump` must not create Git tags.
2121
- `publish` is the only command allowed to create release tags, and only for packages listed in `[workspace.metadata.cargo-mono.publish.tag].packages`.
22+
- `publish` must always delegate to `cargo publish --no-verify`, including when `cargo mono publish --dry-run` is used.
2223
- Publish tag creation is opt-in by default (no config means no tags), must remain local-only (`git tag` without push), and must use `<crate>@v<version>` naming.
2324
- Remote tag publication is owned by CI automation: `.github/workflows/auto-publish.yml` must run `git push --tags` after a successful `publish` command, with checkout credential persistence disabled and authentication bound to `secrets.GH_TOKEN` (non-`GITHUB_TOKEN`) so downstream tag-triggered workflows run.
2425
- If `publish` tag configuration references unknown workspace packages, command execution must fail with `invalid-input`.

docs/project-cargo-mono.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Provide a Cargo subcommand for Rust monorepo lifecycle management, including ver
1616
- The binary must remain compatible with `cargo mono` invocation conventions.
1717
- Release automation integration must keep stable command semantics.
1818
- Release tagging responsibility is split by command: `bump` must not create Git tags, while `publish` may create local Git tags for configured packages.
19+
- `publish` must delegate to `cargo publish --no-verify` for all package uploads and dry-run executions.
1920
- Remote tag publication remains CI-owned: `auto-publish` pushes release tags with `git push --tags` after a successful `publish` run, with checkout credential persistence disabled and authentication bound to `secrets.GH_TOKEN` (non-`GITHUB_TOKEN`) so downstream tag-triggered workflows run.
2021
- Publish tag configuration must be opt-in through `[workspace.metadata.cargo-mono.publish.tag].packages`, and tag naming must remain `<crate>@v<version>`.
2122
- Tag release automation must detect `cargo-mono@v*` and produce signed multi-OS prebuilt artifacts without changing CLI command behavior.

0 commit comments

Comments
 (0)