From 957808030f413cf45cbe6489a3b39137e452c275 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 4 Jan 2022 15:35:39 -0600 Subject: [PATCH] feat: Publish using `rust-version` toolchain This is a last ditch effort to catch MSRV issues. Fixes #380 --- docs/reference.md | 9 +++++---- src/cargo.rs | 48 +++++++++++++++++++++++++++++++++++++++++++---- src/cmd.rs | 8 ++++---- src/config.rs | 19 +++++++++++++++++++ src/release.rs | 24 ++++++++++++++++++++++++ 5 files changed, 96 insertions(+), 12 deletions(-) diff --git a/docs/reference.md b/docs/reference.md index c93805933..d6c1dec65 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -52,11 +52,12 @@ Configuration is read from the following (in precedence order) | `sign-tag` | `--sign-tag` | bool | Use GPG to sign git tag generated by cargo-release. | | `push-remote` | `--push-remote` | string | Default git remote to push | | `registry` | `--registry` | string | Cargo registry name to publish to (default uses Rust's default, which goes to `crates.io`) | -| `release` | `--exclude` | bool | Skip the entire release process (usually for internal crates in a workspace) | -| `push` | `--no-push` | bool | Don't do git push | +| `release` | `--exclude` | bool | Skip the entire release process (usually for internal crates in a workspace) | +| `push` | `--no-push` | bool | Don't do git push | | `push-options` | \- | list of strings | Flags to send to the server when doing a `git push` | -| `tag` | `--no-tag` | bool | Don't do git tag | -| `publish` | `--no-publish` | bool | Don't do cargo publish right now, see [manifest `publish` field](https://doc.rust-lang.org/cargo/reference/manifest.html#the-publish--field-optional) to permanently disable publish. | +| `tag` | `--no-tag` | bool | Don't do git tag | +| `publish` | `--no-publish` | bool | Don't do cargo publish right now, see [manifest `publish` field](https://doc.rust-lang.org/cargo/reference/manifest.html#the-publish--field-optional) to permanently disable publish. | +| `rust-version` | | string | Toolchain version to use for publishing (specify `"manifest"` to use [Cargo.toml's `rust-version`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-rust-version-field) | | `verify` | `--no-verify` | bool | Don't verify the contents by building them | | `shared-version` | \- | bool | Ensure all crates with `shared_version` are the same version | | `consolidate-commits` | \- | bool | When releasing a workspace, use a single commit for the pre-release version bump and a single commit for the post-release version bump. | diff --git a/src/cargo.rs b/src/cargo.rs index 25af68be4..b0dce33c8 100644 --- a/src/cargo.rs +++ b/src/cargo.rs @@ -50,6 +50,36 @@ pub fn package_content(manifest_path: &Path) -> Result, } } +pub fn is_toolchain_present(toolchain_version: &str) -> bool { + let formatted_toolchain_version = format!("+{}", toolchain_version); + + let output = std::process::Command::new("cargo") + .args([&formatted_toolchain_version, "publish", "--help"]) + .output(); + match output { + Ok(output) => { + if output.status.success() { + true + } else { + log::trace!( + "Error when checking for presence of {} toolchain: {}", + toolchain_version, + String::from_utf8_lossy(&output.stderr) + ); + false + } + } + Err(err) => { + log::trace!( + "Error when checking for presence of {} toolchain: {}", + toolchain_version, + err + ); + false + } + } +} + pub fn publish( dry_run: bool, verify: bool, @@ -57,15 +87,25 @@ pub fn publish( features: &Features, registry: Option<&str>, token: Option<&str>, + toolchain_version: Option<&str>, ) -> Result { - let cargo = cargo(); + let mut command: Vec<&str>; + + let bin: String; + let formatted_toolchain_version; + if let Some(toolchain_version) = toolchain_version { + formatted_toolchain_version = format!("+{}", toolchain_version); + command = vec!["cargo", &formatted_toolchain_version]; + } else { + bin = cargo(); + command = vec![&bin]; + } - let mut command: Vec<&str> = vec![ - &cargo, + command.extend([ "publish", "--manifest-path", manifest_path.to_str().unwrap(), - ]; + ]); if let Some(registry) = registry { command.push("--registry"); diff --git a/src/cmd.rs b/src/cmd.rs index 54cfb365a..80de084ec 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -11,11 +11,11 @@ fn do_call( envs: Option>, dry_run: bool, ) -> Result { + if path.is_some() { + log::trace!("cd {}", path.unwrap().display()); + } + log::trace!("{}", command.join(" ")); if dry_run { - if path.is_some() { - log::trace!("cd {}", path.unwrap().display()); - } - log::trace!("{}", command.join(" ")); return Ok(true); } let mut iter = command.iter(); diff --git a/src/config.rs b/src/config.rs index 0fa4cbf9d..cf1202426 100644 --- a/src/config.rs +++ b/src/config.rs @@ -18,6 +18,7 @@ pub struct Config { pub disable_release: Option, pub publish: Option, pub disable_publish: Option, + pub rust_version: Option, pub verify: Option, pub no_verify: Option, pub push: Option, @@ -69,6 +70,9 @@ impl Config { self.publish = Some(publish); self.disable_publish = None; } + if let Some(rust_version) = source.rust_version.as_deref() { + self.rust_version = Some(rust_version.to_owned()); + } if let Some(verify) = resolve_bool_arg(source.verify, source.no_verify) { self.verify = Some(verify); self.no_verify = None; @@ -166,6 +170,10 @@ impl Config { resolve_bool_arg(self.publish, self.disable_publish).unwrap_or(true) } + pub fn rust_version(&self) -> Option<&str> { + self.rust_version.as_deref() + } + pub fn verify(&self) -> bool { resolve_bool_arg(self.verify, self.no_verify).unwrap_or(true) } @@ -413,6 +421,17 @@ pub fn dump_config( release_config.publish = Some(false); release_config.disable_publish = None; } + if release_config.rust_version() == Some("manifest") { + if let Some(rust_version) = cargo_file + .get("package") + .and_then(|p| p.get("rust-version")) + .and_then(|r| r.as_str()) + { + release_config.rust_version = Some(rust_version.to_owned()); + } else { + release_config.rust_version = None; + } + } release_config } else { diff --git a/src/release.rs b/src/release.rs index 8ae35134c..566a0c399 100644 --- a/src/release.rs +++ b/src/release.rs @@ -125,6 +125,29 @@ fn release_packages<'m>( // STEP 0: Help the user make the right decisions. git::git_version()?; + + let mut toolchains = HashSet::new(); + let mut missing_toolchain = false; + for pkg in pkgs { + if let Some(toolchain_version) = pkg.config.rust_version() { + if toolchains.insert(toolchain_version) + && !cargo::is_toolchain_present(toolchain_version) + { + log::error!( + "{} requires rust {} toolchain to publish", + pkg.meta.name, + toolchain_version + ); + missing_toolchain = true; + } + } + } + if missing_toolchain { + if !dry_run { + return Ok(101); + } + } + let mut dirty = false; if ws_config.consolidate_commits() { if git::is_dirty(ws_meta.workspace_root.as_std_path())? { @@ -395,6 +418,7 @@ fn release_packages<'m>( features, pkg.config.registry(), args.token.as_ref().map(AsRef::as_ref), + pkg.config.rust_version(), )? { return Ok(103); }