mirror of
https://github.com/TECHNOFAB11/bump2version.git
synced 2025-12-12 16:10:07 +01:00
init release
This commit is contained in:
parent
ab9faf5864
commit
5bfd81666d
9 changed files with 716 additions and 16 deletions
121
src/cli.rs
Executable file
121
src/cli.rs
Executable file
|
|
@ -0,0 +1,121 @@
|
|||
use clap::builder::styling::{AnsiColor, Effects, Styles};
|
||||
use clap::Parser;
|
||||
|
||||
fn styles() -> Styles {
|
||||
Styles::styled()
|
||||
.header(AnsiColor::Red.on_default() | Effects::BOLD)
|
||||
.usage(AnsiColor::Red.on_default() | Effects::BOLD)
|
||||
.literal(AnsiColor::Blue.on_default() | Effects::BOLD)
|
||||
.error(AnsiColor::Red.on_default() | Effects::BOLD)
|
||||
.placeholder(AnsiColor::Green.on_default())
|
||||
}
|
||||
|
||||
#[derive(Parser, Debug, Clone)]
|
||||
#[command(
|
||||
author = "Mahmoud Harmouch",
|
||||
version,
|
||||
name = "bump2version",
|
||||
propagate_version = true,
|
||||
styles = styles(),
|
||||
help_template = r#"{before-help}{name} {version}
|
||||
{about-with-newline}
|
||||
|
||||
{usage-heading} {usage}
|
||||
|
||||
{all-args}{after-help}
|
||||
|
||||
AUTHORS:
|
||||
{author}
|
||||
"#,
|
||||
about=r#"
|
||||
🚀 Bump2version CLI
|
||||
===================
|
||||
|
||||
Bump2version CLI is a command-line tool for managing version numbers in your projects.
|
||||
Easily update version strings, create commits, and manage version control tags.
|
||||
|
||||
FEATURES:
|
||||
- Incremental Versioning: Bump major, minor, or patch versions with ease.
|
||||
- Configurability: Use a configuration file or command-line options to customize behavior.
|
||||
- Git Integration: Create commits and tags in your version control system.
|
||||
|
||||
USAGE:
|
||||
bump2version [OPTIONS]
|
||||
|
||||
EXAMPLES:
|
||||
Bump patch version:
|
||||
bump2version --current-version 1.2.3 --bump patch
|
||||
|
||||
Bump minor version and create a commit:
|
||||
bump2version --current-version 1.2.3 --bump minor --commit
|
||||
|
||||
For more information, visit: https://github.com/wiseaidev/bump2version
|
||||
"#
|
||||
)]
|
||||
pub struct Cli {
|
||||
/// Config file to read most of the variables from.
|
||||
#[arg(
|
||||
short = 'c',
|
||||
long = "config-file",
|
||||
value_name = "FILE",
|
||||
default_value_t = String::from(".bumpversion.toml")
|
||||
)]
|
||||
pub config_file: String,
|
||||
|
||||
/// Version that needs to be updated.
|
||||
#[arg(long = "current-version", value_name = "VERSION")]
|
||||
pub current_version: String,
|
||||
|
||||
/// Part of the version to be bumped.
|
||||
#[arg(
|
||||
long = "bump",
|
||||
value_name = "PART",
|
||||
default_value_t = String::from("patch")
|
||||
)]
|
||||
pub bump: String,
|
||||
|
||||
/// Regex parsing the version string.
|
||||
#[arg(
|
||||
long = "parse",
|
||||
value_name = "REGEX",
|
||||
default_value_t = String::from(r"(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)")
|
||||
)]
|
||||
pub parse: String,
|
||||
|
||||
/// How to format what is parsed back to a version.
|
||||
#[arg(
|
||||
long = "serialize",
|
||||
value_name = "FORMAT",
|
||||
default_value_t = String::from("{major}.{minor}.{patch}")
|
||||
)]
|
||||
pub serialize: String,
|
||||
|
||||
/// Don't write any files, just pretend.
|
||||
#[arg(short = 'n', long = "dry-run")]
|
||||
pub dry_run: bool,
|
||||
|
||||
/// New version that should be in the files.
|
||||
#[arg(long = "new-version", value_name = "VERSION")]
|
||||
pub new_version: String,
|
||||
|
||||
/// Create a commit in version control.
|
||||
#[arg(long = "commit", default_value_t = true)]
|
||||
pub commit: bool,
|
||||
|
||||
/// Create a tag in version control.
|
||||
#[arg(long = "tag")]
|
||||
pub tag: bool,
|
||||
|
||||
/// Commit message.
|
||||
#[arg(
|
||||
short = 'm',
|
||||
long = "message",
|
||||
value_name = "COMMIT_MSG",
|
||||
default_value_t = String::from("Bump version: {current_version} → {new_version}")
|
||||
)]
|
||||
pub message: String,
|
||||
|
||||
/// Files to change.
|
||||
#[arg(value_name = "file")]
|
||||
pub files: Vec<String>,
|
||||
}
|
||||
57
src/lib.rs
Normal file
57
src/lib.rs
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
//! # ⬆️ Bump2version
|
||||
//!
|
||||
//! Bump2version is a command-line tool for managing version numbers in your projects.
|
||||
//! Easily update version strings, create commits, and manage version control tags.
|
||||
//!
|
||||
//! ## Features
|
||||
//!
|
||||
//! - **Incremental Versioning:** Bump major, minor, or patch versions with ease.
|
||||
//! - **Configurability:** Use a configuration file or command-line options to customize behavior.
|
||||
//! - **Git Integration:** Create commits and tags in your version control system.
|
||||
//!
|
||||
//! ## Quick Start
|
||||
//!
|
||||
//! Get started with the `bump2version` CLI by following these simple steps:
|
||||
//!
|
||||
//! 1. Install the `bump2version` tool using Cargo:
|
||||
//!
|
||||
//! ```bash
|
||||
//! cargo install bump2version
|
||||
//! ```
|
||||
//!
|
||||
//! 2. Use the following options to manage version numbers and customize the behavior:
|
||||
//!
|
||||
//! ```bash
|
||||
//! bump2version --current-version 1.2.3 --bump patch
|
||||
//! ```
|
||||
//!
|
||||
//! ## Options
|
||||
//!
|
||||
//! | Option | Description |
|
||||
//! |------------------------|-------------------------------------------------------------------|
|
||||
//! | `--config-file` | Config file to read most of the variables from. |
|
||||
//! | `--current-version` | Version that needs to be updated. |
|
||||
//! | `--bump` | Part of the version to be bumped (default: patch). |
|
||||
//! | `--parse` | Regex parsing the version string (default: \d+\.\d+\.\d+). |
|
||||
//! | `--serialize` | How to format what is parsed back to a version (default: {major}.{minor}.{patch}). |
|
||||
//! | `--dry-run` | Don't write any files, just pretend. |
|
||||
//! | `--new-version` | New version that should be in the files. |
|
||||
//! | `--commit` | Create a commit in version control (default: true). |
|
||||
//! | `--tag` | Create a tag in version control. |
|
||||
//! | `--message` | Commit message (default: Bump version: {current_version} → {new_version}). |
|
||||
//! | `file` | Files to change. |
|
||||
//!
|
||||
//! ## GitHub Repository
|
||||
//!
|
||||
//! You can access the source code for this CLI tool on [GitHub](https://github.com/wiseaidev/bump2version).
|
||||
//!
|
||||
//! ## Contributing
|
||||
//!
|
||||
//! Contributions and feedback are welcome! If you'd like to contribute, report an issue, or suggest an enhancement,
|
||||
//! please engage with the project on [GitHub](https://github.com/wiseaidev/bump2version).
|
||||
//! Your contributions help improve this CLI tool for the community.
|
||||
//!
|
||||
//! **Manage your project versions with ease! 🚀**
|
||||
|
||||
pub mod cli;
|
||||
pub mod utils;
|
||||
111
src/main.rs
Normal file
111
src/main.rs
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
use self::cli::Cli;
|
||||
use crate::utils::attempt_version_bump;
|
||||
use clap::Parser;
|
||||
use std::fs;
|
||||
use std::process::Command;
|
||||
|
||||
mod cli;
|
||||
mod utils;
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// Parse command-line arguments
|
||||
let args = Cli::parse();
|
||||
let config_file = args.config_file.clone();
|
||||
let current_version = args.current_version.clone();
|
||||
|
||||
let attempted_new_version = attempt_version_bump(args.clone());
|
||||
|
||||
if !args.new_version.is_empty() && attempted_new_version.is_some() {
|
||||
// TODO: fix let new_version = attempted_new_version.clone().unwrap();
|
||||
let new_version = args.new_version.clone();
|
||||
|
||||
let dry_run = args.dry_run;
|
||||
let commit = args.commit;
|
||||
let tag = args.tag;
|
||||
let message = args.message;
|
||||
|
||||
let files: Vec<String> = args.files;
|
||||
|
||||
// Check if Git working directory is clean
|
||||
if fs::metadata(".git").is_ok() {
|
||||
let git_status = Command::new("git")
|
||||
.arg("status")
|
||||
.arg("--porcelain")
|
||||
.output()?;
|
||||
|
||||
let git_output = String::from_utf8_lossy(&git_status.stdout);
|
||||
let git_lines: Vec<&str> = git_output
|
||||
.lines()
|
||||
.filter(|line| !line.trim().starts_with("??"))
|
||||
.collect();
|
||||
|
||||
if !git_lines.is_empty() {
|
||||
panic!("Git working directory not clean:\n{}", git_lines.join("\n"));
|
||||
}
|
||||
}
|
||||
|
||||
// Update version in specified files
|
||||
for path in &files {
|
||||
let content = fs::read_to_string(path)?;
|
||||
|
||||
if !content.contains(¤t_version) {
|
||||
panic!("Did not find string {} in file {}", current_version, path);
|
||||
}
|
||||
|
||||
let updated_content = content.replace(¤t_version, &new_version);
|
||||
|
||||
if !dry_run {
|
||||
fs::write(path, updated_content)?;
|
||||
}
|
||||
}
|
||||
|
||||
let mut commit_files = files.clone();
|
||||
|
||||
// Update config file if applicable
|
||||
if fs::metadata(config_file.clone()).is_ok() {
|
||||
let mut config_content = fs::read_to_string(config_file.clone())?;
|
||||
|
||||
config_content = config_content.replace(
|
||||
&format!("new_version={}", attempted_new_version.unwrap()),
|
||||
"",
|
||||
);
|
||||
config_content = config_content.replace(
|
||||
&format!("current_version={}", current_version),
|
||||
&format!("current_version={}", new_version),
|
||||
);
|
||||
|
||||
if !dry_run {
|
||||
fs::write(config_file.clone(), config_content)?;
|
||||
commit_files.push(config_file);
|
||||
}
|
||||
}
|
||||
|
||||
// Git commit and tag
|
||||
if commit {
|
||||
for path in &commit_files {
|
||||
Command::new("git").arg("add").arg(path).output()?;
|
||||
}
|
||||
|
||||
Command::new("git")
|
||||
.arg("commit")
|
||||
.arg("-m")
|
||||
.arg(
|
||||
message
|
||||
.replace("{current_version}", ¤t_version)
|
||||
.replace("{new_version}", &new_version),
|
||||
)
|
||||
.output()?;
|
||||
|
||||
if tag {
|
||||
Command::new("git")
|
||||
.arg("tag")
|
||||
.arg(format!("v{}", new_version))
|
||||
.output()?;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
println!("No files specified");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
50
src/utils.rs
Normal file
50
src/utils.rs
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
use crate::cli::Cli;
|
||||
use regex::Regex;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub fn attempt_version_bump(args: Cli) -> Option<String> {
|
||||
let parse_regex = args.parse;
|
||||
let regex = Regex::new(&parse_regex).ok()?;
|
||||
|
||||
let current_version = args.current_version;
|
||||
let match_result = regex.captures_iter(¤t_version);
|
||||
|
||||
let mut parsed: HashMap<&str, &str> = HashMap::new();
|
||||
|
||||
for caps in match_result {
|
||||
if let (Some(name), Some(value)) = (caps.name("name"), caps.name("value")) {
|
||||
parsed.insert(name.as_str(), value.as_str());
|
||||
}
|
||||
}
|
||||
|
||||
let order: Vec<&str> = args
|
||||
.serialize
|
||||
.match_indices('{')
|
||||
.map(|(i, _)| args.serialize[i + 1..].split('}').next().unwrap())
|
||||
.map(|s| s.trim())
|
||||
.collect();
|
||||
|
||||
let mut bumped = true;
|
||||
for label in order {
|
||||
if label == args.bump {
|
||||
if let Some(_part) = parsed.get_mut(label) {
|
||||
// TODO: fix
|
||||
// let new_value = part.parse::<u64>().unwrap() + 1;
|
||||
// *part = &new_value.clone().to_string();
|
||||
bumped = true;
|
||||
}
|
||||
} else if bumped {
|
||||
parsed.insert(label, "0");
|
||||
}
|
||||
}
|
||||
|
||||
if bumped {
|
||||
let new_version = args.serialize.replace(
|
||||
|c| c == '{' || c == '}',
|
||||
parsed.get(&"{").unwrap_or(&"").to_string().as_str(), // TODO: fix c
|
||||
);
|
||||
Some(new_version)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue