mirror of
https://github.com/TECHNOFAB11/bump2version.git
synced 2025-12-12 16:10:07 +01:00
parse versions from .bumpversion.toml if args not passed (#2)
This commit is contained in:
parent
5a867eb532
commit
c9e019e8f8
5 changed files with 174 additions and 74 deletions
42
Cargo.lock
generated
42
Cargo.lock
generated
|
|
@ -13,9 +13,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstream"
|
name = "anstream"
|
||||||
version = "0.6.12"
|
version = "0.6.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "96b09b5178381e0874812a9b157f7fe84982617e48f71f4e3235482775e5b540"
|
checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstyle",
|
"anstyle",
|
||||||
"anstyle-parse",
|
"anstyle-parse",
|
||||||
|
|
@ -61,7 +61,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bump2version"
|
name = "bump2version"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"regex",
|
"regex",
|
||||||
|
|
@ -180,9 +180,9 @@ checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.49"
|
version = "2.0.52"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "915aea9e586f80826ee59f8453c1101f9d1c4b3964cd2460185ee8e299ada496"
|
checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
@ -212,9 +212,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-targets"
|
name = "windows-targets"
|
||||||
version = "0.52.0"
|
version = "0.52.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
|
checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows_aarch64_gnullvm",
|
"windows_aarch64_gnullvm",
|
||||||
"windows_aarch64_msvc",
|
"windows_aarch64_msvc",
|
||||||
|
|
@ -227,42 +227,42 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_gnullvm"
|
name = "windows_aarch64_gnullvm"
|
||||||
version = "0.52.0"
|
version = "0.52.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
|
checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_msvc"
|
name = "windows_aarch64_msvc"
|
||||||
version = "0.52.0"
|
version = "0.52.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
|
checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
version = "0.52.0"
|
version = "0.52.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
|
checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_msvc"
|
name = "windows_i686_msvc"
|
||||||
version = "0.52.0"
|
version = "0.52.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
|
checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
version = "0.52.0"
|
version = "0.52.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
|
checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnullvm"
|
name = "windows_x86_64_gnullvm"
|
||||||
version = "0.52.0"
|
version = "0.52.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
|
checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
version = "0.52.0"
|
version = "0.52.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ pub struct Cli {
|
||||||
|
|
||||||
/// Version that needs to be updated.
|
/// Version that needs to be updated.
|
||||||
#[arg(long = "current-version", value_name = "VERSION")]
|
#[arg(long = "current-version", value_name = "VERSION")]
|
||||||
pub current_version: String,
|
pub current_version: Option<String>,
|
||||||
|
|
||||||
/// Part of the version to be bumped.
|
/// Part of the version to be bumped.
|
||||||
#[arg(
|
#[arg(
|
||||||
|
|
@ -91,12 +91,12 @@ pub struct Cli {
|
||||||
pub serialize: String,
|
pub serialize: String,
|
||||||
|
|
||||||
/// Don't write any files, just pretend.
|
/// Don't write any files, just pretend.
|
||||||
#[arg(short = 'n', long = "dry-run")]
|
#[arg(short = 'n', long = "dry-run", default_value_t = false)]
|
||||||
pub dry_run: bool,
|
pub dry_run: bool,
|
||||||
|
|
||||||
/// New version that should be in the files.
|
/// New version that should be in the files.
|
||||||
#[arg(long = "new-version", value_name = "VERSION")]
|
#[arg(long = "new-version", value_name = "VERSION")]
|
||||||
pub new_version: String,
|
pub new_version: Option<String>,
|
||||||
|
|
||||||
/// Create a commit in version control.
|
/// Create a commit in version control.
|
||||||
#[arg(long = "commit", default_value_t = true)]
|
#[arg(long = "commit", default_value_t = true)]
|
||||||
|
|
|
||||||
86
src/main.rs
86
src/main.rs
|
|
@ -1,6 +1,9 @@
|
||||||
use self::cli::Cli;
|
use self::cli::Cli;
|
||||||
use crate::utils::attempt_version_bump;
|
use crate::utils::attempt_version_bump;
|
||||||
|
use crate::utils::get_current_version_from_config;
|
||||||
|
use crate::utils::read_files_from_config;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
use std::collections::HashSet;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
|
|
@ -8,23 +11,32 @@ mod cli;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
// Parse command-line arguments
|
|
||||||
let args = Cli::parse();
|
let args = Cli::parse();
|
||||||
let config_file = args.config_file.clone();
|
let config_file = args.config_file.clone();
|
||||||
let current_version = args.current_version.clone();
|
let config_content = fs::read_to_string(args.config_file.clone()).unwrap();
|
||||||
|
let config_version = get_current_version_from_config(&config_content).ok_or("")?;
|
||||||
|
let current_version = args
|
||||||
|
.current_version
|
||||||
|
.clone()
|
||||||
|
.unwrap_or(config_version)
|
||||||
|
.clone();
|
||||||
|
|
||||||
let attempted_new_version = attempt_version_bump(args.clone());
|
let attempted_new_version = attempt_version_bump(args.clone());
|
||||||
|
|
||||||
if !args.new_version.is_empty() && attempted_new_version.is_some() {
|
if attempted_new_version.is_some() {
|
||||||
// TODO: fix let new_version = attempted_new_version.clone().unwrap();
|
let new_version = attempted_new_version.clone().unwrap();
|
||||||
let new_version = args.new_version.clone();
|
|
||||||
|
|
||||||
let dry_run = args.dry_run;
|
let dry_run = args.dry_run;
|
||||||
let commit = args.commit;
|
let commit = args.commit;
|
||||||
let tag = args.tag;
|
let tag = args.tag;
|
||||||
let message = args.message;
|
let message = args.message;
|
||||||
|
|
||||||
let files: Vec<String> = args.files;
|
let files: Vec<String> = if args.files.is_empty() {
|
||||||
|
let config_files: HashSet<String> = read_files_from_config(&args.config_file)?;
|
||||||
|
config_files.into_iter().collect()
|
||||||
|
} else {
|
||||||
|
args.files
|
||||||
|
};
|
||||||
|
|
||||||
// Check if Git working directory is clean
|
// Check if Git working directory is clean
|
||||||
if fs::metadata(".git").is_ok() {
|
if fs::metadata(".git").is_ok() {
|
||||||
|
|
@ -66,12 +78,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut config_content = fs::read_to_string(config_file.clone())?;
|
let mut config_content = fs::read_to_string(config_file.clone())?;
|
||||||
|
|
||||||
config_content = config_content.replace(
|
config_content = config_content.replace(
|
||||||
&format!("new_version={}", attempted_new_version.unwrap()),
|
&format!("current_version = {}", current_version),
|
||||||
"",
|
&format!("current_version = {}", new_version),
|
||||||
);
|
|
||||||
config_content = config_content.replace(
|
|
||||||
&format!("current_version={}", current_version),
|
|
||||||
&format!("current_version={}", new_version),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if !dry_run {
|
if !dry_run {
|
||||||
|
|
@ -79,14 +87,29 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
commit_files.push(config_file);
|
commit_files.push(config_file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Git commit and tag
|
|
||||||
if commit {
|
if commit {
|
||||||
for path in &commit_files {
|
for path in &commit_files {
|
||||||
Command::new("git").arg("add").arg(path).output()?;
|
let git_add_output = Command::new("git").arg("add").arg(path).output();
|
||||||
}
|
|
||||||
|
|
||||||
Command::new("git")
|
match git_add_output {
|
||||||
|
Ok(output) => {
|
||||||
|
if !output.status.success() {
|
||||||
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||||
|
eprintln!("Error during git add:\n{}", stderr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!("Failed to execute git add: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let git_diff_output = Command::new("git").arg("diff").output();
|
||||||
|
|
||||||
|
match git_diff_output {
|
||||||
|
Ok(output) => {
|
||||||
|
if !output.stdout.is_empty() {
|
||||||
|
// There are changes, proceed with git commit
|
||||||
|
let commit_output = Command::new("git")
|
||||||
.arg("commit")
|
.arg("commit")
|
||||||
.arg("-m")
|
.arg("-m")
|
||||||
.arg(
|
.arg(
|
||||||
|
|
@ -94,7 +117,32 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
.replace("{current_version}", ¤t_version)
|
.replace("{current_version}", ¤t_version)
|
||||||
.replace("{new_version}", &new_version),
|
.replace("{new_version}", &new_version),
|
||||||
)
|
)
|
||||||
.output()?;
|
.output();
|
||||||
|
|
||||||
|
match commit_output {
|
||||||
|
Ok(commit_output) => {
|
||||||
|
if commit_output.status.success() {
|
||||||
|
println!("Git commit successful");
|
||||||
|
} else {
|
||||||
|
eprintln!(
|
||||||
|
"Error during git commit:\n{}",
|
||||||
|
String::from_utf8_lossy(&commit_output.stderr)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!("Failed to execute git commit: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// No changes to commit
|
||||||
|
println!("No changes to commit. Working tree clean.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!("Failed to execute git diff: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if tag {
|
if tag {
|
||||||
Command::new("git")
|
Command::new("git")
|
||||||
|
|
@ -104,7 +152,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
println!("No files specified");
|
eprintln!("No files specified");
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
94
src/utils.rs
94
src/utils.rs
|
|
@ -1,49 +1,101 @@
|
||||||
use crate::cli::Cli;
|
use crate::cli::Cli;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
pub fn get_current_version_from_config(config_content: &str) -> Option<String> {
|
||||||
|
let current_version_regex =
|
||||||
|
Regex::new(r#"\[bumpversion\]\s*current_version\s*=\s*(?P<version>\d+(\.\d+){0,2})\s*"#)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if let Some(captures) = current_version_regex.captures(config_content) {
|
||||||
|
if let Some(version) = captures.name("version") {
|
||||||
|
return Some(version.as_str().to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to read files from the configuration file
|
||||||
|
pub fn read_files_from_config(config_file: &str) -> Result<HashSet<String>, std::io::Error> {
|
||||||
|
let config_content = fs::read_to_string(config_file)?;
|
||||||
|
let mut config_files = HashSet::new();
|
||||||
|
|
||||||
|
for line in config_content.lines() {
|
||||||
|
if let Some(file_section) = line.strip_prefix("[bumpversion:file:") {
|
||||||
|
if let Some(file_name) = file_section.split(']').next() {
|
||||||
|
config_files.insert(file_name.trim().to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(config_files)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn attempt_version_bump(args: Cli) -> Option<String> {
|
pub fn attempt_version_bump(args: Cli) -> Option<String> {
|
||||||
let parse_regex = args.parse;
|
let parse_regex = args.parse.clone();
|
||||||
let regex = Regex::new(&parse_regex).ok()?;
|
let regex = match Regex::new(&parse_regex) {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(_) => {
|
||||||
|
eprintln!("--patch '{}' is not a valid regex", args.parse.clone());
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let current_version = args.current_version;
|
let config_content = fs::read_to_string(args.config_file.clone()).unwrap();
|
||||||
let match_result = regex.captures_iter(¤t_version);
|
let current_version = get_current_version_from_config(&config_content).unwrap_or_else(|| {
|
||||||
|
panic!("Failed to extract current version from config file");
|
||||||
|
});
|
||||||
|
// let current_version = args.current_version.unwrap_or("".to_string());
|
||||||
|
let mut parsed: HashMap<String, String> = HashMap::new();
|
||||||
|
|
||||||
let mut parsed: HashMap<&str, &str> = HashMap::new();
|
if let Some(captures) = regex.captures(¤t_version) {
|
||||||
|
for name in regex.capture_names() {
|
||||||
for caps in match_result {
|
if let Some(name) = name {
|
||||||
if let (Some(name), Some(value)) = (caps.name("name"), caps.name("value")) {
|
if let Some(capture) = captures.name(name) {
|
||||||
parsed.insert(name.as_str(), value.as_str());
|
parsed.insert(name.to_string(), capture.as_str().to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let order: Vec<&str> = args
|
let order: Vec<&str> = args
|
||||||
.serialize
|
.serialize
|
||||||
.match_indices('{')
|
.match_indices('{')
|
||||||
.map(|(i, _)| args.serialize[i + 1..].split('}').next().unwrap())
|
.map(|(i, _)| args.serialize[i + 1..].split('}').next().unwrap().trim())
|
||||||
.map(|s| s.trim())
|
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let mut bumped = true;
|
let mut bumped = false;
|
||||||
|
|
||||||
for label in order {
|
for label in order {
|
||||||
|
if let Some(part) = parsed.get_mut(label) {
|
||||||
if label == args.bump {
|
if label == args.bump {
|
||||||
if let Some(_part) = parsed.get_mut(label) {
|
if let Ok(new_value) = part.parse::<u64>() {
|
||||||
// TODO: fix
|
*part = (new_value + 1).to_string();
|
||||||
// let new_value = part.parse::<u64>().unwrap() + 1;
|
|
||||||
// *part = &new_value.clone().to_string();
|
|
||||||
bumped = true;
|
bumped = true;
|
||||||
|
} else {
|
||||||
|
eprintln!("Failed to parse '{}' as u64", part);
|
||||||
|
return None;
|
||||||
}
|
}
|
||||||
} else if bumped {
|
} else if bumped {
|
||||||
parsed.insert(label, "0");
|
*part = "0".to_string();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if bumped {
|
if bumped {
|
||||||
let new_version = args.serialize.replace(
|
let new_version = format!(
|
||||||
|c| c == '{' || c == '}',
|
"{}.{}.{}",
|
||||||
parsed.get(&"{").unwrap_or(&"").to_string().as_str(), // TODO: fix c
|
parsed.get("major").unwrap_or(&"0".to_string()),
|
||||||
|
parsed.get("minor").unwrap_or(&"0".to_string()),
|
||||||
|
parsed.get("patch").unwrap_or(&"0".to_string())
|
||||||
);
|
);
|
||||||
Some(new_version)
|
let version = args
|
||||||
|
.serialize
|
||||||
|
.replace("{major}.{minor}.{patch}", &new_version);
|
||||||
|
Some(version)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue