Giter Club home page Giter Club logo

verlite's Introduction

Logo

Verlite

Verlite.MsBuild Verlite.CLI Verlite.Core
Codecov Mutation testing score

Versioning with SemVer 2 Git tags. Automatically set the version from Git tags for .NET Core SDK-style projects, or use the CLI tool for all others. Platform agnostic.

Usage

Add the following to your Directory.Build.props or csproj:

<ItemGroup>
  <PackageReference Include="Verlite.MsBuild" Version="x.y.z" PrivateAssets="All" />
</ItemGroup>

Optionally, if your CI/CD pipelines use shallow clones (such as GitHub Actions by default), add build steps to automatically deepen the repository to—and fetch—the nearest tag:

dotnet tool install --global Verlite.CLI --version "x.y.z"
verlite --auto-fetch

Goals and Scope

Verlite aims to fall somewhere between MinVer and GitVersion—using the same versioning scheme as MinVer, with a slightly richer and more flexible feature set.

Verlite is aimed at continuous delivery workflows, not continuous deployment workflows—where versions are denoted from a branching model or commit messages. Instead with Verlite, tags are the source of truth for versions. Any versions with height attached (see version calculation) are intended only for development purposes and to not be released to the primary feed.

Versioning based upon commit messages or branches is out of scope. Such can be done via passing different options into Verlite by your build process, but keep in mind this is not a supported workflow of Verlite, so shouldn't be done for release critical aspects.

Version Calculation

Take the head commit, if one or more version tags exist, use the highest version, otherwise, keep following all parents until a version tag is found, taking the highest version tag, then bumping the version and appending the "commit height" onto the end.

To bump the version, the patch is by default incremented by 1. The version part to bump can be configured via VerliteAutoIncrement/--auto-increment option.

The commit height is applied by concatenating the prerelease tag, a separator ("."), and the height together, where the prerelease tag is either the last tagged version's prerelease, or if not found/was not a prerelease, using the VerliteDefaultPrereleasePhase/--default-prerelease-phase option.

See docs/VersionCalculation.md for further reading.

Options

Description CLI Short, CLI Long, MsBuild Property Default
Disable invoking Verlite. VerliteDisabled false
Tags starting with this represent versions. -t, --tag-prefix, VerliteTagPrefix v
Disable the version prefix. VerliteDisableTagPrefix false
The default phase for the prerelease label -d, --default-prerelease-phase, VerliteDefaultPrereleasePhase alpha
The minimum RTM version that's a core version without a prerelease. -m, --min-version, VerliteMinimumVersion 0.1.0
The height for continuous deliverable auto heights should begin at. -p, --prerelease-base-height, VerlitePrereleaseBaseHeight 1
Force the calculated version to be this version. --version-override, VerliteVersionOverride
Logging level. --verbosity, VerliteVerbosity normal
Set the build data to this value. -b, --build-metadata, VerliteBuildMetadata
Part of the version to print. -s, --show all
Automatically fetch commits and a tag for shallow clones. --auto-fetch false
Create a lightweight tag instead of fetching the remote's. --enable-lightweight-tags false
Set which version part should be bumped after an RTM release. -a, --auto-increment, VerliteAutoIncrement patch
A command to test whether a tag should be ignored via exit code. -f, --filter-tags, VerliteFilterTags
The remote endpoint to use when fetching tags and commits. -r, --remote, VerliteRemote origin
Generate version strings and embed them via a source generator. VerliteEmbedVersion true
Use a shadow repo (partial, only commits) to read commit history. --enable-shadow-repo, VerliteEnableShadowRepo false

Comparison with GitVersion

GitVersion has a focus on branches, and is well suited for a Continuous Deployment workflow, where releases are triggered based upon branches or commit messages. Shallow repositories are not supported.

Verlite cares only about tags, and is well suited for Continuous Delivery workflows, where official releases happen by tagging.

Comparison with MinVer

MinVer's behavior is a subset of Verlite, and so we can configured Verlite to behave the same with the following properties set:

<PropertyGroup>
	<VerliteDisableTagPrefix>true</VerliteDisableTagPrefix>
	<VerliteDefaultPrereleasePhase>alpha.0</VerliteDefaultPrereleasePhase>
<PropertyGroup>

