dunamai

repository·master·Indexed 18 days ago

https://github.com/mtkennerly/dunamai

A Python library and CLI tool for generating dynamic, standards-compliant version strings (such as PEP 440 and SemVer) derived from version control system tags. It supports multiple VCS types including Git, Mercurial, Darcs, Subversion, Bazaar, Fossil, and Pijul. Features include a Version class for parsing, bumping, and serializing versions, as well as a CLI for generating versions and validating version strings.

Tokens
8.6K
Snippets
29
Records
34
Agent score
64%

What's inside dunamai

  1. Configure Tag Patterns and Prefixes

    master

    By default, Dunamai expects tags to have a v prefix. You can override this using patterns or prefixes.

    Using Regex Patterns

    Provide a regular expression with named groups to define how the base version is extracted.

    • CLI: --pattern "(?P<base>...)"
    • Python: pattern=r"(?P<base>...)"
    • Presets: Use Pattern.DefaultUnprefixed (Python) or --pattern default-unprefixed (CLI).

    Using Prefixes

    If your tags have a consistent prefix (e.g., some-package-v1.2.3), you can specify it without a full regex.

    • CLI: --pattern-prefix some-package-
    • Python: pattern_prefix="some-package-"
    # Python example using a custom pattern
    from dunamai import Version
    version = Version.from_any_vcs(pattern=r"(?P<base>\d+\.\d+\.\d+)")
    
    # Python example using a prefix
    version = Version.from_any_vcs(pattern_prefix="some-package-")
  2. Integrate Dunamai into your Project

    master

    Dunamai can be used to inject version strings into various build systems and Python packages.

    Generate a _version.py file during your build process to avoid runtime dependencies:

    echo "__version__ = '$(dunamai from any)'" > your_library/_version.py

    Then import it in your __init__.py:

    from your_library._version import __version__

    Dynamic Inclusion (Runtime Dependency)

    Import Dunamai directly in your __init__.py. Note that this makes Dunamai a required dependency at runtime:

    import dunamai as _dunamai
    __version__ = _dunamai.get_version("your-library", third_choice=_dunamai.Version.from_any_vcs).serialize()

    Integration with Build Tools

    • setuptools (setup.py):
      from setuptools import setup
      from dunamai import Version
      setup(name="your-library", version=Version.from_any_vcs().serialize())
    • Poetry: Use the CLI to set the version during build, or use the poetry-dynamic-versioning plugin:
      poetry version $(dunamai from any)
    # Static inclusion example
    echo "__version__ = '$(dunamai from any)'" > your_library/_version.py
  3. Configure VCS Archives for Git and Mercurial

    master

    If you are working with repository archives (like ZIP files) rather than full VCS histories, Dunamai can still detect versions if specific metadata files are present.

    Git Archival

    1. Create a .git_archival.json file in your repository root with the following structure:
    {
      "hash-full": "$Format:%H$",
      "hash-short": "$Format:%h$",
      "timestamp": "$Format:%cI$",
      "refs": "$Format:%D$",
      "describe": "$Format:%(describe:tags=true,match=v[0-9]*)$"
    }
    1. Add .git_archival.json export-subst to your .gitattributes file.

    Mercurial Archival

    Dunamai will automatically detect and use an .hg_archival.txt file created by the hg archive command. It also recognizes .hgtags files.

  4. Use regex patterns to parse version sources with `--pattern`

    master

    The --pattern PATTERN option allows you to use a regular expression to extract version components from the VCS source.

    Required and Optional Capture Groups:

    • base (Required): Corresponds to the release segment of the source.
    • stage (Optional): Corresponds to a prerelease type (e.g., alpha or rc).
    • revision (Optional): Corresponds to a prerelease number (e.g., 2 in alpha-2).
    • tagged_metadata (Optional): Corresponds to extra metadata (typically after a +).
    • epoch (Optional): Corresponds to the PEP 440 epoch concept.

    If the base group is not present, the pattern is interpreted as a named preset: default or default-unprefixed.

  5. Use the dunamai CLI to check version validity

    master

    The check command validates whether a provided version string conforms to a specific style (e.g., PEP 440).

    Usage

    You can pass the version as a positional argument or pipe it via stdin.

    # Check a specific version
    dunamai check 1.2.3 --style pep440
    
    # Check via stdin
    echo "1.2.3" | dunamai check --style pep440
    dunamai check 1.2.3 --style pep440
  6. Generate versions from a VCS with `dunamai from`

    master

    The dunamai from command is used to generate a dynamic version based on a Version Control System (VCS). You can either let dunamai auto-detect the VCS or specify a particular one.

    Supported VCS types:

    • any (auto-detects)
    • git
    • mercurial
    • darcs
    • subversion
    • bazaar
    • fossil
    • pijul

    Commonly used options:

    • --format FORMAT: Define a custom output format using available substitutions.
    • --style {pep440,semver,pvp}: Use a preconfigured output format (defaults to pep440).
    • --pattern PATTERN: Use a regular expression to match the version source. The pattern must include a base capture group.
    • --bump: Increment the last part of the version base (or the revision if a stage is set).
    • --dirty: Include a dirty flag if the repository has uncommitted changes.
    • --path PATH: Specify a directory to inspect instead of the current working directory.
    # Auto-detect VCS and generate version
    dunamai from any
    
    # Generate version specifically from Git with a custom format
    dunamai from git --format "{base}-{distance}"
    
    # Generate version from a specific path
    dunamai from git --path /path/to/repo
  7. Use the Dunamai Python API

    master

    Import Version and Style to programmatically generate and inspect version strings.

    Generating Versions

    • Version.from_git(): Specifically targets Git repositories.
    • Version.from_any_vcs(): Automatically detects the VCS.

    Serializing Versions

    Use the .serialize() method to convert the version object to a string. By default, it provides a PEP 440-compliant string. You can pass arguments to customize the output:

    • metadata=False: Excludes metadata.
    • dirty=True: Includes a .dirty suffix if there are uncommitted changes.
    • style=Style.SemVer: Uses Semantic Versioning formatting.

    Inspecting Version Components

    The Version object exposes discrete parts of the version for inspection:

    • base: The core version (e.g., 0.1.0).
    • stage: The release stage (e.g., rc).
    • revision: The revision number.
    • distance: Number of commits since the last tag.
    • commit: The commit hash.
    • dirty: Boolean indicating uncommitted changes.
    • tagged_metadata: Metadata attached to the tag (e.g., linux from v0.1.0+linux).
    from dunamai import Version, Style
    
    # Generate version from Git
    version = Version.from_git()
    print(version.serialize())  # e.g., "0.1.0"
    
    # Generate version from any VCS with complex state
    version = Version.from_any_vcs()
    print(version.serialize())                      # "0.1.0rc5.post44.dev0+g644252b"
    print(version.serialize(metadata=False))          # "0.1.0rc5.post44.dev0"
    print(version.serialize(dirty=True))            # "0.1.0rc5.post44.dev0+g644252b.dirty"
    print(version.serialize(style=Style.SemVer))    # "0.1.0-rc.5.post.44+g6442b"
    
    # Inspecting parts
    print(version.base)             # "0.1.0"
    print(version.distance)         # 44
    print(version.commit)           # "g644252b"
  8. Reference: Custom Format Substitutions

    master

    When using the --format flag in the CLI, you can use the following substitutions to build custom version strings. If a substitution is specified, its value is always included in the output.

    {base}           = Base version (e.g., 0.1.2)
    {stage}           = Release stage (e.g., beta)
    {revision}        = Revision number (e.g., 3)
    {distance}        = Number of commits since the last tag
    {commit}          = Commit hash (defaults to short form)
    {dirty}           = "dirty" or "clean"
    {tagged_metadata}= Metadata from the tag (e.g., 'other' from 'v1+other')
    {epoch}           = Epoch (e.g., 9)
    {branch}          = Branch name
    {branch_escaped} = Escaped branch name
    {timestamp}       = UTC timestamp (YYYYmmddHHMMSS)
    {major}           = Major version number
    {minor}           = Minor version number
    {patch}           = Patch version number
  9. Use the Dunamai CLI to generate versions

    master

    The Dunamai CLI can automatically detect your version control system (Git, Mercurial, Darcs, Subversion, Bazaar, Fossil, or Pijul) and generate a version string based on your tags.

    Basic Commands

    • Auto-detect VCS: dunamai from any generates a version based on the detected VCS.
    • Explicit VCS and Style: dunamai from <vcs> --style <style> allows you to specify the system and a versioning style (e.g., semver, pep440, haskell).
    • Custom Formats: Use --format "<format>" to define a custom string using available substitutions.
    • Bumping Versions: Use --bump to frame the version in terms of progress toward the next release rather than distance from the last one.
    • Validation: Use dunamai check <version> --style <style> to validate if a specific version string conforms to a style.
    # Auto-detect and generate version
    $ dunamai from any
    0.2.0.post7.dev0+g29045e8
    
    # Explicit VCS and SemVer style
    $ dunamai from git --no-metadata --style semver
    0.2.0-post.7
    
    # Custom format
    $ dunamai from any --format "v{base}+{distance}.{commit}"
    v0.2.0+7.g29045e8
    
    # Bump version (progress toward next release)
    $ dunamai from any --bump
    0.2.1.dev7+g29045e8
    
    # Validate a version string
    $ dunamai check 0.01.0 --style semver
  10. Validate a version string against a style

    master

    Use check_version(version, style) to verify if a string conforms to a specific versioning standard. It raises a ValueError if the validation fails.

    Supported Style values:

    • Style.Pep440 (PEP 440)
    • Style.SemVer (Semantic Versioning)
    • Style.Pvp (PVP)
  11. Serialize versions using different styles

    master

    The Version.serialize() method allows you to output the version string in various standard formats. You can specify the format using the Style enum or a custom format string/callback.

    Supported Styles (Style enum):

    • Style.Pep440: Python's PEP 440 standard.
    • Style.SemVer: Semantic Versioning.
    • Style.Pvp: Haskell Package Versioning Policy.

    Custom Formatting: If you provide a format string, you can use placeholders like {base}, {stage}, {revision}, {distance}, {commit}, {dirty}, {tagged_metadata}, {epoch}, {branch}, {branch_escaped}, {timestamp}, {major}, {minor}, and {patch}.

    from dunamai import Version, Style
    
    version = Version.parse("v1.2.3")
    
    # Use built-in styles
    pep440_str = version.serialize(style=Style.Pep440)
    semver_str = version.serialize(style=Style.SemVer)
    
    # Use a custom format string
    custom_str = version.serialize(format="Release-{major}.{minor}") # e.g., "Release-1.2"