Bugfix/prerelease versionbump (#4145)

* prerelease updating rc suffix

* added post-run summary

* updated error message
This commit is contained in:
Jędrzej Stuczyński
2023-11-15 12:58:21 +00:00
committed by GitHub
parent 4ec08da36d
commit 6bdba7046f
3 changed files with 136 additions and 39 deletions
+14 -13
View File
@@ -44,7 +44,7 @@ pub(crate) trait ReleasePackage: Sized {
Ok(())
}
fn update_nym_dependencies(&mut self, _: &HashSet<String>) -> anyhow::Result<()> {
fn update_nym_dependencies(&mut self, _: &HashSet<String>, _: bool) -> anyhow::Result<()> {
Ok(())
}
}
@@ -57,28 +57,29 @@ pub(crate) trait VersionBumpExt: Sized {
fn try_remove_prerelease(&self) -> anyhow::Result<Self>;
}
pub(crate) fn try_bump_raw_prerelease(raw: &str) -> anyhow::Result<Prerelease> {
// ugh that's disgusting
let (rc_prefix, pre_version) = raw
.split_once('.')
.context("the prerelease version does not contain a valid rc.X suffix")?;
let parsed_version: u32 = pre_version.parse()?;
let updated_version = parsed_version + 1;
Ok(format!("{rc_prefix}.{updated_version}").parse()?)
}
impl VersionBumpExt for Version {
fn try_bump_prerelease(&self) -> anyhow::Result<Self> {
if self.pre.is_empty() {
bail!("the current version ({self}) does not have pre-release data set - are you sure you followed the release process correctly?")
}
// ugh that's disgusting
let (rc_prefix, pre_version) = self
.pre
.as_str()
.split_once('.')
.context("the prerelease version does not contain a valid rc.X suffix")?;
let parsed_version: u32 = pre_version.parse()?;
let updated_version = parsed_version + 1;
let pre = format!("{rc_prefix}.{updated_version}").parse()?;
Ok(Version {
major: self.major,
minor: self.minor,
patch: self.patch,
pre,
pre: try_bump_raw_prerelease(&self.pre.as_str())?,
build: self.build.clone(),
})
}
+48 -11
View File
@@ -1,6 +1,7 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::helpers::try_bump_raw_prerelease;
use crate::json_types::DepsSet;
use crate::{json_types, ReleasePackage};
use anyhow::{bail, Context};
@@ -14,10 +15,18 @@ pub struct PackageJson {
inner: json_types::Package,
}
fn update_dependencies(deps: &mut DepsSet, names: &HashSet<String>) -> anyhow::Result<()> {
fn update_dependencies(
deps: &mut DepsSet,
names: &HashSet<String>,
pre_release: bool,
) -> anyhow::Result<()> {
for (package, version) in deps.iter_mut() {
if names.contains(package) {
let updated = try_bump_minor_version_req(version)?;
let updated = if pre_release {
try_bump_prerelease_version_req(version)?
} else {
try_bump_minor_version_req(version)?
};
println!("\t\t>>> updating '{package}' from {version} to {updated}");
*version = updated
@@ -52,21 +61,25 @@ impl ReleasePackage for PackageJson {
self.inner.version = version.to_string()
}
fn update_nym_dependencies(&mut self, names: &HashSet<String>) -> anyhow::Result<()> {
fn update_nym_dependencies(
&mut self,
names: &HashSet<String>,
pre_release: bool,
) -> anyhow::Result<()> {
println!("\t>>> updating @nymproject dependencies...");
update_dependencies(&mut self.inner.dependencies, names)?;
update_dependencies(&mut self.inner.dependencies, names, pre_release)?;
println!("\t>>> updating @nymproject peerDependencies...");
update_dependencies(&mut self.inner.peer_dependencies, names)?;
update_dependencies(&mut self.inner.peer_dependencies, names, pre_release)?;
println!("\t>>> updating @nymproject devDependencies...");
update_dependencies(&mut self.inner.dev_dependencies, names)?;
update_dependencies(&mut self.inner.dev_dependencies, names, pre_release)?;
println!("\t>>> updating @nymproject optionalDependencies...");
update_dependencies(&mut self.inner.optional_dependencies, names)?;
update_dependencies(&mut self.inner.optional_dependencies, names, pre_release)?;
println!("\t>>> updating @nymproject bundledDependencies...");
update_dependencies(&mut self.inner.bundled_dependencies, names)?;
update_dependencies(&mut self.inner.bundled_dependencies, names, pre_release)?;
Ok(())
}
@@ -101,9 +114,9 @@ pub(crate) fn find_package_path(dir: &Path) -> anyhow::Result<PathBuf> {
// expected structure: `>=X.Y.Z-rc.W || ^X`
fn try_bump_minor_version_req(raw_req: &str) -> anyhow::Result<String> {
let (req, major) = raw_req
.split_once("||")
.context("invalid version requirement")?;
let (req, major) = raw_req.split_once("||").context(format!(
"'{raw_req}' is not a valid semver version requirement - we expect '`>=X.Y.Z-rc.W || ^X`'"
))?;
let parsed_req = VersionReq::parse(req)?;
let parsed_major = VersionReq::parse(major)?;
if parsed_req.comparators.len() != 1 {
@@ -123,6 +136,30 @@ fn try_bump_minor_version_req(raw_req: &str) -> anyhow::Result<String> {
Ok(format!("{updated} || {parsed_major}"))
}
// expected structure: `>=X.Y.Z-rc.W || ^X`
fn try_bump_prerelease_version_req(raw_req: &str) -> anyhow::Result<String> {
let (req, major) = raw_req.split_once("||").context(format!(
"'{raw_req}' is not a valid semver version requirement - we expect '`>=X.Y.Z-rc.W || ^X`'"
))?;
let parsed_req = VersionReq::parse(req)?;
let parsed_major = VersionReq::parse(major)?;
if parsed_req.comparators.len() != 1 {
bail!("wrong number of version requirements present in {parsed_req}")
}
let updated = VersionReq {
comparators: vec![Comparator {
op: parsed_req.comparators[0].op,
major: parsed_req.comparators[0].major,
minor: parsed_req.comparators[0].minor,
patch: parsed_req.comparators[0].patch,
pre: try_bump_raw_prerelease(parsed_req.comparators[0].pre.as_str())?,
}],
};
Ok(format!("{updated} || {parsed_major}"))
}
#[cfg(test)]
mod tests {
use super::*;
+74 -15
View File
@@ -5,7 +5,7 @@ use crate::cargo::CargoPackage;
use crate::helpers::ReleasePackage;
use crate::json::PackageJson;
use clap::{Parser, Subcommand};
use std::collections::HashSet;
use std::collections::{HashMap, HashSet};
use std::env;
use std::path::{Path, PathBuf};
@@ -18,6 +18,48 @@ fn default_root() -> PathBuf {
env::current_dir().unwrap()
}
struct Summary {
cargo_results: HashMap<String, anyhow::Result<()>>,
json_results: HashMap<String, anyhow::Result<()>>,
}
impl Summary {
fn new(
cargo_results: HashMap<String, anyhow::Result<()>>,
json_results: HashMap<String, anyhow::Result<()>>,
) -> Self {
Summary {
cargo_results,
json_results,
}
}
fn print(&self) {
let cargo_ok = self.cargo_results.values().filter(|p| p.is_ok()).count();
let json_ok = self.json_results.values().filter(|p| p.is_ok()).count();
println!("SUMMARY");
println!("inspected {} cargo packages", self.cargo_results.len());
println!("updated {cargo_ok} cargo packages");
for (package, res) in &self.cargo_results {
if let Err(err) = res {
println!(
"\t>>> ❌ FAILURE: cargo package '{package}' failed to get updated: {err}"
);
}
}
println!("inspected {} json packages", self.json_results.len());
println!("updated {json_ok} json packages");
for (package, res) in &self.json_results {
if let Err(err) = res {
println!("\t>>> ❌ FAILURE: json package '{package}' failed to get updated: {err}");
}
}
}
}
#[derive(Parser)]
struct Args {
#[arg(default_value=default_root().into_os_string())]
@@ -36,12 +78,13 @@ enum Commands {
/// It will also update the `@nymproject/...` dependencies from `">=X.Y.Z-rc.0 || ^X"` to `">=X.Y.(Z+1)-rc.0 || ^X"`
BumpVersion {
#[arg(long)]
/// If enabled, the packages will only have their rc version bumped and the dependencies won't get updated at all
/// If enabled, the packages will only have their rc version bumped and the dependencies
/// will get updated from `">=X.Y.Z-rc.W || ^X"` to `">=X.Y.Z-rc.(W+1) || ^X"`
pre_release: bool,
},
}
fn remove_suffix<Pkg: ReleasePackage>(root: &Path, path: impl AsRef<Path>) {
fn remove_suffix<Pkg: ReleasePackage>(root: &Path, path: impl AsRef<Path>) -> anyhow::Result<()> {
let path = root.join(path);
println!(
">>> [{}] UPDATING PACKAGE {}: ",
@@ -51,8 +94,10 @@ fn remove_suffix<Pkg: ReleasePackage>(root: &Path, path: impl AsRef<Path>) {
if let Err(err) = { remove_suffix_inner::<Pkg>(path) } {
println!("\t>>> ❌ FAILURE: {err}");
Err(err)
} else {
println!("\t>>> ✅ SUCCESS");
Ok(())
}
}
@@ -70,7 +115,7 @@ fn bump_version<Pkg: ReleasePackage>(
path: impl AsRef<Path>,
dependencies_to_update: &HashSet<String>,
pre_release: bool,
) {
) -> anyhow::Result<()> {
let path = root.join(path);
println!(
">>> [{}] UPDATING PACKAGE {}: ",
@@ -79,8 +124,10 @@ fn bump_version<Pkg: ReleasePackage>(
);
if let Err(err) = { bump_version_inner::<Pkg>(path, dependencies_to_update, pre_release) } {
println!("\t>>> ❌ FAILURE: {err}");
Err(err)
} else {
println!("\t>>> ✅ SUCCESS");
Ok(())
}
}
@@ -93,9 +140,7 @@ fn bump_version_inner<Pkg: ReleasePackage>(
let mut package = Pkg::open(path)?;
package.bump_version(pre_release)?;
if !pre_release {
package.update_nym_dependencies(dependencies_to_update)?;
}
package.update_nym_dependencies(dependencies_to_update, pre_release)?;
println!("\t>>> saving the package file...");
package.save_changes()
@@ -132,34 +177,46 @@ impl InternalPackages {
self.internal_js_dependencies.insert(name.into());
}
pub fn remove_suffix(&self) {
pub fn remove_suffix(&self) -> Summary {
let mut cargo_results = HashMap::new();
for cargo_package in &self.cargo {
remove_suffix::<CargoPackage>(&self.root, cargo_package);
let res = remove_suffix::<CargoPackage>(&self.root, cargo_package);
cargo_results.insert(cargo_package.clone(), res);
}
let mut json_results = HashMap::new();
for package_json in &self.json {
remove_suffix::<PackageJson>(&self.root, package_json);
let res = remove_suffix::<PackageJson>(&self.root, package_json);
json_results.insert(package_json.clone(), res);
}
Summary::new(cargo_results, json_results)
}
pub fn bump_version(&self, pre_release: bool) {
pub fn bump_version(&self, pre_release: bool) -> Summary {
let mut cargo_results = HashMap::new();
for cargo_package in &self.cargo {
bump_version::<CargoPackage>(
let res = bump_version::<CargoPackage>(
&self.root,
cargo_package,
&Default::default(),
pre_release,
);
cargo_results.insert(cargo_package.clone(), res);
}
let mut json_results = HashMap::new();
for package_json in &self.json {
bump_version::<PackageJson>(
let res = bump_version::<PackageJson>(
&self.root,
package_json,
&self.internal_js_dependencies,
pre_release,
);
json_results.insert(package_json.clone(), res);
}
Summary::new(cargo_results, json_results)
}
}
@@ -226,10 +283,12 @@ fn main() -> anyhow::Result<()> {
let args = Args::parse();
let packages = initialise_internal_packages(args.root);
match args.command {
let summary = match args.command {
Commands::RemoveSuffix => packages.remove_suffix(),
Commands::BumpVersion { pre_release } => packages.bump_version(pre_release),
}
};
summary.print();
Ok(())
}