Odometer 🚀
A workspace version management tool that keeps package versions synchronized across projects.
Overview
Odometer provides intuitive commands to manage versions across project workspaces, with precise control over which packages get updated. Whether you need lockstep versioning for coordinated releases or independent versioning for different packages, odometer has you covered.
Currently supports: Rust/Cargo workspaces and Node.js/npm workspaces
Planned support: Python/pip and other package ecosystems
Key Features
- 🎯 Precise Package Selection - Target specific packages, all workspace members, or just the root
- 🔄 Flexible Version Strategies - Independent versioning or lockstep synchronization
- 🛡️ Safe Defaults - Operations target workspace root only unless explicitly specified
- 📊 Clear Inspection - See current versions and validate version fields
- 🏗️ Workspace Inheritance Support - Handles
version = { workspace = true }(Cargo) andworkspace:*(Node.js) - ⚡ Fast & Reliable - Written in Rust with comprehensive test coverage
Installation
From crates.io (Recommended)
# Install latest stable release
# Or install specific version
From Source (Development)
Verify Installation
# Output: odometer 0.3.1
Multiple Binary Names
Odometer provides multiple binary names for convenience:
Quick Start
# See current versions
# Bump workspace root patch version
# Bump all workspace members independently
# Set all crates to same version (lockstep)
# Validate all version fields
Commands
odo show - Display Versions
Shows current versions for all workspace members:
odo roll - Increment Versions
Increment versions with precise control:
# Bump workspace root only (safe default)
# Custom increments
# Target all workspace members independently
# Target specific packages
odo set - Set Specific Versions
Set exact versions for packages:
# Set workspace root to specific version
# Set specific packages
odo sync - Lockstep Synchronization
Set ALL workspace members to the same version:
# Synchronize everything to 1.0.0
# After sync, all crates have identical versions
odo lint - Validate Versions
Check for missing or malformed version fields:
# Or with errors:
Package Selection
Odometer uses cargo-style package selection for precise control:
| Flag | Description | Example |
|---|---|---|
| (default) | Workspace root only | odo roll patch |
-p, --package |
Specific package(s) | odo roll patch -p lib1 |
-w, --workspace |
All workspace members | odo roll --workspace patch |
File and Directory Filtering
Odometer respects standard ignore patterns when discovering workspace members. By default, it follows the same conventions as tools like ripgrep and ag.
Default Behavior
- ✅ Hidden files ignored - Files/directories starting with
.are skipped - ✅
.gitignorerespected - Standard git ignore patterns are followed - ✅
.ignorerespected - ripgrep/ag format ignore files are supported - ✅ Global git ignore -
~/.config/git/ignorepatterns are applied - ✅ Local git exclude -
.git/info/excludepatterns are applied
Override Flags
Control exactly what gets ignored with these flags:
| Flag | Description | Example |
|---|---|---|
--hidden |
Include hidden files/directories | odo show --hidden |
--no-ignore |
Don't respect .ignore files |
odo show --no-ignore |
--no-ignore-git |
Don't respect .gitignore files |
odo show --no-ignore-git |
--no-ignore-global |
Don't respect global git ignore | odo show --no-ignore-global |
--no-ignore-all |
Disable all ignore filtering | odo show --no-ignore-all |
Common Use Cases
# Include packages in hidden directories (e.g., .private-pkg)
# Debug: see everything odometer can find
# Ignore git patterns but respect custom .ignore files
# Work in a non-git directory with custom ignore patterns
Ignore File Formats
Odometer supports these ignore files in order of precedence:
.ignore- ripgrep/ag format (highest precedence).gitignore- git format- Global git ignore -
~/.config/git/ignore(lowest precedence)
Example .ignore file:
# Ignore build artifacts
target/
node_modules/
dist/
# Ignore temporary packages
**/temp-*
**/.tmp
Example Workflows
Coordinated Release Workflow
# Get everything synchronized first
# Now bulk operations work predictably
Independent Development Workflow
# Work on different features in different crates
# Bulk patch release when ready
Preparing Major Release
# Review current state
# Synchronize for coordinated release
Workspace Support
Odometer properly handles:
- Workspace roots with
[workspace]sections (Cargo) orworkspacesfield (Node.js) - Member packages in subdirectories
- Workspace inheritance:
- Cargo:
version = { workspace = true } - Node.js:
"version": "workspace:*"or"version": "workspace:~"
- Cargo:
- Mixed scenarios (some packages inherit, others don't)
- Single package projects (no workspace)
- Mixed ecosystems (Rust and Node.js packages in the same workspace)
Node.js Workspace Example
# Initialize a Node.js workspace
&&
# Add workspaces to package.json
# Create some packages
&&
&&
# Now use odometer to manage versions
Rust Workspace Example
# Initialize a Rust workspace
# Add workspace configuration to Cargo.toml
# Create some crates
&&
&&
# Now use odometer to manage versions
Development
Setup
Testing
Available Make Targets
Contributing
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Add tests for new functionality
- Run the test suite (
make test-all) - Commit your changes (
git commit -am 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Architecture
Odometer uses a clean architecture with three main layers:
- Domain (
src/domain.rs) - Pure business logic for version operations - IO (
src/io/) - File system operations (currently Cargo, designed for Node.js/Python expansion) - CLI (
src/cli.rs) - Command-line interface and orchestration
License
This project is licensed under the MIT License - see the LICENSE file for details.
Acknowledgments
Made with ❤️ for the Rust community