Additionally, Verlite has some extra features, some of which I required or desired, hence the creation of this project. These are:

  • Shallow repositories are fully supported.
    • Fetch tags and commits needed for calculating the version with verlite --auto-fetch.
    • Error out if the repository is too shallow instead of silently returning an incorrect version.
  • Continuous Delivery versions can start at the first prelease ordinal to reduce long version fatigue. That is to say, after tagging 1.0.0, the next CD version by default is 1.0.1-alpha.1 instead of 1.0.1-alpha.0.1.
    • CD releases after a tagged prerelease behave identical to MinVer, for example, the commit after 1.0.0-rc.1 becomes 1.0.0-rc.1.1 and not 1.0.0-rc.2.
  • The default base height after a tag can be set, such as 1.0.0 -> 1.0.1-alpha.0.
  • Scripts can query Verlite for a specific version part.

FAQ

Why Verlite?

For if you find GitVersion too complex and MinVer too minimal for your needs. Verlite is a superset of MinVer, but takes on a small amount of complexity to provide a simpler to use tool.

Can I bump the major or minor parts after an RTM tag?

Yes, the VerliteAutoIncrement option will specify which version part should be bumped after an RTM tag.

Can I change the default phase?

Yes, the the default phase of alpha can be changed using the VerliteDefaultPrereleasePhase option.

Why is the default phase "alpha" and not "alpha.0"?

To reduce fatigue. The first commits after a stable tag are likely to be either: hotfixes that are quickly released, or a merge window opening up, resulting in a flurry of change that developers directly consume from the CD pipeline. Therefore, the default behavior is to omit the leading zero, and keep these particular versions as short as possible.

Should the you prefer alpha.0.n be used after a stable release instead of alpha.n, the VerliteDefaultPrereleasePhase can be set to alpha.0.

Can prereleases be tagged?

You should only release tagged prereleases. Then for subsequent untagged commits, they will be versioned with the tagged version with the height appended. For example, the next commit after 2.0.0-rc.1 may be versioned as 2.0.0-rc.1.1.

Can I get the commit hash?

Yes, the commit hash is exposed in the $(VerliteCommit) property which can be used after the Verlite task has run.

Can I use a branching strategy?

Sort of. Verlite is intended for tags to be the cause of a release, not an effect of a release. Verlite is not aware of named branches, and will not natively take them into account for version calculation, instead using only the commit graph and tags for version calculation.

Should you chose to, Verlite can be configured to produce different versions using MsBuild's Condition attribute under CI pipelines, for example:

<!-- apply the PR number for PR builds -->
<PropertyGroup Condition="$(GITHUB_ACTIONS.StartsWith('refs/pull/'))">
  <VerliteBuildMetadata>pr.$(GITHUB_REF.Substring(10))</VerliteBuildMetadata>
</PropertyGroup>
<!-- apply the branch name for branch builds -->
<PropertyGroup Condition="$(GITHUB_ACTIONS.StartsWith('refs/heads/'))">
  <VerliteBuildMetadata>branch.$(GITHUB_REF.Substring(11))</VerliteBuildMetadata>
</PropertyGroup>
<!-- mark locally build builds with +local -->
<PropertyGroup Condition="'$(GITHUB_ACTIONS)' == ''">
  <VerliteBuildMetadata>local</VerliteBuildMetadata>
</PropertyGroup>

Can Verlite be used elsewhere?

Yes, the command line tool can be used elsewhere, for example, in Conan packages:

from six import StringIO

def Project(ConanFile):
    # ...
    def set_version(self):
        buf = StringIO()
        self.run(f"verlite --auto-fetch {self.recipe_folder}", output=buf)
        self.version = buf.getvalue()

What is the default tag prefix?

The default tag prefix is v, so a tag of v1.2.3 is interpreted as SemVer 1.2.3.

The default prefix can be set to nothing by setting VerliteDisableTagPrefix to true for MsBuild, or --tag-prefix="" for the CLI. It can be changed to an arbitrary value setting VerliteTagPrefix or --tag-prefix.

Can multiple versions be nested?

Yes, by setting a unique VerliteTagPrefix for each project.

Can shallow clones be used?

Yes, with a caveat—for performance reasons verlite --auto-fetch must be invoked to deepen the repository prior to building. To avoid footguns, auto-fetching is not exposed under MsBuild as to the need to query the remote for each project would slow down build times too much.

What happens if auto fetch isn't used?

Nothing unsafe. In the event a clone is not deep enough, an exception will be thrown and the build will fail, instead of calculating an incorrect version number silently.

Footguns not included.

Can I use only signed/specific/arbitrary tags?

Yes, this can be done by supplying a command in --filter-tags/VerliteFilterTags that Verlite will execute and then read the exit code. In the supplied command {} will be substituded with the tag under question, along with a number of environment variables set. As an example, the following will only take into account tags signed with a trusted private key, ignoring all others:

