1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318
|
# Version Providers
Version providers are the mechanism by which Commitizen reads and writes version information in your project.
They abstract away the details of where and how version numbers are stored, allowing Commitizen to work seamlessly with different project types and package management systems.
## Overview
By default, Commitizen uses the `commitizen` provider, which stores the version in your Commitizen configuration file.
However, you can configure Commitizen to use any available provider that matches your project's setup.
This is particularly useful when you want Commitizen to manage versions in the same location as your package manager (e.g., `package.json` for Node.js projects, `pyproject.toml` for Python projects).
## Built-in Providers
Commitizen includes several built-in version providers for common package management formats:
### `commitizen` (Default)
The default version provider stores and retrieves the version from your Commitizen configuration file (e.g., `pyproject.toml`, `.cz.toml`, etc.).
**Use when:**
- You want to keep version management separate from your package manager
- Your project doesn't use a standard package manager
- You need maximum flexibility in version management
**Configuration:**
```toml
[tool.commitizen]
version_provider = "commitizen"
version = "0.1.0" # Required when using this provider
```
### `scm`
Fetches the version from Git tags using `git describe`. This provider **only reads** version information and never writes it back to files. It's designed to work with tools like `setuptools-scm` or other package manager `*-scm` plugins that derive version numbers from Git history.
**Use when:**
- You're using `setuptools-scm` or similar tools
- You want version numbers derived from Git tags
- You don't want Commitizen to modify any files for version management
**Configuration:**
```toml
[tool.commitizen]
version_provider = "scm"
# No version field needed - it's read from Git tags
```
!!! note
The `scm` provider is read-only. When you run `cz bump`, it will create a Git tag but won't update any files. This is intentional and works well with tools that derive versions from Git tags.
### `pep621`
Manages version in `pyproject.toml` under the `project.version` field, following [PEP 621](https://peps.python.org/pep-0621/) standards.
**Use when:**
- You're using a modern Python project with PEP 621-compliant `pyproject.toml`
- You want version management integrated with your Python project metadata
**Configuration:**
```toml
[tool.commitizen]
version_provider = "pep621"
```
**Example `pyproject.toml`:**
```toml
[project]
name = "my-package"
version = "0.1.0" # Managed by Commitizen
```
### `poetry`
Manages version in `pyproject.toml` under the `tool.poetry.version` field, which is used by the [Poetry](https://python-poetry.org/) package manager. This approach is recommended only for users running Poetry versions earlier than 2.0 or relying on Poetry-specific features. For most users on Poetry 2.0 or later, it is recommended to use `pep621` instead. [Read More](https://python-poetry.org/docs/main/managing-dependencies/)
**Use when:**
- You're using Poetry < 2.0 as your Python package manager
- You're using Poetry >= 2.0 as your Python package manager, but don't need poetry-specific features
- You want Commitizen to manage the version that Poetry uses
**Configuration:**
```toml
[tool.commitizen]
version_provider = "poetry"
```
**Example `pyproject.toml`:**
```toml
[tool.poetry]
name = "my-package"
version = "0.1.0" # Managed by Commitizen
```
### `uv`
Manages version in both `pyproject.toml` (`project.version`) and `uv.lock` (`package.version` for the matching package name). This ensures consistency between your project metadata and lock file.
!!! note
Even though uv follows PEP 621 format, `pep621` does not manage the version in `uv.lock`. `uv` is still suggested for uv users.
**Use when:**
- You're using `uv` as your Python package manager
- You want version synchronization between `pyproject.toml` and `uv.lock`
**Configuration:**
```toml
[tool.commitizen]
version_provider = "uv"
```
### `cargo`
Manages version in both `Cargo.toml` (`package.version`) and `Cargo.lock` (`package.version` for the matching package name). This ensures consistency between your Rust project's manifest and lock file.
**Use when:**
- You're working with a Rust project using Cargo
- You want Commitizen to manage Rust package versions
**Configuration:**
```toml
[tool.commitizen]
version_provider = "cargo"
```
**Example `Cargo.toml`:**
```toml
[package]
name = "my-crate"
version = "0.1.0" # Managed by Commitizen
```
### `npm`
Manages version in `package.json` and optionally synchronizes with `package-lock.json` and `npm-shrinkwrap.json` if they exist.
**Use when:**
- You're working with a Node.js/JavaScript project
- You want Commitizen to manage npm package versions
**Configuration:**
```toml
[tool.commitizen]
version_provider = "npm"
```
**Example `package.json`:**
```json
{
"name": "my-package",
"version": "0.1.0"
}
```
### `composer`
Manages version in `composer.json` under the `version` field, used by PHP's Composer package manager.
**Use when:**
- You're working with a PHP project using Composer
- You want Commitizen to manage Composer package versions
**Configuration:**
```toml
[tool.commitizen]
version_provider = "composer"
```
**Example `composer.json`:**
```json
{
"name": "vendor/package",
"version": "0.1.0"
}
```
## Provider Comparison Table
| Provider | File(s) Modified | Read-Only | Best For |
| ------------ | ----------------------------------- | --------- | --------------------------------- |
| `commitizen` | Commitizen config file | No | General use, flexible projects |
| `scm` | None (reads from Git tags) | Yes | `setuptools-scm` users |
| `pep621` | `pyproject.toml` (`project.version`) | No | Modern Python (PEP 621) |
| `poetry` | `pyproject.toml` (`tool.poetry.version`) | No | Poetry projects |
| `uv` | `pyproject.toml` + `uv.lock` | No | uv package manager |
| `cargo` | `Cargo.toml` + `Cargo.lock` | No | Rust/Cargo projects |
| `npm` | `package.json` (+ lock files) | No | Node.js/npm projects |
| `composer` | `composer.json` | No | PHP/Composer projects |
## Creating Custom Version Providers
If none of the built-in providers meet your needs, you can create a custom version provider by extending the `VersionProvider` base class and registering it as a plugin.
### Step 1: Create Your Provider Class
Create a Python file (e.g., `my_provider.py`) that extends `VersionProvider`:
```python title="my_provider.py"
from pathlib import Path
from commitizen.providers import VersionProvider
class MyProvider(VersionProvider):
"""
Custom version provider that reads/writes from a VERSION file.
"""
def get_version(self) -> str:
"""Read version from VERSION file."""
version_file = Path("VERSION")
if not version_file.exists():
return "0.0.0"
return version_file.read_text().strip()
def set_version(self, version: str) -> None:
"""Write version to VERSION file."""
version_file = Path("VERSION")
version_file.write_text(f"{version}\n")
```
### Step 2: Register as an Entry Point
Register your provider using the `commitizen.provider` entry point. You can do this in your `setup.py`, `setup.cfg`, or `pyproject.toml`:
**Using `pyproject.toml` (recommended):**
```toml title="pyproject.toml"
[project]
name = "my-commitizen-provider"
version = "0.1.0"
dependencies = ["commitizen"]
[project.entry-points."commitizen.provider"]
my-provider = "my_provider:MyProvider"
```
**Using `setup.py` (for legacy setup):**
```python title="setup.py"
from setuptools import setup
setup(
name="my-commitizen-provider",
version="0.1.0",
py_modules=["my_provider"],
install_requires=["commitizen"],
entry_points={
"commitizen.provider": [
"my-provider = my_provider:MyProvider",
]
},
)
```
### Step 3: Install and Use
1. Install your provider package:
```bash
pip install -e .
```
2. Configure Commitizen to use your provider:
```toml
[tool.commitizen]
version_provider = "my-provider"
```
### Provider Implementation Guidelines
When creating a custom provider, keep these guidelines in mind:
- **`get_version()`** should return a string representing the current version. If no version is found, you can return `"0.0.0"` or raise an appropriate exception.
- **`set_version(version: str)`** should write the version to your chosen storage location. The version string will be properly formatted according to your `version_scheme` setting.
- The provider has access to `self.config`, which is a `BaseConfig` instance containing all Commitizen settings.
- For file-based providers, consider using the `FileProvider` or `JsonProvider`/`TomlProvider` base classes from `commitizen.providers.base_provider` to simplify implementation.
### Example: JSON-based Provider
Here's a more complete example using the `JsonProvider` base class:
```python title="json_version_provider.py"
from commitizen.providers.base_provider import JsonProvider
class JsonVersionProvider(JsonProvider):
"""
Version provider that uses a custom version.json file.
"""
filename = "version.json"
def get(self, document):
"""Extract version from JSON document."""
return document["version"]
def set(self, document, version):
"""Set version in JSON document."""
document["version"] = version
```
This example leverages the `JsonProvider` base class, which handles file reading, writing, and JSON parsing automatically.
## Choosing the Right Provider
Select a version provider based on your project's characteristics:
- **Python projects**
- **with `uv`**: Use `uv`
- **with `pyproject.toml` that follows PEP 621**: Use `pep621`
- **with Poetry**: Use `poetry`
- **setuptools-scm**: Use `scm`
- **Rust projects**: Use `cargo`
- **Node.js projects**: Use `npm`
- **PHP projects**: Use `composer`
- **Other cases or custom needs**: Use `commitizen` (default) or create a custom provider
Remember that you can always use `version_files` in combination with any provider to update additional files during version bumps, regardless of which provider you choose for reading/writing the primary version.
|