Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions docfx/docs/build-systems/msbuild.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,15 @@ Property | Default | Description
`NBGV_ThisAssemblyIncludesPackageVersion` | `false` | When `true`, a `NuGetPackageVersion` property is added to the `ThisAssembly` class.
`NBGV_UseAssemblyVersionInNativeVersion` | `true` | When `false`, uses the `AssemblyFileVersion` as a native `PRODUCTVERSION`.

### Items

The following MSBuild items may be declared in your project to customize the computed version:

Item type | Description
--|--
`BuildMetadata` | Adds `+ItemName` build metadata for each item to the computed version.
`PrereleaseIdentifier` | Adds `-ItemName` build metadata for each item to the computed version.

### Custom `ThisAssembly` static fields and constants

Custom constants may be added to the `ThisAssembly` class through `AdditionalThisAssemblyFields` items defined in your project.
Expand Down
32 changes: 31 additions & 1 deletion src/NerdBank.GitVersioning/VersionOracle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,31 @@ public IEnumerable<string> BuildMetadataWithCommitId
/// <summary>
/// Gets the prerelease version information, including a leading hyphen.
/// </summary>
public string PrereleaseVersion => this.ReplaceMacros(this.VersionOptions?.Version?.Prerelease ?? string.Empty);
/// <value>An empty string for a stable release, or a string like <c>-beta</c>.</value>
public string PrereleaseVersion
{
get
{
string result = this.ReplaceMacros(this.VersionOptions?.Version?.Prerelease ?? string.Empty);

foreach (string identifier in this.ExtraPrereleaseIdentifiers)
{
if (result.Length == 0)
{
result = "-";
}
else
{
// In semver v2, identifiers should be separated by periods.
result += this.VersionOptions?.NuGetPackageVersionOrDefault.SemVerOrDefault >= 2 ? '.' : '-';
}

result += identifier;
}

return result;
}
}

/// <summary>
/// Gets the prerelease version information, omitting the leading hyphen, if any.
Expand Down Expand Up @@ -379,6 +403,12 @@ public IDictionary<string, string> CloudBuildVersionVars
[Ignore]
public List<string> BuildMetadata { get; } = new List<string>();

/// <summary>
/// Gets a list of prerelease identifiers to add to whatever the default prerelease identifiers are.
/// </summary>
[Ignore]
public List<string> ExtraPrereleaseIdentifiers { get; } = new List<string>();

/// <summary>
/// Gets the +buildMetadata fragment for the semantic version.
/// </summary>
Expand Down
15 changes: 10 additions & 5 deletions src/Nerdbank.GitVersioning.Tasks/GetBuildVersion.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
// Copyright (c) .NET Foundation and Contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using MSBuildExtensionTask;
Expand All @@ -28,6 +23,11 @@ public GetBuildVersion()
/// </summary>
public string BuildMetadata { get; set; }

/// <summary>
/// Gets or sets an array of prerelease identifiers to append to whatever else may be determined by default.
/// </summary>
public string PrereleaseIdentifiers { get; set; }

/// <summary>
/// Gets or sets the value of the PublicRelease property in MSBuild at the
/// start of this Task.
Expand Down Expand Up @@ -256,6 +256,11 @@ protected override bool ExecuteInner()
oracle.BuildMetadata.AddRange(this.BuildMetadata.Split(';'));
}

if (this.PrereleaseIdentifiers is { Length: > 0 })
{
oracle.ExtraPrereleaseIdentifiers.AddRange(this.PrereleaseIdentifiers.Split(';'));
}

if (IsMisconfiguredPrereleaseAndSemVer1(oracle))
{
this.Log.LogWarning("The 'nugetPackageVersion' is explicitly set to 'semVer': 1 but the prerelease version '{0}' is not SemVer1 compliant. Change the 'nugetPackageVersion'.'semVer' value to 2 or change the 'version' member to follow SemVer1 rules (e.g.: '{1}').", oracle.PrereleaseVersion, GetSemVer1WithoutPaddingOrBuildMetadata(oracle));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
CallTarget invoked targets do not see properties set by the calling target. -->
<PropertyGroup>
<BuildMetadata>@(BuildMetadata, ',')</BuildMetadata>
<PrereleaseIdentifiers>@(PrereleaseIdentifier, ',')</PrereleaseIdentifiers>
</PropertyGroup>
</Target>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@
<NBGV_GlobalPropertiesToRemove Include="RuntimeIdentifier" />

<_BuildMetadataSnapped Include="@(BuildMetadata)" />
<_PrereleaseIdentifierSnapped Include="@(PrereleaseIdentifier)" />
</ItemGroup>

<ItemGroup>
<NBGV_CachingProjectReference Include="$(NBGV_CachingProjectReference)">
<Targets>GetBuildVersion_Properties;GetBuildVersion_CloudBuildVersionVars</Targets>
<Properties>$(NBGV_InnerGlobalProperties)BuildMetadata=@(BuildMetadata, ',');</Properties>
<Properties>$(NBGV_InnerGlobalProperties)BuildMetadata=@(BuildMetadata, ',');PrereleaseIdentifiers=@(PrereleaseIdentifier, ',')</Properties>
<SetConfiguration>Configuration=Release</SetConfiguration>
<SetPlatform>Platform=AnyCPU</SetPlatform>
<GlobalPropertiesToRemove>@(NBGV_GlobalPropertiesToRemove)</GlobalPropertiesToRemove>
Expand All @@ -44,6 +45,7 @@

<Target Name="InvokeGetBuildVersionTask">
<Error Text="BuildMetadata items changed after a copy was made. Add all BuildMetadata items before importing this file." Condition=" '@(BuildMetadata)' != '@(_BuildMetadataSnapped)' " />
<Error Text="PrereleaseIdentifier items changed after a copy was made. Add all PrereleaseIdentifier items before importing this file." Condition=" '@(PrereleaseIdentifier)' != '@(_PrereleaseIdentifierSnapped)' " />

<!-- Calculate version by invoking another "project" with global properties that will serve as a key
into an msbuild cache to ensure we only invoke the GetBuildVersion task as many times as will produce a unique value. -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<Nerdbank.GitVersioning.Tasks.GetBuildVersion
BuildingRef="$(_NBGV_BuildingRef)"
BuildMetadata="$(BuildMetadata.Replace(',',';'))"
PrereleaseIdentifiers="$(PrereleaseIdentifiers.Replace(',',';'))"
DefaultPublicRelease="$(PublicRelease)"
ProjectDirectory="$(GitVersionBaseDirectory)"
GitRepoRoot="$(GitRepoRoot)"
Expand Down
15 changes: 15 additions & 0 deletions test/Nerdbank.GitVersioning.Tests/BuildIntegrationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,21 @@ public async Task GetBuildVersion_Without_Git_HighPrecisionAssemblyVersion()
Assert.Equal("3.4.0", buildResult.AssemblyInformationalVersion);
}

