Package: dunamai
DunamaiDunamai is a Python 3.5+ library and command line tool for producing dynamic,
standards-compliant version strings, derived from tags in your version control system.
This facilitates uniquely identifying nightly or per-commit builds in continuous integration
and releasing new versions of your software simply by creating a tag.Dunamai is also available as aGitHub Action.FeaturesVersion control system support:Git(2.7.0+ is recommended, but versions as old as 1.8.2.3 will work with some reduced functionality)MercurialDarcsSubversionBazaarFossilPijulVersion styles:PEP 440Semantic VersioningHaskell Package Versioning PolicyCustom output formatsCan be used for projects written in any programming language.
For Python, this means you do not need a setup.py.UsageInstallationpip install dunamaiCLI#Supposeyouareoncommitg29045e8,7commitsafterthev0.2.0tag.#Auto-detecttheversioncontrolsystemandgenerateaversion:$dunamaifromany0.2.0.post7.dev0+g29045e8#OruseanexplicitVCSandstyle:$dunamaifromgit--no-metadata--stylesemver0.2.0-post.7#Customformats:$dunamaifromany--format"v{base}+{distance}.{commit}"v0.2.0+7.g29045e8#Ifyou'dprefertoframetheversionintermsofprogresstowardthenext#releaseratherthandistancefromthelatestone,youcanbumpit:$dunamaifromany--bump0.2.1.dev7+g29045e8#Validationofcustomformats:$dunamaifromany--format"v{base}"--stylepep440Version 'v0.2.0' does not conform to the PEP 440 style#Validateyourownfreeformversions:$dunamaicheck0.01.0--stylesemverVersion '0.01.0' does not conform to the Semantic Versioning style#Moreinfo:$dunamai--help$dunamaifrom--help$dunamaifromgit--helpLibraryfromdunamaiimportVersion,Style# Let's say you're on commit g644252b, which is tagged as v0.1.0.version=Version.from_git()assertversion.serialize()=="0.1.0"# Let's say there was a v0.1.0rc5 tag 44 commits ago# and you have some uncommitted changes.version=Version.from_any_vcs()assertversion.serialize()=="0.1.0rc5.post44.dev0+g644252b"assertversion.serialize(metadata=False)=="0.1.0rc5.post44.dev0"assertversion.serialize(dirty=True)=="0.1.0rc5.post44.dev0+g644252b.dirty"assertversion.serialize(style=Style.SemVer)=="0.1.0-rc.5.post.44+g644252b"Theserialize()method gives you an opinionated, PEP 440-compliant default
that ensures that versions for untagged commits are compatible with Pip's--preflag.
The individual parts of the version are also available for you to use and inspect as you please:assertversion.base=="0.1.0"assertversion.stage=="rc"assertversion.revision==5assertversion.distance==44assertversion.commit=="g644252b"assertversion.dirtyisTrue# Available if the latest tag includes metadata, like v0.1.0+linux:assertversion.tagged_metadata=="linux"TipsBy default, the "v" prefix on the tag is required,
unless you specify a custom tag pattern.
You can either write a regular expression:$dunamaifromany--pattern"(?P<base>\d+\.\d+\.\d+)"fromdunamaiimportVersionversion=Version.from_any_vcs(pattern=r"(?P<base>\d+\.\d+\.\d+)")...or use a named preset:$dunamaifromany--patterndefault-unprefixedfromdunamaiimportVersion,Patternversion=Version.from_any_vcs(pattern=Pattern.DefaultUnprefixed)VCS archivesSometimes, you may only have access to an archive of a repository (e.g., a zip file) without the full history.
Dunamai can still detect a version in some of these cases:For Git, you can configuregit archiveto produce a file with some metadata for Dunamai.Add a.git_archival.jsonfile to the root of your repository with this content:{
  "hash-full": "$Format:%H$",
  "hash-short": "$Format:%h$",
  "timestamp": "$Format:%cI$",
  "refs": "$Format:%D$",
  "describe": "$Format:%(describe:tags=true,match=v[0-9]*)$"
}Add this line to your.gitattributesfile.
If you don't already have this file, add it to the root of your repository:.git_archival.json  export-substFor Mercurial, Dunamai will detect and use an.hg_archival.txtfile created byhg archive.
It will also recognize.hgtagsif present.Custom formatsHere are the available substitutions for custom formats.
If you have a tag likev9!0.1.2-beta.3+other, then:{base}=0.1.2{stage}=beta{revision}=3{distance}is the number of commits since the last{commit}is the commit hash (defaults to short form, unless you use--full-commit){dirty}expands to either "dirty" or "clean" if you have uncommitted modified files{tagged_metadata}=other{epoch}=9{branch}=feature/foo{branch_escaped}=featurefoo{timestamp}is in the formatYYYYmmddHHMMSSas UTCIf you specify a substitution, its value will always be included in the output.
For conditional formatting, you can do something like this (Bash):distance=$(dunamaifromany--format"{distance}")if["$distance"="0"];thendunamaifromany--format"v{base}"elsedunamaifromany--format"v{base}+{distance}.{dirty}"fiComparison to VersioneerVersioneeris another great library for dynamic versions,
but there are some design decisions that prompted the creation of Dunamai as an alternative:Versioneer requires a setup.py file to exist, or elseversioneer installwill fail,
rendering it incompatible with non-setuptools-based projects such as those using Poetry or Flit.
Dunamai can be used regardless of the project's build system.Versioneer has a CLI that generates Python code which needs to be committed into your repository,
whereas Dunamai is just a normal importable library
with an optional CLI to help statically include your version string.Versioneer produces the version as an opaque string,
whereas Dunamai provides a Version class with discrete parts
that can then be inspected and serialized separately.Versioneer provides customizability through a config file,
whereas Dunamai aims to offer customizability through its library API and CLI
for both scripting support and use in other libraries.IntegrationSetting a__version__statically:$echo"__version__ = '$(dunamaifromany)'">your_library/_version.py# your_library/__init__.pyfromyour_library._versionimport__version__Or dynamically (but Dunamai becomes a runtime dependency):# your_library/__init__.pyimportdunamaias_dunamai__version__=_dunamai.get_version("your-library",third_choice=_dunamai.Version.from_any_vcs).serialize()setup.py (no install-time dependency on Dunamai as long as you use wheels):fromsetuptoolsimportsetupfromdunamaiimportVersionsetup(name="your-library",version=Version.from_any_vcs().serialize(),)Or you could use a static inclusion approach as in the prior example.Poetry:$poetryversion$(dunamaifromany)Or you can use thepoetry-dynamic-versioningplugin.Other notesDunamai needs access to the full version history to find tags and compute distance.
Be careful if your CI system does a shallow clone by default.For GitHub workflows, invokeactions/checkout@v3withfetch-depth: 0.For GitLab pipelines, set theGIT_DEPTHvariable to 0.For Docker builds, copy the VCS history (e.g.,.gitfolder) into the container.For Git, you can also avoid doing a full clone by specifying a remote branch for tags
(e.g.,--tag-branch remotes/origin/master).When using Git, remember that lightweight tags do not store their creation time.
Therefore, if a commit has multiple lightweight tags,
we cannot reliably determine which one should be considered the newest.
The solution is to use annotated tags instead.When using Git, the initial commit mustnotbe both tagged and empty
(i.e., created with--allow-empty).
This is related to a reporting issue in Git.
For more info,click here.