EonaCat.Versioning.Helpers
1.5.0
Prefix Reserved
dotnet add package EonaCat.Versioning.Helpers --version 1.5.0
NuGet\Install-Package EonaCat.Versioning.Helpers -Version 1.5.0
<PackageReference Include="EonaCat.Versioning.Helpers" Version="1.5.0" />
<PackageVersion Include="EonaCat.Versioning.Helpers" Version="1.5.0" />
<PackageReference Include="EonaCat.Versioning.Helpers" />
paket add EonaCat.Versioning.Helpers --version 1.5.0
#r "nuget: EonaCat.Versioning.Helpers, 1.5.0"
#:package EonaCat.Versioning.Helpers@1.5.0
#addin nuget:?package=EonaCat.Versioning.Helpers&version=1.5.0
#tool nuget:?package=EonaCat.Versioning.Helpers&version=1.5.0
EonaCat.Versioning
Automatic GIT or SVN versioning for your .NET assemblies. Injects VCS revision data into AssemblyInfo, NuGet packages, and version files - zero manual version management required.
Features
- Automatic versioning from Git tags and SVN revision numbers
- Semantic Versioning (SemVer 2.0.0) with full parsing, comparison, bumping, and range matching
- Calendar Versioning (CalVer) support (YYYY.MM.DD, YYYY.MM.MICRO, etc.)
- Conventional Commits analysis for automatic version bump detection
- Changeset-based version management for monorepo workflows
- Git SHA versioning for continuous deployment pipelines
- Build number auto-increment via persistent counter file
- Rich format placeholders - 50+ tokens including OS, architecture, environment variables, timestamps, and more
- MSBuild integration - works with
dotnet build,msbuild, and CI/CD pipelines - Fail-on-dirty support to prevent releases from modified repositories
- Version file output - write the resolved version to a custom file path
- Quiet mode to suppress informational messages during builds
Debug/Console Information
Build your project using:
dotnet build
dotnet build -v d
or with MSBuild directly:
msbuild YourProject.csproj /v:d
or to log to a file:
msbuild YourProject.csproj -fl -flp:logfile=YourProjectOutput.log;verbosity=diagnostic
Note:
dotnet buildworks on all platforms (Windows, Linux, macOS). The standalonemsbuildcommand requires Visual Studio on Windows or Mono on Linux/macOS.
Installation
Just install the NuGet package EonaCat.Versioning to your .NET Framework 4.8 or .NET Standard 2.1 / .NET 6.0 or higher project.
Cross-platform: EonaCat.Versioning works on Windows, Linux, and macOS. On non-Windows platforms, the package targets .NET Standard 2.1. All VCS operations, file handling, and version resolution are fully cross-platform.
If you’re creating a NuGet package of your project, make sure to declare this package reference as private in your .csproj so that your final package does not depend on EonaCat.Versioning.
<ItemGroup>
<PackageReference Include="EonaCat.Versioning" Version="..." PrivateAssets="all" />
</ItemGroup>
Default behaviour for Git
If not configured, tags following semantic versioning:
{semtagver}+{chash:10}.{c:ymd}
Examples:
- 0.0.1+8dda362328.20240207
- 1.0.0+8dda362328.20240207
Default behaviour for Subversion
If not configured otherwise, the revision number is used as the patch number. You should change that before you make a release. Its format is defined as:
0.0.{revnum}
Examples:
- 0.0.1 (Default version if not or incorrectly specified)
- 0.0.20
- 0.0.200
Configuration
MSBuild properties
Configuration of the version scheme is done through MSBuild properties defined in the project file to which the NuGet package was added. If you have multiple projects in your solution, you’d basically have to repeat these steps for each project, or you could factor them out into a separate .props file and import that into each project or you can use Directory.Build.props. This also applies to classic-style projects, even though editing the project file is a bit more involved.
Automatic build number incrementation: <EVBuildNumberFile>$(MSBuildProjectDirectory)\build.number</EVBuildNumberFile>
Revision Format example (which has version 1.0.0): <EVRevisionFormat>1.0.0+{chash:10}.{c:ymd}</EVRevisionFormat>
Revision Format example with build number: <EVRevisionFormat>1.0.0+{chash:10}.{c:ymd}.B{build}</EVRevisionFormat>
Revision Format example with SemVer components: <EVRevisionFormat>{major}.{minor}.{patch}-{branch}+{chash:10}.{c:ymd}</EVRevisionFormat>
Project csproj Example:
<PropertyGroup>
<EVRevisionFormat>{semtagver}+{chash:10}.{c:ymd}</EVRevisionFormat>
<EVDefault>true</EVDefault>
<EVInfo>true</EVInfo>
<EVTagMatch>v[0-9]*</EVTagMatch>
<EVRemoveTagV>true</EVRemoveTagV>
<EVVcs>git</EVVcs>
<EVCheckAllAttributes>true</EVCheckAllAttributes>
<EVShowRevision>true</EVShowRevision>
<EVBuildNumberFile>$(MSBuildProjectDirectory)\build.number</EVBuildNumberFile>
</PropertyGroup>
Default version example: <EVDefaultVersion>1.0.0</EVDefaultVersion>
The following MSBuild properties are supported:
EVRevisionFormat:
The revision format template. This is automatically detected from the AssemblyInfo file in your project, if it exists. It can be overridden for .NET Core/Standard projects.
EVDefault: boolean, default: true.
Specifies whether default version attributes are resolved to the determined version. This affects Version (AssemblyVersionAttribute). The Version identifies the assembly and must be dotted-numeric (max. 65535).
EVInfo: boolean, default: true.
Specifies whether the infor version attribute is resolved to the determined version. This affects InformationalVersion (AssemblyInfoVersionAttribute). It is a free descriptive text that may contain version names like "beta" or a VCS commit hash.
DefaultVersion:
Determines if we need to set a default version instead of the 0.0.0.1
EVTagMatch: glob pattern, default: v[0-9]*
The pattern of tag names to match when looking for version tags. These tag names usually look like "v0.1" or "v1.0.0". Other tags should be ignored for this use. This should usually not be changed.
EVRemoveTagV: boolean, default: true.
Specifies whether the "v" prefix of a matching version tag should be removed to determine its version. This should usually not be disabled.
EVVcs: string, default: "git".
Specifies the name of the VCS that is expected to be found in the project directory. Can be "git" or "svn" (IVcsProvider.Name).
EVShowRevision: boolean, default: false.
Specifies whether the determined revision ID is printed during the build with higher importance than normal, so it can be seen more easily. When patching the AssemblyInfo file, it is also displayed to the console.
EVProjectDirectory: string, default: $(MSBuildProjectDirectory).
Sets the directory where EV starts searching for the VCS files. This is helpful if EV is added to a project that is a submodule of another repository and should observe the parent repository.
EVReplaceMetadata: boolean, default: true.
Indicates whether the AssemblyMetadata attribute is processed
ChangedRepoErrorPattern: string, default: ".Release."
Determines the value of the build configuration RegEx pattern that triggers an error on match if the repository is modified
CheckAllAttributes: boolean, default: true.
Determines if we need to check all the custom attributes from the AssemblyInfo
EVBuildNumberFile: string, default: empty.
Path to a file that stores the build number counter. When set, the build number is read from this file, incremented by 1 on each build, and written back. The file is created automatically if it doesn't exist. Use the {build} placeholder in your revision format to include the build number.
Example:
<PropertyGroup>
<EVBuildNumberFile>$(MSBuildProjectDirectory)\build.number</EVBuildNumberFile>
<EVRevisionFormat>1.0.0+{chash:10}.{c:ymd}.B{build}</EVRevisionFormat>
</PropertyGroup>
EVFailOnDirty: boolean, default: false.
When enabled, the build will fail with an error if the repository has uncommitted changes. Useful for release builds to ensure only clean commits are versioned.
Example:
<PropertyGroup>
<EVFailOnDirty>true</EVFailOnDirty>
</PropertyGroup>
EVVersionFile: string, default: empty.
Path to a file where the resolved version string will be written after each build. Useful for CI/CD pipelines that need to read the version from a file (e.g. for Docker tagging, deployment scripts, etc.).
Example:
<PropertyGroup>
<EVVersionFile>$(MSBuildProjectDirectory)\version.txt</EVVersionFile>
</PropertyGroup>
EVQuiet: boolean, default: false.
When enabled, suppresses informational version messages during the build. Only warnings and errors will be shown.
Example:
<PropertyGroup>
<EVQuiet>true</EVQuiet>
</PropertyGroup>
Revision format
You can customise the format of the resulting version with a revision format string that defines how information about the commit or revision is formatted into the final revision ID.
It is a plain string that contains placeholders in {curly braces}.
The following data field placeholders are supported:
{chash}: Full commit hash.
{CHASH}: Full commit hash, in upper case.
{chash:<length>}: Commit hash truncated to the specified length. (Also for upper case)
{revnum}: Revision number.
{revnum-<offset>}: Revision number minus the offset. (Also available with +)
{!}: The "!" character if the working directory is modified, otherwise empty.
{!:<string>}: The specified string if the working directory is modified, otherwise empty.
{cname}, {cmail}: Committer’s name or e-mail address.
{aname}, {amail}: Author’s name or e-mail address.
{mname}: Build machine name (computer name).
{user}: Current OS username.
{os}: Operating system description (e.g. "Microsoft Windows 10.0.22631").
{arch}: Process architecture in lowercase (e.g. "x64", "arm64").
{rid}: Runtime identifier (e.g. "win-x64", "linux-arm64").
{tick}: Current UTC time as .NET ticks (useful for truly unique build identifiers).
{epoch}: Current UTC time as Unix epoch seconds.
{guid}: A newly generated GUID in standard "D" format (e.g. "550e8400-e29b-41d4-a716-446655440000").
{guid:<format>}: A newly generated GUID formatted with the given specifier ("N", "D", "B", or "P").
{build}: Build number counter (auto-incremented when EVBuildNumberFile is set).
{build:<length>}: Build number zero-padded to the specified length (e.g. {build:4} → 0042).
{major}: Major version component extracted from the tag (e.g. 1 from tag v1.2.3).
{minor}: Minor version component extracted from the tag.
{patch}: Patch version component extracted from the tag.
{prerelease}: Pre-release label from the tag (e.g. beta.1 from v1.0.0-beta.1).
{buildmeta}: Build metadata from the tag (the part after + in SemVer).
{dirty}: Outputs "dirty" if the working directory is modified, otherwise empty.
{dirty:<string>}: Outputs the specified string if the working directory is modified, otherwise empty.
{env:<NAME>}: Value of the environment variable <NAME> (useful for CI variables like BUILD_ID, GITHUB_RUN_NUMBER, etc.).
{utcnow:<format>}: Current UTC time formatted with a .NET date/time format string (e.g. {utcnow:yyyyMMddHHmmss}).
{now:<format>}: Current local time formatted with a .NET date/time format string (e.g. {now:yyyy-MM-dd}).
{branch}: Currently checked-out branch.
{branch:<sep>:<ref>}: Branch name, if not <ref> or empty, separated by <sep>, otherwise empty.
{semtagver}: Semantic version based on the most recent matching tag name. Revisions that are not directly tagged are considered a pre-release after the last tag (the patch value is incremented by 1) and the branch name and number of commits after the tag will be appended.
{semtagver+chash}: Semantic version based on the most recent matching tag name, see {semtagver}. Pre-releases also have the abbreviated commit hash appended after a plus (+) sign as build info. This is part of the default format for Git repositories.
{semtagver+chash:<length>}: Same as {semtagver+chash} but with the commit hash truncated to the specified length instead of the default 7.
{semtagver+CHASH:<length>}: Same as {semtagver+chash:<length>} but with the commit hash in upper case.
{semtagver:<development>}: Same as {semtagver} but with the branch name left out if it is equal to <development>.
{semtagver:<development>:+chash}: Same as {semtagver+chash} but with the branch name left out if it is equal to <development>.
{semtagver:<development>:+chash:<length>}: Same as {semtagver+chash:<length>} but with the branch name left out if it is equal to <development>.
{semtagver:<development>:+CHASH:<length>}: Same as {semtagver+CHASH:<length>} but with the branch name left out if it is equal to <development>.
{tag}: Most recent matching tag name, with additional info.
{tagname}: Most recent matching tag name only.
{tagadd}: Number of commits since the most recent matching tag.
{tagadd:<sep>}: Number of commits since the most recent matching tag, prefixed with <sep>, or empty.
{tz}: Local time zone offset like "+02:00".
{url}: Repository URL.
{copyright}: Abbreviation for the copyright year (commit or build time).
{copyright:<first>-}: Abbreviation for the copyright year range, starting at <first>. The following dash is optional but recommended for clearer understanding.
Revision format examples
| Format | Example output |
|---|---|
1.0.0+{chash:10}.{c:ymd} |
1.0.0+8dda362328.20240207 |
1.0.0+{chash:10}.{c:ymd}.B{build} |
1.0.0+8dda362328.20240207.B42 |
{major}.{minor}.{patch}+{chash:10} |
1.2.3+8dda362328 |
{major}.{minor}.{patch}-{branch}+{build:4} |
1.2.3-feature-x+0005 |
{semtagver}+{dirty:.dirty}.{now:yyyyMMdd} |
1.0.1-main.2+dirty.20240210 |
{major}.{minor}.{patch}+{env:BUILD_ID} |
1.0.0+12345 |
{semtagver}+{user}@{mname} |
1.0.0+john@DESKTOP-ABC |
{semtagver}+{arch}.{epoch} |
1.0.0+x64.1718291234 |
{major}.{minor}.{patch}+{rid} |
1.2.3+win-x64 |
{semtagver}+{guid:N} |
1.0.0+550e8400e29b41d4a716446655440000 |
Schemes
Schemes convert a commit or build time to a compact string representation. They can be used to assign incrementing versions if no revision number is provided by the VCS. First, select from the build, commit or authoring time with {b:…}, {c:…} or {a:…}. This is followed by the scheme name. There are 4 types of schemes.
The following time schemes are supported:
Readable date/time: Produces a readable date or time string in several formats.
| Format | Description |
|---|---|
ymd |
Year, month, day, no separator. |
ymd- |
Year, month, day, separated by "-". |
ymd. |
Year, month, day, separated by ".". |
hms |
Hour, minute, second, no separator. |
hms- |
Hour, minute, second, separated by "-". |
hms: |
Hour, minute, second, separated by ":". |
hms. |
Hour, minute, second, separated by ".". |
hm |
Hour, minute, no separator. |
hm- |
Hour, minute, separated by "-". |
hm: |
Hour, minute, separated by ":". |
hm. |
Hour, minute, separated by ".". |
h |
Hour only. |
Prefix with "u" for UTC instead of local time zone.
Dotted-decimal: Generates regular dotted version numbers with two segments. The first describes the days since the base year, the second the number of intervals since midnight (UTC). This scheme consists of multiple colon-separated values: interval length, base year.
The interval length is a number followed by "s" for seconds, "m" for minutes, "h" for hours, or "d" for days. Practical intervals are "15m" (2 digits), "2m" (3 digits).
A shortcut to the 15-minute interval is {dmin:<year>}.
Base-encoding: Converts a linear value to a higher number base to create more compact digit/letter combinations. These schemes consist of multiple colon-separated values: number base, interval length, base year, minimum output length.
Number base can be from 2 to 36. The digits 0–9 and then letters a–z are used. The higher the base, the higher the chance that profane words appear in a revision ID. Base 28 uses an optimised alphabet without vowels and similar characters to avoid errors when hand-writing and undesired words.
The number of passed intervals since the base year is encoded for the result (UTC). The minimum length padding generates fixed-length comparable strings. Set the length to a value that lasts for as long as you plan to use this versioning scheme (30 years recommended). Practical combinations are "16:1m" (6 chars), "28:20m" (4 chars), "36:10m" (4 chars).
All letters are lower case. Use a capital {A:…}, {B:…} or {C:…} for upper case.
Hours: Generates a single number of hours passed since the given base year and month. This scheme begins with "h:" followed by two hyphen-separated values: base year, base month.
For values up to 65535 this lasts over 7 years.
Examples:
| Format | Description |
|---|---|
{b:ymd-} |
Local build date, like "2024-02-10". |
{c:hm.} |
Local commit time of day, like "23.59". |
{c:uhm} |
UTC commit time of day, like "2359". |
{c:15m:2023} |
Dotted decimal from commit time since 2023, like "365.95". |
{dmin:2023} |
Same as previous (short syntax from version 1.x). |
{c:16:1m:2024} |
Base-16 encoding of minutes from commit time since 2024, like "abcdef". |
{b:28:20m:2023:4} |
Base-28 encoding of 20-minute intervals from build time since 2023. |
{bmin:2023:4} |
Same as previous (short syntax from version 1.x). |
{B:28:20m:2023:4} |
Base-28 encoding (upper case) of 20-minute intervals from build time since 2023". |
{b:h:2024-02} |
Hours encoding of UTC build time since February 2024. |
Usage in C# source code
The following sample code from the AssemblyInfo.cs file would be resolved as described.
[assembly: AssemblyVersion("0.0")]
[assembly: AssemblyInfoVersion("1.0.0{chash:10}.{c:ymd}")]
Result:
Version: 1.0.0 InformationalVersion: 1.0.0+05876ca02e+20240210
API PowerShell example (Windows, Linux, macOS with PowerShell):
Add-Type -Path EonaCat.Versioning.dll
[EonaCat.Versioning.Api]::GetVersion()
API Bash example (Linux, macOS):
#!/bin/bash
dotnet script -e 'Console.WriteLine(EonaCat.Versioning.Api.GetVersion())'
API Batch example (Windows):
@echo off
powershell -Command "Add-Type -Path EonaCat.Versioning.dll; [EonaCat.Versioning.Api]::GetVersion()"
exit /b %errorlevel%
VCS providers
Git
The Git CLI must be available on your system:
- Windows: Install Git for Windows. The binary is auto-detected from the PATH, registry,
%ProgramFiles%\Git*, SourceTree, Tower, or SmartGit locations. - Linux: Install via your package manager (e.g.
sudo apt install git,sudo dnf install git). - macOS: Install via Xcode Command Line Tools (
xcode-select --install) or Homebrew (brew install git).
On Linux and macOS, the git binary must be available in your PATH.
The revision number is provided by counting revisions with the --first-parent option in the current branch.
This is a stable value for the master branch if merges from other branches are done the correct way
(always merge temporary/work/feature branches into master, not reverse).
Subversion
The SVN CLI (svn and svnversion) must be available on your system:
- Windows: Install TortoiseSVN with the "CLI" option, or CollabNet SVN. Auto-detected from the PATH, registry, and
%ProgramFiles%locations. - Linux: Install via your package manager (e.g.
sudo apt install subversion). - macOS: Install via Homebrew (
brew install subversion).
On Linux and macOS, the svn and svnversion binaries must be available in your PATH.
Semantic Versioning API
EonaCat.Versioning includes a full Semantic Versioning 2.0.0 implementation for parsing, comparing, sorting, bumping and validating version strings.
SemanticVersion class
using EonaCat.Versioning;
// Parse a version string
var version = SemanticVersion.Parse("1.2.3-beta.1+build.42");
// Access components
Console.WriteLine(version.Major); // 1
Console.WriteLine(version.Minor); // 2
Console.WriteLine(version.Patch); // 3
Console.WriteLine(version.PreRelease); // "beta.1"
Console.WriteLine(version.BuildMetadata);// "build.42"
Console.WriteLine(version.IsPreRelease); // true
Console.WriteLine(version.IsStable); // false
// Safe parsing
if (SemanticVersion.TryParse("not-a-version", out var v))
{
// ...
}
// Validation
bool valid = SemanticVersion.IsValid("1.0.0"); // true
// Bump versions
var next = version.BumpMinor(); // 1.3.0
var major = version.BumpMajor(); // 2.0.0
var patch = version.BumpPatch(); // 1.2.4
// Modify labels
var rc = version.WithPreRelease("rc.1"); // 1.2.3-rc.1+build.42
var release = version.ToRelease(); // 1.2.3
// Comparison (follows SemVer 2.0.0 precedence)
bool isNewer = SemanticVersion.Parse("2.0.0") > SemanticVersion.Parse("1.9.9"); // true
// Tag string
Console.WriteLine(version.ToTagString()); // "v1.2.3-beta.1+build.42"
Version Range Matching
using EonaCat.Versioning;
var version = SemanticVersion.Parse("1.5.0");
// Simple comparisons
version.Satisfies(">=1.0.0"); // true
version.Satisfies("<2.0.0"); // true
version.Satisfies("!=1.5.0"); // false
// Caret range (compatible with): ^1.2.0 means >=1.2.0 <2.0.0
version.Satisfies("^1.2.0"); // true
// Tilde range (patch-level): ~1.5.0 means >=1.5.0 <1.6.0
version.Satisfies("~1.5.0"); // true
// VersionRange class for complex ranges
var range = new VersionRange(">=1.0.0 <2.0.0 || >=3.0.0");
range.IsSatisfiedBy(version); // true
// Filter and find max from a list
var versions = new List<SemanticVersion>
{
SemanticVersion.Parse("1.0.0"),
SemanticVersion.Parse("1.5.0"),
SemanticVersion.Parse("2.0.0"),
};
var filtered = range.Filter(versions); // [1.0.0, 1.5.0]
var max = range.MaxSatisfying(versions); // 1.5.0
Version Bumping with Enum
using EonaCat.Versioning;
var current = SemanticVersion.Parse("1.2.3");
// Bump by type
var bumped = current.Bump(VersionBumpType.Minor); // 1.3.0
bumped = current.Bump(VersionBumpType.Major); // 2.0.0
bumped = current.Bump(VersionBumpType.Patch, "rc.1"); // 1.2.4-rc.1
Conventional Commits Analysis
Automatically determine the version bump type by analyzing commit messages following the Conventional Commits specification.
using EonaCat.Versioning;
// Single message analysis
ConventionalCommitAnalyzer.AnalyzeMessage("feat: add new feature"); // Minor
ConventionalCommitAnalyzer.AnalyzeMessage("fix: correct typo"); // Patch
ConventionalCommitAnalyzer.AnalyzeMessage("feat!: breaking change"); // Major
ConventionalCommitAnalyzer.AnalyzeMessage("refactor: clean up code"); // Patch
// Check if a message follows the convention
ConventionalCommitAnalyzer.IsConventionalCommit("feat(api): new endpoint"); // true
ConventionalCommitAnalyzer.GetCommitType("feat(api): new endpoint"); // "feat"
ConventionalCommitAnalyzer.GetCommitScope("feat(api): new endpoint"); // "api"
// Analyze multiple messages to get the highest bump
var messages = new[]
{
"fix: patch change",
"feat: minor change",
"docs: update readme"
};
var bump = ConventionalCommitAnalyzer.AnalyzeMessages(messages); // Minor
// Combine with SemanticVersion
var current = SemanticVersion.Parse("1.2.3");
var next = current.Bump(bump); // 1.3.0
Interactive API Extensions
The Api class provides additional methods for querying VCS state:
using EonaCat.Versioning;
var api = new Api(projectDir: @"C:\MyProject");
// Get a SemanticVersion object
SemanticVersion semver = api.GetSemanticVersion();
// Bump with a specific type
SemanticVersion next = api.GetBumpedVersion(VersionBumpType.Minor);
// Query VCS state
string branch = api.GetBranch();
string hash = api.GetCommitHash();
bool dirty = api.IsDirty();
int count = api.GetCommitCount();
int afterTag = api.GetCommitsAfterTag();
string tag = api.GetTag();
// Get all version info as a dictionary
var info = api.GetVersionInfo();
foreach (var kv in info)
{
Console.WriteLine($"{kv.Key}: {kv.Value}");
}
Helper Extensions
The VersionHelper class in EonaCat.Versioning.Helpers provides additional methods:
using EonaCat.Versioning.Helpers;
// Get individual version components
int major = VersionHelper.GetMajorVersion();
int minor = VersionHelper.GetMinorVersion();
int patch = VersionHelper.GetPatchVersion();
// Get pre-release and build metadata from informational version
string preRelease = VersionHelper.GetPreReleaseLabel(); // e.g. "beta.1"
string buildMeta = VersionHelper.GetBuildMetadata(); // e.g. "abc123.20240210"
bool isPreRel = VersionHelper.IsPreRelease();
// Get a formatted display string
string display = VersionHelper.GetFormattedVersion(); // e.g. "MyApp v1.2.3-beta+abc123"
string product = VersionHelper.GetProductName();
Additional Format Placeholders
The following additional placeholders are available in revision format strings:
{commitcount}: Total number of commits (same as {revnum}, for clarity).
{shortbranch}: The last segment of the branch name after / (e.g. my-feature from feature/my-feature).
{commitsaftertag}: Number of additional commits since the last matching tag (same as {tagadd}, for clarity).
Revision format examples (extended)
| Format | Example output |
|---|---|
{major}.{minor}.{patch}+{commitcount} |
1.2.3+42 |
{semtagver}-{shortbranch}+{chash:8} |
1.0.1-my-feature+8dda3623 |
{major}.{minor}.{patch}+{commitsaftertag}.{dirty} |
1.0.0+5.dirty |
Versioning Strategies
EonaCat.Versioning supports multiple versioning strategies beyond standard SemVer. Each strategy is available as a standalone class that can be used independently or combined.
semantic-release / Release Please
Automatically determine the next release version and generate changelogs from conventional commit messages, compatible with both semantic-release and Release Please.
using EonaCat.Versioning;
var commits = new[]
{
"feat(api): add user endpoint",
"fix: correct null reference in parser",
"docs: update README",
"feat!: redesign authentication flow"
};
// Determine next version
var next = ReleaseVersion.GetNextVersion("1.2.3", commits);
// => 2.0.0 (breaking change detected)
// With a pre-release channel (e.g. beta releases)
var beta = ReleaseVersion.GetNextVersion("1.2.3", commits, preReleaseChannel: "beta", preReleaseNumber: 1);
// => 2.0.0-beta.1
// Check if commits warrant a release
bool shouldRelease = ReleaseVersion.ShouldRelease(commits); // true
// Generate a changelog
string changelog = ReleaseVersion.GenerateChangelog(next, commits);
// Produces grouped Markdown: Breaking Changes, Features, Bug Fixes, etc.
// Generate a Release Please-style manifest entry
string manifest = ReleaseVersion.GenerateManifestEntry("MyPackage", next);
// => { "MyPackage": "2.0.0" }
Git SHA Deploys
Use Git commit SHAs as deploy identifiers - ideal for continuous deployment pipelines, container image tagging, and environments where every commit is a deployable artifact.
using EonaCat.Versioning;
// Create from a commit hash
var sha = new GitShaVersion("8dda362328abcdef1234567890abcdef12345678");
// Deploy tags
sha.ToDeployTag(); // "sha-8dda3623"
sha.ToImageTag("myapp"); // "myapp:sha-8dda3623"
// Attach to a semantic version as build metadata
var withBase = GitShaVersion.FromVersion("8dda362328ab", "1.0.0");
withBase.ToSemanticVersion(); // 1.0.0+sha.8dda3623
withBase.ToString(); // "1.0.0+sha.8dda3623"
// Validate a SHA string
GitShaVersion.IsValidSha("8dda362328ab"); // true
GitShaVersion.IsValidSha("not-a-sha"); // false
CalVer + Build Metadata
Calendar Versioning (CalVer) uses date-based version components. EonaCat.Versioning supports CalVer with optional modifiers and build metadata. See calver.org for the specification.
using EonaCat.Versioning;
// Create from current date
var calver = CalendarVersion.Today(); // e.g. 2024.6.15
var monthly = CalendarVersion.Now(micro: 3); // e.g. 2024.6.3
// Parse a CalVer string
var parsed = CalendarVersion.Parse("2024.6.15-beta+build.42");
Console.WriteLine(parsed.Year); // 2024
Console.WriteLine(parsed.Month); // 6
Console.WriteLine(parsed.Micro); // 15
Console.WriteLine(parsed.Modifier); // "beta"
Console.WriteLine(parsed.BuildMetadata); // "build.42"
// Add Git SHA as build metadata
var withSha = calver.WithGitSha("8dda362328abcdef");
// => 2024.6.15+8dda362
// Bump micro, add modifier
var next = calver.BumpMicro().WithModifier("rc.1");
// => 2024.6.16-rc.1
// Convert to SemanticVersion (Year.Month.Micro)
SemanticVersion semver = calver.ToSemanticVersion();
// Short year format (YY.MM.DD)
var short = CalendarVersion.Today(shortYear: true); // e.g. 24.6.15
// Comparison
bool newer = CalendarVersion.Parse("2024.7.1") > CalendarVersion.Parse("2024.6.30"); // true
Changesets
Changesets is a versioning approach where version bump intent is declared in Markdown files that can be reviewed in pull requests. Each changeset file specifies which packages are affected and the bump level.
using EonaCat.Versioning;
// Generate a changeset file
string content = Changeset.Generate("MyPackage", ChangesetBumpLevel.Minor, "Added new search feature");
// Produces:
// ---
// "MyPackage": minor
// ---
//
// Added new search feature
// Parse a changeset file
var entries = Changeset.Parse(content);
// entries[0].PackageName => "MyPackage"
// entries[0].BumpLevel => ChangesetBumpLevel.Minor
// entries[0].Summary => "Added new search feature"
// Apply changesets to current versions
var currentVersions = new Dictionary<string, string>
{
{ "MyPackage", "1.2.3" },
{ "MyOtherPackage", "2.0.0" }
};
var allEntries = new List<ChangesetEntry>
{
new ChangesetEntry("MyPackage", ChangesetBumpLevel.Minor, "Added search"),
new ChangesetEntry("MyPackage", ChangesetBumpLevel.Patch, "Fixed typo"),
new ChangesetEntry("MyOtherPackage", ChangesetBumpLevel.Major, "Breaking API change")
};
var newVersions = Changeset.ApplyChangesets(currentVersions, allEntries);
// newVersions["MyPackage"] => 1.3.0 (highest bump: minor)
// newVersions["MyOtherPackage"] => 3.0.0 (highest bump: major)
// Generate a combined changelog
string changelog = Changeset.GenerateChangelog(newVersions, allEntries);
Compatibility & Distance
using EonaCat.Versioning;
var v1 = SemanticVersion.Parse("1.5.0");
var v2 = SemanticVersion.Parse("1.2.0");
var v3 = SemanticVersion.Parse("2.0.0");
// Check API compatibility (same major, this >= other)
v1.IsCompatibleWith(v2); // true - 1.5.0 is compatible with 1.2.0
v1.IsCompatibleWith(v3); // false - different major
// Measure distance between versions
var dist = v1.Distance(v3);
// dist.Major = 1, dist.Minor = 5, dist.Patch = 0
// Implicit string conversion
SemanticVersion v = "3.1.4";
Console.WriteLine(v.Major); // 3
Complete MSBuild Property Reference
Input Properties
| Property | Type | Default | Description |
|---|---|---|---|
EVRevisionFormat |
string | {semtagver}+{chash:10}.{c:ymd} |
The revision format template |
EVDefaultVersion |
string | 0.0.1 |
Fallback version when no tag is found |
EVDefault |
bool | true |
Resolve Version / AssemblyVersionAttribute |
EVInfo |
bool | true |
Resolve InformationalVersion |
EVTagMatch |
glob | v[0-9]* |
Tag name matching pattern |
EVRemoveTagV |
bool | true |
Strip leading "v" from tags |
EVVcs |
string | git |
Expected VCS (git or svn) |
EVShowRevision |
bool | false |
Print resolved version during build |
EVProjectDirectory |
string | $(MSBuildProjectDirectory) |
VCS search start directory |
EVReplaceMetadata |
bool | true |
Process AssemblyMetadata attribute |
EVCheckAllAttributes |
bool | true |
Check all custom AssemblyInfo attributes |
EVBuildNumberFile |
string | (empty) | Path to build number counter file |
EVFailOnDirty |
bool | false |
Fail build if repository is modified |
EVVersionFile |
string | (empty) | Write resolved version to this file |
EVQuiet |
bool | false |
Suppress informational build messages |
ChangedRepoErrorPattern |
regex | .*Release.* |
Configuration pattern that triggers error on dirty repo |
EVVersionJsonFile |
string | (empty) | Write version metadata as JSON to this file |
EVRequireTag |
bool | false |
Fail build if no VCS tag found |
EVVersionPrefix |
string | (empty) | Prefix prepended to version (e.g. v) |
EVVersionSuffix |
string | (empty) | Suffix appended to version (e.g. -preview) |
EVPreReleaseLabel |
string | (empty) | Fixed pre-release label to always append (e.g. alpha) |
EVBuildMetadataLabel |
string | (empty) | Fixed build metadata to always append (e.g. CI job ID) |
EVForceVersion |
string | (empty) | Force exact version, bypassing VCS resolution |
EVStampAssemblyVersion |
bool | true |
Whether to stamp AssemblyVersion |
EVStampFileVersion |
bool | true |
Whether to stamp FileVersion |
EVStampPackageVersion |
bool | true |
Whether to stamp PackageVersion |
EVStampInformationalVersion |
bool | true |
Whether to stamp InformationalVersion |
EVDisable |
bool | false |
Kill switch - disable all EonaCat versioning |
EVSkipPatch |
bool | false |
Skip AssemblyInfo patching |
EVAutoIncrementPatch |
bool | false |
Auto-increment patch on each build |
EVAutoIncrementMinor |
bool | false |
Auto-increment minor on each build |
EVBuildNumberReset |
bool | false |
Reset build number to 0 when version changes |
EVBuildNumberPadding |
int | 0 |
Pad build number to this many digits (e.g. 4 → 0042) |
EVTagPrefix |
string | (empty) | Tag prefix to strip (alternative to EVRemoveTagV) |
EVDefaultBranch |
string | main |
Default/main branch name for semtagver logic |
EVDirtyMarker |
string | dirty |
String output when repo is dirty |
EVCleanMarker |
string | (empty) | String output when repo is clean |
EVRequireStable |
bool | false |
Fail build if resolved version is pre-release |
EVRequireSemVer |
bool | false |
Fail build if version is not valid SemVer 2.0.0 |
EVMaxVersion |
string | (empty) | Maximum allowed version (build fails if exceeded) |
EVMinVersion |
string | (empty) | Minimum allowed version (build fails if below) |
EVForbiddenBranches |
string | (empty) | Semicolon-separated branch names where builds are forbidden |
EVAllowedChannels |
string | (empty) | Semicolon-separated allowed pre-release channels |
EVWarnOnPreRelease |
bool | false |
Warn (don't fail) when version is pre-release |
EVWarnOnNonDefaultBranch |
bool | false |
Warn when not building on default branch |
EVFailOnDetachedHead |
bool | false |
Fail build on detached HEAD |
EVMaxCommitsAfterTag |
int | 0 |
Max commits after tag before build fails (0 = unlimited) |
EVVersionYamlFile |
string | (empty) | Write version metadata as YAML to this file |
EVVersionXmlFile |
string | (empty) | Write version metadata as XML to this file |
EVVersionEnvFile |
string | (empty) | Write version as shell env file (KEY=VALUE) |
EVVersionHeaderFile |
string | (empty) | Write version as C/C++ header file |
EVVersionPropsFile |
string | (empty) | Write version as .props file for other projects |
EVVersionCsvFile |
string | (empty) | Write version metadata as CSV |
EVVersionTomlFile |
string | (empty) | Write version metadata as TOML |
EVVersionIniFile |
string | (empty) | Write version metadata as INI |
EVVersionSqlFile |
string | (empty) | Write version as SQL INSERT script |
EVVersionBadgeFile |
string | (empty) | Write Markdown badge to this file |
EVGitHubActionsOutput |
bool | false |
Write GitHub Actions ::set-output commands |
EVAzureDevOpsOutput |
bool | false |
Write Azure DevOps ##vso commands |
EVTeamCityOutput |
bool | false |
Write TeamCity service messages |
EVGitLabCIOutput |
bool | false |
Write GitLab CI variable exports |
EVSetEnvironmentVariables |
bool | false |
Set environment variables in current process |
EVEnvVariablePrefix |
string | EV_ |
Prefix for environment variable names |
EVDockerImageName |
string | (empty) | Docker image name for tag generation |
EVDockerRegistry |
string | (empty) | Docker registry URL for full image path |
EVCopyrightHolder |
string | (empty) | Copyright holder name |
EVCopyrightStartYear |
int | 0 |
Copyright start year for year-range generation |
EVLogLevel |
string | info |
Log level: trace, info, warning, error |
EVLogFile |
string | (empty) | Path to write a build version log |
EVTimestampFormat |
string | o |
.NET format string for build timestamp |
EVTimestampTimeZone |
string | (empty) | Time zone ID for timestamps (default: UTC) |
EVCustomPlaceholders |
string | (empty) | Semicolon-separated custom placeholders (key=value) |
EVAdditionalFormats |
string | (empty) | Semicolon-separated additional format templates to resolve |
EVIncludeProjectHash |
bool | false |
Include project file hash in build metadata |
EVIncludeTargetFramework |
bool | false |
Include target framework in build metadata |
EVDeterministic |
bool | false |
Generate deterministic version (no timestamps/random) |
EVVersionCacheFile |
string | (empty) | Cache file for last resolved version |
EVUseCache |
bool | false |
Skip version generation if cache is up to date |
EVExtraJsonProperties |
string | (empty) | Semicolon-separated extra properties for JSON output |
EVNuGetCompatible |
bool | false |
Produce NuGet-compatible version (strip build metadata) |
EVCalVerBaseYear |
int | 0 |
Base year for CalVer versioning |
EVCalVerShortYear |
bool | false |
Use 2-digit year in CalVer |
EVAssemblyName |
string | $(AssemblyName) |
Assembly name override |
EVProductName |
string | $(Product) |
Product name for metadata |
EVCompanyName |
string | $(Company) |
Company name for metadata |
EVMajorBumpTypes |
string | (empty) | Semicolon-separated commit types that trigger major bump |
EVMinorBumpTypes |
string | (empty) | Semicolon-separated commit types that trigger minor bump |
EVConventionalCommitsEnabled |
bool | false |
Enable conventional commits analysis |
EVMaxCommitsToAnalyze |
int | 0 |
Max commits to analyze (0 = unlimited) |
EVAppendBranchToPreRelease |
bool | false |
Append branch name to pre-release versions |
EVPreReleaseBranchPattern |
regex | (empty) | Branch pattern that produces pre-release versions |
EVReleaseBranchPattern |
regex | (empty) | Branch pattern that produces stable releases |
EVSanitizeBranchName |
bool | false |
Sanitize branch name for SemVer pre-release use |
EVBranchNameMaxLength |
int | 0 |
Max length for branch name in version strings |
EVVersionSeparator |
string | . |
Separator between version components |
EVWriteOutputVersion |
bool | false |
Write .version file to output directory |
EVGitHubEnvFile |
bool | false |
Append version to $GITHUB_ENV file |
EVGitHubEnvFilePath |
string | (empty) | Custom path for GITHUB_ENV file |
EVHashAlgorithm |
string | SHA256 |
Hash algorithm for checksum generation (SHA256, SHA512, MD5) |
EVGenerateChecksum |
bool | false |
Generate a checksum file alongside the version file |
EVChecksumFile |
string | (empty) | Path to write checksum file |
EVGenerateSbom |
bool | false |
Generate a Software Bill of Materials file |
EVSbomFormat |
string | CycloneDX |
SBOM format: CycloneDX or SPDX |
EVSbomFile |
string | (empty) | Path to write SBOM file |
EVMonorepoRoot |
string | (empty) | Root path of the monorepo |
EVProjectScope |
string | (empty) | Package/project scope name within a monorepo |
EVIndependentVersioning |
bool | false |
Version each project independently in a monorepo |
EVSyncVersions |
bool | false |
Synchronize all project versions to the same value |
EVChangesetDir |
string | (empty) | Directory containing changeset markdown files |
EVConsumeChangesets |
bool | false |
Auto-consume changeset files during build |
EVAutoTag |
bool | false |
Automatically create a git tag after version generation |
EVAutoTagPrefix |
string | v |
Prefix for auto-created tags |
EVAutoTagMessage |
string | (empty) | Message template for auto-created tags |
EVChangelogFile |
string | (empty) | Path to CHANGELOG.md for auto-generation |
EVChangelogFormat |
string | keepachangelog |
Changelog format: keepachangelog or conventional |
EVAutoChangelog |
bool | false |
Auto-generate changelog from commit messages |
EVReleaseNotesFile |
string | (empty) | Path to write release notes file |
EVAutoReleaseNotes |
bool | false |
Auto-generate release notes from commits |
EVWebhookUrl |
string | (empty) | Webhook URL to POST version info after build |
EVWebhookOnRelease |
bool | false |
Send webhook notification on release builds |
EVSlackWebhook |
string | (empty) | Slack incoming webhook URL for version notifications |
EVTeamsWebhook |
string | (empty) | Microsoft Teams webhook URL for version notifications |
EVNotifyOnMajor |
bool | false |
Notify on major version bumps only |
EVBuildAgent |
string | (empty) | CI build agent name |
EVBuildUrl |
string | (empty) | CI build URL for traceability |
EVBuildPipelineId |
string | (empty) | CI pipeline identifier |
EVBuildJobId |
string | (empty) | CI job identifier |
EVSourceBranch |
string | (empty) | Source branch for pull requests |
EVTargetBranch |
string | (empty) | Target branch for pull requests |
EVPullRequestId |
string | (empty) | Pull request number or ID |
EVBuildReason |
string | (empty) | Build trigger reason (manual, CI, schedule, webhook) |
EVAppleBundleVersionBase |
int | 0 |
Apple CFBundleVersion base number |
EVAndroidVersionCodeBase |
int | 0 |
Base offset for Android versionCode calculation |
EVAndroidVersionCodeScheme |
string | semver |
Android versionCode scheme: semver or timestamp |
EVFlutterBuildNumber |
int | 0 |
Flutter build number for pubspec.yaml |
EVUnityVersion |
bool | false |
Generate Unity-compatible version output |
EVElectronVersion |
bool | false |
Generate Electron-compatible version output |
EVJsonIndented |
bool | false |
Pretty-print JSON output with indentation |
EVXmlNamespace |
string | (empty) | XML namespace URI for version XML files |
EVOutputEncoding |
string | utf-8 |
Output file encoding: utf-8, utf-8-bom, ascii |
EVLineEnding |
string | auto |
Line ending style: crlf, lf, auto |
EVBuildNumberStrategy |
string | increment |
Build number strategy: increment, timestamp, hash |
EVVersionTemplate |
string | (empty) | Custom version template for non-standard schemes |
EVVersionRegex |
string | (empty) | Regex pattern to validate the final resolved version |
EVBumpStrategy |
string | semver |
Bump strategy: semver, calver, auto |
EVVersionLock |
bool | false |
Lock version to current value (no auto-increment) |
EVVersionLockFile |
string | (empty) | Path to version lock file |
EVSnapshotSuffix |
string | -SNAPSHOT |
Suffix for snapshot versions |
EVNightlySuffix |
string | -nightly |
Suffix for nightly versions |
EVDevVersionFormat |
string | (empty) | Format for development versions |
EVRcNumberStart |
int | 1 |
Starting number for RC pre-release versions |
EVPreReleaseNumberStart |
int | 1 |
Starting number for pre-release versions |
EVGitDepth |
int | 0 |
Git depth for shallow clones (0 = full) |
EVGitFetchTags |
bool | false |
Fetch tags before version resolution |
EVGitRemote |
string | origin |
Git remote name |
EVUseGitDescribe |
bool | false |
Use git describe for version resolution |
EVGitDescribeArgs |
string | (empty) | Extra arguments passed to git describe |
EVGitSubmoduleVersioning |
bool | false |
Include submodule version info in metadata |
EVRequireChangelog |
bool | false |
Require a changelog entry for the current version |
EVMaxPatchVersion |
int | 0 |
Maximum allowed patch version (0 = unlimited) |
EVMaxMinorVersion |
int | 0 |
Maximum allowed minor version (0 = unlimited) |
EVMaxMajorVersion |
int | 0 |
Maximum allowed major version (0 = unlimited) |
EVAllowDowngrade |
bool | false |
Allow version downgrades |
EVRequireCI |
bool | false |
Require a CI environment to build |
EVAllowLocalBuild |
bool | true |
Allow local (non-CI) builds |
EVBackupVersionFile |
bool | false |
Backup version files before modification |
EVBackupDir |
string | (empty) | Directory for version file backups |
EVRollbackOnFailure |
bool | false |
Rollback version changes on build failure |
EVCompatibilityMode |
string | strict |
Compatibility mode: strict or loose |
EVNuGetV2Compatible |
bool | false |
Generate NuGet v2-compatible version strings |
EVLegacyVersionFormat |
bool | false |
Use legacy 4-part version format |
EVJenkinsOutput |
bool | false |
Write Jenkins-compatible env vars to stdout |
EVBitbucketOutput |
bool | false |
Write Bitbucket Pipelines export lines |
EVCircleCIOutput |
bool | false |
Write CircleCI env export lines |
EVAppVeyorOutput |
bool | false |
Write AppVeyor service messages |
EVTravisCIOutput |
bool | false |
Write TravisCI export lines |
EVAWSCodeBuildOutput |
bool | false |
Write AWS CodeBuild env exports |
EVCloudBuildOutput |
bool | false |
Write Google Cloud Build substitutions |
EVCSharpVersionFile |
string | (empty) | Path to write generated C# version constants file |
EVCSharpNamespace |
string | (empty) | Namespace for generated C# version file |
EVTypeScriptVersionFile |
string | (empty) | Path to write generated TypeScript version file |
EVPythonVersionFile |
string | (empty) | Path to write generated Python version file |
EVGoVersionFile |
string | (empty) | Path to write generated Go version file |
EVRustVersionFile |
string | (empty) | Path to write generated Rust version file |
EVSwiftVersionFile |
string | (empty) | Path to write generated Swift version file |
EVKotlinVersionFile |
string | (empty) | Path to write generated Kotlin version file |
EVJavaVersionFile |
string | (empty) | Path to write generated Java version file |
EVJavaPackageName |
string | (empty) | Java package name for generated version class |
EVDartVersionFile |
string | (empty) | Path to write generated Dart version file |
EVPhpVersionFile |
string | (empty) | Path to write generated PHP version file |
EVRubyVersionFile |
string | (empty) | Path to write generated Ruby version file |
Output Properties
After the EVGenerateVersion target runs, the following MSBuild properties are available for use in subsequent targets:
| Property | Description |
|---|---|
EonaCatVersion |
The full resolved EonaCat version string |
BuildTimestamp |
Build timestamp in ISO 8601 UTC format |
EVCommitHash |
Full commit hash |
EVCommitHashShort |
Short commit hash (first 7 characters) |
EVBranchName |
Current branch name |
EVShortBranchName |
Last segment of branch after / |
EVSafeBranchName |
Branch name sanitized for SemVer use |
EVTagName |
Most recent matching tag |
EVCommitsAfterTag |
Commits since last tag |
EVRevisionNumber |
Total revision/commit number |
EVCommitterName |
Committer's name |
EVCommitterEmail |
Committer's email |
EVAuthorName |
Author's name |
EVAuthorEmail |
Author's email |
EVRepositoryUrl |
Repository URL |
EVIsDirty |
true / false - whether repo has uncommitted changes |
EVCommitDate |
Commit date (ISO 8601) |
EVAuthorDate |
Author date (ISO 8601) |
EVMajorVersion |
Major version component |
EVMinorVersion |
Minor version component |
EVPatchVersion |
Patch version component |
EVPreRelease |
Pre-release label |
EVBuildMeta |
Build metadata |
EVBuildNumber |
Resolved build number |
EVIsPreRelease |
true / false - whether version is pre-release |
EVIsTagged |
true / false - whether a VCS tag was found |
EVCommitCount |
Total commit count |
EVBuildDate |
Build date (yyyy-MM-dd) |
EVBuildMachine |
Build machine hostname |
EVOsDescription |
OS description |
EVProcessArch |
Process architecture (e.g. x64) |
EVRuntimeId |
Runtime identifier (e.g. win-x64) |
EVUserName |
Current OS user name |
EVNuGetVersion |
NuGet-compatible version (no build metadata) |
EVAssemblyVersion |
Assembly version (major.minor.0.0) |
EVFileVersion |
File version (major.minor.patch.0) |
EVDockerTag |
Docker image tag (if EVDockerImageName set) |
EVDockerImageTag |
Full Docker image path with tag |
EVVersionOrdinal |
Sortable integer (major×1000000 + minor×1000 + patch) |
EVBuildEpoch |
Unix epoch seconds at build time |
EVBuildTicks |
.NET ticks at build time |
EVVersionTag |
Version as tag string (v1.2.3) |
EVVersionMSBuildXml |
Version as MSBuild XML element |
EVGitHubActionsVersionOutput |
GitHub Actions set-output command |
EVAzureDevOpsBuildNumber |
Azure DevOps build number command |
EVTeamCityBuildNumber |
TeamCity build number service message |
EVCalVerVersion |
CalVer version (YYYY.MM.DD) |
EVAdditionalVersions |
Resolved additional format strings |
EVFullCopyright |
Full copyright string with holder and year |
EVVcsProviderName |
VCS provider name used |
EVShortVersion |
Short version (major.minor) |
EVWindowsVersion |
Windows 4-part version (major.minor.patch.build) |
EVAndroidVersionCode |
Android versionCode integer |
EVBadgeUrl |
Shields.io badge URL |
EVVersionJson |
Full version metadata as JSON string |
EVVersionYaml |
Full version metadata as YAML string |
EVFullVersion |
Full 4-part version (major.minor.patch.revision) |
EVSemVer2Version |
SemVer 2.0.0 compatible version string |
EVNuGetV2Version |
NuGet v2-compatible version (max 3 parts, no dots in pre-release) |
EVPep440Version |
PEP 440 (Python) compatible version |
EVGemVersion |
Ruby gem-style version |
EVMavenVersion |
Maven-compatible version string |
EVDebianVersion |
Debian package version string |
EVRpmVersion |
RPM package version string |
EVAppleShortVersion |
Apple CFBundleShortVersionString |
EVAppleBundleVersion |
Apple CFBundleVersion |
EVFlutterVersion |
Flutter-compatible version (version+build) |
EVHelmVersion |
Helm chart-compatible version |
EVTerraformConstraint |
Terraform constraint (~> major.minor) |
EVChocolateyVersion |
Chocolatey-compatible version |
EVSnapVersion |
Snap-compatible version |
EVFlatpakVersion |
Flatpak-compatible version |
EVWixVersion |
WiX installer-compatible version (clamped limits) |
EVOciTag |
OCI/container tag-safe version |
EVFullDockerImagePath |
Full Docker image path with registry, name, and tag |
EVDockerLatestTag |
Docker latest tag string |
EVDockerMajorTag |
Docker major version tag (e.g. myapp:1) |
EVDockerMinorTag |
Docker major.minor tag (e.g. myapp:1.2) |
EVJenkinsBuildNumber |
Jenkins-compatible version string |
EVBitbucketVersionOutput |
Bitbucket Pipelines variable export |
EVCircleCIVersionOutput |
CircleCI env export string |
EVAppVeyorBuildVersion |
AppVeyor build number update string |
EVTravisCIVersionOutput |
TravisCI env export string |
EVGitLabDotEnvVersion |
GitLab CI DOTENV artifact line |
EVBuildYear |
Build year (4 digit) |
EVBuildMonth |
Build month (1-12) |
EVBuildDay |
Build day of month (1-31) |
EVBuildHour |
Build hour (0-23) |
EVBuildMinute |
Build minute (0-59) |
EVBuildSecond |
Build second (0-59) |
EVBuildDayOfYear |
Build day of year (1-366) |
EVBuildWeekOfYear |
Build week of year (ISO 8601) |
EVBuildQuarter |
Build quarter (1-4) |
EVCommitSubject |
Commit message subject (first line) |
EVCommitBody |
Commit message body (lines after first) |
EVDirtyFileCount |
Number of files changed in working directory |
EVMatchingTagCount |
Number of tags matching the pattern |
EVPreviousTag |
Previous tag name (second most recent) |
EVCommitDepth |
Commit depth (total ancestors in first-parent chain) |
EVHeadRef |
Current git HEAD reference |
EVIsDetachedHead |
true / false - whether HEAD is detached |
EVIsDirectlyTagged |
true / false - whether current commit is directly tagged |
EVIsClean |
true / false - whether working directory is clean |
EVStashCount |
Number of stashed entries |
EVRemoteName |
Name of the remote (e.g. origin) |
EVRemoteUrl |
Remote URL of the repository |
EVRepoSlug |
GitHub-style repository slug (owner/repo) |
EVRepoName |
Repository name only |
EVRepoOwner |
Repository owner |
EVHostingProvider |
Hosting provider (github, gitlab, bitbucket, azure, unknown) |
EVCloneUrlHttps |
HTTPS clone URL |
EVCloneUrlSsh |
SSH clone URL |
EVCommitUrl |
Web URL to the commit on the hosting provider |
EVCompareUrl |
Web URL to compare view between tag and HEAD |
EVFullAssemblyVersion |
Assembly version (major.minor.build.0) |
EVFullFileVersion |
File version with build (major.minor.patch.build) |
EVProductVersion |
Product version (same as InformationalVersion) |
EVPreReleaseChannel |
Pre-release channel name only (alpha, beta, rc) |
EVPreReleaseNumber |
Pre-release number only (e.g. 1 from beta.1) |
EVIsStable |
true / false - whether version is a stable release |
EVIsDevelopment |
true / false - whether version is in 0.x.x range |
EVIsCI |
true / false - whether build is running in CI |
EVCIPlatform |
Detected CI platform name |
EVProjectHash |
Checksum/hash of the project file |
EVVersionHash |
SHA256 hash of the resolved version string |
EVDotNetRuntimeVersion |
.NET runtime version used during build |
EVDotNetSdkVersion |
.NET SDK version used during build |
EVTargetFrameworkOutput |
Target framework moniker used in the build |
EVMSBuildVersion |
MSBuild version |
EVCSharpVersionConstant |
Generated C# version constant source code |
EVCDefineBlock |
Generated C/C++ #define source code |
EVBashExports |
Generated bash export statements |
EVPowerShellVars |
Generated PowerShell variable assignments |
EVPackageJsonVersion |
package.json compatible version line |
EVBadgeMarkdown |
Markdown badge image string |
EVHtmlMetaVersion |
HTML meta tag with version |
EVVersionToml |
TOML version string |
EVVersionIni |
INI-formatted version string |
EVVersionEnv |
ENV-formatted version string |
EVVersionCsv |
CSV-formatted version record |
EVVersionSql |
SQL INSERT statement for the version |
EVVersionXml |
XML-formatted version record |
EVVersionProps |
Version as MSBuild properties file content |
EVBuildBadgeUrl |
Shields.io URL for a "build passing" badge |
EVConventionalBumpType |
Conventional commit bump type (Major, Minor, Patch, None) |
EVVersionOrdinalHex |
Version ordinal as hex string |
EVSortableVersion |
Sortable zero-padded version (001.002.003) |
Using Output Properties
You can reference any output property in subsequent MSBuild targets or in your project file:
<PropertyGroup>
<EVDockerImageName>myregistry/myapp</EVDockerImageName>
<EVCopyrightHolder>My Company</EVCopyrightHolder>
<EVCopyrightStartYear>2020</EVCopyrightStartYear>
<EVGitHubActionsOutput>true</EVGitHubActionsOutput>
</PropertyGroup>
<Target Name="PrintVersionInfo" AfterTargets="EVGenerateVersion">
<Message Text="Version: $(EonaCatVersion)" Importance="High" />
<Message Text="Commit: $(EVCommitHash)" Importance="High" />
<Message Text="Branch: $(EVBranchName)" Importance="High" />
<Message Text="Docker: $(EVDockerTag)" Importance="High" />
<Message Text="NuGet: $(EVNuGetVersion)" Importance="High" />
<Message Text="Copyright: $(EVFullCopyright)" Importance="High" />
<Message Text="Is dirty: $(EVIsDirty)" Importance="High" />
<Message Text="CalVer: $(EVCalVerVersion)" Importance="High" />
</Target>
Example: CI/CD Pipeline Configuration
<PropertyGroup>
<EVGitHubActionsOutput>true</EVGitHubActionsOutput>
<EVGitHubEnvFile>true</EVGitHubEnvFile>
<EVAzureDevOpsOutput>true</EVAzureDevOpsOutput>
<EVTeamCityOutput>true</EVTeamCityOutput>
<EVSetEnvironmentVariables>true</EVSetEnvironmentVariables>
<EVEnvVariablePrefix>BUILD_</EVEnvVariablePrefix>
</PropertyGroup>
Example: Version Policy Enforcement
<PropertyGroup>
<EVRequireStable Condition="$(Configuration) == 'Release'">true</EVRequireStable>
<EVMaxCommitsAfterTag>50</EVMaxCommitsAfterTag>
<EVForbiddenBranches>deprecated;archived</EVForbiddenBranches>
<EVWarnOnNonDefaultBranch>true</EVWarnOnNonDefaultBranch>
<EVDefaultBranch>main</EVDefaultBranch>
<EVMinVersion>1.0.0</EVMinVersion>
<EVMaxVersion>99.0.0</EVMaxVersion>
</PropertyGroup>
Example: Multi-Format File Output
<PropertyGroup>
<EVVersionFile>$(OutputPath)\version.txt</EVVersionFile>
<EVVersionJsonFile>$(OutputPath)\version.json</EVVersionJsonFile>
<EVVersionYamlFile>$(OutputPath)\version.yaml</EVVersionYamlFile>
<EVVersionXmlFile>$(OutputPath)\version.xml</EVVersionXmlFile>
<EVVersionEnvFile>$(OutputPath)\version.env</EVVersionEnvFile>
<EVVersionHeaderFile>$(OutputPath)\version.h</EVVersionHeaderFile>
<EVVersionPropsFile>$(OutputPath)\version.props</EVVersionPropsFile>
<EVVersionCsvFile>$(OutputPath)\version.csv</EVVersionCsvFile>
<EVVersionTomlFile>$(OutputPath)\version.toml</EVVersionTomlFile>
<EVVersionIniFile>$(OutputPath)\version.ini</EVVersionIniFile>
<EVVersionSqlFile>$(OutputPath)\version.sql</EVVersionSqlFile>
<EVVersionBadgeFile>$(OutputPath)\badge.md</EVVersionBadgeFile>
</PropertyGroup>
Example: Docker Tag Generation
<PropertyGroup>
<EVDockerImageName>myregistry.azurecr.io/myapp</EVDockerImageName>
<EVDockerRegistry>myregistry.azurecr.io</EVDockerRegistry>
</PropertyGroup>
Example: Version Prefix/Suffix
<PropertyGroup>
<EVPreReleaseLabel>beta</EVPreReleaseLabel>
<EVBuildMetadataLabel>$(BUILD_BUILDID)</EVBuildMetadataLabel>
<EVForceVersion>99.0.0-special</EVForceVersion>
</PropertyGroup>
Example: Selective Stamping
<PropertyGroup>
<EVStampAssemblyVersion>false</EVStampAssemblyVersion>
<EVStampFileVersion>false</EVStampFileVersion>
<EVStampPackageVersion>false</EVStampPackageVersion>
<EVStampInformationalVersion>true</EVStampInformationalVersion>
</PropertyGroup>
Example: Copyright Generation
<PropertyGroup>
<EVCopyrightHolder>EonaCat</EVCopyrightHolder>
<EVCopyrightStartYear>2020</EVCopyrightStartYear>
</PropertyGroup>
## Version Formatting API
### Built-in Format Specifiers
```csharp
using EonaCat.Versioning;
var v = SemanticVersion.Parse("1.2.3-beta.1+build.42");
// Built-in format specifiers
VersionFormatter.Format(v, "S"); // "1.2.3" (Short)
VersionFormatter.Format(v, "F"); // "1.2.3-beta.1+build.42" (Full)
VersionFormatter.Format(v, "T"); // "v1.2.3-beta.1+build.42" (Tag)
VersionFormatter.Format(v, "M"); // "1.2" (Major.Minor)
VersionFormatter.Format(v, "N"); // "1002003" (Numeric)
VersionFormatter.Format(v, "D"); // "v1.2.3" (Display)
VersionFormatter.Format(v, "C"); // "1002003" (Compact)
VersionFormatter.Format(v, "H"); // "Version 1.2.3 ..." (Human-readable)
Cross-Ecosystem Formatting
// JSON output
VersionFormatter.ToJson(v);
// { "major": 1, "minor": 2, "patch": 3, "preRelease": "beta.1", ... }
// XML output
VersionFormatter.ToXml(v);
// <version major="1" minor="2" patch="3" preRelease="beta.1" ... />
// YAML output
VersionFormatter.ToYaml(v);
// version:
// major: 1
// minor: 2
// ...
// TOML output (Cargo.toml style)
VersionFormatter.ToToml(v); // version = "1.2.3-beta.1+build.42"
// INI file output
VersionFormatter.ToIni(v);
// [Version]
// Major=1
// ...
// SQL INSERT
VersionFormatter.ToSqlInsert(v);
// INSERT INTO Versions (Major, Minor, ...) VALUES (1, 2, ...);
Package Manager Formats
VersionFormatter.ToNuGetVersion(v); // "1.2.3-beta.1"
VersionFormatter.ToPythonVersion(v); // "1.2.3b1" (PEP 440)
VersionFormatter.ToGemVersion(v); // "1.2.3.beta.1"
VersionFormatter.ToMavenVersion(v); // "1.2.3-BETA.1"
VersionFormatter.ToDebianVersion(v); // "1.2.3~beta.1"
VersionFormatter.ToRpmVersion(v); // "0:1.2.3-0.beta.1"
VersionFormatter.ToWindowsVersion(v); // "1.2.3.0"
CI/CD Platform Formats
// GitHub Actions
VersionFormatter.ToGitHubActionsOutput(v);
// ::set-output name=version::1.2.3-beta.1+build.42
// ::set-output name=version-major::1
// ...
// Azure DevOps
VersionFormatter.ToAzureDevOpsBuildNumber(v);
// ##vso[build.updatebuildnumber]1.2.3-beta.1+build.42
VersionFormatter.ToAzureDevOpsVariable(v);
// ##vso[task.setvariable variable=Version]1.2.3-beta.1+build.42
// TeamCity
VersionFormatter.ToTeamCityBuildNumber(v);
// ##teamcity[buildNumber '1.2.3-beta.1+build.42']
// GitLab CI
VersionFormatter.ToGitLabVariable(v);
// echo "VERSION=1.2.3-beta.1+build.42" >> $GITLAB_ENV
Container & Cloud Formats
// Docker image tags (single and multi-tag)
VersionFormatter.ToDockerTag(v, "myapp");
// "myapp:1.2.3-beta.1"
VersionFormatter.ToDockerTags(SemanticVersion.Parse("1.2.3"), "myapp");
// ["myapp:latest", "myapp:1", "myapp:1.2", "myapp:1.2.3"]
// Helm chart version
VersionFormatter.ToHelmVersion(v); // "1.2.3-beta.1+build.42"
.NET Assembly Formats
VersionFormatter.ToAssemblyVersion(v); // "1.2.0.0"
VersionFormatter.ToAssemblyFileVersion(v); // "1.2.3.0"
VersionFormatter.ToAssemblyInformationalVersion(v); // "1.2.3-beta.1+build.42"
VersionFormatter.ToMSBuildProperty(v); // "<Version>1.2.3-beta.1+build.42</Version>"
Code Generation Formats
// C# constant
VersionFormatter.ToCSharpConstant(v);
// public const string Version = "1.2.3-beta.1+build.42";
// C preprocessor defines
VersionFormatter.ToCDefine(v);
// #define VERSION_MAJOR 1
// #define VERSION_MINOR 2
// ...
// Shell exports
VersionFormatter.ToBashExport(v);
// export VERSION_MAJOR=1
// export VERSION_MINOR=2
// ...
VersionFormatter.ToPowerShellVars(v);
// $VersionMajor = 1
// $VersionMinor = 2
// ...
Badge & Display Formats
// Shields.io badge URL
VersionFormatter.ToShieldsBadgeUrl(v);
// https://img.shields.io/badge/version-1.2.3--beta.1+build.42-blue
// Markdown badge
VersionFormatter.ToShieldsBadgeMarkdown(v);
// 
// package.json
VersionFormatter.ToPackageJsonVersion(v);
// "version": "1.2.3-beta.1+build.42"
Custom Template Formatting
// Custom templates with tokens
VersionFormatter.FormatCustom(v, "App v{major}.{minor}.{patch} ({stable})");
// "App v1.2.3 (unstable)"
VersionFormatter.FormatCustom(v, "Build {major:3}.{minor:3}.{patch:4}");
// "Build 001.002.0003"
// CalVer formatting
var calVer = CalendarVersion.Today();
VersionFormatter.FormatCalVer(calVer, "{YYYY}.{MM}.{DD}");
// "2024.06.15"
Ordinal Conversion
// Convert to/from sortable integer
long ord = VersionFormatter.ToOrdinal(v); // 1002003000
var back = VersionFormatter.FromOrdinal(ord); // 1.2.3
Version Converter API
The VersionConverter class provides conversions between versioning ecosystems.
Cross-System Conversions
using EonaCat.Versioning;
var v = SemanticVersion.Parse("1.2.3");
// .NET System.Version ↔ SemVer
Version sysVer = VersionConverter.ToSystemVersion(v); // 1.2.3.0
SemanticVersion back = VersionConverter.FromSystemVersion(sysVer); // 1.2.3
// CalVer ↔ SemVer
CalendarVersion calVer = VersionConverter.SemVerToCalVer(v); // 2024.6.3
SemanticVersion fromCal = VersionConverter.CalVerToSemVer(calVer);
// Date-based conversions
SemanticVersion fromDate = VersionConverter.DateToSemVer(DateTime.UtcNow); // 2024.6.15
CalendarVersion fromEpoch = VersionConverter.FromEpoch(1718291234);
SemanticVersion fromDateStr = VersionConverter.FromDateString("2024-06-15");
// Build number → SemVer
SemanticVersion fromBuild = VersionConverter.FromBuildNumber(42); // 0.0.42
// Sortable integer
int sortable = VersionConverter.ToSortableInt(v); // 1002003
SemanticVersion fromInt = VersionConverter.FromSortableInt(sortable); // 1.2.3
// Four-part .NET version
string fourPart = VersionConverter.ToFourPartVersion("1.2.3"); // "1.2.3.0"
SemanticVersion from4 = VersionConverter.FromFourPartVersion("1.2.3.4"); // 1.2.3
Package Manager Conversions
VersionConverter.ToNuGetVersion(v); // "1.2.3"
VersionConverter.ToNpmVersion(v); // "1.2.3"
VersionConverter.ToPep440(v); // "1.2.3"
VersionConverter.ToRubyGemsVersion(v); // "1.2.3"
VersionConverter.ToMavenVersion(v); // "1.2.3"
VersionConverter.ToDebianVersion(v); // "1.2.3"
VersionConverter.ToRpmVersion(v); // "0:1.2.3-1"
VersionConverter.ToChocolateyVersion(v); // "1.2.3"
VersionConverter.ToSnapVersion(v); // "1.2.3"
VersionConverter.ToFlatpakVersion(v); // "1.2.3"
VersionConverter.ToWixVersion(v); // "1.2.3" (clamped to WiX limits)
VersionConverter.ToDockerTag(v, "app"); // "app:1.2.3"
VersionConverter.ToOciTag(v); // "1.2.3" (OCI-safe)
Mobile & Platform Conversions
// Android
int versionCode = VersionConverter.ToAndroidVersionCode(v); // 10203
SemanticVersion fromCode = VersionConverter.FromAndroidVersionCode(10203); // 1.2.3
// Apple
string bundle = VersionConverter.ToAppleBundleVersion(v, 42); // "42"
string shortVer = VersionConverter.ToAppleShortVersion(v); // "1.2.3"
// Windows
VersionConverter.ToWindowsProductVersion(v); // "1.2.3.0"
// CalVer ecosystem
VersionConverter.ToUbuntuVersion(CalendarVersion.Parse("2024.4.1")); // "24.04"
VersionConverter.ToUnityVersion(CalendarVersion.Parse("2024.4.1")); // "2024.4.1"
Loose String Coercion
// Auto-fix incomplete/loose version strings
var coerced = VersionConverter.CoerceLoose("v1"); // 1.0.0
coerced = VersionConverter.CoerceLoose("1.2"); // 1.2.0
coerced = VersionConverter.CoerceLoose("v1.2.3-beta"); // 1.2.3-beta
// Parse and sort mixed version strings
var sorted = VersionConverter.ParseAndSort(new[] { "2.0.0", "1.0.0", "1.5.0" });
// [1.0.0, 1.5.0, 2.0.0]
// Resolve best version from a range
var best = VersionConverter.Resolve("^1.0.0", sorted); // 1.5.0
Infrastructure Conversions
VersionConverter.ToTerraformConstraint(v); // "~> 1.2"
// Composer (PHP) ↔ SemVer range
VersionConverter.ComposerToSemVerRange("^1.0||^2.0"); // "^1.0 || ^2.0"
VersionConverter.SemVerRangeToComposer("^1.0 || ^2.0"); // "^1.0||^2.0"
// Homebrew
var fromBrew = VersionConverter.FromHomebrewVersion("1.2.3_1"); // 1.2.3
Version Policy & Governance API
The VersionPolicy class provides policy enforcement, validation, lifecycle management, filtering, and analysis for collections of versions.
Policy Validation
using EonaCat.Versioning;
var v = SemanticVersion.Parse("1.2.3-beta.1");
// Check bump validity
VersionPolicy.IsValidBump(SemanticVersion.Parse("1.0.0"), v); // true
VersionPolicy.IsConsecutiveBump(SemanticVersion.Parse("1.2.2"), v); // false (has prerelease)
// Get diff type
VersionPolicy.GetDiffType(SemanticVersion.Parse("1.0.0"), v); // "Minor"
VersionPolicy.HasBreakingChanges(SemanticVersion.Parse("1.0.0"), v); // false
// Bounds checking
VersionPolicy.IsWithinBounds(v, SemanticVersion.Parse("1.0.0"), SemanticVersion.Parse("2.0.0")); // true
// Full policy validation with rules
var rules = new VersionPolicyRules
{
RequireStable = true,
MaxMajor = 5,
ForbidBuildMetadata = false,
AllowedChannels = new List<string> { "alpha", "beta", "rc" },
MinVersion = SemanticVersion.Parse("1.0.0")
};
var violations = VersionPolicy.Validate(v, rules);
// ["Pre-release versions are not allowed by policy."]
Pre-Release Lifecycle
var v = SemanticVersion.Parse("1.2.3-alpha.3");
// Classify pre-release
VersionPolicy.IsAlpha(v); // true
VersionPolicy.IsBeta(v); // false
VersionPolicy.IsReleaseCandidate(v); // false
VersionPolicy.IsDevelopment(v); // false (major > 0)
VersionPolicy.GetPreReleaseChannel(v); // "alpha"
VersionPolicy.GetPreReleaseNumber(v); // 3
VersionPolicy.GetLifecycleStage(v); // "ALPHA"
// Bump pre-release number
var next = VersionPolicy.BumpPreRelease(v); // 1.2.3-alpha.4
// Promote through lifecycle stages
var promoted = VersionPolicy.Promote(v); // 1.2.3-beta.1
promoted = VersionPolicy.Promote(promoted); // 1.2.3-rc.1
promoted = VersionPolicy.Promote(promoted); // 1.2.3 (release!)
// Create special versions
var snapshot = VersionPolicy.CreateSnapshot(v); // 1.2.3-alpha.3+snapshot.20240615...
var nightly = VersionPolicy.CreateNightly(v); // 1.2.3-nightly.20240615
Collection Operations
var versions = new List<SemanticVersion>
{
SemanticVersion.Parse("1.0.0"),
SemanticVersion.Parse("1.1.0-beta.1"),
SemanticVersion.Parse("1.1.0"),
SemanticVersion.Parse("2.0.0-alpha.1"),
SemanticVersion.Parse("2.0.0"),
SemanticVersion.Parse("3.0.0-rc.1"),
};
// Find newest/oldest
VersionPolicy.GetNewest(versions); // 3.0.0-rc.1
VersionPolicy.GetOldest(versions); // 1.0.0
VersionPolicy.LatestStable(versions); // 2.0.0
// Sort
var asc = VersionPolicy.SortAscending(versions);
var desc = VersionPolicy.SortDescending(versions);
// Filter
var stable = VersionPolicy.FilterStable(versions); // [1.0.0, 1.1.0, 2.0.0]
var prerel = VersionPolicy.FilterPreRelease(versions); // [1.1.0-beta.1, 2.0.0-alpha.1, 3.0.0-rc.1]
var alphas = VersionPolicy.FilterByChannel(versions, "alpha"); // [2.0.0-alpha.1]
var v1line = VersionPolicy.FilterByMajor(versions, 1); // [1.0.0, 1.1.0-beta.1, 1.1.0]
// Group
var byMajor = VersionPolicy.GroupByMajor(versions); // {1: [...], 2: [...], 3: [...]}
var byChan = VersionPolicy.GroupByChannel(versions); // {"stable": [...], "beta": [...], ...}
// Parse from strings (skips invalid)
var parsed = VersionPolicy.ParseMany(new[] { "1.0.0", "invalid", "2.0.0" }); // [1.0.0, 2.0.0]
// Bulk checks
VersionPolicy.AllStable(stable); // true
VersionPolicy.AnyPreRelease(versions); // true
Analysis & Migration
// Suggest next version
var next = VersionPolicy.SuggestNext(versions, VersionBumpType.Minor); // 3.1.0
// Check compatibility
VersionPolicy.IsSameSeries(
SemanticVersion.Parse("1.2.0"),
SemanticVersion.Parse("1.2.5")); // true
VersionPolicy.MajorDistance(
SemanticVersion.Parse("1.0.0"),
SemanticVersion.Parse("3.0.0")); // 2
// Migration path
var path = VersionPolicy.GetMigrationPath(
SemanticVersion.Parse("1.0.0"),
SemanticVersion.Parse("2.0.0"),
versions);
// [1.1.0-beta.1, 1.1.0, 2.0.0-alpha.1, 2.0.0]
// Version age
int age = VersionPolicy.GetVersionAge(SemanticVersion.Parse("1.0.0"), versions); // 5
// Diff between versions
string diff = VersionPolicy.Diff(
SemanticVersion.Parse("1.0.0"),
SemanticVersion.Parse("2.1.3-beta.1"));
// Major: 1 → 2
// Minor: 0 → 1
// Patch: 0 → 3
// PreRelease: '' → 'beta.1'
// Timeline
string timeline = VersionPolicy.GenerateTimeline(versions);
// 1.0.0 --[Minor]--> 1.1.0-beta.1 --[Patch]--> 1.1.0 --[Major]--> ...
// Statistics
var stats = VersionPolicy.GetStatistics(versions);
// Total=6, Stable=3, PreRelease=3, Newest="3.0.0-rc.1", ...
// String coercion for loose inputs
var coerced = VersionPolicy.Coerce("v1.2"); // 1.2.0
// Naming convention matching
VersionPolicy.MatchesNamingConvention("v1.2.3", "v{major}.{minor}.{patch}"); // true
Version File Manager API
The VersionFileManager class provides read/write support for version files in formats across all major ecosystems.
Plain Text & JSON
using EonaCat.Versioning;
// Plain text version file
VersionFileManager.WriteVersionFile("version.txt", "1.2.3");
string ver = VersionFileManager.ReadVersionFile("version.txt"); // "1.2.3"
// JSON version file
VersionFileManager.WriteVersionJson("version.json", SemanticVersion.Parse("1.2.3-beta.1+build.42"));
var fromJson = VersionFileManager.ReadVersionJson("version.json"); // 1.2.3-beta.1+build.42
// Structured VERSION file (key=value format)
VersionFileManager.WriteStructuredVersionFile("./output", SemanticVersion.Parse("1.2.3"), "abc123", "main");
var data = VersionFileManager.ReadStructuredVersionFile("./output/VERSION");
// data["VERSION"] = "1.2.3", data["COMMIT"] = "abc123", data["BRANCH"] = "main"
.NET Project Files
// Read/write .csproj Version
var csprojVer = VersionFileManager.ReadCsprojVersion("MyApp.csproj");
VersionFileManager.UpdateCsprojVersion("MyApp.csproj", SemanticVersion.Parse("2.0.0"));
VersionFileManager.UpdatePackageVersion("MyApp.csproj", SemanticVersion.Parse("2.0.0"));
VersionFileManager.UpdateAssemblyVersion("MyApp.csproj", SemanticVersion.Parse("2.0.0"));
VersionFileManager.UpdateFileVersion("MyApp.csproj", SemanticVersion.Parse("2.0.0"));
VersionFileManager.UpdateInformationalVersion("MyApp.csproj", SemanticVersion.Parse("2.0.0"));
Cross-Ecosystem Project Files
// Node.js
VersionFileManager.UpdatePackageJson("package.json", v);
var npmVer = VersionFileManager.ReadPackageJson("package.json");
// Rust
VersionFileManager.UpdateCargoToml("Cargo.toml", v);
// Python
VersionFileManager.UpdatePyprojectToml("pyproject.toml", v);
// Ruby
VersionFileManager.UpdateGemspec("myapp.gemspec", v);
// Java/Maven
VersionFileManager.UpdatePomXml("pom.xml", v);
// Gradle
VersionFileManager.UpdateBuildGradle("build.gradle", v);
// Auto-detect format based on file extension
VersionFileManager.AutoUpdate("MyApp.csproj", v);
VersionFileManager.AutoUpdate("package.json", v);
VersionFileManager.AutoUpdate("Cargo.toml", v);
Code Generation
Generate version files for any programming language:
// C/C++ header
string header = VersionFileManager.GenerateCHeader(v);
// #ifndef VERSION_H
// #define VERSION_H
// #define VERSION_MAJOR 1
// ...
// Swift struct
string swift = VersionFileManager.GenerateSwiftVersion(v);
// Kotlin object
string kotlin = VersionFileManager.GenerateKotlinVersion(v);
// TypeScript constants
string ts = VersionFileManager.GenerateTypeScriptVersion(v);
// Python __version__.py
string py = VersionFileManager.GeneratePythonVersion(v);
// Go package
string go = VersionFileManager.GenerateGoVersion(v);
// Rust constants
string rust = VersionFileManager.GenerateRustVersion(v);
// Java class
string java = VersionFileManager.GenerateJavaVersion(v, "com.example", "BuildVersion");
// Dart constants
string dart = VersionFileManager.GenerateDartVersion(v);
// PHP constants
string php = VersionFileManager.GeneratePhpVersion(v);
// Ruby module
string ruby = VersionFileManager.GenerateRubyVersion(v);
Platform-Specific Files
// Windows RC VERSIONINFO
string rc = VersionFileManager.GenerateWindowsRc(v, "MyApp", "MyCompany");
// Android Gradle
string android = VersionFileManager.GenerateAndroidVersionGradle(v);
// versionCode 10203
// versionName "1.2.3"
// iOS Info.plist
string plist = VersionFileManager.GenerateIosPlistVersion(v, 42);
// Flutter pubspec.yaml
string flutter = VersionFileManager.GenerateFlutterVersion(v, 42);
// version: 1.2.3+42
// Electron Builder
string electron = VersionFileManager.GenerateElectronBuilderVersion(v);
// Helm Chart.yaml
string helm = VersionFileManager.GenerateHelmChartVersion(v);
// Terraform
string terraform = VersionFileManager.GenerateTerraformConstraint(v);
// version = "~> 1.2"
Changelog Management
// Prepend changelog entry
VersionFileManager.PrependChangelog("CHANGELOG.md", "## 2.0.0 (2024-06-15)\n\n- Breaking change\n");
Directory Scanning
// Scan a directory for all version files
var found = VersionFileManager.ScanDirectory(@"C:\MySolution");
// { "Project1.csproj": 1.2.3, "Project2.csproj": 1.0.0, "package.json": 2.0.0 }
Version Workspace API
The VersionWorkspace class provides multi-project/monorepo version management with dependency tracking, compatibility analysis, and build ordering.
Project Registration
using EonaCat.Versioning;
var workspace = new VersionWorkspace();
// Register projects
workspace.AddProject("Core", "1.2.3");
workspace.AddProject("Api", "1.1.0");
workspace.AddProject("Web", "1.0.0");
// Add dependencies
workspace.AddDependency("Api", "Core", "^1.2.0");
workspace.AddDependency("Web", "Api", ">=1.0.0 <2.0.0");
workspace.AddDependency("Web", "Core", "^1.0.0");
Version Operations
// Get/set versions
var coreVer = workspace.GetVersion("Core"); // 1.2.3
var allVers = workspace.GetAllVersions();
// Bump all projects
workspace.BumpAll(VersionBumpType.Minor);
// Lock all to same version
workspace.LockAll(SemanticVersion.Parse("2.0.0"));
// Check sync status
bool inSync = workspace.AreAllVersionsSynced();
var outOfSync = workspace.GetOutOfSyncProjects();
Dependency Analysis
// Validate all dependency constraints
var violations = workspace.ValidateDependencies();
// ["Api requires Core ^1.2.0, but found 2.0.0."]
// Get dependency graph
var graph = workspace.GetDependencyGraph();
// { "Core": [], "Api": ["Core"], "Web": ["Api", "Core"] }
// Get build order (topological sort)
var buildOrder = workspace.GetBuildOrder();
// ["Core", "Api", "Web"]
// Get dependents of a project
var dependents = workspace.GetDependents("Core"); // ["Api", "Web"]
// Check breaking impact before updating
var impact = workspace.CheckBreakingImpact("Core", SemanticVersion.Parse("2.0.0"));
// ["Api requires Core ^1.2.0, but proposed version is 2.0.0."]
Compatibility & Export
// Generate compatibility matrix
string matrix = workspace.GenerateCompatibilityMatrix();
// Export formats
string markdown = workspace.ExportMarkdownTable();
string json = workspace.ExportJson();
string props = workspace.ExportDirectoryBuildProps();
// Workspace summary
var summary = workspace.GetSummary();
// ProjectCount=3, InSync=false, TotalDependencies=3, ...
// Apply changesets
var newVersions = workspace.ApplyChangesets(new[]
{
new ChangesetEntry("Core", ChangesetBumpLevel.Minor, "New feature"),
});
Version History API
The VersionHistory class provides version tracking, timeline analysis, release cadence metrics, and changelog generation.
Recording & Querying
using EonaCat.Versioning;
var history = new VersionHistory();
// Record releases
history.Record(SemanticVersion.Parse("1.0.0"), "Initial release", "john");
history.Record(SemanticVersion.Parse("1.1.0"), "Feature release", "jane",
new[] { "feat: add search", "fix: pagination" });
history.Record(SemanticVersion.Parse("2.0.0"), "Major release", "john",
new[] { "feat!: new API", "refactor: core" });
// Query
var latest = history.GetLatest(); // 2.0.0
var entry = history.Get(SemanticVersion.Parse("1.1.0"));
var prev = history.GetPrevious(SemanticVersion.Parse("2.0.0")); // 1.1.0
var next = history.GetNext(SemanticVersion.Parse("1.0.0")); // 1.1.0
var series = history.GetSeries(1); // all 1.x releases
int count = history.Count; // 3
Time-Based Analysis
// Time between versions
var span = history.GetTimeBetween(
SemanticVersion.Parse("1.0.0"),
SemanticVersion.Parse("2.0.0"));
// TimeSpan
// Average release cadence
var cadence = history.AverageReleaseCadence();
// e.g. 14 days average
// Releases per month
var perMonth = history.ReleasesPerMonth();
// { "2024-01": 1, "2024-03": 2 }
// Release type breakdown
var byType = history.ReleasesByType();
// { Major: 1, Minor: 1, Patch: 0, PreRelease: 0 }
// Date range query
var recent = history.GetBetween(
DateTimeOffset.UtcNow.AddMonths(-3),
DateTimeOffset.UtcNow);
Changelog & Release Notes
// Full changelog
string changelog = history.GenerateChangelog();
// # Changelog
// ## 2.0.0 (2024-06-15)
// - feat!: new API
// ...
// Release notes for a specific version
string notes = history.GenerateReleaseNotes(SemanticVersion.Parse("2.0.0"));
// # Release 2.0.0
// Released: 2024-06-15
// Previous: 1.1.0
// Time since last release: 30 days
// ...
// Version diff
string diff = history.GetDiff(
SemanticVersion.Parse("1.0.0"),
SemanticVersion.Parse("2.0.0"));
Rollback & Timeline
// Find rollback target
var rollback = history.FindRollbackTarget(SemanticVersion.Parse("2.0.0"));
// 1.1.0 (previous stable)
// Visual timeline
string timeline = history.GetTimeline();
// ● 1.0.0 2024-01-15 Initial release
// ● 1.1.0 2024-03-01 Feature release
// ● 2.0.0 2024-06-15 Major release
// Export as JSON
string json = history.ExportJson();
License
See LICENSE file.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.1 is compatible. |
| .NET Framework | net48 is compatible. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETFramework 4.8
- No dependencies.
-
.NETStandard 2.1
- No dependencies.
-
net6.0
- No dependencies.
-
net7.0
- No dependencies.
-
net8.0
- No dependencies.
NuGet packages (8)
Showing the top 5 NuGet packages that depend on EonaCat.Versioning.Helpers:
| Package | Downloads |
|---|---|
|
EonaCat.Dns
This is a Dns Server |
|
|
EonaCat.Logger
EonaCat.Logger is a logging library |
|
|
EonaCat.Versioning
Generate build information of GIT and SVN to be used as your product versioning. |
|
|
EonaCat.Security
EonaCat Security library |
|
|
EonaCat.LogStack
flow-based logging library for .NET, designed for zero-allocation logging paths and superior memory efficiency. It features a rich fluent API for routing log events to dozens of destinations from console and file to Slack, Discord, Redis, Elasticsearch, and beyond. |
GitHub repositories
This package is not used by any popular GitHub repositories.