#!/usr/bin/env cargo +nightly -Zscript
fn get_pkg_version() -> (String, usize) {
let cargo_toml = std::fs::read_to_string("Cargo.toml").unwrap();
let mut line_number = 0;
for line in cargo_toml.lines() {
line_number += 1;
if line.starts_with("version") {
let version = line
.split("=")
.nth(1)
.expect("Invariant state")
.trim()
.trim_matches('"')
.to_string();
return (version, line_number);
}
}
return ("".to_string(), 0);
}
fn get_next_version(current_version: &str, segment_or_version: Option<&str>) -> String {
let mut version = current_version
.split(".")
.map(|s| s.parse::<u32>().unwrap())
.collect::<Vec<u32>>();
match segment_or_version.unwrap_or("patch") {
"major" => {
version[0] += 1;
version[1] = 0;
version[2] = 0;
}
"minor" => {
version[1] += 1;
version[2] = 0;
}
"patch" => version[2] += 1,
_ => return segment_or_version.expect("Invariant state").to_string(),
}
version
.iter()
.map(|v| v.to_string())
.collect::<Vec<String>>()
.join(".")
}
fn write_pkg_version(new_version: &str, line_number: usize) {
let cargo_toml = std::fs::read_to_string("Cargo.toml").unwrap();
let mut curr_line_number = 0;
let new_cargo_toml = cargo_toml
.lines()
.map(|line| {
curr_line_number += 1;
if curr_line_number == line_number {
format!("version = \"{new_version}\"")
} else {
line.to_string()
}
})
.collect::<Vec<String>>()
.join("\n");
let new_cargo_toml = format!("{}\n", new_cargo_toml);
std::fs::write("Cargo.toml", new_cargo_toml).unwrap();
}
fn update_readme(line_prefix: &str, command: &mut std::process::Command) {
let readme = std::fs::read_to_string("README.md").unwrap();
let mut new_readme = Vec::new();
let output = command.output().expect("Failed to execute command");
let output_lines = output
.stdout
.iter()
.map(|b| *b as char)
.collect::<String>()
.split("\n")
.map(|s| s.to_string().trim_end().to_string())
.collect::<Vec<String>>()
.join("\n");
let mut lines = readme.lines();
while let Some(line) = lines.next() {
if line.starts_with(line_prefix) {
new_readme.push(line.to_string());
new_readme.push(output_lines.clone());
while let Some(line) = lines.next() {
if line.starts_with("```") {
new_readme.push(line.to_string());
break;
}
}
} else {
new_readme.push(line.to_string());
}
}
new_readme.push("".to_string());
std::fs::write("README.md", new_readme.join("\n")).unwrap();
}
fn main() {
let (current_version, line_number) = get_pkg_version();
let mut args = std::env::args();
let should_commit = args.any(|arg| arg == "--commit");
let arg = args.skip(1).skip_while(|arg| arg.starts_with("--")).next();
let segment_or_version = arg.as_deref();
let new_version = get_next_version(¤t_version, segment_or_version);
println!("Bumping version from {current_version} to {new_version}");
write_pkg_version(&new_version, line_number);
println!("Building package");
std::process::Command::new("cargo")
.arg("build")
.output()
.expect("Failed to build package");
println!("Updating README.md");
update_readme(
"$ toggl help",
std::process::Command::new("cargo")
.arg("run")
.arg("--")
.arg("help"),
);
update_readme(
"$ toggl help start",
std::process::Command::new("cargo")
.arg("run")
.arg("--")
.arg("help")
.arg("start"),
);
if !should_commit {
return;
}
println!("Committing changes");
std::process::Command::new("git")
.arg("commit")
.arg("-am")
.arg(format!("🚢 Release {}", new_version))
.output()
.expect("Failed to commit changes");
}