<PropertyGroup>
	<VerliteFilterTags>git tag --verify {}</VerliteFilterTags>
</PropertyGroup>

See docs/FilteringTags.md for further reading.

What is a good changelog strategy?

While not related to Verlite per se, a good method for which changes to include in your release notes is: include all changes since the last version which was as equally stable or better.

Changelogs for _____ releases should contain changes since the last _____ build.
stable stable
release candidate release candidate or stable
beta beta, release candidate, or stable
alpha alpha, beta, release candidate, or stable

What happens if tag buildmeta and options buildmeta are set?

If a tag with height is being used, the build metadata is discarded, and the options's build metadata used if present. In the case of both tag without height and options having build metadata, they are concatenated together with a hash.

Tagging a release as say, v1.2.3+abc and also specifying --build-metadata xyz will result in a final version of 1.2.3+abc-xyz.

Can I access computed versions in my assembly?

Yes, since v2.1, the computed versions are added by default using a source generator. This can be disabled by setting the VerliteEmbedVersion property to false.

The embedded version is structured as follows:

namespace Verlite
{
	internal static class Version
	{
		public const string Full;
		public const string Core;
		public const string Major;
		public const string Minor;
		public const string Patch;
		public const string Prerelease;
		public const string BuildMetadata;
		public const string Commit;
		public const string Height;
	}
}

Can others access computed versions in the assembly?

No, the generated structure is marked as internal, and only visible to your assembly. Should you wish to expose this version, it is recomended you use a public static property:

namespace MyLibrary;
public static class Version
{
	public string Version => Verlite.Version.FullVersion;
}

What is a shadow repo?

Using a shadow repo is an experimental method of allowing shallow depth=1 clones without causing any issues with Verlite. A special repo within your repositories .git directory will be created and updated as needed, where only commits are fetched (via --filter=tree:0).

Can I query the version from the command line for a project?

Yes, this has been possible since .NET 8 with the following command:

$ dotnet msbuild $ProjectPath -getproperty:Version -target:Restore,Verlite

verlite's People

Contributors

ashleighadams avatar dependabot-preview[bot] avatar dependabot[bot] avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

verlite's Issues

Allow Framework Projects

As it stands now, Verlite.MsBuild targets .NET Standard 2.0. The restriction imposed is likely to be artificial and self-imposed. It might be worth derestricting the Framework requirement, and possibly for completion, adding an AssemblyInfo.cs generator for version information.

Add integration tests

Unit tests are great for verifying the algorithms and core logic and all, but sometimes you really just need to test the thing in full.

Some integration tests should be added to test some real-world repositories/use cases:

  • No tags.
  • A direct tag.
  • A direct tag with many versions.
  • Test auto fetching behavior.
  • Test branching with multiple parents.
  • Test the output of the CLI.
    • Tag prefix.
    • Minimum version.
    • Auto increment.
    • Test version override.
    • Show part.
  • Test the following crucial msbuild params.
    • Tag prefix.
    • Minimum version.
    • Auto increment.
    • Test version override.

Best practice in Azure DevOps and Verlite

Hey guys,

In our team we are trying to implement a versioning system for our NuGet projects. In short what are we trying to achieve is exactly like in this photo: https://raaviblog.com/wp-content/uploads/gitversion-2.png

I know Verlite and MinVer are branch agnostic and it's all about tags, but is there a way we can use Verlite to behave this way?

The problem is that we are using DevOps Pipelines, therefore every commit in every feature or hotfix branch will autogenerate a new NuGet package that can be tested by developers and Q&A. Therefore we can't have 2 feature branches create the same NuGet package.

We tested GitVersion already and wasted over 30 hours, it behave randomly especially on PR build and PR merges to main.

Investigate alternate ways to fetch original tags

For now, --enable-lightweight-tags can be used with --auto-fetch to create tags locally, but if instead annotated tags are present, and the developer desires them, fetching them is proving somewhat problematic, where the tags aren't correctly being pulled down in a way that allows future verlite invocations to find those tags. With new Git versions, it might be possible to fetch only the tags with --filter=object:type=tag

https://github.com/git/git/blob/master/Documentation/rev-list-options.txt

Verlite.MsBuild beta is broken

The new style MsBuild project is breaking when used in a project with Visual Studio (MsBuild using Framework), even with .NET Core projects.

For this reason, the .NET Standard version needs to drop to 2.0.

Make appending a dot after prerelease phases optional.

Instead of forcing a tag structure upon consumers---the reason for this project's creation to begin with---Verlite should be agnostic, and be configurable, but provide sane defaults. This flexibility is intended to allow the adoption of Verlite without necessitating a change to the structure of existing versions.

For this reason, I believe the following options should be added to VersionCalculationOptions:

public enum PhaseSeperatorRule
{
	Alphanumeric = default,
	Numeric = 1,
}
public class VersionCalculationOptions
{
	// ...
	public PhaseSeperatorRule PhaseSeperationRule { get; set; } = default;
	public string PhaseSeperator { get; set; } = ".";
}

This would then allow CD prebuilds to go out structured as 1.0.0-alpha1 instead of 1.0.0-alpha.1 (taking care to ensure 1.0.0-rc.2.1 on tagged prereleases is retained with the Numeric option).

Standalone binaries

For other ecosystems not under .NET, for example, Conan, dotnet may not be installed, nor be desirable to install, therefore there should be official standalone binaries attached to the release page.

Config file

Instead of specifying all options thru CLI args or MsBuild properties, it may be beneficial to have a yml Verlite can point to instead, so CI/CD verlites, such as autofetching, won't need to by synced up.

Allow "one-time" bumping of a version part to better support CI/CD

As I understand it currently when using the CLI, I can only set the auto increment portion at the command line using -a patch which is probably fine for many cases. However, it would be nice to be able to indicate to verlite that the next version is going to be a new minor or even major version bump without having to specify -a minor every time on the command line going forward until the next RTM. Perhaps supporting a tag or commit message like "bump-minor". That way CI/CD systems could still use the default "patch" auto-increment without having to update the command line used.

I recognize that I COULD tag the commit with something like v1.1.0-beta.1 and I would be okay with that except for the way the next commit version gets calculated. I need the next commit to be v1.1.0-beta.2 and not v1.1.0-beta.1.1 because the latter is not valid for python pypi packages and I don't have enough information to convert the version to a PEP 440 compliant version at that point. Note that the former is not technically compliant either but the python tooling is able to convert it to 1.1.0b2 on its own. This sounds similar to your own proposal #7 and possibly could be solved using a slightly expanded mechanism as what's proposed in that issue.

Alternatively, and I thought about making a separate feature request for this, I would love to see an option such as --output json or add "json" to existing -s that would dump out a structured listing of all of the version parts and possibly additional information (height, for example) that verlite used to calculate said version. This would allow scripts/external tooling to more easily parse the output of verlite and come up with its own version format. That would also allow users of verlite to handle your proposal #7 . "environment" would be another option that would spit out the version parts to environment variables which would also be huge for CI/CD systems and you sort of already do capture those parts when using --filter-tags with "VERLITE_VERSION_MAJOR" etc.

Our project consists of multiple python and C# projects and I would love to use a single tool to help us with versioning. We were using GitVersion but for some reason it stopped working and just errors out during our builds complaining about a "detached head" (and it's always been a detached head when using AzureDevOps). Verlite looks like it could be that tool and I appreciate your time and consideration of this request!

Version regarding merges is counter intuitive

Because Verlite only follows first parents by design for version calculation, intuitive and actual behavior diverge given the following state:

branches

I would expect feature to be versioned as 2.0.1-alpha.1, given that master was tagged with a 2.0.0 release. Instead, it will be versioned as 1.2.4-alpha.2, taking only the direct tag from before.

Changing this behavior is a breaking change. The expected behavior is also how MinVer functions.

Allow filtering tags

Filtering tags would be extremely handy for some workflows, such as those that should require signed commits, only use annotated tags, etc.

My proposal is something similar to Pandoc's filters or find's -exec, where a command can be executed and the return value tested, such as verlite --filter "git tag -v {}".

Documentation

The following things should be done:

  • Describe the difference between:
    • GitVersion
    • MinVer
  • Document height calculation
    • High level
    • In depth
  • Usage
  • What each of the different options does
  • Why this was created, and project scope
  • FAQ

Shadow repo does not take authentication details for Github Actions pipeline

Description

GitHub sets some repo-local authentication header within .git/.gitconfig, for which the shadow clone will not receive.

Reproduction steps

Attempt to use verlite . --auto-fetch --enable-shadow-repo in a GitHub Actions pipeline with a depth=0 clone.

Expected behavior

The tags to be fetched and a shadow repo set up, fetching commits as needed

Actual behavior

Authentication failure

Regression?

No, a result of the new shadow clone feature

Known workarounds

No response

Configuration

2.5.0-rc.1

Other information

No response

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.