CVM - Crate Version Manager
A powerful command-line tool for managing semantic versioning of Rust crates in both single-crate and workspace projects.
Features
- ๐ Interactive Version Bumping: Select crates and bump types (major, minor, patch) interactively
- ๐ฆ Workspace Support: Manage multiple crates in a Cargo workspace
- ๐ Change Queue System: Stage version changes and apply them all at once
- ๐งช Prerelease Mode: Built-in support for canary/alpha/beta releases with automatic prerelease numbering
- ๐ Change Summaries: Require descriptions for all version changes
- ๐ฏ Semantic Versioning: Full compliance with SemVer specification
Installation
Or build from source:
Quick Start
Initialize CVM in your project
This creates:
.cvm/config.toml- Configuration file.cvm/changes/- Directory for pending version changes.cvm/README.md- Information about CVM
Basic Workflow
-
Initialize CVM (first time only):
-
Stage a version change (interactive mode):
This will prompt you to select crates and bump types (major, minor, or patch).
-
Apply all staged changes:
Prerelease Workflow
-
Start prerelease mode:
This saves the current version as the base and enables prerelease mode.
-
Stage and apply changes (they will be prerelease versions):
-
Exit prerelease mode when ready for production:
How It Works
Change Queue
When you run cvm without arguments, it creates timestamped change files in .cvm/changes/. Each file contains:
- A summary of the change
- Which crates to bump (major, minor, or patch)
- Whether it was created in prerelease mode
Running cvm apply processes all change files in chronological order and updates the Cargo.toml files accordingly.
Prerelease Mode
Prerelease mode intelligently handles version bumps:
Example flow starting from 0.1.0:
Then applying changes sequentially:
patchโ0.1.0-canary.0(first prerelease of this base)patchโ0.1.0-canary.1(increments prerelease number)minorโ0.2.0-canary.0(new base: 0.1.0 + minor = 0.2.0)patchโ0.2.0-canary.1(same base, increment number)minorโ0.2.0-canary.2(base 0.1.0 + minor = 0.2.0, same as current)majorโ1.0.0-canary.0(new base: 0.1.0 + major = 1.0.0)
Rules:
- PATCH in prerelease: Always keeps the current base version, increments prerelease number
- MINOR/MAJOR in prerelease: Calculates new base from stored base version
- If different from current base: applies bump and resets to
.0 - If same as current base: increments prerelease number
- If different from current base: applies bump and resets to
Commands
cvm setup
Initialize CVM in the current project. Creates configuration files and directories.
Example:
Output:
โ
CVM initialized successfully!
Configuration file created at: .cvm/config.toml
Change files will be stored in: .cvm/changes/
Next steps:
1. Run 'cvm' to create version changes interactively
2. Run 'cvm apply' to apply pending changes
3. Run 'cvm status' to check for pending changes
cvm (no arguments)
Interactive mode to select crates and bump types. Creates a change file in .cvm/changes/.
Example:
# Select crates for major bump: [none]
# Select crates for minor bump: [my-crate]
# Select crates for patch bump: [none]
# Summary: Add new feature X
cvm apply
Applies all pending changes in chronological order.
Example:
# Applying update: Add new feature X
# my-crate minor โ 0.2.0
# All updates applied successfully!
Options:
--dry-run: Preview changes without applying them
cvm status
Check for pending version changes.
Example:
Returns exit code 0 if no pending changes, exit code 1 if there are pending changes (useful for CI/CD).
cvm info
Get crate information as JSON. Useful for extracting version numbers and crate metadata in CI/CD pipelines.
Example:
# [{"name":"my-crate","version":"1.0.0","path":"Cargo.toml"}]
Options:
--format <FORMAT>: Output format (default: json)
cvm publish
Publish crates to crates.io.
Example:
Options:
--dry-run: Show what would be published without making changes--token <TOKEN>: Cargo registry token (overrides CARGO_REGISTRY_TOKEN env var)--allow-dirty: Allow publishing with uncommitted changes
Output: The command outputs JSON at the end with published crate information:
::cvm-output-json::[{"name":"my-crate","version":"1.0.0"}]
This makes it easy to parse in CI/CD scripts.
cvm pre start [identifier]
Enables prerelease mode with the specified identifier (e.g., canary, alpha, beta, rc).
Examples:
cvm pre exit
Disables prerelease mode and clears stored base versions.
Example:
# Prerelease mode exited.
File Structure
your-project/
โโโ .cvm/
โ โโโ config.toml # CVM configuration
โ โโโ changes/ # Pending version changes
โ โ โโโ 1234567890.toml
โ โ โโโ 1234567891.toml
โ โโโ README.md # Auto-generated info
โโโ Cargo.toml
โโโ src/
.cvm/config.toml
Stores CVM configuration:
# CVM Configuration
[]
= true
= "canary"
[]
= "0.1.0"
.cvm/changes/1234567890.toml
[]
= "Add new feature X"
= []
= ["my-crate"]
= []
= false
Use Cases
Single Crate Project
Perfect for managing versions of a single library or binary crate.
Workspace Project
Manage multiple related crates with independent versioning:
- Select which crates to bump
- Different bump types for different crates
- Apply all changes atomically
Continuous Deployment
- Developers stage changes with
cvmas they work - CI/CD applies changes with
cvm applybefore publishing - Prerelease mode for canary deployments
Release Management
- Use prerelease mode for beta testing
- Stage multiple changes before release
- Apply all changes at once when ready
CI/CD Integration
CVM is designed to work seamlessly in CI/CD pipelines. Here's a typical workflow:
Checking for Pending Changes
Use cvm status to check if there are pending version changes:
- Exit code 0: No pending changes
- Exit code 1: There are pending changes (useful for CI conditionals)
Dry Run
Preview what would be applied without making changes:
Example GitHub Actions Workflow
name: Version Management
on:
push:
branches:
jobs:
apply-versions:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Install CVM
run: cargo install cvm
- name: Check for pending changes
id: check
run: |
if ! cvm status; then
echo "has_changes=true" >> $GITHUB_OUTPUT
fi
- name: Apply version changes
if: steps.check.outputs.has_changes == 'true'
run: cvm apply
- name: Commit changes
if: steps.check.outputs.has_changes == 'true'
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add Cargo.toml */Cargo.toml
git commit -m "chore: apply version bumps"
git push
Typical CI/CD Flow
-
Development Branch (
canary):- Developers create changes:
cvmโ select crates โ add summary - Commit changes to
.cvm/changes/directory - Push to canary branch
- Developers create changes:
-
CI Pipeline Runs:
- Check for pending changes:
cvm status - Apply changes:
cvm apply - Run tests with new versions
- Commit updated
Cargo.tomlfiles - Create PR to main or commit directly
- Check for pending changes:
-
Production Branch (
main):- Merge PR with version bumps
- Publish to crates.io:
cvm publish
Extracting Version Information in Scripts
Use cvm info to extract version information programmatically:
# Get current version for a single crate project
VERSION=
# Get all crate names and versions
|
# Check if a specific crate exists
HAS_CRATE=
When using cvm publish, extract the JSON output:
# Capture publish output
OUTPUT=
# Extract JSON from output
JSON=
# Parse published crates
|
Best Practices
- Always add meaningful summaries: They serve as a changelog for your version bumps
- Use prerelease mode for testing: Test breaking changes with canary releases
- Commit
.cvm/to version control: Share pending changes with your team - Apply changes before publishing: Run
cvm applybeforecvm publish - Use
--dry-runin CI: Preview changes before applying them - Check status in pipelines: Use
cvm statusexit codes for conditional logic
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Authors
- Lucas Arch luketsx@icloud.com