Skip to main content

Crate bump2version

Crate bump2version 

Source
Expand description

§⬆️ Bump2version

bump2version logo

Crates.io Docs.rs PyPI npm License: MIT

bump2version is a multi-language version bumper written entirely in 100% safe Rust, with no_std support and native Python and Node.js bindings 🗿.

🦀 Rust🐍 Python🟩 Node.js
cargo add bump2versionpip install bump-rsnpm install bump2version
DocumentationRead PYTHON.mdRead NODE.md

bump2version banner

§🤔 What does this crate provide?

bump2version automates semantic version management for any project regardless of language. It:

  • Parses version strings using a fully configurable regex (default: semver major.minor.patch).
  • Bumps any named component (major, minor, patch, or custom cyclic stages).
  • Rewrites version occurrences across multiple files, including multiline CHANGELOG patterns, using (?ms) DOTALL + MULTILINE semantics identical to Python’s re.MULTILINE | re.DOTALL.
  • Commits and tags via 100% pure gix (gitoxide); zero subprocess calls, zero web-flow ghost-author bugs.
  • Reads author identity from the local git config.

§🦀 Rust

The Rust crate is available on crates.io. For a complete API reference, installation guide, and worked examples, visit the Rust Usage Guide.

The crate ships the following Cargo features:

FeatureDefaultDescription
stdFile I/O, git integration, regex stdlib cache
cliStandalone bump2version binary via clap
pythonPython extension module via PyO3/maturin
nodeNode.js native add-on via napi-rs

§Quick Start

[dependencies]
bump2version = "0.2.0"
use bump2version::{config::BumpConfig, version::{parse_version, bump_version, serialize_version}};

fn main() {
    let cfg = BumpConfig::default();
    let v   = parse_version("1.2.3", &cfg).unwrap();
    let v2  = bump_version(&v, "patch", &cfg).unwrap();
    println!("{}", serialize_version(&v2, &cfg)); // 1.2.4
}

§no_std Support

Core modules (config, version, files, error) compile in no_std + alloc:

# no_std (alloc required by the target):
bump2version = { version = "0.2.0", default-features = false }
Moduleno_std+allocstd
config
version
files
error
git
CLI
Python / Node.js

§🐍 Python

The Python bindings are published to PyPI as bump-rs and can be installed with pip install bump-rs. Built with maturin, pre-compiled wheels for CPython 3.12+.

For installation instructions, full method signatures, and examples, read the Python Usage Guide.

pip install bump-rs
from bump_rs import bump_version, apply_file_change, BumpConfig

print(bump_version("1.2.3", "patch"))   # "1.2.4"
print(bump_version("1.2.3", "minor"))   # "1.3.0"
print(bump_version("1.2.3", "major"))   # "2.0.0"

content = 'version = "1.0.0"\n'
print(apply_file_change(content, "1.0.0", "1.0.1"))
# 'version = "1.0.1"\n'

# Multiline CHANGELOG pattern
content = "## 1.0.0\nRelease notes\n\n## 0.9.0\nOld notes\n"
updated = apply_file_change(
    content,
    current_version="1.0.0",
    new_version="1.0.1",
    search="## {current_version}\nRelease notes",
    replace="## {new_version}\nRelease notes",
)
print(updated)  # "## 1.0.1\nRelease notes\n\n## 0.9.0\nOld notes\n"

# Custom parse/serialize config
cfg = BumpConfig(parse=r"(?P<major>\d+)\.(?P<minor>\d+)", serialize="{major}.{minor}")
print(bump_version("2.0", "minor", config=cfg))  # "2.1"

§🟩 Node.js

The Node.js bindings are published to npm as bump2version and can be installed with npm install bump2version. Built with napi-rs, pre-compiled .node add-on.

For installation instructions, TypeScript type definitions, and examples, read the Node.js Usage Guide.

npm install bump2version
const { bumpVersion, applyFileChange } = require("bump2version");

console.log(bumpVersion("1.2.3", "patch")); // '1.2.4'
console.log(bumpVersion("1.2.3", "minor")); // '1.3.0'

§💻 Command-line interface

cargo install bump2version --features rust-binary

bump2version --bump patch   # 1.0.0 → 1.0.1
bump2version --bump minor   # 1.0.0 → 1.1.0
bump2version --bump major   # 1.0.0 → 2.0.0
OptionDescription
--config-fileConfig file path (default: .bumpversion.toml)
--current-versionOverride current version
--bumpComponent: major, minor, patch
--parseParse regex override
--serializeSerialize format override
--dry-run / -nSimulate without writing files
--new-versionExplicit new version
--commit / --tagGit commit + tag

§⚙️ Configuration File (.bumpversion.toml)

[bumpversion]
current_version = "1.0.0"
commit = true
tag = true

[bumpversion:file:Cargo.toml]
search = 'version = "{current_version}"'
replace = 'version = "{new_version}"'

[bumpversion:file:CHANGELOG.md]
search = """
## {current_version}
    Release notes line 1
    Release notes line 2"""
replace = """
## {new_version}
    Release notes line 1
    Release notes line 2"""

§🔒 Safety

This crate enforces a zero-unsafe policy via #![forbid(unsafe_code)] at the crate root (except the Node.js FFI layer which requires unsafe for napi-rs interop). Every byte of the implementation, config parsing, regex matching, version bumping, git object creation, is written in safe Rust. The compiler will reject any future unsafe block introduced into the safe portions.

§📊 Benchmarks

§Rust (cargo bench)

Run with cargo bench. Results on x86-64 Linux (rustc stable):

cargo bench output
BenchmarkTime
config_parse/minimal~12 µs
config_parse/full_with_parts~18 µs
version_parse/1.0.0~439 µs
version_bump/patch~13.5 µs
version_bump/minor~14.1 µs
version_bump/major~6.0 µs
file_replace/100 lines~247 µs
file_replace/1 000 lines~1.35 ms
file_replace/10 000 lines~14.4 ms
multiline_replace (CHANGELOG)~87 µs

§Python Nano-Benchmarks (benchmarks/benchmark.py)

Times measured via 3-sigma filtered timeit (CPython 3.12, x86-64 Linux). Run with:

pip install bump-rs bumpversion
python benchmarks/benchmark.py
§Version Bumping: full round-trip (parse + bump + serialize)
Librarypatchminormajor
bump-rs (Rust, Arc<Regex> cache)~57 µs~54 µs~53 µs
bump-my-version (Python library)~79 µs~95 µs~72 µs
Pure Python (re.compile + int())~3.6 µs~2.2 µs~2.2 µs
bump-my-version CLI (subprocess)~585 ms~585 ms~585 ms

bump-rs is 1.4-1.8× faster than bump-my-version’s Python library and ~10 000× faster than the CLI.

§File Search/Replace
LibrarySingle-lineMultiline CHANGELOG
bump-rs (Rust, cached)~65 µs~104 µs
Pure Python re.sub~1.7 µs~1.3 µs

When bump-rs wins:

  • vs bump-my-version library: 1.4-1.8× faster version bumping, correct multiline pattern semantics.
  • vs bump-my-version CLI: ~10 000× faster, no subprocess startup.
  • Thread safety: #![forbid(unsafe_code)] + no GIL constraint → scales across threads.
  • Full pipeline: config + bump + git commit entirely in safe Rust.

When pure Python wins:

  • Single in-memory arithmetic on a tiny string where ~50 µs PyO3 FFI overhead dominates: use bump_rs in batch or for full-pipeline work.

§📚 Further Reading

§📄 License

Licensed under the MIT License.

§bump2version Rust Documentation 🦀

The bump2version Rust crate provides a fully thread-safe, library-quality version bumper. All logic is available both as a CLI binary and as a library importable in other Rust projects.

§📦 Installation (CLI)

cargo install bump2version --features rust-binary

§📦 Library Usage

[dependencies]
bump2version = { version = "0.2.0", default-features = false }

§🛠 Usage Overview

§Parse a version

use bump2version::config::BumpConfig;
use bump2version::version::parse_version;

let cfg = BumpConfig::default();
let v = parse_version("1.2.3", &cfg).unwrap();
assert_eq!(v["major"].value, "1");
assert_eq!(v["patch"].value, "3");

§Bump a version

use bump2version::config::BumpConfig;
use bump2version::version::{parse_version, bump_version, serialize_version};

let cfg = BumpConfig::default();
let v = parse_version("1.2.3", &cfg).unwrap();
let bumped = bump_version(&v, "minor", &cfg).unwrap();
assert_eq!(serialize_version(&bumped, &cfg), "1.3.0");

§Parse config file

use bump2version::config::parse_config_file;

let cfg = parse_config_file(".bumpversion.toml").unwrap();
println!("{:?}", cfg.current_version);

§Apply file search/replace

use bump2version::config::{BumpConfig, FileConfig};
use bump2version::files::apply_file_change;

let cfg = BumpConfig::default();
let mut fc = FileConfig::new("Cargo.toml");
fc.search = Some(r#"version = "{current_version}""#.to_string());
fc.replace = Some(r#"version = "{new_version}""#.to_string());

let content = r#"version = "1.0.0""#.to_string();
let updated = apply_file_change(&content, &fc, &cfg, "1.0.0", "1.0.1").unwrap();
assert!(updated.contains("1.0.1"));

§Read git author from local config

use bump2version::git::get_git_author;
use gix::open;

let repo = open(".").unwrap();
let (name, email) = get_git_author(&repo).unwrap();
println!("{name} <{email}>");

§📖 Module Overview

ModuleDescription
configParse .bumpversion.toml into BumpConfig, FileConfig, PartConfig
versionParse version strings, bump components, serialize back to string
filesApply single/multiline search-replace with {current_version} tokens
gitThread-safe git commit + tag via gix; reads author from git config
errorTyped BumpError enum
utilsHigher-level helpers: load_config, compute_new_version, collect_file_configs
cliclap-based CLI argument struct (requires cli feature)
pythonPyO3 bindings (requires python feature)
nodenapi-rs bindings (requires node feature)

§🔗 See Also

Modules§

clicli and std
CLI Argument Definitions
config
Configuration Parsing
error
Error Types
files
File Search and Replace
gitstd
Git Integration
nodenode and std
Node.js Bindings
utilsstd
Utility Helpers
version
Version Parsing and Bumping