A dotnet core CLI tool that maintains the semantic version of your dotnet assemblies and git tags based on a git commit message convention. This repository and tool version are currently maintained by this tool.
Versioning.NET is designed to take the responsibility of maintaining the version of the code away from the developers, but still allow developers to control the outcome of the versioning automation through their commit messages. Although this tool works locally, it's intended and recommended to be utilized on CI servers where the developer can be abstracted.
In short, the tool will read the commits on the specified branch (passed in as a command parameter), parse through the commit history starting from HEAD and traversing back to the latest version tag (commonly referred to as git height
) looking for commit hints in order to determine the version increment (Major, Minor, Patch, or None), update all of the .csproj files in a single commit using the determined increment, and finally create and push a git tag to that commit representing the semantic version.
The tool currently works with a single branch. This branch will be used for maintaining the version tags and will also be used to determine which commits will be included when determining what the latest version will be. It is recommended to select a long-lived branch such as master, main, or dev, but other branches can be used for testing without impacting current versions.
Git Flow - It is possible to work with Git Flow. When release branches are cut, the version will not increase on the release branch, but each bug fix that is merged back into the versioned branch will cause the version to increment. However, because commits will be entering the release branch and not affecting the version that is deployed, this may not be a desired result.
GitHub Flow - This flow is more appropriate for this tool as feature branches are merged into the target branch, the version increments appropriately, and the code is deployed immediately afterwards, promoting continuous release.
In order for the tool to work with any git repository, it expects that a remote target has been configured with credentials. When running the command, passing in the git repository path and the name of the configured remote target is sufficient.
When the tool is looking through the commits for hints
, it's expecting that the commits follow a this convention in order to determine the version increment. Currently, commits that do not follow this convention are ignored (not desired and will updated to default to Patch) and will not be included when calculating the version. When commits do follow the convention, but it is not desired for the commit to affect the version, it is possible to include a hint that will tell the tool to ignore it (see Commit Hints). This is useful when updating parts of the repository that are not deployed such as documentation and build scripts.
Currently, this tool only supports updating .csproj files targeting the <Version>
and <VersionPrefix>
elements. In the future, other ways of maintaining version info for dotnet projects such as AssemblyInfo.cs
are expected to be supported. The .csproj files that are targeted are in the git repository and have the previously mentioned xml elements. This means that repositories with more than one project (mono-repo) is not currently supported. It is also expected to have path filtering supported in a later version so that files changed by the commit are only included when the file path is a child of a specified path filter.
Once the version increment has been determined and the files have been updated, the tool will create a git commit with a message (not yet configurable) describing the version changes. In order to avoid circular builds, CI servers are required to support [skip ci]
(both Azure DevOps Pipelines and GitHub Actions support this) in the commit message to stop the version commit from triggering another build. The following is an example commit from the tool:
ci(Versioning): Increment version 0.3.1 -> 0.3.2 [skip ci] [skip hint]
This commit will not trigger another build, provided that the CI server supports the skip build hint, and the commit will also not be included in subsequent version increments. Once the commit exists, the commit ID will be targeted when pushing the semver git tag to remote.
This section will provide an example scenario to give a more clear picture of what is happening.
Assume that the following commits exist on the master branch.
// HEAD on master
82d2d2a feat(Versioning): Changed git integration from PowerShell to LibGit2Sharp #breaking
38basd2 fix(Versioning): Fixed issue where git tag could not be found
23a32s3 feat(Versioning): Added support to modify .csproj files
828asd2 docs(README): Updated overview section [skip hint]
28s8d28 Updated some files
// Latest version tag: v1.1.5 (targeting 67ds273)
67ds273 ci(Versioning): Increment version 1.1.4 -> 1.1.5 [skip ci] [skip hint]
The commits above the v1.1.5 tag will be used to determine the version increment, here's what the tool will do:
#breaking
is found.fix
is found.feat
is found.[skip hint]
was found.In a later version, when no hint is found, the increment will default to Patch.
When all the commits have been assigned a version increment, the highest priority is used to determine what the final increment will be. The version increment that will result from the above commits is Major.
// HEAD on master
// Latest version tag: v2.0.0 (targeting 87sd2s2)
87sd2s2 ci(Versioning): Increment version 1.1.5 -> 2.0.0 [skip ci] [skip hint]
82d2d2a feat(Versioning): Changed git integration from PowerShell to LibGit2Sharp #breaking
38basd2 fix(Versioning): Fixed issue where git tag could not be found
23a32s3 feat(Versioning): Added support to modify .csproj files
828asd2 docs(README): Updated overview section [skip hint]
28s8d28 Updated some files
// Latest version tag: v1.1.5 (targeting 67ds273)
67ds273 ci(Versioning): Increment version 1.1.4 -> 1.1.5 [skip ci] [skip hint]
Below is an excerpt from the code showing how increment priority is determined.
List<VersionIncrement> incrementsList = increments.ToList();
bool isBreaking = incrementsList.Any(x => x == VersionIncrement.Major);
bool isMinor = incrementsList.Any(x => x == VersionIncrement.Minor);
bool isPatch = incrementsList.Any(x => x == VersionIncrement.Patch);
bool isNone = incrementsList.Any(x => x == VersionIncrement.None);
return isBreaking ? VersionIncrement.Major
: isMinor ? VersionIncrement.Minor
: isPatch ? VersionIncrement.Patch
: isNone ? VersionIncrement.None
: VersionIncrement.Unknown;
Get started by first installing the tool.
dotnet tool install --global Versioning.NET
Once the tool is installed, run dotnet-version
to see the help menu.
Usage: dotnet-version [command] [options]
Options:
-?|-h|--help Show help information.
Commands:
increment-version
increment-version-with-git
Run 'dotnet-version [command] -?|-h|--help' for more information about a command.
For more information on the command details, see the wiki page for Commands.
Want to add a feature or fix a bug? Glad to have the help! There's just a couple of things to go over before you start submitting pull requests:
These templates are licensed under the MIT License.