[Fact]
public async Task WithExtraPrereleaseIdentifiers()
{
this.WriteVersionFile(new VersionOptions
{
Version = SemanticVersion.Parse("3.4"),
});
this.InitializeSourceControl();
this.testProject.AddItem("PrereleaseIdentifier", "i1");
this.testProject.AddItem("PrereleaseIdentifier", "i2");
this.globalProperties["PublicRelease"] = "true";
BuildResults buildResult = await this.BuildAsync();
Assert.Matches(@"^3\.4\.[01]-i1-i2$", buildResult.NuGetPackageVersion);
}

// TODO: add key container test.
[Theory]
[InlineData("keypair.snk", false)]
Expand Down
105 changes: 105 additions & 0 deletions test/Nerdbank.GitVersioning.Tests/VersionOracleTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,111 @@ public void SemVerStableNonPublicVersionShortened()
Assert.Matches(@"^2.3.1-g[a-f0-9]{7}$", oracle.ChocolateyPackageVersion);
}

[Fact]
public void ExtraPrereleaseIdentifiers_StableBase_V1()
{
var workingCopyVersion = new VersionOptions
{
Version = SemanticVersion.Parse("2.3"),
NuGetPackageVersion = new VersionOptions.NuGetPackageVersionOptions
{
SemVer = 1,
},
};
this.WriteVersionFile(workingCopyVersion);
this.InitializeSourceControl();
VersionOracle oracle = new(this.Context)
{
ExtraPrereleaseIdentifiers = { "i1", "i2" },
PublicRelease = true,
};
Assert.Equal(@"2.3.1-i1-i2", oracle.NuGetPackageVersion);
}

[Fact]
public void ExtraPrereleaseIdentifiers_StableBase_V2()
{
var workingCopyVersion = new VersionOptions
{
Version = SemanticVersion.Parse("2.3"),
NuGetPackageVersion = new VersionOptions.NuGetPackageVersionOptions
{
SemVer = 2,
},
};
this.WriteVersionFile(workingCopyVersion);
this.InitializeSourceControl();
VersionOracle oracle = new(this.Context)
{
ExtraPrereleaseIdentifiers = { "i1", "i2" },
PublicRelease = true,
};
Assert.Equal(@"2.3.1-i1.i2", oracle.NuGetPackageVersion);
}

[Fact]
public void ExtraPrereleaseIdentifiers_StableBase_V2_NonPublic()
{
var workingCopyVersion = new VersionOptions
{
Version = SemanticVersion.Parse("2.3"),
NuGetPackageVersion = new VersionOptions.NuGetPackageVersionOptions
{
SemVer = 2,
},
};
this.WriteVersionFile(workingCopyVersion);
this.InitializeSourceControl();
VersionOracle oracle = new(this.Context)
{
ExtraPrereleaseIdentifiers = { "i1", "i2" },
PublicRelease = false,
};
Assert.Matches(@"^2\.3\.1-i1\.i2\.g", oracle.NuGetPackageVersion);
}

[Fact]
public void ExtraPrereleaseIdentifiers_UnstableBase_V1()
{
var workingCopyVersion = new VersionOptions
{
Version = SemanticVersion.Parse("2.3-abc"),
NuGetPackageVersion = new VersionOptions.NuGetPackageVersionOptions
{
SemVer = 1,
},
};
this.WriteVersionFile(workingCopyVersion);
this.InitializeSourceControl();
VersionOracle oracle = new(this.Context)
{
ExtraPrereleaseIdentifiers = { "i1", "i2" },
PublicRelease = true,
};
Assert.Equal(@"2.3.1-abc-i1-i2", oracle.NuGetPackageVersion);
}

[Fact]
public void ExtraPrereleaseIdentifiers_UnstableBase_V2()
{
var workingCopyVersion = new VersionOptions
{
Version = SemanticVersion.Parse("2.3-abc"),
NuGetPackageVersion = new VersionOptions.NuGetPackageVersionOptions
{
SemVer = 2,
},
};
this.WriteVersionFile(workingCopyVersion);
this.InitializeSourceControl();
VersionOracle oracle = new(this.Context)
{
ExtraPrereleaseIdentifiers = { "i1", "i2" },
PublicRelease = true,
};
Assert.Equal(@"2.3.1-abc.i1.i2", oracle.NuGetPackageVersion);
}

[Theory]
[InlineData("1.2.0.0", null, null)]
[InlineData("1.0.0.0", null, VersionOptions.VersionPrecision.Major)]
Expand Down