Versioning It with your Version In Git - automatic package versioning based on VCS tags
—
Pre-built implementations for each pipeline step including VCS querying, version formatting, file writing, and onbuild processing. These methods provide sensible defaults and can be customized through configuration parameters.
Convert VCS tags to version strings with prefix/suffix removal and regex processing.
def basic_tag2version(*, tag: str, params: dict[str, Any]) -> str:
"""
Implements the "basic" tag2version method for converting tags to versions.
Parameters:
- tag: The VCS tag string
- params: Configuration parameters:
- rmprefix (str, optional): Prefix to remove from tag
- rmsuffix (str, optional): Suffix to remove from tag
- regex (str, optional): Regex to extract version from tag
- require-match (bool, default False): Whether regex must match
Returns:
str: Version string extracted from tag (with leading 'v' stripped)
Raises:
- InvalidTagError: if require-match is True and regex doesn't match
"""Apply formatting templates based on repository state and calculated versions.
def basic_format(
*,
description: VCSDescription,
base_version: str,
next_version: str,
params: dict[str, Any],
) -> str:
"""
Implements the "basic" format method for version formatting.
Parameters:
- description: VCS repository state
- base_version: Version extracted from tag
- next_version: Calculated next version
- params: Format templates keyed by repository state:
- distance (str): Template for commits ahead of tag
- dirty (str): Template for uncommitted changes
- distance-dirty (str): Template for both conditions
Returns:
str: Formatted version string
Raises:
- ConfigError: if no format template found for repository state
"""
# Default format templates
DEFAULT_FORMATS = {
"distance": "{version}.post{distance}+{vcs}{rev}",
"dirty": "{version}+d{build_date:%Y%m%d}",
"distance-dirty": "{version}.post{distance}+{vcs}{rev}.d{build_date:%Y%m%d}",
}Write version information to files using configurable templates.
def basic_write(
*,
project_dir: str | Path,
template_fields: dict[str, Any],
params: dict[str, Any],
) -> None:
"""
Implements the "basic" write method for writing version to files.
Parameters:
- project_dir: Path to project root
- template_fields: Variables for template substitution
- params: Configuration parameters:
- file (str): Relative path to file to write
- encoding (str, default "utf-8"): File encoding
- template (str, optional): Template string (auto-detected by extension)
Raises:
- ConfigError: if template not specified and file extension unknown
"""Generate template variables for use in write and onbuild steps.
def basic_template_fields(
*,
version: str,
description: Optional[VCSDescription],
base_version: Optional[str],
next_version: Optional[str],
params: dict[str, Any],
) -> dict[str, Any]:
"""
Implements the "basic" template-fields method.
Parameters:
- version: Final version string
- description: VCS repository state or None
- base_version: Version from tag or None
- next_version: Calculated next version or None
- params: Configuration parameters:
- version-tuple: Dict configuring version tuple generation:
- pep440 (bool, default False): Use PEP 440 parsing
- epoch (bool, optional): Include epoch in tuple
- split-on (str, optional): Characters to split on (ignored if pep440=True)
- double-quote (bool, default True): Use double quotes in tuple
Returns:
dict[str, Any]: Template fields including version, version_tuple, normalized_version, etc.
"""Built-in methods for calculating the next version after the current tag.
def next_minor_version(
*,
version: str,
branch: Optional[str],
params: dict[str, Any],
) -> str:
"""
Implements the "minor" next-version method.
Increments the minor version and sets patch to 0.
Parameters:
- version: Base version string
- branch: Current branch name (unused)
- params: Configuration parameters (none used)
Returns:
str: Next minor version (e.g., "1.2.3" -> "1.3.0")
"""
def next_smallest_version(
*,
version: str,
branch: Optional[str],
params: dict[str, Any],
) -> str:
"""
Implements the "smallest" next-version method.
Increments the smallest (rightmost) version component.
Parameters:
- version: Base version string
- branch: Current branch name (unused)
- params: Configuration parameters (none used)
Returns:
str: Next smallest version (e.g., "1.2.3" -> "1.2.4")
"""
def next_minor_release_version(
*,
version: str,
branch: Optional[str],
params: dict[str, Any],
) -> str:
"""
Implements the "minor-release" next-version method.
If version is a prerelease, returns base version; otherwise increments minor.
Parameters:
- version: Base version string
- branch: Current branch name (unused)
- params: Configuration parameters (none used)
Returns:
str: Next minor or base version
"""
def next_smallest_release_version(
*,
version: str,
branch: Optional[str],
params: dict[str, Any],
) -> str:
"""
Implements the "smallest-release" next-version method.
If version is a prerelease, returns base version; otherwise increments smallest.
Parameters:
- version: Base version string
- branch: Current branch name (unused)
- params: Configuration parameters (none used)
Returns:
str: Next smallest or base version
"""
def null_next_version(
*,
version: str,
branch: Optional[str],
params: dict[str, Any],
) -> str:
"""
Implements the "null" next-version method.
Returns the same version unchanged.
Parameters:
- version: Base version string
- branch: Current branch name (unused)
- params: Configuration parameters (none used)
Returns:
str: Unchanged version
"""Replace version strings in files during the build process.
def replace_version_onbuild(
*,
file_provider: OnbuildFileProvider,
is_source: bool,
template_fields: dict[str, Any],
params: dict[str, Any],
) -> None:
"""
Implements the "replace-version" onbuild method.
Parameters:
- file_provider: Interface for accessing build files
- is_source: True for sdist, False for wheel
- template_fields: Variables for template substitution
- params: Configuration parameters:
- source-file (str): Path in source tree
- build-file (str): Path in build/install tree
- encoding (str, default "utf-8"): File encoding
- regex (str): Regex to find version line (default: __version__ pattern)
- require-match (bool, default False): Whether regex must match
- replacement (str): Replacement template (default: '"{version}"')
- append-line (str, optional): Line to append if no match found
Raises:
- ConfigError: if regex is invalid
- RuntimeError: if require-match is True and no match found
"""# Basic prefix/suffix removal
config = {
"tag2version": {
"method": "basic",
"rmprefix": "v",
"rmsuffix": "-release"
}
}
# v1.2.3-release -> 1.2.3
# Regex extraction
config = {
"tag2version": {
"method": "basic",
"regex": r"release-(?P<version>.*)",
"require-match": True
}
}
# release-1.2.3 -> 1.2.3config = {
"format": {
"distance": "{version}.dev{distance}+g{rev}",
"dirty": "{version}+dirty.{build_date:%Y%m%d}",
"distance-dirty": "{version}.dev{distance}+g{rev}.dirty.{build_date:%Y%m%d}"
}
}
# Examples:
# Exact tag: "1.2.3"
# 5 commits ahead: "1.2.3.dev5+g1234567"
# Dirty working tree: "1.2.3+dirty.20231201"
# Both: "1.2.3.dev5+g1234567.dirty.20231201"# Python file
config = {
"write": {
"file": "src/mypackage/_version.py",
"template": '__version__ = "{version}"'
}
}
# Text file
config = {
"write": {
"file": "VERSION",
"template": "{version}"
}
}
# Custom template with multiple fields
config = {
"write": {
"file": "src/mypackage/_build_info.py",
"template": '''
__version__ = "{version}"
__version_tuple__ = {version_tuple}
__build_date__ = "{build_date}"
__git_revision__ = "{rev}"
'''
}
}# Basic version tuple
config = {
"template-fields": {
"method": "basic",
"version-tuple": {
"pep440": False,
"split-on": ".",
"double-quote": True
}
}
}
# "1.2.3" -> ("1", "2", "3")
# PEP 440 parsing
config = {
"template-fields": {
"method": "basic",
"version-tuple": {
"pep440": True,
"epoch": True,
"double-quote": False
}
}
}
# "1!2.3.4a1" -> (1, 2, 3, 4, 'a', 1)# minor: 1.2.3 -> 1.3.0
config = {"next-version": {"method": "minor"}}
# smallest: 1.2.3 -> 1.2.4
config = {"next-version": {"method": "smallest"}}
# minor-release: 1.2.3a1 -> 1.2.3, 1.2.3 -> 1.3.0
config = {"next-version": {"method": "minor-release"}}
# smallest-release: 1.2.3a1 -> 1.2.3, 1.2.3 -> 1.2.4
config = {"next-version": {"method": "smallest-release"}}
# null: 1.2.3 -> 1.2.3 (unchanged)
config = {"next-version": {"method": "null"}}# Replace __version__ in Python file
config = {
"onbuild": {
"method": "replace-version",
"source-file": "src/mypackage/__init__.py",
"build-file": "mypackage/__init__.py",
"regex": r'^__version__ = .*$',
"replacement": '__version__ = "{version}"'
}
}
# Custom regex pattern
config = {
"onbuild": {
"method": "replace-version",
"source-file": "version.h",
"build-file": "version.h",
"regex": r'#define VERSION ".*"',
"replacement": '#define VERSION "{version}"',
"require-match": True
}
}
# Append if no match found
config = {
"onbuild": {
"method": "replace-version",
"source-file": "setup.cfg",
"build-file": "setup.cfg",
"regex": r'^version = .*$',
"replacement": 'version = {version}',
"append-line": 'version = {version}'
}
}config = {
"default-version": "0.0.0.dev0",
"vcs": {
"method": "git",
"match": ["v*.*.*"],
"exclude": ["*rc*"]
},
"tag2version": {
"method": "basic",
"rmprefix": "v"
},
"next-version": {
"method": "smallest"
},
"format": {
"distance": "{version}.post{distance}+{vcs}{rev}",
"dirty": "{version}+d{build_date:%Y%m%d}",
"distance-dirty": "{version}.post{distance}+{vcs}{rev}.d{build_date:%Y%m%d}"
},
"template-fields": {
"method": "basic",
"version-tuple": {
"pep440": True,
"double-quote": False
}
},
"write": {
"file": "src/mypackage/_version.py",
"template": '__version__ = "{version}"\n__version_tuple__ = {version_tuple}'
},
"onbuild": {
"method": "replace-version",
"source-file": "src/mypackage/__init__.py",
"build-file": "mypackage/__init__.py"
}
}Install with Tessl CLI
npx tessl i tessl/pypi-versioningit