init release

This commit is contained in:
wiseaidev 2024-02-19 16:50:38 +02:00
parent ab9faf5864
commit 5bfd81666d
No known key found for this signature in database
GPG key ID: 581B9704F8B836C3
9 changed files with 716 additions and 16 deletions

121
src/cli.rs Executable file
View 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
View 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
View 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(&current_version) {
panic!("Did not find string {} in file {}", current_version, path);
}
let updated_content = content.replace(&current_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}", &current_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
View 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(&current_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
}
}