diff options
-rw-r--r-- | xtask/src/release.rs | 98 | ||||
-rw-r--r-- | xtask/src/release/bump.rs (renamed from xtask/src/release/version.rs) | 148 |
2 files changed, 115 insertions, 131 deletions
diff --git a/xtask/src/release.rs b/xtask/src/release.rs index 8bf4444..acb8888 100644 --- a/xtask/src/release.rs +++ b/xtask/src/release.rs @@ -4,9 +4,9 @@ use anyhow::Result; use clap::{Args, Subcommand}; use semver::Version; -use self::version::{Bump, Level, Replacement}; +use self::bump::{Bump, Level}; -mod version; +mod bump; #[derive(Debug, Clone, Args)] pub struct Release { @@ -15,7 +15,7 @@ pub struct Release { /// Level of version bump version. #[arg(global = true, required = false)] - level: version::Level, + level: bump::Level, /// Options passed to git commit. #[arg(global = true, last = true)] @@ -42,7 +42,7 @@ pub enum Step { /// Bump version in package files and commit changes. Bump { #[arg(from_global)] - level: version::Level, + level: bump::Level, }, /// Make a release commit. @@ -54,7 +54,7 @@ pub enum Step { /// Create git tag for release. Tag { #[arg(from_global)] - level: version::Level, + level: bump::Level, }, } @@ -85,54 +85,50 @@ impl Step { pub fn bump(level: Level) -> Result<Bump> { let mut bump = Bump::from(level); - bump.bump_file("README.md", &[Replacement::Version])?; - bump.bump_file("pkg/archlinux/projectr/PKGBUILD", &[Replacement::Version])?; - bump.bump_file( - "pkg/archlinux/projectr-bin/PKGBUILD", - &[Replacement::Version], - )?; - - let stdout = std::process::Command::new("git") - .arg("describe") - .arg("--long") - .arg("--abbrev=7") - .output()? - .stdout; - let pkgver = std::str::from_utf8(&stdout)? - .trim() - .trim_start_matches('v') - .replacen("-g", ".g", 1) - .replacen('-', "-r", 1) - .replace('-', "."); - - bump.bump_file( - "pkg/archlinux/projectr-git/PKGBUILD", - &[Replacement::FindLine( - |l| l.starts_with("pkgver="), - format!("pkgver={pkgver}"), - )], - )?; - - bump.bump_file( - "CHANGELOG.md", - &[ - Replacement::Append( - "## [Unreleased]".to_string(), - format!( - "\n## [{}] - {}", - bump.next, - chrono::Utc::now().format("%Y-%m-%d") + bump.bump_file("Cargo.toml", bump::replace_cargo)?; + bump.bump_file("README.md", bump::replace)?; + bump.bump_file("pkg/archlinux/projectr/PKGBUILD", bump::replace)?; + bump.bump_file("pkg/archlinux/projectr-bin/PKGBUILD", bump::replace)?; + bump.bump_file("pkg/archlinux/projectr-git/PKGBUILD", |buf, _| { + let stdout = std::process::Command::new("git") + .arg("describe") + .arg("--long") + .arg("--abbrev=7") + .output()? + .stdout; + + let pkgver = std::str::from_utf8(&stdout)? + .trim() + .trim_start_matches('v') + .replacen("-g", ".g", 1) + .replacen('-', "-r", 1) + .replace('-', "."); + + if let Some(from) = buf.lines().find(|l| l.starts_with("pkgver=")) { + Ok(buf.replace(from, &format!("pkgver={pkgver}"))) + } else { + Ok(buf) + } + })?; + + bump.bump_file("CHANGELOG.md", |buf, Bump { version: _, next }| { + let date = chrono::Utc::now().format("%Y-%m-%d"); + Ok(buf + .replace( + "## [Unreleased]", + &format!( + "## [Unreleased]\n\n\ + ## [{next}] - {date}" ), - ), - Replacement::Append( - "[Unreleased]: https://git.sr.ht/~tobyvin/projectr/log/HEAD".to_string(), - format!( - "[{0}]: https://git.sr.ht/~tobyvin/projectr/log/v{0}", - bump.next + ) + .replace( + "[Unreleased]: https://git.sr.ht/~tobyvin/projectr/log/HEAD", + &format!( + "[Unreleased]: https://git.sr.ht/~tobyvin/projectr/log/HEAD\n\ + [{next}]: https://git.sr.ht/~tobyvin/projectr/log/v{next}" ), - ), - ], - )?; + )) + })?; Ok(bump) } diff --git a/xtask/src/release/version.rs b/xtask/src/release/bump.rs index 0c8cffd..617cfd6 100644 --- a/xtask/src/release/version.rs +++ b/xtask/src/release/bump.rs @@ -70,9 +70,10 @@ impl Bump { .success()) } - pub fn bump_file<P>(&mut self, path: P, replacements: &[Replacement]) -> Result<()> + pub fn bump_file<P, F>(&mut self, path: P, mutator: F) -> Result<()> where P: AsRef<Path>, + F: Fn(String, &Self) -> Result<String>, { let path = path.as_ref(); @@ -84,7 +85,7 @@ impl Bump { let file = File::open(path)?; - self.bump(&file, &file, replacements)?; + self.bump(&file, &file, mutator)?; let git_added = Command::new("git").arg("add").arg(path).status()?; @@ -93,17 +94,16 @@ impl Bump { Ok(()) } - fn bump<R, W>(&self, mut reader: R, mut writer: W, replacements: &[Replacement]) -> Result<()> + fn bump<R, W, F>(&self, mut reader: R, mut writer: W, mutator: F) -> Result<()> where R: Read, W: Write, + F: Fn(String, &Self) -> Result<String>, { let mut buf = String::new(); reader.read_to_string(&mut buf)?; - let buf = replacements - .iter() - .try_fold(buf, |acc, r| r.replace(self, acc))?; + let buf = mutator(buf, self)?; writer.write_all(buf.as_bytes()).map_err(Into::into) } @@ -133,36 +133,27 @@ impl From<Level> for Bump { } } -#[derive(Default)] -pub enum Replacement { - #[default] - Version, - CargoVersion, - FindLine(fn(&&str) -> bool, String), - Replace(String, String), - Append(String, String), +/// Utility function for replacing version with next in a string. +pub fn replace(buf: String, Bump { version, next }: &Bump) -> Result<String> { + Ok(buf.replace(&version.to_string(), &next.to_string())) } -impl Replacement { - pub fn replace(&self, bump: &Bump, buf: String) -> Result<String> { - let buf = match self { - Replacement::Version => buf.replace(&bump.version.to_string(), &bump.next.to_string()), - Replacement::Replace(from, to) => buf.replace(from, to), - Replacement::Append(line, append) => buf.replace(line, &format!("{line}\n{append}")), - Replacement::FindLine(find, replace) => match buf.lines().find(find) { - Some(line) => buf.replace(line, replace), - None => buf, - }, - Replacement::CargoVersion => { - let mut cargo_toml: toml_edit::Document = buf.parse()?; - cargo_toml["workspace"]["package"]["version"] = - toml_edit::value(bump.next.to_string()); - cargo_toml.to_string() - } - }; +/// Utility function for bumping the version in a Cargo.toml file. +pub fn replace_cargo(buf: String, Bump { version: _, next }: &Bump) -> Result<String> { + let mut cargo_toml: toml_edit::Document = buf.parse()?; - Ok(buf) - } + if cargo_toml["package"]["version"]["workspace"] + .as_bool() + .unwrap_or_default() + { + cargo_toml["workspace"]["package"]["version"] = toml_edit::value(next.to_string()); + } else if cargo_toml["package"]["version"].is_str() { + cargo_toml["package"]["version"] = toml_edit::value(next.to_string()); + } else { + anyhow::bail!("Failed to find version in Cargo.toml"); + }; + + Ok(cargo_toml.to_string()) } #[cfg(test)] @@ -186,6 +177,7 @@ mod test { let right = std::str::from_utf8(writer).unwrap(); let diff = SimpleDiff::from_str(left, right, "old", "new"); + assert_ne!(left, right); println!("{diff}") } @@ -200,9 +192,7 @@ mod test { let reader = content.as_bytes(); let mut writer = Vec::new(); - let replacements = &[Replacement::CargoVersion]; - - bump.bump(reader, &mut writer, replacements).unwrap(); + bump.bump(reader, &mut writer, replace_cargo).unwrap(); println!("{file}: {bump}"); print_diff(reader, &writer) @@ -219,25 +209,25 @@ mod test { let reader = content.as_bytes(); let mut writer = Vec::new(); - let replacements = &[ - Replacement::Append( - "## [Unreleased]".to_string(), - format!( - "\n## [{}] - {}", - bump.next, - chrono::Utc::now().format("%Y-%m-%d") - ), - ), - Replacement::Append( - "[Unreleased]: https://git.sr.ht/~tobyvin/projectr/log/HEAD".to_string(), - format!( - "[{0}]: https://git.sr.ht/~tobyvin/projectr/log/v{0}", - bump.next - ), - ), - ]; - - bump.bump(reader, &mut writer, replacements).unwrap(); + bump.bump(reader, &mut writer, |buf, Bump { version: _, next }| { + let date = chrono::Utc::now().format("%Y-%m-%d"); + Ok(buf + .replace( + "## [Unreleased]", + &format!( + "## [Unreleased]\n\n\ + ## [{next}] - {date}" + ), + ) + .replace( + "[Unreleased]: https://git.sr.ht/~tobyvin/projectr/log/HEAD", + &format!( + "[Unreleased]: https://git.sr.ht/~tobyvin/projectr/log/HEAD\n\ + [{next}]: https://git.sr.ht/~tobyvin/projectr/log/v{next}" + ), + )) + }) + .unwrap(); println!("{file}: {bump}"); print_diff(reader, &writer) @@ -254,9 +244,7 @@ mod test { let reader = content.as_deref().unwrap().as_bytes(); let mut writer = Vec::new(); - let replacements = &[Replacement::Version]; - - bump.bump(reader, &mut writer, replacements).unwrap(); + bump.bump(reader, &mut writer, replace).unwrap(); println!("{file}: {bump}"); print_diff(reader, &writer) @@ -273,28 +261,28 @@ mod test { let reader = content.as_bytes(); let mut writer = Vec::new(); - let stdout = std::process::Command::new("git") - .arg("describe") - .arg("--long") - .arg("--abbrev=7") - .output() - .unwrap() - .stdout; - - let pkgver = std::str::from_utf8(&stdout) - .unwrap() - .trim() - .trim_start_matches('v') - .replacen("-g", ".g", 1) - .replacen('-', "-r", 1) - .replace('-', "."); - - let replacements = &[Replacement::FindLine( - |l| l.starts_with("pkgver="), - format!("pkgver={pkgver}"), - )]; - - bump.bump(reader, &mut writer, replacements).unwrap(); + bump.bump(reader, &mut writer, |buf, _| { + let stdout = std::process::Command::new("git") + .arg("describe") + .arg("--long") + .arg("--abbrev=7") + .output()? + .stdout; + + let pkgver = std::str::from_utf8(&stdout)? + .trim() + .trim_start_matches('v') + .replacen("-g", ".g", 1) + .replacen('-', "-r", 1) + .replace('-', "."); + + if let Some(from) = buf.lines().find(|l| l.starts_with("pkgver=")) { + Ok(buf.replace(from, &format!("pkgver={pkgver}"))) + } else { + Ok(buf) + } + }) + .unwrap(); println!("{file}: {bump}"); print_diff(reader, &writer) |