diff --git a/test/Nerdbank.GitVersioning.Tests/BuildIntegrationInProjectManagedTests.cs b/test/Nerdbank.GitVersioning.Tests/BuildIntegrationInProjectManagedTests.cs
new file mode 100644
index 00000000..ea0e4a47
--- /dev/null
+++ b/test/Nerdbank.GitVersioning.Tests/BuildIntegrationInProjectManagedTests.cs
@@ -0,0 +1,22 @@
+// 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 Xunit;
+using Xunit.Abstractions;
+
+[Trait("Engine", EngineString)]
+[Collection("Build")] // msbuild sets current directory in the process, so we can't have it be concurrent with other build tests.
+public class BuildIntegrationInProjectManagedTests : BuildIntegrationManagedTests
+{
+ public BuildIntegrationInProjectManagedTests(ITestOutputHelper logger)
+ : base(logger)
+ {
+ }
+
+ ///
+ protected override void ApplyGlobalProperties(IDictionary globalProperties)
+ {
+ base.ApplyGlobalProperties(globalProperties);
+ globalProperties["NBGV_CacheMode"] = "None";
+ }
+}
diff --git a/test/Nerdbank.GitVersioning.Tests/BuildIntegrationManagedTests.cs b/test/Nerdbank.GitVersioning.Tests/BuildIntegrationManagedTests.cs
index 5231dfa1..f7b839dc 100644
--- a/test/Nerdbank.GitVersioning.Tests/BuildIntegrationManagedTests.cs
+++ b/test/Nerdbank.GitVersioning.Tests/BuildIntegrationManagedTests.cs
@@ -9,7 +9,7 @@
[Collection("Build")] // msbuild sets current directory in the process, so we can't have it be concurrent with other build tests.
public class BuildIntegrationManagedTests : SomeGitBuildIntegrationTests
{
- private const string EngineString = "Managed";
+ protected const string EngineString = "Managed";
public BuildIntegrationManagedTests(ITestOutputHelper logger)
: base(logger)
diff --git a/test/Nerdbank.GitVersioning.Tests/BuildIntegrationTests.cs b/test/Nerdbank.GitVersioning.Tests/BuildIntegrationTests.cs
index 6453aa7d..c694b991 100644
--- a/test/Nerdbank.GitVersioning.Tests/BuildIntegrationTests.cs
+++ b/test/Nerdbank.GitVersioning.Tests/BuildIntegrationTests.cs
@@ -1,6 +1,8 @@
// 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.Collections.Immutable;
+using System.Globalization;
using System.Reflection;
using System.Text;
using System.Xml;
@@ -15,11 +17,20 @@
using Validation;
using Xunit;
using Xunit.Abstractions;
+using Version = System.Version;
public abstract class BuildIntegrationTests : RepoTestBase, IClassFixture
{
- protected const string GitVersioningTargetsFileName = "NerdBank.GitVersioning.targets";
+ protected const string GitVersioningPropsFileName = "Nerdbank.GitVersioning.props";
+ protected const string GitVersioningTargetsFileName = "Nerdbank.GitVersioning.targets";
protected const string UnitTestCloudBuildPrefix = "UnitTest: ";
+ protected static readonly string[] ToxicEnvironmentVariablePrefixes = new string[]
+ {
+ "APPVEYOR",
+ "SYSTEM_",
+ "BUILD_",
+ "NBGV_GitEngine",
+ };
protected BuildManager buildManager;
protected ProjectCollection projectCollection;
@@ -34,14 +45,6 @@ public abstract class BuildIntegrationTests : RepoTestBase, IClassFixture this.Context.GitCommitId?.Substring(0, VersionOptions.DefaultGitCommitIdShortFixedLength);
+ public static IEnumerable CloudBuildOfBranch(string branchName)
+ {
+ return new object[][]
+ {
+ new object[] { CloudBuild.AppVeyor.SetItem("APPVEYOR_REPO_BRANCH", branchName) },
+ new object[] { CloudBuild.VSTS.SetItem("BUILD_SOURCEBRANCH", $"refs/heads/{branchName}") },
+ new object[] { CloudBuild.VSTS.SetItem("BUILD_SOURCEBRANCH", $"refs/tags/{branchName}") },
+ new object[] { CloudBuild.Teamcity.SetItem("BUILD_GIT_BRANCH", $"refs/heads/{branchName}") },
+ new object[] { CloudBuild.Teamcity.SetItem("BUILD_GIT_BRANCH", $"refs/tags/{branchName}") },
+ };
+ }
+
+ [Fact]
+ public async Task GetBuildVersion_Returns_BuildVersion_Property()
+ {
+ this.WriteVersionFile();
+ this.InitializeSourceControl();
+ BuildResults buildResult = await this.BuildAsync();
+ Assert.Equal(
+ buildResult.BuildVersion,
+ buildResult.BuildResult.ResultsByTarget[Targets.GetBuildVersion].Items.Single().ItemSpec);
+ }
+
[Fact]
public async Task GetBuildVersion_Without_Git()
{
@@ -79,54 +147,88 @@ public async Task GetBuildVersion_Without_Git_HighPrecisionAssemblyVersion()
Assert.Equal("3.4.0", buildResult.AssemblyInformationalVersion);
}
- [Fact]
- public async Task GetBuildVersion_Returns_BuildVersion_Property()
+ // TODO: add key container test.
+ [Theory]
+ [InlineData("keypair.snk", false)]
+ [InlineData("public.snk", true)]
+ [InlineData("protectedPair.pfx", true)]
+ public async Task AssemblyInfo_HasKeyData(string keyFile, bool delaySigned)
{
+ TestUtilities.ExtractEmbeddedResource($@"Keys\{keyFile}", Path.Combine(this.projectDirectory, keyFile));
+ this.testProject.AddProperty("SignAssembly", "true");
+ this.testProject.AddProperty("AssemblyOriginatorKeyFile", keyFile);
+ this.testProject.AddProperty("DelaySign", delaySigned.ToString());
+
this.WriteVersionFile();
- this.InitializeSourceControl();
- BuildResults buildResult = await this.BuildAsync();
- Assert.Equal(
- buildResult.BuildVersion,
- buildResult.BuildResult.ResultsByTarget[Targets.GetBuildVersion].Items.Single().ItemSpec);
+ BuildResults result = await this.BuildAsync(Targets.GenerateAssemblyNBGVVersionInfo, logVerbosity: LoggerVerbosity.Minimal);
+ string versionCsContent = File.ReadAllText(
+ Path.GetFullPath(
+ Path.Combine(
+ this.projectDirectory,
+ result.BuildResult.ProjectStateAfterBuild.GetPropertyValue("VersionSourceFile"))));
+ this.Logger.WriteLine(versionCsContent);
+
+ SyntaxTree sourceFile = CSharpSyntaxTree.ParseText(versionCsContent);
+ SyntaxNode syntaxTree = await sourceFile.GetRootAsync();
+ IEnumerable fields = syntaxTree.DescendantNodes().OfType();
+
+ var publicKeyField = (LiteralExpressionSyntax)fields.SingleOrDefault(f => f.Identifier.ValueText == "PublicKey")?.Initializer.Value;
+ var publicKeyTokenField = (LiteralExpressionSyntax)fields.SingleOrDefault(f => f.Identifier.ValueText == "PublicKeyToken")?.Initializer.Value;
+ if (Path.GetExtension(keyFile) == ".pfx")
+ {
+ // No support for PFX (yet anyway), since they're encrypted.
+ // Note for future: I think by this point, the user has typically already decrypted
+ // the PFX and stored the key pair in a key container. If we knew how to find which one,
+ // we could perhaps divert to that.
+ Assert.Null(publicKeyField);
+ Assert.Null(publicKeyTokenField);
+ }
+ else
+ {
+ Assert.Equal(
+ "002400000480000094000000060200000024000052534131000400000100010067cea773679e0ecc114b7e1d442466a90bf77c755811a0d3962a546ed716525b6508abf9f78df132ffd3fb75fe604b3961e39c52d5dfc0e6c1fb233cb4fb56b1a9e3141513b23bea2cd156cb2ef7744e59ba6b663d1f5b2f9449550352248068e85b61c68681a6103cad91b3bf7a4b50d2fabf97e1d97ac34db65b25b58cd0dc",
+ publicKeyField?.Token.ValueText);
+ Assert.Equal("ca2d1515679318f5", publicKeyTokenField?.Token.ValueText);
+ }
}
///
/// Emulate a project with an unsupported language, and verify that
- /// no errors are emitted because the target is skipped.
+ /// one warning is emitted because the assembly info file couldn't be generated.
///
[Fact]
- public async Task AssemblyInfo_Suppressed()
+ public async Task AssemblyInfo_NotProducedWithoutCodeDomProvider()
{
ProjectPropertyGroupElement propertyGroup = this.testProject.CreatePropertyGroupElement();
this.testProject.AppendChild(propertyGroup);
propertyGroup.AddProperty("Language", "NoCodeDOMProviderForThisLanguage");
- propertyGroup.AddProperty(Targets.GenerateAssemblyVersionInfo, "false");
this.WriteVersionFile();
- BuildResults result = await this.BuildAsync(Targets.GenerateAssemblyVersionInfo, logVerbosity: LoggerVerbosity.Minimal);
+ BuildResults result = await this.BuildAsync(Targets.GenerateAssemblyNBGVVersionInfo, logVerbosity: LoggerVerbosity.Minimal, assertSuccessfulBuild: false);
+ Assert.Equal(BuildResultCode.Failure, result.BuildResult.OverallResult);
string versionCsFilePath = Path.Combine(this.projectDirectory, result.BuildResult.ProjectStateAfterBuild.GetPropertyValue("VersionSourceFile"));
Assert.False(File.Exists(versionCsFilePath));
- Assert.Empty(result.LoggedEvents.OfType());
- Assert.Empty(result.LoggedEvents.OfType());
+ Assert.Single(result.LoggedEvents.OfType());
}
///
/// Emulate a project with an unsupported language, and verify that
- /// one warning is emitted because the assembly info file couldn't be generated.
+ /// no errors are emitted because the target is skipped.
///
[Fact]
- public async Task AssemblyInfo_NotProducedWithoutCodeDomProvider()
+ public async Task AssemblyInfo_Suppressed()
{
ProjectPropertyGroupElement propertyGroup = this.testProject.CreatePropertyGroupElement();
this.testProject.AppendChild(propertyGroup);
propertyGroup.AddProperty("Language", "NoCodeDOMProviderForThisLanguage");
+ propertyGroup.AddProperty(Properties.GenerateAssemblyVersionInfo, "false");
this.WriteVersionFile();
- BuildResults result = await this.BuildAsync(Targets.GenerateAssemblyVersionInfo, logVerbosity: LoggerVerbosity.Minimal, assertSuccessfulBuild: false);
- Assert.Equal(BuildResultCode.Failure, result.BuildResult.OverallResult);
+ BuildResults result = await this.BuildAsync(Targets.GenerateAssemblyNBGVVersionInfo, logVerbosity: LoggerVerbosity.Minimal);
string versionCsFilePath = Path.Combine(this.projectDirectory, result.BuildResult.ProjectStateAfterBuild.GetPropertyValue("VersionSourceFile"));
Assert.False(File.Exists(versionCsFilePath));
- Assert.Single(result.LoggedEvents.OfType());
+ Assert.Empty(result.LoggedEvents.OfType());
+ Assert.Empty(result.LoggedEvents.OfType());
}
///
@@ -142,74 +244,138 @@ public async Task AssemblyInfo_SuppressedImplicitlyByTargetExt()
propertyGroup.AddProperty("TargetExt", ".notdll");
this.WriteVersionFile();
- BuildResults result = await this.BuildAsync(Targets.GenerateAssemblyVersionInfo, logVerbosity: LoggerVerbosity.Minimal);
+ BuildResults result = await this.BuildAsync(Targets.GenerateAssemblyNBGVVersionInfo, logVerbosity: LoggerVerbosity.Minimal);
string versionCsFilePath = Path.Combine(this.projectDirectory, result.BuildResult.ProjectStateAfterBuild.GetPropertyValue("VersionSourceFile"));
Assert.False(File.Exists(versionCsFilePath));
Assert.Empty(result.LoggedEvents.OfType());
Assert.Empty(result.LoggedEvents.OfType());
}
- // TODO: add key container test.
- [Theory]
- [InlineData("keypair.snk", false)]
- [InlineData("public.snk", true)]
- [InlineData("protectedPair.pfx", true)]
- public async Task AssemblyInfo_HasKeyData(string keyFile, bool delaySigned)
+ protected static Version GetExpectedAssemblyVersion(VersionOptions versionOptions, Version version)
{
- TestUtilities.ExtractEmbeddedResource($@"Keys\{keyFile}", Path.Combine(this.projectDirectory, keyFile));
- this.testProject.AddProperty("SignAssembly", "true");
- this.testProject.AddProperty("AssemblyOriginatorKeyFile", keyFile);
- this.testProject.AddProperty("DelaySign", delaySigned.ToString());
-
- this.WriteVersionFile();
- BuildResults result = await this.BuildAsync(Targets.GenerateAssemblyVersionInfo, logVerbosity: LoggerVerbosity.Minimal);
- string versionCsContent = File.ReadAllText(
- Path.GetFullPath(
- Path.Combine(
- this.projectDirectory,
- result.BuildResult.ProjectStateAfterBuild.GetPropertyValue("VersionSourceFile"))));
- this.Logger.WriteLine(versionCsContent);
+ // Function should be very similar to VersionOracle.GetAssemblyVersion()
+ Version assemblyVersion = (versionOptions?.AssemblyVersion?.Version ?? versionOptions.Version.Version).EnsureNonNegativeComponents();
- SyntaxTree sourceFile = CSharpSyntaxTree.ParseText(versionCsContent);
- SyntaxNode syntaxTree = await sourceFile.GetRootAsync();
- IEnumerable fields = syntaxTree.DescendantNodes().OfType();
-
- var publicKeyField = (LiteralExpressionSyntax)fields.SingleOrDefault(f => f.Identifier.ValueText == "PublicKey")?.Initializer.Value;
- var publicKeyTokenField = (LiteralExpressionSyntax)fields.SingleOrDefault(f => f.Identifier.ValueText == "PublicKeyToken")?.Initializer.Value;
- if (Path.GetExtension(keyFile) == ".pfx")
+ if (versionOptions?.AssemblyVersion?.Version is null)
{
- // No support for PFX (yet anyway), since they're encrypted.
- // Note for future: I think by this point, the user has typically already decrypted
- // the PFX and stored the key pair in a key container. If we knew how to find which one,
- // we could perhaps divert to that.
- Assert.Null(publicKeyField);
- Assert.Null(publicKeyTokenField);
+ VersionOptions.VersionPrecision precision = versionOptions?.AssemblyVersion?.Precision ?? VersionOptions.DefaultVersionPrecision;
+ assemblyVersion = version;
+
+ assemblyVersion = new Version(
+ assemblyVersion.Major,
+ precision >= VersionOptions.VersionPrecision.Minor ? assemblyVersion.Minor : 0,
+ precision >= VersionOptions.VersionPrecision.Build ? assemblyVersion.Build : 0,
+ precision >= VersionOptions.VersionPrecision.Revision ? assemblyVersion.Revision : 0);
}
- else
+
+ return assemblyVersion;
+ }
+
+ protected static RestoreEnvironmentVariables ApplyEnvironmentVariables(IReadOnlyDictionary variables)
+ {
+ Requires.NotNull(variables, nameof(variables));
+
+ var oldValues = new Dictionary(StringComparer.OrdinalIgnoreCase);
+ foreach (KeyValuePair variable in variables)
{
- Assert.Equal(
- "002400000480000094000000060200000024000052534131000400000100010067cea773679e0ecc114b7e1d442466a90bf77c755811a0d3962a546ed716525b6508abf9f78df132ffd3fb75fe604b3961e39c52d5dfc0e6c1fb233cb4fb56b1a9e3141513b23bea2cd156cb2ef7744e59ba6b663d1f5b2f9449550352248068e85b61c68681a6103cad91b3bf7a4b50d2fabf97e1d97ac34db65b25b58cd0dc",
- publicKeyField?.Token.ValueText);
- Assert.Equal("ca2d1515679318f5", publicKeyTokenField?.Token.ValueText);
+ oldValues[variable.Key] = Environment.GetEnvironmentVariable(variable.Key);
+ Environment.SetEnvironmentVariable(variable.Key, variable.Value);
}
- }
- protected abstract void ApplyGlobalProperties(IDictionary globalProperties);
+ return new RestoreEnvironmentVariables(oldValues);
+ }
- protected override void Dispose(bool disposing)
+ protected static string GetSemVerAppropriatePrereleaseTag(VersionOptions versionOptions)
{
- Environment.SetEnvironmentVariable("_NBGV_UnitTest", string.Empty);
- base.Dispose(disposing);
+ return versionOptions.NuGetPackageVersionOrDefault.SemVer == 1
+ ? versionOptions.Version.Prerelease?.Replace('.', '-')
+ : versionOptions.Version.Prerelease;
}
- protected ProjectRootElement CreateProjectRootElement(string projectDirectory, string projectName)
+ protected void AssertStandardProperties(VersionOptions versionOptions, BuildResults buildResult, string relativeProjectDirectory = null)
{
- using (var reader = XmlReader.Create(Assembly.GetExecutingAssembly().GetManifestResourceStream($"{ThisAssembly.RootNamespace}.test.prj")))
+ int versionHeight = this.GetVersionHeight(relativeProjectDirectory);
+ Version idAsVersion = this.GetVersion(relativeProjectDirectory);
+ string commitIdShort = this.CommitIdShort;
+ Version version = this.GetVersion(relativeProjectDirectory);
+ Version assemblyVersion = GetExpectedAssemblyVersion(versionOptions, version);
+ IEnumerable additionalBuildMetadata = from item in buildResult.BuildResult.ProjectStateAfterBuild.GetItems("BuildMetadata")
+ select item.EvaluatedInclude;
+ string expectedBuildMetadata = $"+{commitIdShort}";
+ if (additionalBuildMetadata.Any())
{
- var pre = ProjectRootElement.Create(reader, this.projectCollection);
- pre.FullPath = Path.Combine(projectDirectory, projectName);
- pre.AddImport(Path.Combine(this.RepoPath, GitVersioningTargetsFileName));
- return pre;
+ expectedBuildMetadata += "." + string.Join(".", additionalBuildMetadata);
+ }
+
+ string expectedBuildMetadataWithoutCommitId = additionalBuildMetadata.Any() ? $"+{string.Join(".", additionalBuildMetadata)}" : string.Empty;
+ string optionalFourthComponent = versionOptions.VersionHeightPosition == SemanticVersion.Position.Revision ? $".{idAsVersion.Revision}" : string.Empty;
+
+ Assert.Equal($"{version}", buildResult.AssemblyFileVersion);
+ Assert.Equal($"{idAsVersion.Major}.{idAsVersion.Minor}.{idAsVersion.Build}{optionalFourthComponent}{versionOptions.Version.Prerelease}{expectedBuildMetadata}", buildResult.AssemblyInformationalVersion);
+
+ // The assembly version property should always have four integer components to it,
+ // per bug https://github.com/dotnet/Nerdbank.GitVersioning/issues/26
+ Assert.Equal($"{assemblyVersion.Major}.{assemblyVersion.Minor}.{assemblyVersion.Build}.{assemblyVersion.Revision}", buildResult.AssemblyVersion);
+
+ Assert.Equal(idAsVersion.Build.ToString(), buildResult.BuildNumber);
+ Assert.Equal($"{version}", buildResult.BuildVersion);
+ Assert.Equal($"{idAsVersion.Major}.{idAsVersion.Minor}.{idAsVersion.Build}", buildResult.BuildVersion3Components);
+ Assert.Equal(idAsVersion.Build.ToString(), buildResult.BuildVersionNumberComponent);
+ Assert.Equal($"{idAsVersion.Major}.{idAsVersion.Minor}.{idAsVersion.Build}", buildResult.BuildVersionSimple);
+ Assert.Equal(this.LibGit2Repository.Head.Tip.Id.Sha, buildResult.GitCommitId);
+ Assert.Equal(this.LibGit2Repository.Head.Tip.Author.When.UtcTicks.ToString(CultureInfo.InvariantCulture), buildResult.GitCommitDateTicks);
+ Assert.Equal(commitIdShort, buildResult.GitCommitIdShort);
+ Assert.Equal(versionHeight.ToString(), buildResult.GitVersionHeight);
+ Assert.Equal($"{version.Major}.{version.Minor}", buildResult.MajorMinorVersion);
+ Assert.Equal(versionOptions.Version.Prerelease, buildResult.PrereleaseVersion);
+ Assert.Equal(expectedBuildMetadata, buildResult.SemVerBuildSuffix);
+
+ string GetPkgVersionSuffix(bool useSemVer2)
+ {
+ string pkgVersionSuffix = buildResult.PublicRelease ? string.Empty : $"-g{commitIdShort}";
+ if (useSemVer2)
+ {
+ pkgVersionSuffix += expectedBuildMetadataWithoutCommitId;
+ }
+
+ return pkgVersionSuffix;
+ }
+
+ // NuGet is now SemVer 2.0 and will pass additional build metadata if provided
+ string nugetPkgVersionSuffix = GetPkgVersionSuffix(useSemVer2: versionOptions?.NuGetPackageVersionOrDefault.SemVer == 2);
+ Assert.Equal($"{idAsVersion.Major}.{idAsVersion.Minor}.{idAsVersion.Build}{GetSemVerAppropriatePrereleaseTag(versionOptions)}{nugetPkgVersionSuffix}", buildResult.NuGetPackageVersion);
+
+ // Chocolatey only supports SemVer 1.0
+ string chocolateyPkgVersionSuffix = GetPkgVersionSuffix(useSemVer2: false);
+ Assert.Equal($"{idAsVersion.Major}.{idAsVersion.Minor}.{idAsVersion.Build}{GetSemVerAppropriatePrereleaseTag(versionOptions)}{chocolateyPkgVersionSuffix}", buildResult.ChocolateyPackageVersion);
+
+ VersionOptions.CloudBuildNumberOptions buildNumberOptions = versionOptions.CloudBuildOrDefault.BuildNumberOrDefault;
+ if (buildNumberOptions.EnabledOrDefault)
+ {
+ VersionOptions.CloudBuildNumberCommitIdOptions commitIdOptions = buildNumberOptions.IncludeCommitIdOrDefault;
+ var buildNumberSemVer = SemanticVersion.Parse(buildResult.CloudBuildNumber);
+ bool hasCommitData = commitIdOptions.WhenOrDefault == VersionOptions.CloudBuildNumberCommitWhen.Always
+ || (commitIdOptions.WhenOrDefault == VersionOptions.CloudBuildNumberCommitWhen.NonPublicReleaseOnly && !buildResult.PublicRelease);
+ Version expectedVersion = hasCommitData && commitIdOptions.WhereOrDefault == VersionOptions.CloudBuildNumberCommitWhere.FourthVersionComponent
+ ? idAsVersion
+ : new Version(version.Major, version.Minor, version.Build);
+ Assert.Equal(expectedVersion, buildNumberSemVer.Version);
+ Assert.Equal(buildResult.PrereleaseVersion, buildNumberSemVer.Prerelease);
+ string expectedBuildNumberMetadata = hasCommitData && commitIdOptions.WhereOrDefault == VersionOptions.CloudBuildNumberCommitWhere.BuildMetadata
+ ? $"+{commitIdShort}"
+ : string.Empty;
+ if (additionalBuildMetadata.Any())
+ {
+ expectedBuildNumberMetadata = expectedBuildNumberMetadata.Length == 0
+ ? "+" + string.Join(".", additionalBuildMetadata)
+ : expectedBuildNumberMetadata + "." + string.Join(".", additionalBuildMetadata);
+ }
+
+ Assert.Equal(expectedBuildNumberMetadata, buildNumberSemVer.BuildMetadata);
+ }
+ else
+ {
+ Assert.Equal(string.Empty, buildResult.CloudBuildNumber);
}
}
@@ -237,6 +403,65 @@ protected async Task BuildAsync(string target = Targets.GetBuildVe
return result;
}
+ protected ProjectRootElement CreateNativeProjectRootElement(string projectDirectory, string projectName)
+ {
+ using (var reader = XmlReader.Create(Assembly.GetExecutingAssembly().GetManifestResourceStream($"{ThisAssembly.RootNamespace}.test.vcprj")))
+ {
+ var pre = ProjectRootElement.Create(reader, this.projectCollection);
+ pre.FullPath = Path.Combine(projectDirectory, projectName);
+ pre.InsertAfterChild(pre.CreateImportElement(Path.Combine(this.RepoPath, GitVersioningPropsFileName)), null);
+ pre.AddImport(Path.Combine(this.RepoPath, GitVersioningTargetsFileName));
+ return pre;
+ }
+ }
+
+ protected ProjectRootElement CreateProjectRootElement(string projectDirectory, string projectName)
+ {
+ using (var reader = XmlReader.Create(Assembly.GetExecutingAssembly().GetManifestResourceStream($"{ThisAssembly.RootNamespace}.test.prj")))
+ {
+ var pre = ProjectRootElement.Create(reader, this.projectCollection);
+ pre.FullPath = Path.Combine(projectDirectory, projectName);
+ pre.InsertAfterChild(pre.CreateImportElement(Path.Combine(this.RepoPath, GitVersioningPropsFileName)), null);
+ pre.AddImport(Path.Combine(this.RepoPath, GitVersioningTargetsFileName));
+ return pre;
+ }
+ }
+
+ protected void MakeItAVBProject()
+ {
+ ProjectImportElement csharpImport = this.testProject.Imports.Single(i => i.Project.Contains("CSharp"));
+ csharpImport.Project = "$(MSBuildToolsPath)/Microsoft.VisualBasic.targets";
+ ProjectPropertyElement isVbProperty = this.testProject.Properties.Single(p => p.Name == "IsVB");
+ isVbProperty.Value = "true";
+ }
+
+ protected abstract void ApplyGlobalProperties(IDictionary globalProperties);
+
+ ///
+ protected override void Dispose(bool disposing)
+ {
+ Environment.SetEnvironmentVariable("_NBGV_UnitTest", string.Empty);
+ base.Dispose(disposing);
+ }
+
+ private void LoadTargetsIntoProjectCollection()
+ {
+ string prefix = $"{ThisAssembly.RootNamespace}.Targets.";
+
+ IEnumerable streamNames = from name in Assembly.GetExecutingAssembly().GetManifestResourceNames()
+ where name.StartsWith(prefix, StringComparison.Ordinal)
+ select name;
+ foreach (string name in streamNames)
+ {
+ using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(name))
+ {
+ var targetsFile = ProjectRootElement.Create(XmlReader.Create(stream), this.projectCollection);
+ targetsFile.FullPath = Path.Combine(this.RepoPath, name.Substring(prefix.Length));
+ targetsFile.Save(); // persist files on disk
+ }
+ }
+ }
+
private void Init()
{
int seed = (int)DateTime.Now.Ticks;
@@ -262,31 +487,61 @@ private void Init()
}
}
- private void LoadTargetsIntoProjectCollection()
+ protected struct RestoreEnvironmentVariables : IDisposable
{
- string prefix = $"{ThisAssembly.RootNamespace}.Targets.";
+ private readonly IReadOnlyDictionary applyVariables;
- IEnumerable streamNames = from name in Assembly.GetExecutingAssembly().GetManifestResourceNames()
- where name.StartsWith(prefix, StringComparison.Ordinal)
- select name;
- foreach (string name in streamNames)
+ internal RestoreEnvironmentVariables(IReadOnlyDictionary applyVariables)
{
- using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(name))
- {
- var targetsFile = ProjectRootElement.Create(XmlReader.Create(stream), this.projectCollection);
- targetsFile.FullPath = Path.Combine(this.RepoPath, name.Substring(prefix.Length));
- targetsFile.Save(); // persist files on disk
- }
+ this.applyVariables = applyVariables;
+ }
+
+ public void Dispose()
+ {
+ ApplyEnvironmentVariables(this.applyVariables);
}
}
+ protected static class CloudBuild
+ {
+ public static readonly ImmutableDictionary SuppressEnvironment = ImmutableDictionary.Empty
+
+ // AppVeyor
+ .Add("APPVEYOR", string.Empty)
+ .Add("APPVEYOR_REPO_TAG", string.Empty)
+ .Add("APPVEYOR_REPO_TAG_NAME", string.Empty)
+ .Add("APPVEYOR_PULL_REQUEST_NUMBER", string.Empty)
+
+ // VSTS
+ .Add("SYSTEM_TEAMPROJECTID", string.Empty)
+ .Add("BUILD_SOURCEBRANCH", string.Empty)
+
+ // Teamcity
+ .Add("BUILD_VCS_NUMBER", string.Empty)
+ .Add("BUILD_GIT_BRANCH", string.Empty);
+
+ public static readonly ImmutableDictionary VSTS = SuppressEnvironment
+ .SetItem("SYSTEM_TEAMPROJECTID", "1");
+
+ public static readonly ImmutableDictionary AppVeyor = SuppressEnvironment
+ .SetItem("APPVEYOR", "True");
+
+ public static readonly ImmutableDictionary Teamcity = SuppressEnvironment
+ .SetItem("BUILD_VCS_NUMBER", "1");
+ }
+
protected static class Targets
{
internal const string Build = "Build";
internal const string GetBuildVersion = "GetBuildVersion";
internal const string GetNuGetPackageVersion = "GetNuGetPackageVersion";
- internal const string GenerateAssemblyVersionInfo = "GenerateAssemblyNBGVVersionInfo";
- internal const string GenerateNativeVersionInfo = "GenerateNativeVersionInfo";
+ internal const string GenerateAssemblyNBGVVersionInfo = "GenerateAssemblyNBGVVersionInfo";
+ internal const string GenerateNativeNBGVVersionInfo = "GenerateNativeNBGVVersionInfo";
+ }
+
+ protected static class Properties
+ {
+ internal const string GenerateAssemblyVersionInfo = "GenerateAssemblyVersionInfo";
}
protected class BuildResults
@@ -381,7 +636,7 @@ public override string ToString()
}
}
- protected class MSBuildLogger : ILogger
+ private class MSBuildLogger : ILogger
{
public string Parameters { get; set; }
diff --git a/test/Nerdbank.GitVersioning.Tests/SomeGitBuildIntegrationTests.cs b/test/Nerdbank.GitVersioning.Tests/SomeGitBuildIntegrationTests.cs
index 38777be0..5ced01af 100644
--- a/test/Nerdbank.GitVersioning.Tests/SomeGitBuildIntegrationTests.cs
+++ b/test/Nerdbank.GitVersioning.Tests/SomeGitBuildIntegrationTests.cs
@@ -27,60 +27,6 @@ protected SomeGitBuildIntegrationTests(ITestOutputHelper logger)
{
}
- public static object[][] CloudBuildVariablesData
- {
- get
- {
- return new object[][]
- {
- new object[] { CloudBuild.VSTS, "##vso[task.setvariable variable={NAME};]{VALUE}", false },
- new object[] { CloudBuild.VSTS, "##vso[task.setvariable variable={NAME};]{VALUE}", true },
- };
- }
- }
-
- public static object[][] BuildNumberData
- {
- get
- {
- return new object[][]
- {
- new object[] { BuildNumberVersionOptionsBasis, CloudBuild.VSTS, "##vso[build.updatebuildnumber]{CLOUDBUILDNUMBER}" },
- };
- }
- }
-
- private static VersionOptions BuildNumberVersionOptionsBasis
- {
- get
- {
- return new VersionOptions
- {
- Version = SemanticVersion.Parse("1.0"),
- CloudBuild = new VersionOptions.CloudBuildOptions
- {
- BuildNumber = new VersionOptions.CloudBuildNumberOptions
- {
- Enabled = true,
- IncludeCommitId = new VersionOptions.CloudBuildNumberCommitIdOptions(),
- },
- },
- };
- }
- }
-
- public static IEnumerable CloudBuildOfBranch(string branchName)
- {
- return new object[][]
- {
- new object[] { CloudBuild.AppVeyor.SetItem("APPVEYOR_REPO_BRANCH", branchName) },
- new object[] { CloudBuild.VSTS.SetItem("BUILD_SOURCEBRANCH", $"refs/heads/{branchName}") },
- new object[] { CloudBuild.VSTS.SetItem("BUILD_SOURCEBRANCH", $"refs/tags/{branchName}") },
- new object[] { CloudBuild.Teamcity.SetItem("BUILD_GIT_BRANCH", $"refs/heads/{branchName}") },
- new object[] { CloudBuild.Teamcity.SetItem("BUILD_GIT_BRANCH", $"refs/tags/{branchName}") },
- };
- }
-
[Fact]
public async Task GetBuildVersion_WithThreeVersionIntegers()
{
@@ -440,7 +386,7 @@ public async Task PublicRelease_RegEx_SatisfiedByCI(IReadOnlyDictionary properties, string expectedMessage, bool setAllVariables)
{
@@ -498,7 +444,9 @@ public async Task CloudBuildVariables_SetInCI(IReadOnlyDictionary string.Equals(e.Message, $"n1=v1", StringComparison.OrdinalIgnoreCase));
+ Assert.Contains(
+ buildResult.LoggedEvents,
+ e => string.Equals(e.Message, $"n1=v1", StringComparison.OrdinalIgnoreCase) || string.Equals(e.Message, $"n1='v1'", StringComparison.OrdinalIgnoreCase));
versionOptions.CloudBuild.SetVersionVariables = false;
this.WriteVersionFile(versionOptions);
@@ -733,7 +681,7 @@ public async Task AssemblyInfo(bool isVB, bool includeNonVersionAttributes, bool
}
[Fact]
- [Trait("TestCategory", "FailsOnAzurePipelines")]
+ [Trait("TestCategory", "FailsInCloudTest")]
public async Task AssemblyInfo_IncrementalBuild()
{
this.WriteVersionFile(prerelease: "-beta");
@@ -762,190 +710,11 @@ public async Task NativeVersionInfo_CreateNativeResourceDll()
Assert.Equal("1.2", fileInfo.FileVersion);
Assert.Equal("1.2.0", fileInfo.ProductVersion);
Assert.Equal("test", fileInfo.InternalName);
- Assert.Equal("NerdBank", fileInfo.CompanyName);
+ Assert.Equal("Nerdbank", fileInfo.CompanyName);
Assert.Equal($"Copyright (c) {DateTime.Now.Year}. All rights reserved.", fileInfo.LegalCopyright);
}
#endif
+ ///
protected override GitContext CreateGitContext(string path, string committish = null) => throw new NotImplementedException();
-
- private static Version GetExpectedAssemblyVersion(VersionOptions versionOptions, Version version)
- {
- // Function should be very similar to VersionOracle.GetAssemblyVersion()
- Version assemblyVersion = (versionOptions?.AssemblyVersion?.Version ?? versionOptions.Version.Version).EnsureNonNegativeComponents();
- VersionOptions.VersionPrecision precision = versionOptions?.AssemblyVersion?.Precision ?? VersionOptions.DefaultVersionPrecision;
-
- assemblyVersion = new System.Version(
- assemblyVersion.Major,
- precision >= VersionOptions.VersionPrecision.Minor ? assemblyVersion.Minor : 0,
- precision >= VersionOptions.VersionPrecision.Build ? version.Build : 0,
- precision >= VersionOptions.VersionPrecision.Revision ? version.Revision : 0);
- return assemblyVersion;
- }
-
- private static RestoreEnvironmentVariables ApplyEnvironmentVariables(IReadOnlyDictionary variables)
- {
- Requires.NotNull(variables, nameof(variables));
-
- var oldValues = new Dictionary(StringComparer.OrdinalIgnoreCase);
- foreach (KeyValuePair variable in variables)
- {
- oldValues[variable.Key] = Environment.GetEnvironmentVariable(variable.Key);
- Environment.SetEnvironmentVariable(variable.Key, variable.Value);
- }
-
- return new RestoreEnvironmentVariables(oldValues);
- }
-
- private static string GetSemVerAppropriatePrereleaseTag(VersionOptions versionOptions)
- {
- return versionOptions.NuGetPackageVersionOrDefault.SemVer == 1
- ? versionOptions.Version.Prerelease?.Replace('.', '-')
- : versionOptions.Version.Prerelease;
- }
-
- private void AssertStandardProperties(VersionOptions versionOptions, BuildResults buildResult, string relativeProjectDirectory = null)
- {
- int versionHeight = this.GetVersionHeight(relativeProjectDirectory);
- Version idAsVersion = this.GetVersion(relativeProjectDirectory);
- string commitIdShort = this.CommitIdShort;
- Version version = this.GetVersion(relativeProjectDirectory);
- Version assemblyVersion = GetExpectedAssemblyVersion(versionOptions, version);
- IEnumerable additionalBuildMetadata = from item in buildResult.BuildResult.ProjectStateAfterBuild.GetItems("BuildMetadata")
- select item.EvaluatedInclude;
- string expectedBuildMetadata = $"+{commitIdShort}";
- if (additionalBuildMetadata.Any())
- {
- expectedBuildMetadata += "." + string.Join(".", additionalBuildMetadata);
- }
-
- string expectedBuildMetadataWithoutCommitId = additionalBuildMetadata.Any() ? $"+{string.Join(".", additionalBuildMetadata)}" : string.Empty;
-
- Assert.Equal($"{version}", buildResult.AssemblyFileVersion);
- Assert.Equal($"{idAsVersion.Major}.{idAsVersion.Minor}.{idAsVersion.Build}{versionOptions.Version.Prerelease}{expectedBuildMetadata}", buildResult.AssemblyInformationalVersion);
-
- // The assembly version property should always have four integer components to it,
- // per bug https://github.com/dotnet/Nerdbank.GitVersioning/issues/26
- Assert.Equal($"{assemblyVersion.Major}.{assemblyVersion.Minor}.{assemblyVersion.Build}.{assemblyVersion.Revision}", buildResult.AssemblyVersion);
-
- Assert.Equal(idAsVersion.Build.ToString(), buildResult.BuildNumber);
- Assert.Equal($"{version}", buildResult.BuildVersion);
- Assert.Equal($"{idAsVersion.Major}.{idAsVersion.Minor}.{idAsVersion.Build}", buildResult.BuildVersion3Components);
- Assert.Equal(idAsVersion.Build.ToString(), buildResult.BuildVersionNumberComponent);
- Assert.Equal($"{idAsVersion.Major}.{idAsVersion.Minor}.{idAsVersion.Build}", buildResult.BuildVersionSimple);
- Assert.Equal(this.LibGit2Repository.Head.Tip.Id.Sha, buildResult.GitCommitId);
- Assert.Equal(this.LibGit2Repository.Head.Tip.Author.When.UtcTicks.ToString(CultureInfo.InvariantCulture), buildResult.GitCommitDateTicks);
- Assert.Equal(commitIdShort, buildResult.GitCommitIdShort);
- Assert.Equal(versionHeight.ToString(), buildResult.GitVersionHeight);
- Assert.Equal($"{version.Major}.{version.Minor}", buildResult.MajorMinorVersion);
- Assert.Equal(versionOptions.Version.Prerelease, buildResult.PrereleaseVersion);
- Assert.Equal(expectedBuildMetadata, buildResult.SemVerBuildSuffix);
-
- string GetPkgVersionSuffix(bool useSemVer2)
- {
- string pkgVersionSuffix = buildResult.PublicRelease ? string.Empty : $"-g{commitIdShort}";
- if (useSemVer2)
- {
- pkgVersionSuffix += expectedBuildMetadataWithoutCommitId;
- }
-
- return pkgVersionSuffix;
- }
-
- // NuGet is now SemVer 2.0 and will pass additional build metadata if provided
- string nugetPkgVersionSuffix = GetPkgVersionSuffix(useSemVer2: versionOptions?.NuGetPackageVersionOrDefault.SemVer == 2);
- Assert.Equal($"{idAsVersion.Major}.{idAsVersion.Minor}.{idAsVersion.Build}{GetSemVerAppropriatePrereleaseTag(versionOptions)}{nugetPkgVersionSuffix}", buildResult.NuGetPackageVersion);
-
- // Chocolatey only supports SemVer 1.0
- string chocolateyPkgVersionSuffix = GetPkgVersionSuffix(useSemVer2: false);
- Assert.Equal($"{idAsVersion.Major}.{idAsVersion.Minor}.{idAsVersion.Build}{GetSemVerAppropriatePrereleaseTag(versionOptions)}{chocolateyPkgVersionSuffix}", buildResult.ChocolateyPackageVersion);
-
- VersionOptions.CloudBuildNumberOptions buildNumberOptions = versionOptions.CloudBuildOrDefault.BuildNumberOrDefault;
- if (buildNumberOptions.EnabledOrDefault)
- {
- VersionOptions.CloudBuildNumberCommitIdOptions commitIdOptions = buildNumberOptions.IncludeCommitIdOrDefault;
- var buildNumberSemVer = SemanticVersion.Parse(buildResult.CloudBuildNumber);
- bool hasCommitData = commitIdOptions.WhenOrDefault == VersionOptions.CloudBuildNumberCommitWhen.Always
- || (commitIdOptions.WhenOrDefault == VersionOptions.CloudBuildNumberCommitWhen.NonPublicReleaseOnly && !buildResult.PublicRelease);
- Version expectedVersion = hasCommitData && commitIdOptions.WhereOrDefault == VersionOptions.CloudBuildNumberCommitWhere.FourthVersionComponent
- ? idAsVersion
- : new Version(version.Major, version.Minor, version.Build);
- Assert.Equal(expectedVersion, buildNumberSemVer.Version);
- Assert.Equal(buildResult.PrereleaseVersion, buildNumberSemVer.Prerelease);
- string expectedBuildNumberMetadata = hasCommitData && commitIdOptions.WhereOrDefault == VersionOptions.CloudBuildNumberCommitWhere.BuildMetadata
- ? $"+{commitIdShort}"
- : string.Empty;
- if (additionalBuildMetadata.Any())
- {
- expectedBuildNumberMetadata = expectedBuildNumberMetadata.Length == 0
- ? "+" + string.Join(".", additionalBuildMetadata)
- : expectedBuildNumberMetadata + "." + string.Join(".", additionalBuildMetadata);
- }
-
- Assert.Equal(expectedBuildNumberMetadata, buildNumberSemVer.BuildMetadata);
- }
- else
- {
- Assert.Equal(string.Empty, buildResult.CloudBuildNumber);
- }
- }
-
- private ProjectRootElement CreateNativeProjectRootElement(string projectDirectory, string projectName)
- {
- using (var reader = XmlReader.Create(Assembly.GetExecutingAssembly().GetManifestResourceStream($"{ThisAssembly.RootNamespace}.test.vcprj")))
- {
- var pre = ProjectRootElement.Create(reader, this.projectCollection);
- pre.FullPath = Path.Combine(projectDirectory, projectName);
- pre.AddImport(Path.Combine(this.RepoPath, GitVersioningTargetsFileName));
- return pre;
- }
- }
-
- private void MakeItAVBProject()
- {
- ProjectImportElement csharpImport = this.testProject.Imports.Single(i => i.Project.Contains("CSharp"));
- csharpImport.Project = "$(MSBuildToolsPath)/Microsoft.VisualBasic.targets";
- ProjectPropertyElement isVbProperty = this.testProject.Properties.Single(p => p.Name == "IsVB");
- isVbProperty.Value = "true";
- }
-
- private struct RestoreEnvironmentVariables : IDisposable
- {
- private readonly IReadOnlyDictionary applyVariables;
-
- internal RestoreEnvironmentVariables(IReadOnlyDictionary applyVariables)
- {
- this.applyVariables = applyVariables;
- }
-
- public void Dispose()
- {
- ApplyEnvironmentVariables(this.applyVariables);
- }
- }
-
- private static class CloudBuild
- {
- public static readonly ImmutableDictionary SuppressEnvironment = ImmutableDictionary.Empty
- // AppVeyor
- .Add("APPVEYOR", string.Empty)
- .Add("APPVEYOR_REPO_TAG", string.Empty)
- .Add("APPVEYOR_REPO_TAG_NAME", string.Empty)
- .Add("APPVEYOR_PULL_REQUEST_NUMBER", string.Empty)
- // VSTS
- .Add("SYSTEM_TEAMPROJECTID", string.Empty)
- .Add("BUILD_SOURCEBRANCH", string.Empty)
- // Teamcity
- .Add("BUILD_VCS_NUMBER", string.Empty)
- .Add("BUILD_GIT_BRANCH", string.Empty);
-
- public static readonly ImmutableDictionary VSTS = SuppressEnvironment
- .SetItem("SYSTEM_TEAMPROJECTID", "1");
-
- public static readonly ImmutableDictionary AppVeyor = SuppressEnvironment
- .SetItem("APPVEYOR", "True");
-
- public static readonly ImmutableDictionary Teamcity = SuppressEnvironment
- .SetItem("BUILD_VCS_NUMBER", "1");
- }
}