aboutsummaryrefslogtreecommitdiffstats
path: root/xtask/src/main.rs
diff options
context:
space:
mode:
authorToby Vincent <tobyv@tobyvin.dev>2023-07-15 18:34:02 -0500
committerToby Vincent <tobyv@tobyvin.dev>2023-07-15 18:34:02 -0500
commit74793d28cf25ea1cd6203bdc8e27a265175be1c1 (patch)
treec8fe9934fc6015589bfcadb93a6035d46356bdcd /xtask/src/main.rs
parentfea9dd1a69968e5857d85f3466f3f9f4d302a17f (diff)
build: move PKGBUILDs into seperate reposdevelop
Diffstat (limited to 'xtask/src/main.rs')
-rw-r--r--xtask/src/main.rs193
1 files changed, 143 insertions, 50 deletions
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
index 76fca16..42ff2cf 100644
--- a/xtask/src/main.rs
+++ b/xtask/src/main.rs
@@ -6,20 +6,20 @@
//! This binary is integrated into the `cargo` command line by using an alias in
//! `.cargo/config`.
-use std::path::{Path, PathBuf};
-use std::{fs::File, process::Command};
+use std::{fs::File, io::Write, process::Command};
+use std::{
+ io::{BufReader, BufWriter, Read},
+ path::{Path, PathBuf},
+};
use anyhow::{anyhow, bail, ensure, Context, Result};
use build_info::BuildInfo;
-use bump::{Bump, Level};
-use clap::{Parser, Subcommand};
+use clap::{Parser, Subcommand, ValueEnum};
use flate2::{write::GzEncoder, Compression};
use once_cell::sync::Lazy;
-use semver::Version;
+use semver::{Prerelease, Version};
use tar::Builder;
-mod bump;
-
const PKG_NAME: &str = "projectr";
const PKG_VER: &str = env!("CARGO_PKG_VERSION");
const PKG_INCLUDE: &[&str] = &[
@@ -34,28 +34,19 @@ fn main() -> Result<()> {
match cli.command {
Commands::OutDir => println!("{}", out_dir()?.display()),
- Commands::Version => match version(cli.pre_release) {
+ Commands::Version => match version(cli.force) {
Ok(v) => println!("{v}"),
Err(_) => std::process::exit(1),
},
Commands::Dist => {
- let version = version(cli.pre_release)?;
+ let version = version(cli.force)?;
let targz = generate_tar_gz(version)?;
println!("{}", targz.display());
}
- Commands::Release { level } => {
- let Bump { prev, next } = release(level, cli.pre_release)?;
-
- println!("Bumped version: {prev} -> {next}");
- println!();
- println!("Create release commit:");
- println!("git commit -m 'chore: release projectr version {next}'");
- println!();
- println!("Create release tag:");
- println!("git shortlog v{prev}..HEAD | git tag -s v{next} --file -");
- println!();
- println!("Push refs:");
- println!("git push --follow-tags");
+ Commands::Bump { level, pre_release } => {
+ let prev = version(cli.force)?;
+ let next = bump(prev, level, pre_release)?;
+ println!("{next}");
}
};
@@ -65,9 +56,9 @@ fn main() -> Result<()> {
#[derive(Debug, Clone, Parser)]
#[command(author, version, about)]
struct Cli {
- /// Disable version/git tag check and appends `-dev` to the version
- #[arg(short, long, global = true, required = false)]
- pre_release: bool,
+ /// Disable version/git tag check
+ #[arg(short, long, global = true)]
+ force: bool,
#[command(subcommand)]
command: Commands,
@@ -84,17 +75,43 @@ enum Commands {
/// Generate distributable package.
Dist,
- /// Automation for create a new release.
- Release {
- /// Level of version bump.
- #[arg(required = false)]
- level: bump::Level,
+ /// Bump the version and update version dependant locations in files.
+ Bump {
+ /// SemVer field to increment.
+ #[arg(value_enum, required = false)]
+ level: Level,
+ /// Set pre-release field.
+ #[arg(short, long)]
+ pre_release: Option<Prerelease>,
},
}
-fn version(pre_release: bool) -> Result<String> {
+#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
+pub enum Level {
+ Major,
+ Minor,
+ #[default]
+ Patch,
+}
+
+impl std::str::FromStr for Level {
+ type Err = anyhow::Error;
+
+ fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
+ match s.to_lowercase().as_str() {
+ "major" => Ok(Level::Major),
+ "minor" => Ok(Level::Minor),
+ "patch" => Ok(Level::Patch),
+ s => Err(anyhow::anyhow!("Invalid bump level: {s}")),
+ }
+ }
+}
+
+fn version(force: bool) -> Result<Version> {
use build_info::VersionControl::Git;
+ let version: Version = PKG_VER.parse()?;
+
let BuildInfo {
version_control: Some(Git(git)),
..
@@ -102,10 +119,8 @@ fn version(pre_release: bool) -> Result<String> {
bail!("Failed to get version control info.");
};
- if pre_release {
- Ok(format!("{PKG_VER}-dev"))
- } else if git.tags.contains(&format!("v{PKG_VER}")) {
- Ok(PKG_VER.to_owned())
+ if force || git.tags.contains(&format!("v{version}")) {
+ Ok(version)
} else {
Err(anyhow!("Failed to find git tag matching package version."))
}
@@ -136,7 +151,7 @@ fn out_dir() -> Result<PathBuf> {
.context("Failed to find `out` directory for latest build")
}
-fn generate_tar_gz(version: String) -> Result<PathBuf> {
+fn generate_tar_gz(version: Version) -> Result<PathBuf> {
let target = build_info::format!("{}", $.target.triple);
let dist_pkg = DIST_DIR.join(format!("{PKG_NAME}-v{version}-{target}.tar.gz"));
@@ -181,22 +196,22 @@ fn build_binary() -> Result<PathBuf> {
Ok(binary)
}
-pub fn release(level: Level, pre_release: bool) -> Result<Bump> {
- let prev = PKG_VER.parse().unwrap_or_else(|_| Version::new(0, 1, 0));
- let mut next = level.bump(&prev);
+fn bump(prev: Version, level: Level, pre_release: Option<Prerelease>) -> Result<Version> {
+ let mut next = prev.clone();
- if pre_release {
- next.pre = semver::Prerelease::new("dev")?
- }
+ match level {
+ Level::Major => next.major += 1,
+ Level::Minor => next.minor += 1,
+ Level::Patch => next.patch += 1,
+ };
- let bump = Bump { next, prev };
+ if let Some(pre) = pre_release {
+ next.pre = pre;
+ }
- bump.bump_file("./Cargo.toml", bump::cargo)?;
- bump.bump_file("./README.md", bump::replace)?;
- bump.bump_file("./CHANGELOG.md", bump::changelog)?;
- 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", bump::vsc_pkgbuild)?;
+ bump_cargo(&next)?;
+ bump_readme(&prev, &next)?;
+ bump_changelog(&next)?;
let cargo_update = Command::new("cargo")
.arg("update")
@@ -210,7 +225,85 @@ pub fn release(level: Level, pre_release: bool) -> Result<Bump> {
.status()?;
anyhow::ensure!(git_added.success(), "Failed to add Cargo.lock to git");
- Ok(bump)
+ Ok(next)
+}
+
+fn bump_readme(prev: &Version, next: &Version) -> Result<()> {
+ bump_file("./README.md", |contents| {
+ Ok(contents.replace(&prev.to_string(), &next.to_string()))
+ })
+}
+
+fn bump_changelog(next: &Version) -> Result<()> {
+ bump_file("./CHANGELOG.md", |contents| {
+ let date = chrono::Utc::now().format("%Y-%m-%d");
+
+ let lines: Vec<String> = contents
+ .lines()
+ .flat_map(|line| {
+ if line.starts_with("## [Unreleased]") {
+ vec![
+ line.to_owned(),
+ "".to_owned(),
+ format!("## [{next}] - {date}"),
+ ]
+ } else if line.starts_with("[Unreleased]: ") {
+ vec![
+ line.to_owned(),
+ line.replace("[Unreleased]", &format!("[{next}]"))
+ .replace("HEAD", &format!("v{next}")),
+ ]
+ } else {
+ vec![line.to_owned()]
+ }
+ })
+ .collect();
+
+ Ok(lines.join("\n"))
+ })
+}
+
+fn bump_cargo(next: &Version) -> Result<()> {
+ bump_file("./Cargo.toml", |contents| {
+ let mut cargo_toml: toml_edit::Document = contents.parse()?;
+
+ 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())
+ })
+}
+
+fn bump_file<P, F>(path: P, mutator: F) -> Result<()>
+where
+ P: AsRef<Path>,
+ F: Fn(String) -> Result<String>,
+{
+ let path = path.as_ref();
+
+ let mut reader = BufReader::new(File::open(path)?);
+ let mut buf = String::new();
+ reader.read_to_string(&mut buf)?;
+
+ let buf = mutator(buf)?;
+
+ let mut writer = BufWriter::new(File::open(path)?);
+ writer.write_all(buf.as_bytes())?;
+ writer.flush()?;
+
+ let git_added = Command::new("git").arg("add").arg(path).status()?;
+
+ anyhow::ensure!(git_added.success(), "Failed to add bumped files to git");
+
+ Ok(())
}
static PROJECT_ROOT: Lazy<PathBuf> = Lazy::new(|| {