diff --git a/src/ops/cargo.rs b/src/ops/cargo.rs index 539ac28ad..018e71ee0 100644 --- a/src/ops/cargo.rs +++ b/src/ops/cargo.rs @@ -148,6 +148,42 @@ pub fn is_published(index: &crates_index::Index, name: &str, version: &str) -> b .any(|v| v.version() == version) } +pub fn set_workspace_version( + manifest_path: &Path, + version: &str, + dry_run: bool, +) -> Result<(), FatalError> { + let original_manifest = std::fs::read_to_string(manifest_path)?; + let mut manifest: toml_edit::Document = original_manifest.parse().map_err(FatalError::from)?; + manifest["workspace"]["package"]["version"] = toml_edit::value(version); + let manifest = manifest.to_string(); + + if dry_run { + if manifest != original_manifest { + let display_path = manifest_path.display().to_string(); + let old_lines: Vec<_> = original_manifest + .lines() + .map(|s| format!("{}\n", s)) + .collect(); + let new_lines: Vec<_> = manifest.lines().map(|s| format!("{}\n", s)).collect(); + let diff = difflib::unified_diff( + &old_lines, + &new_lines, + display_path.as_str(), + display_path.as_str(), + "original", + "updated", + 0, + ); + log::debug!("Change:\n{}", itertools::join(diff.into_iter(), "")); + } + } else { + atomic_write(manifest_path, &manifest)?; + } + + Ok(()) +} + pub fn set_package_version( manifest_path: &Path, version: &str, diff --git a/src/steps/release.rs b/src/steps/release.rs index 9221f26a7..fbb0b114f 100644 --- a/src/steps/release.rs +++ b/src/steps/release.rs @@ -233,7 +233,8 @@ impl ReleaseStep { // STEP 2: update current version, save and commit if consolidate_commits { - let update_lock = super::version::update_versions(&ws_meta, &selected_pkgs, dry_run)?; + let update_lock = + super::version::update_versions(&ws_meta, &selected_pkgs, &excluded_pkgs, dry_run)?; if update_lock { log::debug!("Updating lock file"); if !dry_run { diff --git a/src/steps/version.rs b/src/steps/version.rs index 0a6b15181..5fe948dc9 100644 --- a/src/steps/version.rs +++ b/src/steps/version.rs @@ -118,7 +118,7 @@ impl VersionStep { let pkgs = plan::plan(pkgs)?; - let (selected_pkgs, _excluded_pkgs): (Vec<_>, Vec<_>) = pkgs + let (selected_pkgs, excluded_pkgs): (Vec<_>, Vec<_>) = pkgs .into_iter() .map(|(_, pkg)| pkg) .partition(|p| p.config.release()); @@ -157,7 +157,7 @@ impl VersionStep { super::confirm("Bump", &selected_pkgs, self.no_confirm, dry_run)?; // STEP 2: update current version, save and commit - let update_lock = update_versions(&ws_meta, &selected_pkgs, dry_run)?; + let update_lock = update_versions(&ws_meta, &selected_pkgs, &excluded_pkgs, dry_run)?; if update_lock { log::debug!("Updating lock file"); if !dry_run { @@ -228,22 +228,68 @@ pub fn changed_since<'m>( pub fn update_versions( ws_meta: &cargo_metadata::Metadata, selected_pkgs: &[plan::PackageRelease], + excluded_pkgs: &[plan::PackageRelease], dry_run: bool, ) -> Result { let mut changed = false; - for pkg in selected_pkgs { - if let Some(version) = pkg.planned_version.as_ref() { - let crate_name = pkg.meta.name.as_str(); - log::info!( - "Update {} to version {}", - crate_name, - version.full_version_string - ); - crate::ops::cargo::set_package_version( - &pkg.manifest_path, - version.full_version_string.as_str(), - dry_run, - )?; + + let workspace_version = selected_pkgs + .iter() + .filter(|p| p.config.shared_version() == Some(crate::config::SharedVersion::WORKSPACE)) + .find_map(|p| p.planned_version.clone()); + + if let Some(workspace_version) = &workspace_version { + log::info!( + "Update workspace to version {}", + workspace_version.full_version_string + ); + let workspace_path = ws_meta.workspace_root.as_std_path().join("Cargo.toml"); + crate::ops::cargo::set_workspace_version( + &workspace_path, + workspace_version.full_version_string.as_str(), + dry_run, + )?; + // Deferring `update_dependent_versions` to the per-package logic + changed = true; + } + + for (selected, pkg) in selected_pkgs + .iter() + .map(|s| (true, s)) + .chain(excluded_pkgs.iter().map(|s| (false, s))) + { + let is_inherited = + pkg.config.shared_version() == Some(crate::config::SharedVersion::WORKSPACE); + let planned_version = if is_inherited { + workspace_version.as_ref() + } else if let Some(version) = pkg.planned_version.as_ref() { + assert!(selected); + Some(version) + } else { + None + }; + + if let Some(version) = planned_version { + if is_inherited { + let crate_name = pkg.meta.name.as_str(); + log::info!( + "Update {} to version {} (inherited from workspace)", + crate_name, + version.full_version_string + ); + } else { + let crate_name = pkg.meta.name.as_str(); + log::info!( + "Update {} to version {}", + crate_name, + version.full_version_string + ); + crate::ops::cargo::set_package_version( + &pkg.manifest_path, + version.full_version_string.as_str(), + dry_run, + )?; + } update_dependent_versions(&ws_meta, pkg, version, dry_run)?; changed = true; }