diff --git a/src/NerdBank.GitVersioning/Commands/CloudCommand.cs b/src/NerdBank.GitVersioning/Commands/CloudCommand.cs index 42890eaac..518ab254d 100644 --- a/src/NerdBank.GitVersioning/Commands/CloudCommand.cs +++ b/src/NerdBank.GitVersioning/Commands/CloudCommand.cs @@ -94,7 +94,7 @@ public void SetBuildVariables(string projectDirectory, IEnumerable metad activeCloudBuild = CloudBuild.SupportedCloudBuilds[matchingIndex]; } - using var context = GitContext.Create(projectDirectory, writable: alwaysUseLibGit2); + using var context = GitContext.Create(projectDirectory, engine: alwaysUseLibGit2 ? GitContext.Engine.ReadWrite : GitContext.Engine.ReadOnly); var oracle = new VersionOracle(context, cloudBuild: activeCloudBuild); if (metadata is not null) { diff --git a/src/NerdBank.GitVersioning/DisabledGit/DisabledGitContext.cs b/src/NerdBank.GitVersioning/DisabledGit/DisabledGitContext.cs new file mode 100644 index 000000000..baf180128 --- /dev/null +++ b/src/NerdBank.GitVersioning/DisabledGit/DisabledGitContext.cs @@ -0,0 +1,42 @@ +// 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. + +#nullable enable + +using System.Diagnostics; + +namespace Nerdbank.GitVersioning; + +[DebuggerDisplay("{" + nameof(DebuggerDisplay) + ",nq}")] +internal class DisabledGitContext : GitContext +{ + public DisabledGitContext(string workingTreePath) + : base(workingTreePath, null) + { + this.VersionFile = new DisabledGitVersionFile(this); + } + + public override VersionFile VersionFile { get; } + + public override string? GitCommitId => null; + + public override bool IsHead => false; + + public override DateTimeOffset? GitCommitDate => null; + + public override string? HeadCanonicalName => null; + + private string DebuggerDisplay => $"\"{this.WorkingTreePath}\" (disabled-git)"; + + public override void ApplyTag(string name) => throw new NotSupportedException(); + + public override void Stage(string path) => throw new NotSupportedException(); + + public override string GetShortUniqueCommitId(int minLength) => "nerdbankdisabled"; + + public override bool TrySelectCommit(string committish) => true; + + internal override int CalculateVersionHeight(VersionOptions? committedVersion, VersionOptions? workingVersion) => 0; + + internal override Version GetIdAsVersion(VersionOptions? committedVersion, VersionOptions? workingVersion, int versionHeight) => Version0; +} diff --git a/src/NerdBank.GitVersioning/DisabledGit/DisabledGitVersionFile.cs b/src/NerdBank.GitVersioning/DisabledGit/DisabledGitVersionFile.cs new file mode 100644 index 000000000..33fb50992 --- /dev/null +++ b/src/NerdBank.GitVersioning/DisabledGit/DisabledGitVersionFile.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. + +#nullable enable + +namespace Nerdbank.GitVersioning; + +internal class DisabledGitVersionFile : VersionFile +{ + public DisabledGitVersionFile(GitContext context) + : base(context) + { + } + + protected new DisabledGitContext Context => (DisabledGitContext)base.Context; + + protected override VersionOptions? GetVersionCore(out string? actualDirectory) + { + actualDirectory = null; + return null; + } +} diff --git a/src/NerdBank.GitVersioning/GitContext.cs b/src/NerdBank.GitVersioning/GitContext.cs index 3f481f170..22e792f49 100644 --- a/src/NerdBank.GitVersioning/GitContext.cs +++ b/src/NerdBank.GitVersioning/GitContext.cs @@ -41,6 +41,24 @@ protected GitContext(string workingTreePath, string? dotGitPath) this.DotGitPath = dotGitPath; } + public enum Engine + { + /// + /// Uses the faster and platform independent managed git implementation. + /// + ReadOnly, + + /// + /// Uses the LibGit2 engine. + /// + ReadWrite, + + /// + /// Uses a stubbed out engine that doesn't compute versions at all. + /// + Disabled, + } + /// /// Gets the absolute path to the base directory of the git working tree. /// @@ -110,17 +128,21 @@ public string RepoRelativeProjectDirectory /// /// The path to a directory for which version information is required. /// The SHA-1 or ref for a git commit. - /// if mutating the git repository may be required; otherwise. + /// The git engine to use. /// The newly created . - public static GitContext Create(string path, string? committish = null, bool writable = false) + public static GitContext Create(string path, string? committish = null, Engine engine = Engine.ReadOnly) { Requires.NotNull(path, nameof(path)); if (TryFindGitPaths(path, out string? gitDirectory, out string? workingTreeDirectory, out string? workingTreeRelativePath)) { - GitContext result = writable - ? new LibGit2.LibGit2Context(workingTreeDirectory, gitDirectory, committish) - : new Managed.ManagedGitContext(workingTreeDirectory, gitDirectory, committish); + GitContext result = engine switch + { + Engine.Disabled => new DisabledGitContext(workingTreeDirectory), + Engine.ReadWrite => new LibGit2.LibGit2Context(workingTreeDirectory, gitDirectory, committish), + Engine.ReadOnly => new Managed.ManagedGitContext(workingTreeDirectory, gitDirectory, committish), + _ => throw new ArgumentException("Unrecognized value.", nameof(engine)), + }; result.RepoRelativeProjectDirectory = workingTreeRelativePath; return result; } diff --git a/src/NerdBank.GitVersioning/ReleaseManager.cs b/src/NerdBank.GitVersioning/ReleaseManager.cs index af5f9fd18..9dc198010 100644 --- a/src/NerdBank.GitVersioning/ReleaseManager.cs +++ b/src/NerdBank.GitVersioning/ReleaseManager.cs @@ -311,7 +311,7 @@ private LibGit2Context GetRepository(string projectDirectory) { // open git repo and use default configuration (in order to commit we need a configured user name and email // which is most likely configured on a user/system level rather than the repo level. - var context = GitContext.Create(projectDirectory, writable: true); + var context = GitContext.Create(projectDirectory, engine: GitContext.Engine.ReadWrite); if (!context.IsRepository) { this.stderr.WriteLine($"No git repository found above directory '{projectDirectory}'."); diff --git a/src/Nerdbank.GitVersioning.Tasks/GetBuildVersion.cs b/src/Nerdbank.GitVersioning.Tasks/GetBuildVersion.cs index 816951e1c..f38aeb252 100644 --- a/src/Nerdbank.GitVersioning.Tasks/GetBuildVersion.cs +++ b/src/Nerdbank.GitVersioning.Tasks/GetBuildVersion.cs @@ -219,13 +219,16 @@ protected override bool ExecuteInner() Requires.Argument(!containsDotDotSlash, nameof(this.ProjectPathRelativeToGitRepoRoot), "Path must not use ..\\"); } - bool useLibGit2 = false; + GitContext.Engine engine = GitContext.Engine.ReadOnly; if (!string.IsNullOrWhiteSpace(this.GitEngine)) { - useLibGit2 = - this.GitEngine == "Managed" ? false : - this.GitEngine == "LibGit2" ? true : - throw new ArgumentException("GitEngine property must be set to either \"Managed\" or \"LibGit2\" or left empty."); + engine = this.GitEngine switch + { + "Managed" => GitContext.Engine.ReadOnly, + "LibGit2" => GitContext.Engine.ReadWrite, + "Disabled" => GitContext.Engine.Disabled, + _ => throw new ArgumentException("GitEngine property must be set to either \"Disabled\", \"Managed\" or \"LibGit2\" or left empty."), + }; } ICloudBuild cloudBuild = CloudBuild.Active; @@ -233,7 +236,7 @@ protected override bool ExecuteInner() string projectDirectory = this.ProjectPathRelativeToGitRepoRoot is object && this.GitRepoRoot is object ? Path.Combine(this.GitRepoRoot, this.ProjectPathRelativeToGitRepoRoot) : this.ProjectDirectory; - using var context = GitContext.Create(projectDirectory, writable: useLibGit2); + using var context = GitContext.Create(projectDirectory, engine: engine); var oracle = new VersionOracle(context, cloudBuild, overrideBuildNumberOffset); if (!string.IsNullOrEmpty(this.DefaultPublicRelease)) { diff --git a/src/Nerdbank.GitVersioning.Tasks/build/MSBuildTargetCaching.targets b/src/Nerdbank.GitVersioning.Tasks/build/MSBuildTargetCaching.targets index 3f367900f..2a9a7daa0 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/MSBuildTargetCaching.targets +++ b/src/Nerdbank.GitVersioning.Tasks/build/MSBuildTargetCaching.targets @@ -7,6 +7,7 @@ $(NBGV_InnerGlobalProperties)GitVersionBaseDirectory=$(GitVersionBaseDirectory); $(NBGV_InnerGlobalProperties)OverrideBuildNumberOffset=$(OverrideBuildNumberOffset); $(NBGV_InnerGlobalProperties)NBGV_PrivateP2PAuxTargets=$(NBGV_PrivateP2PAuxTargets); + $(NBGV_InnerGlobalProperties)NBGV_GitEngine=$(NBGV_GitEngine); diff --git a/src/nbgv/Program.cs b/src/nbgv/Program.cs index d1380d711..960e2062f 100644 --- a/src/nbgv/Program.cs +++ b/src/nbgv/Program.cs @@ -315,7 +315,7 @@ private static async Task OnInstallCommand(string path, string version, str return (int)ExitCodes.NoGitRepo; } - using var context = GitContext.Create(searchPath, writable: true); + using var context = GitContext.Create(searchPath, engine: GitContext.Engine.ReadWrite); if (!context.IsRepository) { Console.Error.WriteLine("No git repo found at or above: \"{0}\"", searchPath); @@ -417,7 +417,7 @@ private static Task OnGetVersionCommand(string project, string[] metadata, string searchPath = GetSpecifiedOrCurrentDirectoryPath(project); - using var context = GitContext.Create(searchPath, writable: AlwaysUseLibGit2); + using var context = GitContext.Create(searchPath, engine: AlwaysUseLibGit2 ? GitContext.Engine.ReadWrite : GitContext.Engine.ReadOnly); if (!context.IsRepository) { Console.Error.WriteLine("No git repo found at or above: \"{0}\"", searchPath); @@ -500,7 +500,7 @@ private static Task OnSetVersionCommand(string project, string version) }; string searchPath = GetSpecifiedOrCurrentDirectoryPath(project); - using var context = GitContext.Create(searchPath, writable: true); + using var context = GitContext.Create(searchPath, engine: GitContext.Engine.ReadWrite); VersionOptions existingOptions = context.VersionFile.GetVersion(out string actualDirectory); string versionJsonPath; if (existingOptions is not null) @@ -540,7 +540,7 @@ private static Task OnTagCommand(string project, string versionOrRef) string searchPath = GetSpecifiedOrCurrentDirectoryPath(project); - using var context = (LibGit2Context)GitContext.Create(searchPath, writable: true); + using var context = (LibGit2Context)GitContext.Create(searchPath, engine: GitContext.Engine.ReadWrite); if (context is null) { Console.Error.WriteLine("No git repo found at or above: \"{0}\"", searchPath); @@ -639,7 +639,7 @@ private static Task OnGetCommitsCommand(string project, bool quiet, string string searchPath = GetSpecifiedOrCurrentDirectoryPath(project); - using var context = (LibGit2Context)GitContext.Create(searchPath, writable: true); + using var context = (LibGit2Context)GitContext.Create(searchPath, engine: GitContext.Engine.ReadWrite); if (!context.IsRepository) { Console.Error.WriteLine("No git repo found at or above: \"{0}\"", searchPath); diff --git a/test/Nerdbank.GitVersioning.Benchmarks/GetVersionBenchmarks.cs b/test/Nerdbank.GitVersioning.Benchmarks/GetVersionBenchmarks.cs index 7a97daa88..b1bbda93e 100644 --- a/test/Nerdbank.GitVersioning.Benchmarks/GetVersionBenchmarks.cs +++ b/test/Nerdbank.GitVersioning.Benchmarks/GetVersionBenchmarks.cs @@ -28,7 +28,7 @@ public class GetVersionBenchmarks [Benchmark(Baseline = true)] public void GetVersionLibGit2() { - using var context = GitContext.Create(GetPath(this.ProjectDirectory), writable: true); + using var context = GitContext.Create(GetPath(this.ProjectDirectory), engine: GitContext.Engine.ReadWrite); var oracle = new VersionOracle(context, cloudBuild: null); this.Version = oracle.Version; } @@ -36,7 +36,7 @@ public void GetVersionLibGit2() [Benchmark] public void GetVersionManaged() { - using var context = GitContext.Create(GetPath(this.ProjectDirectory), writable: false); + using var context = GitContext.Create(GetPath(this.ProjectDirectory), engine: GitContext.Engine.ReadOnly); var oracle = new VersionOracle(context, cloudBuild: null); this.Version = oracle.Version; } diff --git a/test/Nerdbank.GitVersioning.Tests/BuildIntegrationDisabledTests.cs b/test/Nerdbank.GitVersioning.Tests/BuildIntegrationDisabledTests.cs new file mode 100644 index 000000000..c9ef482fa --- /dev/null +++ b/test/Nerdbank.GitVersioning.Tests/BuildIntegrationDisabledTests.cs @@ -0,0 +1,24 @@ +// 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 Nerdbank.GitVersioning; +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 BuildIntegrationDisabledTests : BuildIntegrationTests +{ + private const string EngineString = "Disabled"; + + public BuildIntegrationDisabledTests(ITestOutputHelper logger) + : base(logger) + { + } + + protected override GitContext CreateGitContext(string path, string committish = null) + => GitContext.Create(path, committish, GitContext.Engine.Disabled); + + protected override void ApplyGlobalProperties(IDictionary globalProperties) + => globalProperties["NBGV_GitEngine"] = EngineString; +} diff --git a/test/Nerdbank.GitVersioning.Tests/BuildIntegrationInProjectManagedTests.cs b/test/Nerdbank.GitVersioning.Tests/BuildIntegrationInProjectManagedTests.cs new file mode 100644 index 000000000..ea0e4a472 --- /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/BuildIntegrationLibGit2Tests.cs b/test/Nerdbank.GitVersioning.Tests/BuildIntegrationLibGit2Tests.cs new file mode 100644 index 000000000..42884ff91 --- /dev/null +++ b/test/Nerdbank.GitVersioning.Tests/BuildIntegrationLibGit2Tests.cs @@ -0,0 +1,24 @@ +// 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 Nerdbank.GitVersioning; +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 BuildIntegrationLibGit2Tests : SomeGitBuildIntegrationTests +{ + private const string EngineString = "LibGit2"; + + public BuildIntegrationLibGit2Tests(ITestOutputHelper logger) + : base(logger) + { + } + + protected override GitContext CreateGitContext(string path, string committish = null) + => GitContext.Create(path, committish, GitContext.Engine.ReadWrite); + + protected override void ApplyGlobalProperties(IDictionary globalProperties) + => globalProperties["NBGV_GitEngine"] = EngineString; +} diff --git a/test/Nerdbank.GitVersioning.Tests/BuildIntegrationManagedTests.cs b/test/Nerdbank.GitVersioning.Tests/BuildIntegrationManagedTests.cs new file mode 100644 index 000000000..f7b839dcd --- /dev/null +++ b/test/Nerdbank.GitVersioning.Tests/BuildIntegrationManagedTests.cs @@ -0,0 +1,24 @@ +// 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 Nerdbank.GitVersioning; +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 BuildIntegrationManagedTests : SomeGitBuildIntegrationTests +{ + protected const string EngineString = "Managed"; + + public BuildIntegrationManagedTests(ITestOutputHelper logger) + : base(logger) + { + } + + protected override GitContext CreateGitContext(string path, string committish = null) + => GitContext.Create(path, committish, GitContext.Engine.ReadOnly); + + protected override void ApplyGlobalProperties(IDictionary globalProperties) + => globalProperties["NBGV_GitEngine"] = EngineString; +} diff --git a/test/Nerdbank.GitVersioning.Tests/BuildIntegrationTests.cs b/test/Nerdbank.GitVersioning.Tests/BuildIntegrationTests.cs index 33f636d3f..c694b9916 100644 --- a/test/Nerdbank.GitVersioning.Tests/BuildIntegrationTests.cs +++ b/test/Nerdbank.GitVersioning.Tests/BuildIntegrationTests.cs @@ -2,12 +2,10 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Collections.Immutable; -using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Text; using System.Xml; -using LibGit2Sharp; using Microsoft.Build.Construction; using Microsoft.Build.Evaluation; using Microsoft.Build.Execution; @@ -21,72 +19,12 @@ using Xunit.Abstractions; using Version = System.Version; -#pragma warning disable SA1402 // File may only contain a single type -#pragma warning disable SA1649 // File name should match first type name - -[Trait("Engine", "Managed")] -[Collection("Build")] // msbuild sets current directory in the process, so we can't have it be concurrent with other build tests. -public class BuildIntegrationManagedTests : BuildIntegrationTests -{ - public BuildIntegrationManagedTests(ITestOutputHelper logger) - : base(logger) - { - } - - /// - protected override GitContext CreateGitContext(string path, string committish = null) - => GitContext.Create(path, committish, writable: false); - - /// - protected override void ApplyGlobalProperties(IDictionary globalProperties) - => globalProperties["NBGV_GitEngine"] = "Managed"; -} - -[Trait("Engine", "Managed")] -[Collection("Build")] // msbuild sets current directory in the process, so we can't have it be concurrent with other build tests. -public class BuildIntegrationInProjectManagedTests : BuildIntegrationTests -{ - public BuildIntegrationInProjectManagedTests(ITestOutputHelper logger) - : base(logger) - { - } - - /// - protected override GitContext CreateGitContext(string path, string committish = null) - => GitContext.Create(path, committish, writable: false); - - /// - protected override void ApplyGlobalProperties(IDictionary globalProperties) - { - globalProperties["NBGV_GitEngine"] = "Managed"; - globalProperties["NBGV_CacheMode"] = "None"; - } -} - -[Trait("Engine", "LibGit2")] -[Collection("Build")] // msbuild sets current directory in the process, so we can't have it be concurrent with other build tests. -public class BuildIntegrationLibGit2Tests : BuildIntegrationTests -{ - public BuildIntegrationLibGit2Tests(ITestOutputHelper logger) - : base(logger) - { - } - - /// - protected override GitContext CreateGitContext(string path, string committish = null) - => GitContext.Create(path, committish, writable: true); - - /// - protected override void ApplyGlobalProperties(IDictionary globalProperties) - => globalProperties["NBGV_GitEngine"] = "LibGit2"; -} - public abstract class BuildIntegrationTests : RepoTestBase, IClassFixture { - private const string GitVersioningPropsFileName = "Nerdbank.GitVersioning.props"; - private const string GitVersioningTargetsFileName = "Nerdbank.GitVersioning.targets"; - private const string UnitTestCloudBuildPrefix = "UnitTest: "; - private static readonly string[] ToxicEnvironmentVariablePrefixes = new string[] + 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_", @@ -94,18 +32,18 @@ public abstract class BuildIntegrationTests : RepoTestBase, IClassFixture globalProperties = new Dictionary(StringComparer.OrdinalIgnoreCase) + protected BuildManager buildManager; + protected ProjectCollection projectCollection; + protected string projectDirectory; + protected ProjectRootElement testProject; + protected Dictionary globalProperties = new Dictionary(StringComparer.OrdinalIgnoreCase) { // Set global properties to neutralize environment variables // that might actually be defined by a CI that is building and running these tests. { "PublicRelease", string.Empty }, }; - private Random random; + protected Random random; public BuildIntegrationTests(ITestOutputHelper logger) : base(logger) @@ -140,7 +78,7 @@ public static object[][] CloudBuildVariablesData } } - private static VersionOptions BuildNumberVersionOptionsBasis + protected static VersionOptions BuildNumberVersionOptionsBasis { get { @@ -159,7 +97,7 @@ private static VersionOptions BuildNumberVersionOptionsBasis } } - private string CommitIdShort => this.Context.GitCommitId?.Substring(0, VersionOptions.DefaultGitCommitIdShortFixedLength); + protected string CommitIdShort => this.Context.GitCommitId?.Substring(0, VersionOptions.DefaultGitCommitIdShortFixedLength); public static IEnumerable CloudBuildOfBranch(string branchName) { @@ -193,20 +131,6 @@ public async Task GetBuildVersion_Without_Git() Assert.Equal("3.4.0", buildResult.AssemblyInformationalVersion); } - [Fact] - public async Task GetBuildVersion_WithThreeVersionIntegers() - { - VersionOptions workingCopyVersion = new VersionOptions - { - Version = SemanticVersion.Parse("7.8.9-beta.3"), - SemVer1NumericIdentifierPadding = 1, - }; - this.WriteVersionFile(workingCopyVersion); - this.InitializeSourceControl(); - BuildResults buildResult = await this.BuildAsync(); - this.AssertStandardProperties(workingCopyVersion, buildResult); - } - [Fact] public async Task GetBuildVersion_Without_Git_HighPrecisionAssemblyVersion() { @@ -223,645 +147,6 @@ public async Task GetBuildVersion_Without_Git_HighPrecisionAssemblyVersion() Assert.Equal("3.4.0", buildResult.AssemblyInformationalVersion); } - [Fact] - public async Task GetBuildVersion_OutsideGit_PointingToGit() - { - // Write a version file to the 'virtualized' repo. - string version = "3.4"; - this.WriteVersionFile(version); - - string repoRelativeProjectPath = this.testProject.FullPath.Substring(this.RepoPath.Length + 1); - - // Update the repo path so we create the 'normal' one elsewhere - this.RepoPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); - this.InitializeSourceControl(); - - // Write the same version file to the 'real' repo - this.WriteVersionFile(version); - - // Point the project to the 'real' repo - this.testProject.AddProperty("GitRepoRoot", this.RepoPath); - this.testProject.AddProperty("ProjectPathRelativeToGitRepoRoot", repoRelativeProjectPath); - - BuildResults buildResult = await this.BuildAsync(); - - var workingCopyVersion = VersionOptions.FromVersion(new Version(version)); - - this.AssertStandardProperties(workingCopyVersion, buildResult); - } - - [Fact] - public async Task GetBuildVersion_In_Git_But_Without_Commits() - { - Repository.Init(this.RepoPath); - var repo = new Repository(this.RepoPath); // do not assign Repo property to avoid commits being generated later - this.WriteVersionFile("3.4"); - Assumes.False(repo.Head.Commits.Any()); // verification that the test is doing what it claims - BuildResults buildResult = await this.BuildAsync(); - Assert.Equal("3.4.0.0", buildResult.BuildVersion); - Assert.Equal("3.4.0", buildResult.AssemblyInformationalVersion); - } - - [Fact] - public async Task GetBuildVersion_In_Git_But_Head_Lacks_VersionFile() - { - Repository.Init(this.RepoPath); - var repo = new Repository(this.RepoPath); // do not assign Repo property to avoid commits being generated later - repo.Commit("empty", this.Signer, this.Signer, new CommitOptions { AllowEmptyCommit = true }); - this.WriteVersionFile("3.4"); - Assumes.True(repo.Index[VersionFile.JsonFileName] is null); - BuildResults buildResult = await this.BuildAsync(); - Assert.Equal("3.4.0." + this.GetVersion().Revision, buildResult.BuildVersion); - Assert.Equal("3.4.0+" + repo.Head.Tip.Id.Sha.Substring(0, VersionOptions.DefaultGitCommitIdShortFixedLength), buildResult.AssemblyInformationalVersion); - } - - [Fact] - public async Task GetBuildVersion_In_Git_But_WorkingCopy_Has_Changes() - { - const string majorMinorVersion = "5.8"; - const string prerelease = ""; - - this.WriteVersionFile(majorMinorVersion, prerelease); - this.InitializeSourceControl(); - var workingCopyVersion = VersionOptions.FromVersion(new Version("6.0")); - this.Context.VersionFile.SetVersion(this.RepoPath, workingCopyVersion); - BuildResults buildResult = await this.BuildAsync(); - this.AssertStandardProperties(workingCopyVersion, buildResult); - } - - [Fact] - public async Task GetBuildVersion_In_Git_No_VersionFile_At_All() - { - Repository.Init(this.RepoPath); - var repo = new Repository(this.RepoPath); // do not assign Repo property to avoid commits being generated later - repo.Commit("empty", this.Signer, this.Signer, new CommitOptions { AllowEmptyCommit = true }); - BuildResults buildResult = await this.BuildAsync(); - Assert.Equal("0.0.0." + this.GetVersion().Revision, buildResult.BuildVersion); - Assert.Equal("0.0.0+" + repo.Head.Tip.Id.Sha.Substring(0, VersionOptions.DefaultGitCommitIdShortFixedLength), buildResult.AssemblyInformationalVersion); - } - - [Fact] - public async Task GetBuildVersion_In_Git_With_Version_File_In_Subdirectory_Works() - { - const string majorMinorVersion = "5.8"; - const string prerelease = ""; - const string subdirectory = "projdir"; - - this.WriteVersionFile(majorMinorVersion, prerelease, subdirectory); - this.InitializeSourceControl(); - this.AddCommits(this.random.Next(15)); - BuildResults buildResult = await this.BuildAsync(); - this.AssertStandardProperties(VersionOptions.FromVersion(new Version(majorMinorVersion)), buildResult, subdirectory); - } - - [Fact] - public async Task GetBuildVersion_In_Git_With_Version_File_In_Root_And_Subdirectory_Works() - { - var rootVersionSpec = new VersionOptions - { - Version = SemanticVersion.Parse("14.1"), - AssemblyVersion = new VersionOptions.AssemblyVersionOptions(new Version(14, 0)), - }; - var subdirVersionSpec = new VersionOptions { Version = SemanticVersion.Parse("11.0") }; - const string subdirectory = "projdir"; - - this.WriteVersionFile(rootVersionSpec); - this.WriteVersionFile(subdirVersionSpec, subdirectory); - this.InitializeSourceControl(); - this.AddCommits(this.random.Next(15)); - BuildResults buildResult = await this.BuildAsync(); - this.AssertStandardProperties(subdirVersionSpec, buildResult, subdirectory); - } - - [Fact] - public async Task GetBuildVersion_In_Git_With_Version_File_In_Root_And_Project_In_Root_Works() - { - var rootVersionSpec = new VersionOptions - { - Version = SemanticVersion.Parse("14.1"), - AssemblyVersion = new VersionOptions.AssemblyVersionOptions(new Version(14, 0)), - }; - - this.WriteVersionFile(rootVersionSpec); - this.InitializeSourceControl(); - this.AddCommits(this.random.Next(15)); - this.testProject = this.CreateProjectRootElement(this.RepoPath, "root.proj"); - BuildResults buildResult = await this.BuildAsync(); - this.AssertStandardProperties(rootVersionSpec, buildResult); - } - - [Fact] - public async Task GetBuildVersion_StablePreRelease() - { - const string majorMinorVersion = "5.8"; - const string prerelease = ""; - - this.WriteVersionFile(majorMinorVersion, prerelease); - this.InitializeSourceControl(); - this.AddCommits(this.random.Next(15)); - BuildResults buildResult = await this.BuildAsync(); - this.AssertStandardProperties(VersionOptions.FromVersion(new Version(majorMinorVersion)), buildResult); - } - - [Fact] - public async Task GetBuildVersion_StableRelease() - { - const string majorMinorVersion = "5.8"; - const string prerelease = ""; - - this.WriteVersionFile(majorMinorVersion, prerelease); - this.InitializeSourceControl(); - this.AddCommits(this.random.Next(15)); - this.globalProperties["PublicRelease"] = "true"; - BuildResults buildResult = await this.BuildAsync(); - this.AssertStandardProperties(VersionOptions.FromVersion(new Version(majorMinorVersion)), buildResult); - - Version version = this.GetVersion(); - Assert.Equal($"{version.Major}.{version.Minor}.{buildResult.GitVersionHeight}", buildResult.NuGetPackageVersion); - } - - [Fact] - public async Task GetBuildVersion_UnstablePreRelease() - { - const string majorMinorVersion = "5.8"; - const string prerelease = "-beta"; - - this.WriteVersionFile(majorMinorVersion, prerelease); - this.InitializeSourceControl(); - this.AddCommits(this.random.Next(15)); - BuildResults buildResult = await this.BuildAsync(); - this.AssertStandardProperties(VersionOptions.FromVersion(new Version(majorMinorVersion), prerelease), buildResult); - } - - [Fact] - public async Task GetBuildVersion_UnstableRelease() - { - const string majorMinorVersion = "5.8"; - const string prerelease = "-beta"; - - this.WriteVersionFile(majorMinorVersion, prerelease); - this.InitializeSourceControl(); - this.AddCommits(this.random.Next(15)); - this.globalProperties["PublicRelease"] = "true"; - BuildResults buildResult = await this.BuildAsync(); - this.AssertStandardProperties(VersionOptions.FromVersion(new Version(majorMinorVersion), prerelease), buildResult); - } - - [Fact] - public async Task GetBuildVersion_CustomAssemblyVersion() - { - this.WriteVersionFile("14.0"); - this.InitializeSourceControl(); - var versionOptions = new VersionOptions - { - Version = new SemanticVersion(new Version(14, 1)), - AssemblyVersion = new VersionOptions.AssemblyVersionOptions(new Version(14, 0)), - }; - this.WriteVersionFile(versionOptions); - BuildResults buildResult = await this.BuildAsync(); - this.AssertStandardProperties(versionOptions, buildResult); - } - - [Theory] - [InlineData(VersionOptions.VersionPrecision.Major)] - [InlineData(VersionOptions.VersionPrecision.Build)] - [InlineData(VersionOptions.VersionPrecision.Revision)] - public async Task GetBuildVersion_CustomAssemblyVersionWithPrecision(VersionOptions.VersionPrecision precision) - { - var versionOptions = new VersionOptions - { - Version = new SemanticVersion("14.1"), - AssemblyVersion = new VersionOptions.AssemblyVersionOptions - { - Version = new Version("15.2"), - Precision = precision, - }, - }; - this.WriteVersionFile(versionOptions); - this.InitializeSourceControl(); - BuildResults buildResult = await this.BuildAsync(); - this.AssertStandardProperties(versionOptions, buildResult); - } - - [Theory] - [InlineData(VersionOptions.VersionPrecision.Major)] - [InlineData(VersionOptions.VersionPrecision.Build)] - [InlineData(VersionOptions.VersionPrecision.Revision)] - public async Task GetBuildVersion_CustomAssemblyVersionPrecision(VersionOptions.VersionPrecision precision) - { - var versionOptions = new VersionOptions - { - Version = new SemanticVersion("14.1"), - AssemblyVersion = new VersionOptions.AssemblyVersionOptions - { - Precision = precision, - }, - }; - this.WriteVersionFile(versionOptions); - this.InitializeSourceControl(); - BuildResults buildResult = await this.BuildAsync(); - this.AssertStandardProperties(versionOptions, buildResult); - } - - [Fact] - public async Task GetBuildVersion_CustomBuildNumberOffset() - { - this.WriteVersionFile("14.0"); - this.InitializeSourceControl(); - var versionOptions = new VersionOptions - { - Version = new SemanticVersion(new Version(14, 1)), - VersionHeightOffset = 5, - }; - this.WriteVersionFile(versionOptions); - BuildResults buildResult = await this.BuildAsync(); - this.AssertStandardProperties(versionOptions, buildResult); - } - - [Fact] - public async Task GetBuildVersion_OverrideBuildNumberOffset() - { - this.WriteVersionFile("14.0"); - this.InitializeSourceControl(); - var versionOptions = new VersionOptions - { - Version = new SemanticVersion(new Version(14, 1)), - }; - this.WriteVersionFile(versionOptions); - this.testProject.AddProperty("OverrideBuildNumberOffset", "10"); - BuildResults buildResult = await this.BuildAsync(); - Assert.StartsWith("14.1.11.", buildResult.AssemblyFileVersion); - } - - [Fact] - public async Task GetBuildVersion_Minus1BuildOffset_NotYetCommitted() - { - this.WriteVersionFile("14.0"); - this.InitializeSourceControl(); - var versionOptions = new VersionOptions - { - Version = new SemanticVersion(new Version(14, 1)), - VersionHeightOffset = -1, - }; - this.Context.VersionFile.SetVersion(this.RepoPath, versionOptions); - BuildResults buildResult = await this.BuildAsync(); - this.AssertStandardProperties(versionOptions, buildResult); - } - - [Theory] - [InlineData(0)] - [InlineData(21)] - public async Task GetBuildVersion_BuildNumberSpecifiedInVersionJson(int buildNumber) - { - var versionOptions = new VersionOptions - { - Version = SemanticVersion.Parse("14.0." + buildNumber), - }; - this.WriteVersionFile(versionOptions); - this.InitializeSourceControl(); - BuildResults buildResult = await this.BuildAsync(); - this.AssertStandardProperties(versionOptions, buildResult); - } - - [Fact] - public async Task PublicRelease_RegEx_Unsatisfied() - { - var versionOptions = new VersionOptions - { - Version = SemanticVersion.Parse("1.0"), - PublicReleaseRefSpec = new string[] { "^refs/heads/release$" }, - }; - this.WriteVersionFile(versionOptions); - this.InitializeSourceControl(); - - // Just build "master", which doesn't conform to the regex. - BuildResults buildResult = await this.BuildAsync(); - Assert.False(buildResult.PublicRelease); - this.AssertStandardProperties(versionOptions, buildResult); - } - - [Theory] - [MemberData(nameof(CloudBuildOfBranch), "release")] - public async Task PublicRelease_RegEx_SatisfiedByCI(IReadOnlyDictionary serverProperties) - { - var versionOptions = new VersionOptions - { - Version = SemanticVersion.Parse("1.0"), - PublicReleaseRefSpec = new string[] - { - "^refs/heads/release$", - "^refs/tags/release$", - }, - }; - this.WriteVersionFile(versionOptions); - this.InitializeSourceControl(); - - // Don't actually switch the checked out branch in git. CI environment variables - // should take precedence over actual git configuration. (Why? because these variables may - // retain information about which tag was checked out on a detached head). - using (ApplyEnvironmentVariables(serverProperties)) - { - BuildResults buildResult = await this.BuildAsync(); - Assert.True(buildResult.PublicRelease); - this.AssertStandardProperties(versionOptions, buildResult); - } - } - - [Theory] - [Trait("TestCategory", "FailsInCloudTest")] - [MemberData(nameof(CloudBuildVariablesData))] - public async Task CloudBuildVariables_SetInCI(IReadOnlyDictionary properties, string expectedMessage, bool setAllVariables) - { - using (ApplyEnvironmentVariables(properties)) - { - string keyName = "n1"; - string value = "v1"; - this.testProject.AddItem("CloudBuildVersionVars", keyName, new Dictionary { { "Value", value } }); - - string alwaysExpectedMessage = UnitTestCloudBuildPrefix + expectedMessage - .Replace("{NAME}", keyName) - .Replace("{VALUE}", value); - - var versionOptions = new VersionOptions - { - Version = SemanticVersion.Parse("1.0"), - CloudBuild = new VersionOptions.CloudBuildOptions { SetAllVariables = setAllVariables, SetVersionVariables = true }, - }; - this.WriteVersionFile(versionOptions); - this.InitializeSourceControl(); - - BuildResults buildResult = await this.BuildAsync(); - this.AssertStandardProperties(versionOptions, buildResult); - - // Assert GitBuildVersion was set - string conditionallyExpectedMessage = UnitTestCloudBuildPrefix + expectedMessage - .Replace("{NAME}", "GitBuildVersion") - .Replace("{VALUE}", buildResult.BuildVersion); - Assert.Contains(alwaysExpectedMessage, buildResult.LoggedEvents.Select(e => e.Message.TrimEnd())); - Assert.Contains(conditionallyExpectedMessage, buildResult.LoggedEvents.Select(e => e.Message.TrimEnd())); - - // Assert GitBuildVersionSimple was set - conditionallyExpectedMessage = UnitTestCloudBuildPrefix + expectedMessage - .Replace("{NAME}", "GitBuildVersionSimple") - .Replace("{VALUE}", buildResult.BuildVersionSimple); - Assert.Contains(alwaysExpectedMessage, buildResult.LoggedEvents.Select(e => e.Message.TrimEnd())); - Assert.Contains(conditionallyExpectedMessage, buildResult.LoggedEvents.Select(e => e.Message.TrimEnd())); - - // Assert that project properties are also set. - Assert.Equal(buildResult.BuildVersion, buildResult.GitBuildVersion); - Assert.Equal(buildResult.BuildVersionSimple, buildResult.GitBuildVersionSimple); - Assert.Equal(buildResult.AssemblyInformationalVersion, buildResult.GitAssemblyInformationalVersion); - - if (setAllVariables) - { - // Assert that some project properties were set as build properties prefaced with "NBGV_". - Assert.Equal(buildResult.GitCommitIdShort, buildResult.NBGV_GitCommitIdShort); - Assert.Equal(buildResult.NuGetPackageVersion, buildResult.NBGV_NuGetPackageVersion); - } - else - { - // Assert that the NBGV_ prefixed properties are *not* set. - Assert.Equal(string.Empty, buildResult.NBGV_GitCommitIdShort); - Assert.Equal(string.Empty, buildResult.NBGV_NuGetPackageVersion); - } - - // Assert that env variables were also set in context of the build. - 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); - this.SetContextToHead(); - buildResult = await this.BuildAsync(); - this.AssertStandardProperties(versionOptions, buildResult); - - // Assert GitBuildVersion was not set - conditionallyExpectedMessage = UnitTestCloudBuildPrefix + expectedMessage - .Replace("{NAME}", "GitBuildVersion") - .Replace("{VALUE}", buildResult.BuildVersion); - Assert.Contains(alwaysExpectedMessage, buildResult.LoggedEvents.Select(e => e.Message.TrimEnd())); - Assert.DoesNotContain(conditionallyExpectedMessage, buildResult.LoggedEvents.Select(e => e.Message.TrimEnd())); - Assert.NotEqual(buildResult.BuildVersion, buildResult.BuildResult.ProjectStateAfterBuild.GetPropertyValue("GitBuildVersion")); - - // Assert GitBuildVersionSimple was not set - conditionallyExpectedMessage = UnitTestCloudBuildPrefix + expectedMessage - .Replace("{NAME}", "GitBuildVersionSimple") - .Replace("{VALUE}", buildResult.BuildVersionSimple); - Assert.Contains(alwaysExpectedMessage, buildResult.LoggedEvents.Select(e => e.Message.TrimEnd())); - Assert.DoesNotContain(conditionallyExpectedMessage, buildResult.LoggedEvents.Select(e => e.Message.TrimEnd())); - Assert.NotEqual(buildResult.BuildVersionSimple, buildResult.BuildResult.ProjectStateAfterBuild.GetPropertyValue("GitBuildVersionSimple")); - } - } - - [Theory] - [MemberData(nameof(BuildNumberData))] - public async Task BuildNumber_SetInCI(VersionOptions versionOptions, IReadOnlyDictionary properties, string expectedBuildNumberMessage) - { - this.WriteVersionFile(versionOptions); - this.InitializeSourceControl(); - using (ApplyEnvironmentVariables(properties)) - { - BuildResults buildResult = await this.BuildAsync(); - this.AssertStandardProperties(versionOptions, buildResult); - expectedBuildNumberMessage = expectedBuildNumberMessage.Replace("{CLOUDBUILDNUMBER}", buildResult.CloudBuildNumber); - Assert.Contains(UnitTestCloudBuildPrefix + expectedBuildNumberMessage, buildResult.LoggedEvents.Select(e => e.Message.TrimEnd())); - } - - versionOptions.CloudBuild.BuildNumber.Enabled = false; - this.WriteVersionFile(versionOptions); - using (ApplyEnvironmentVariables(properties)) - { - BuildResults buildResult = await this.BuildAsync(); - this.AssertStandardProperties(versionOptions, buildResult); - expectedBuildNumberMessage = expectedBuildNumberMessage.Replace("{CLOUDBUILDNUMBER}", buildResult.CloudBuildNumber); - Assert.DoesNotContain(UnitTestCloudBuildPrefix + expectedBuildNumberMessage, buildResult.LoggedEvents.Select(e => e.Message.TrimEnd())); - } - } - - [Theory] - [PairwiseData] - public async Task BuildNumber_VariousOptions(bool isPublic, VersionOptions.CloudBuildNumberCommitWhere where, VersionOptions.CloudBuildNumberCommitWhen when, [CombinatorialValues(0, 1, 2)] int extraBuildMetadataCount, [CombinatorialValues(1, 2)] int semVer) - { - VersionOptions versionOptions = BuildNumberVersionOptionsBasis; - versionOptions.CloudBuild.BuildNumber.IncludeCommitId.Where = where; - versionOptions.CloudBuild.BuildNumber.IncludeCommitId.When = when; - versionOptions.NuGetPackageVersion = new VersionOptions.NuGetPackageVersionOptions - { - SemVer = semVer, - }; - this.WriteVersionFile(versionOptions); - this.InitializeSourceControl(); - - this.globalProperties["PublicRelease"] = isPublic.ToString(); - for (int i = 0; i < extraBuildMetadataCount; i++) - { - this.testProject.AddItem("BuildMetadata", $"A{i}"); - } - - BuildResults buildResult = await this.BuildAsync(); - this.AssertStandardProperties(versionOptions, buildResult); - } - - [Fact] - public void GitLab_BuildTag() - { - // Based on the values defined in https://docs.gitlab.com/ee/ci/variables/#syntax-of-environment-variables-in-job-scripts - using (ApplyEnvironmentVariables( - CloudBuild.SuppressEnvironment.SetItems( - new Dictionary() - { - { "CI_COMMIT_TAG", "1.0.0" }, - { "CI_COMMIT_SHA", "1ecfd275763eff1d6b4844ea3168962458c9f27a" }, - { "GITLAB_CI", "true" }, - { "SYSTEM_TEAMPROJECTID", string.Empty }, - }))) - { - ICloudBuild activeCloudBuild = Nerdbank.GitVersioning.CloudBuild.Active; - Assert.NotNull(activeCloudBuild); - Assert.Null(activeCloudBuild.BuildingBranch); - Assert.Equal("refs/tags/1.0.0", activeCloudBuild.BuildingTag); - Assert.Equal("1ecfd275763eff1d6b4844ea3168962458c9f27a", activeCloudBuild.GitCommitId); - Assert.True(activeCloudBuild.IsApplicable); - Assert.False(activeCloudBuild.IsPullRequest); - } - } - - [Fact] - public void GitLab_BuildBranch() - { - // Based on the values defined in https://docs.gitlab.com/ee/ci/variables/#syntax-of-environment-variables-in-job-scripts - using (ApplyEnvironmentVariables( - CloudBuild.SuppressEnvironment.SetItems( - new Dictionary() - { - { "CI_COMMIT_REF_NAME", "master" }, - { "CI_COMMIT_SHA", "1ecfd275763eff1d6b4844ea3168962458c9f27a" }, - { "GITLAB_CI", "true" }, - }))) - { - ICloudBuild activeCloudBuild = Nerdbank.GitVersioning.CloudBuild.Active; - Assert.NotNull(activeCloudBuild); - Assert.Equal("refs/heads/master", activeCloudBuild.BuildingBranch); - Assert.Null(activeCloudBuild.BuildingTag); - Assert.Equal("1ecfd275763eff1d6b4844ea3168962458c9f27a", activeCloudBuild.GitCommitId); - Assert.True(activeCloudBuild.IsApplicable); - Assert.False(activeCloudBuild.IsPullRequest); - } - } - - [Fact] - public async Task PublicRelease_RegEx_SatisfiedByCheckedOutBranch() - { - var versionOptions = new VersionOptions - { - Version = SemanticVersion.Parse("1.0"), - PublicReleaseRefSpec = new string[] { "^refs/heads/release$" }, - }; - this.WriteVersionFile(versionOptions); - this.InitializeSourceControl(); - - using (ApplyEnvironmentVariables(CloudBuild.SuppressEnvironment)) - { - // Check out a branch that conforms. - Branch releaseBranch = this.LibGit2Repository.CreateBranch("release"); - Commands.Checkout(this.LibGit2Repository, releaseBranch); - BuildResults buildResult = await this.BuildAsync(); - Assert.True(buildResult.PublicRelease); - this.AssertStandardProperties(versionOptions, buildResult); - } - } - - // This test builds projects using 'classic' MSBuild projects, which target net45. - // This is not supported on Linux. - [WindowsTheory] - [PairwiseData] - public async Task AssemblyInfo(bool isVB, bool includeNonVersionAttributes, bool gitRepo, bool isPrerelease, bool isPublicRelease) - { - this.WriteVersionFile(prerelease: isPrerelease ? "-beta" : string.Empty); - if (gitRepo) - { - this.InitializeSourceControl(); - } - - if (isVB) - { - this.MakeItAVBProject(); - } - - if (includeNonVersionAttributes) - { - this.testProject.AddProperty("NBGV_EmitNonVersionCustomAttributes", "true"); - } - - this.globalProperties["PublicRelease"] = isPublicRelease ? "true" : "false"; - - BuildResults result = await this.BuildAsync("Build", logVerbosity: LoggerVerbosity.Minimal); - string assemblyPath = result.BuildResult.ProjectStateAfterBuild.GetPropertyValue("TargetPath"); - string versionFileContent = File.ReadAllText(Path.Combine(this.projectDirectory, result.BuildResult.ProjectStateAfterBuild.GetPropertyValue("VersionSourceFile"))); - this.Logger.WriteLine(versionFileContent); - - var assembly = Assembly.LoadFile(assemblyPath); - - AssemblyFileVersionAttribute assemblyFileVersion = assembly.GetCustomAttribute(); - AssemblyInformationalVersionAttribute assemblyInformationalVersion = assembly.GetCustomAttribute(); - AssemblyTitleAttribute assemblyTitle = assembly.GetCustomAttribute(); - AssemblyProductAttribute assemblyProduct = assembly.GetCustomAttribute(); - AssemblyCompanyAttribute assemblyCompany = assembly.GetCustomAttribute(); - AssemblyCopyrightAttribute assemblyCopyright = assembly.GetCustomAttribute(); - Type thisAssemblyClass = assembly.GetType("ThisAssembly") ?? assembly.GetType("TestNamespace.ThisAssembly"); - Assert.NotNull(thisAssemblyClass); - - Assert.Equal(new Version(result.AssemblyVersion), assembly.GetName().Version); - Assert.Equal(result.AssemblyFileVersion, assemblyFileVersion.Version); - Assert.Equal(result.AssemblyInformationalVersion, assemblyInformationalVersion.InformationalVersion); - if (includeNonVersionAttributes) - { - Assert.Equal(result.AssemblyTitle, assemblyTitle.Title); - Assert.Equal(result.AssemblyProduct, assemblyProduct.Product); - Assert.Equal(result.AssemblyCompany, assemblyCompany.Company); - Assert.Equal(result.AssemblyCopyright, assemblyCopyright.Copyright); - } - else - { - Assert.Null(assemblyTitle); - Assert.Null(assemblyProduct); - Assert.Null(assemblyCompany); - Assert.Null(assemblyCopyright); - } - - const BindingFlags fieldFlags = BindingFlags.Static | BindingFlags.NonPublic; - Assert.Equal(result.AssemblyVersion, thisAssemblyClass.GetField("AssemblyVersion", fieldFlags).GetValue(null)); - Assert.Equal(result.AssemblyFileVersion, thisAssemblyClass.GetField("AssemblyFileVersion", fieldFlags).GetValue(null)); - Assert.Equal(result.AssemblyInformationalVersion, thisAssemblyClass.GetField("AssemblyInformationalVersion", fieldFlags).GetValue(null)); - Assert.Equal(result.AssemblyName, thisAssemblyClass.GetField("AssemblyName", fieldFlags).GetValue(null)); - Assert.Equal(result.RootNamespace, thisAssemblyClass.GetField("RootNamespace", fieldFlags).GetValue(null)); - Assert.Equal(result.AssemblyConfiguration, thisAssemblyClass.GetField("AssemblyConfiguration", fieldFlags).GetValue(null)); - Assert.Equal(result.AssemblyTitle, thisAssemblyClass.GetField("AssemblyTitle", fieldFlags)?.GetValue(null)); - Assert.Equal(result.AssemblyProduct, thisAssemblyClass.GetField("AssemblyProduct", fieldFlags)?.GetValue(null)); - Assert.Equal(result.AssemblyCompany, thisAssemblyClass.GetField("AssemblyCompany", fieldFlags)?.GetValue(null)); - Assert.Equal(result.AssemblyCopyright, thisAssemblyClass.GetField("AssemblyCopyright", fieldFlags)?.GetValue(null)); - Assert.Equal(result.GitCommitId, thisAssemblyClass.GetField("GitCommitId", fieldFlags)?.GetValue(null) ?? string.Empty); - Assert.Equal(result.PublicRelease, thisAssemblyClass.GetField("IsPublicRelease", fieldFlags)?.GetValue(null)); - Assert.Equal(!string.IsNullOrEmpty(result.PrereleaseVersion), thisAssemblyClass.GetField("IsPrerelease", fieldFlags)?.GetValue(null)); - - if (gitRepo) - { - Assert.True(long.TryParse(result.GitCommitDateTicks, out _), $"Invalid value for GitCommitDateTicks: '{result.GitCommitDateTicks}'"); - var gitCommitDate = new DateTime(long.Parse(result.GitCommitDateTicks), DateTimeKind.Utc); - Assert.Equal(gitCommitDate, thisAssemblyClass.GetProperty("GitCommitDate", fieldFlags)?.GetValue(null) ?? thisAssemblyClass.GetField("GitCommitDate", fieldFlags)?.GetValue(null) ?? string.Empty); - } - else - { - Assert.Empty(result.GitCommitDateTicks); - Assert.Null(thisAssemblyClass.GetProperty("GitCommitDate", fieldFlags)); - } - - // Verify that it doesn't have key fields - Assert.Null(thisAssemblyClass.GetField("PublicKey", fieldFlags)); - Assert.Null(thisAssemblyClass.GetField("PublicKeyToken", fieldFlags)); - } - // TODO: add key container test. [Theory] [InlineData("keypair.snk", false)] @@ -907,16 +192,6 @@ public async Task AssemblyInfo_HasKeyData(string keyFile, bool delaySigned) } } - [Fact] - [Trait("TestCategory", "FailsInCloudTest")] - public async Task AssemblyInfo_IncrementalBuild() - { - this.WriteVersionFile(prerelease: "-beta"); - await this.BuildAsync("Build", logVerbosity: LoggerVerbosity.Minimal); - this.WriteVersionFile(prerelease: "-rc"); // two characters SHORTER, to test file truncation. - await this.BuildAsync("Build", logVerbosity: LoggerVerbosity.Minimal); - } - /// /// Emulate a project with an unsupported language, and verify that /// one warning is emitted because the assembly info file couldn't be generated. @@ -976,44 +251,7 @@ public async Task AssemblyInfo_SuppressedImplicitlyByTargetExt() Assert.Empty(result.LoggedEvents.OfType()); } -#if !NETCOREAPP - /// - /// Create a native resource .dll and verify that its version - /// information is set correctly. - /// - [Fact] - public async Task NativeVersionInfo_CreateNativeResourceDll() - { - this.testProject = this.CreateNativeProjectRootElement(this.projectDirectory, "test.vcxproj"); - this.WriteVersionFile(); - BuildResults result = await this.BuildAsync(Targets.Build, logVerbosity: LoggerVerbosity.Minimal); - Assert.Empty(result.LoggedEvents.OfType()); - - string targetFile = Path.Combine(this.projectDirectory, result.BuildResult.ProjectStateAfterBuild.GetPropertyValue("TargetPath")); - Assert.True(File.Exists(targetFile)); - - var fileInfo = FileVersionInfo.GetVersionInfo(targetFile); - 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($"Copyright (c) {DateTime.Now.Year}. All rights reserved.", fileInfo.LegalCopyright); - } -#endif - - /// - protected override GitContext CreateGitContext(string path, string committish = null) => throw new NotImplementedException(); - - protected abstract void ApplyGlobalProperties(IDictionary globalProperties); - - /// - protected override void Dispose(bool disposing) - { - Environment.SetEnvironmentVariable("_NBGV_UnitTest", string.Empty); - base.Dispose(disposing); - } - - private static Version GetExpectedAssemblyVersion(VersionOptions versionOptions, Version version) + protected static Version GetExpectedAssemblyVersion(VersionOptions versionOptions, Version version) { // Function should be very similar to VersionOracle.GetAssemblyVersion() Version assemblyVersion = (versionOptions?.AssemblyVersion?.Version ?? versionOptions.Version.Version).EnsureNonNegativeComponents(); @@ -1033,7 +271,7 @@ private static Version GetExpectedAssemblyVersion(VersionOptions versionOptions, return assemblyVersion; } - private static RestoreEnvironmentVariables ApplyEnvironmentVariables(IReadOnlyDictionary variables) + protected static RestoreEnvironmentVariables ApplyEnvironmentVariables(IReadOnlyDictionary variables) { Requires.NotNull(variables, nameof(variables)); @@ -1047,14 +285,14 @@ private static RestoreEnvironmentVariables ApplyEnvironmentVariables(IReadOnlyDi return new RestoreEnvironmentVariables(oldValues); } - private static string GetSemVerAppropriatePrereleaseTag(VersionOptions versionOptions) + protected 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) + protected void AssertStandardProperties(VersionOptions versionOptions, BuildResults buildResult, string relativeProjectDirectory = null) { int versionHeight = this.GetVersionHeight(relativeProjectDirectory); Version idAsVersion = this.GetVersion(relativeProjectDirectory); @@ -1141,7 +379,7 @@ string GetPkgVersionSuffix(bool useSemVer2) } } - private async Task BuildAsync(string target = Targets.GetBuildVersion, LoggerVerbosity logVerbosity = LoggerVerbosity.Detailed, bool assertSuccessfulBuild = true) + protected async Task BuildAsync(string target = Targets.GetBuildVersion, LoggerVerbosity logVerbosity = LoggerVerbosity.Detailed, bool assertSuccessfulBuild = true) { var eventLogger = new MSBuildLogger { Verbosity = LoggerVerbosity.Minimal }; var loggers = new ILogger[] { eventLogger }; @@ -1165,25 +403,7 @@ private async Task BuildAsync(string target = Targets.GetBuildVers return result; } - 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 ProjectRootElement CreateNativeProjectRootElement(string projectDirectory, string projectName) + protected ProjectRootElement CreateNativeProjectRootElement(string projectDirectory, string projectName) { using (var reader = XmlReader.Create(Assembly.GetExecutingAssembly().GetManifestResourceStream($"{ThisAssembly.RootNamespace}.test.vcprj"))) { @@ -1195,7 +415,7 @@ private ProjectRootElement CreateNativeProjectRootElement(string projectDirector } } - private ProjectRootElement CreateProjectRootElement(string projectDirectory, string projectName) + protected ProjectRootElement CreateProjectRootElement(string projectDirectory, string projectName) { using (var reader = XmlReader.Create(Assembly.GetExecutingAssembly().GetManifestResourceStream($"{ThisAssembly.RootNamespace}.test.prj"))) { @@ -1207,7 +427,7 @@ private ProjectRootElement CreateProjectRootElement(string projectDirectory, str } } - private void MakeItAVBProject() + protected void MakeItAVBProject() { ProjectImportElement csharpImport = this.testProject.Imports.Single(i => i.Project.Contains("CSharp")); csharpImport.Project = "$(MSBuildToolsPath)/Microsoft.VisualBasic.targets"; @@ -1215,6 +435,33 @@ private void MakeItAVBProject() 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; @@ -1240,7 +487,7 @@ private void Init() } } - private struct RestoreEnvironmentVariables : IDisposable + protected struct RestoreEnvironmentVariables : IDisposable { private readonly IReadOnlyDictionary applyVariables; @@ -1255,7 +502,7 @@ public void Dispose() } } - private static class CloudBuild + protected static class CloudBuild { public static readonly ImmutableDictionary SuppressEnvironment = ImmutableDictionary.Empty @@ -1283,7 +530,7 @@ private static class CloudBuild .SetItem("BUILD_VCS_NUMBER", "1"); } - private static class Targets + protected static class Targets { internal const string Build = "Build"; internal const string GetBuildVersion = "GetBuildVersion"; @@ -1292,12 +539,12 @@ private static class Targets internal const string GenerateNativeNBGVVersionInfo = "GenerateNativeNBGVVersionInfo"; } - private static class Properties + protected static class Properties { internal const string GenerateAssemblyVersionInfo = "GenerateAssemblyVersionInfo"; } - private class BuildResults + protected class BuildResults { internal BuildResults(BuildResult buildResult, IReadOnlyList loggedEvents) { diff --git a/test/Nerdbank.GitVersioning.Tests/GitContextTests.cs b/test/Nerdbank.GitVersioning.Tests/GitContextTests.cs index 185e8e2b1..36093811e 100644 --- a/test/Nerdbank.GitVersioning.Tests/GitContextTests.cs +++ b/test/Nerdbank.GitVersioning.Tests/GitContextTests.cs @@ -20,7 +20,7 @@ public GitContextManagedTests(ITestOutputHelper logger) /// protected override GitContext CreateGitContext(string path, string committish = null) - => GitContext.Create(path, committish, writable: false); + => GitContext.Create(path, committish, engine: GitContext.Engine.ReadOnly); } [Trait("Engine", "LibGit2")] @@ -33,7 +33,7 @@ public GitContextLibGit2Tests(ITestOutputHelper logger) /// protected override GitContext CreateGitContext(string path, string committish = null) - => GitContext.Create(path, committish, writable: true); + => GitContext.Create(path, committish, engine: GitContext.Engine.ReadWrite); } public abstract class GitContextTests : RepoTestBase diff --git a/test/Nerdbank.GitVersioning.Tests/LibGit2GitExtensionsTests.cs b/test/Nerdbank.GitVersioning.Tests/LibGit2GitExtensionsTests.cs index 8740e0bf8..78952c85a 100644 --- a/test/Nerdbank.GitVersioning.Tests/LibGit2GitExtensionsTests.cs +++ b/test/Nerdbank.GitVersioning.Tests/LibGit2GitExtensionsTests.cs @@ -482,7 +482,7 @@ public void TestBiggerRepo() } /// - protected override GitContext CreateGitContext(string path, string committish = null) => GitContext.Create(path, committish, writable: true); + protected override GitContext CreateGitContext(string path, string committish = null) => GitContext.Create(path, committish, engine: GitContext.Engine.ReadWrite); private Commit[] CommitsWithVersion(string majorMinorVersion) { diff --git a/test/Nerdbank.GitVersioning.Tests/ManagedGit/GitRepositoryTests.cs b/test/Nerdbank.GitVersioning.Tests/ManagedGit/GitRepositoryTests.cs index 3a30c162f..582dfbdca 100644 --- a/test/Nerdbank.GitVersioning.Tests/ManagedGit/GitRepositoryTests.cs +++ b/test/Nerdbank.GitVersioning.Tests/ManagedGit/GitRepositoryTests.cs @@ -329,7 +329,7 @@ public void ParseAlternates_PathWithColon_Test() /// protected override Nerdbank.GitVersioning.GitContext CreateGitContext(string path, string committish = null) - => Nerdbank.GitVersioning.GitContext.Create(path, committish, writable: false); + => Nerdbank.GitVersioning.GitContext.Create(path, committish, engine: GitContext.Engine.ReadOnly); private static void AssertPath(string expected, string actual) { diff --git a/test/Nerdbank.GitVersioning.Tests/ReleaseManagerTests.cs b/test/Nerdbank.GitVersioning.Tests/ReleaseManagerTests.cs index 3218f371c..9ced1c7a2 100644 --- a/test/Nerdbank.GitVersioning.Tests/ReleaseManagerTests.cs +++ b/test/Nerdbank.GitVersioning.Tests/ReleaseManagerTests.cs @@ -30,7 +30,7 @@ public ReleaseManagerManagedTests(ITestOutputHelper logger) /// protected override GitContext CreateGitContext(string path, string committish = null) - => GitContext.Create(path, committish, writable: false); + => GitContext.Create(path, committish, engine: GitContext.Engine.ReadOnly); } [Trait("Engine", "LibGit2")] @@ -43,7 +43,7 @@ public ReleaseManagerLibGit2Tests(ITestOutputHelper logger) /// protected override GitContext CreateGitContext(string path, string committish = null) - => GitContext.Create(path, committish, writable: true); + => GitContext.Create(path, committish, engine: GitContext.Engine.ReadWrite); } public abstract class ReleaseManagerTests : RepoTestBase diff --git a/test/Nerdbank.GitVersioning.Tests/RepoTestBase.cs b/test/Nerdbank.GitVersioning.Tests/RepoTestBase.cs index f34e5ff7f..d8edefb80 100644 --- a/test/Nerdbank.GitVersioning.Tests/RepoTestBase.cs +++ b/test/Nerdbank.GitVersioning.Tests/RepoTestBase.cs @@ -181,7 +181,7 @@ protected void AddCommits(int count = 1) } bool localContextCreated = this.Context is null; - GitContext? context = this.Context ?? GitContext.Create(this.RepoPath, writable: true); + GitContext? context = this.Context ?? GitContext.Create(this.RepoPath, engine: GitContext.Engine.ReadWrite); try { string versionFilePath = context.VersionFile.SetVersion(Path.Combine(this.RepoPath, relativeDirectory), versionData); diff --git a/test/Nerdbank.GitVersioning.Tests/SomeGitBuildIntegrationTests.cs b/test/Nerdbank.GitVersioning.Tests/SomeGitBuildIntegrationTests.cs new file mode 100644 index 000000000..5ced01af5 --- /dev/null +++ b/test/Nerdbank.GitVersioning.Tests/SomeGitBuildIntegrationTests.cs @@ -0,0 +1,720 @@ +// 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.Diagnostics; +using System.Globalization; +using System.Reflection; +using System.Xml; +using LibGit2Sharp; +using Microsoft.Build.Construction; +using Microsoft.Build.Framework; +using Microsoft.CodeAnalysis; +using Nerdbank.GitVersioning; +using Validation; +using Xunit; +using Xunit.Abstractions; +using Version = System.Version; + +/// +/// The base class for tests that require some actual git implementation behind it. +/// In other words, NOT the disabled engine implementation. +/// +public abstract class SomeGitBuildIntegrationTests : BuildIntegrationTests +{ + protected SomeGitBuildIntegrationTests(ITestOutputHelper logger) + : base(logger) + { + } + + [Fact] + public async Task GetBuildVersion_WithThreeVersionIntegers() + { + VersionOptions workingCopyVersion = new VersionOptions + { + Version = SemanticVersion.Parse("7.8.9-beta.3"), + SemVer1NumericIdentifierPadding = 1, + }; + this.WriteVersionFile(workingCopyVersion); + this.InitializeSourceControl(); + BuildResults buildResult = await this.BuildAsync(); + this.AssertStandardProperties(workingCopyVersion, buildResult); + } + + [Fact] + public async Task GetBuildVersion_OutsideGit_PointingToGit() + { + // Write a version file to the 'virtualized' repo. + string version = "3.4"; + this.WriteVersionFile(version); + + string repoRelativeProjectPath = this.testProject.FullPath.Substring(this.RepoPath.Length + 1); + + // Update the repo path so we create the 'normal' one elsewhere + this.RepoPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + this.InitializeSourceControl(); + + // Write the same version file to the 'real' repo + this.WriteVersionFile(version); + + // Point the project to the 'real' repo + this.testProject.AddProperty("GitRepoRoot", this.RepoPath); + this.testProject.AddProperty("ProjectPathRelativeToGitRepoRoot", repoRelativeProjectPath); + + BuildResults buildResult = await this.BuildAsync(); + + var workingCopyVersion = VersionOptions.FromVersion(new Version(version)); + + this.AssertStandardProperties(workingCopyVersion, buildResult); + } + + [Fact] + public async Task GetBuildVersion_In_Git_But_Without_Commits() + { + Repository.Init(this.RepoPath); + var repo = new Repository(this.RepoPath); // do not assign Repo property to avoid commits being generated later + this.WriteVersionFile("3.4"); + Assumes.False(repo.Head.Commits.Any()); // verification that the test is doing what it claims + BuildResults buildResult = await this.BuildAsync(); + Assert.Equal("3.4.0.0", buildResult.BuildVersion); + Assert.Equal("3.4.0", buildResult.AssemblyInformationalVersion); + } + + [Fact] + public async Task GetBuildVersion_In_Git_But_Head_Lacks_VersionFile() + { + Repository.Init(this.RepoPath); + var repo = new Repository(this.RepoPath); // do not assign Repo property to avoid commits being generated later + repo.Commit("empty", this.Signer, this.Signer, new CommitOptions { AllowEmptyCommit = true }); + this.WriteVersionFile("3.4"); + Assumes.True(repo.Index[VersionFile.JsonFileName] is null); + BuildResults buildResult = await this.BuildAsync(); + Assert.Equal("3.4.0." + this.GetVersion().Revision, buildResult.BuildVersion); + Assert.Equal("3.4.0+" + repo.Head.Tip.Id.Sha.Substring(0, VersionOptions.DefaultGitCommitIdShortFixedLength), buildResult.AssemblyInformationalVersion); + } + + [Fact] + public async Task GetBuildVersion_In_Git_But_WorkingCopy_Has_Changes() + { + const string majorMinorVersion = "5.8"; + const string prerelease = ""; + + this.WriteVersionFile(majorMinorVersion, prerelease); + this.InitializeSourceControl(); + var workingCopyVersion = VersionOptions.FromVersion(new Version("6.0")); + this.Context.VersionFile.SetVersion(this.RepoPath, workingCopyVersion); + BuildResults buildResult = await this.BuildAsync(); + this.AssertStandardProperties(workingCopyVersion, buildResult); + } + + [Fact] + public async Task GetBuildVersion_In_Git_No_VersionFile_At_All() + { + Repository.Init(this.RepoPath); + var repo = new Repository(this.RepoPath); // do not assign Repo property to avoid commits being generated later + repo.Commit("empty", this.Signer, this.Signer, new CommitOptions { AllowEmptyCommit = true }); + BuildResults buildResult = await this.BuildAsync(); + Assert.Equal("0.0.0." + this.GetVersion().Revision, buildResult.BuildVersion); + Assert.Equal("0.0.0+" + repo.Head.Tip.Id.Sha.Substring(0, VersionOptions.DefaultGitCommitIdShortFixedLength), buildResult.AssemblyInformationalVersion); + } + + [Fact] + public async Task GetBuildVersion_In_Git_With_Version_File_In_Subdirectory_Works() + { + const string majorMinorVersion = "5.8"; + const string prerelease = ""; + const string subdirectory = "projdir"; + + this.WriteVersionFile(majorMinorVersion, prerelease, subdirectory); + this.InitializeSourceControl(); + this.AddCommits(this.random.Next(15)); + BuildResults buildResult = await this.BuildAsync(); + this.AssertStandardProperties(VersionOptions.FromVersion(new Version(majorMinorVersion)), buildResult, subdirectory); + } + + [Fact] + public async Task GetBuildVersion_In_Git_With_Version_File_In_Root_And_Subdirectory_Works() + { + var rootVersionSpec = new VersionOptions + { + Version = SemanticVersion.Parse("14.1"), + AssemblyVersion = new VersionOptions.AssemblyVersionOptions(new Version(14, 0)), + }; + var subdirVersionSpec = new VersionOptions { Version = SemanticVersion.Parse("11.0") }; + const string subdirectory = "projdir"; + + this.WriteVersionFile(rootVersionSpec); + this.WriteVersionFile(subdirVersionSpec, subdirectory); + this.InitializeSourceControl(); + this.AddCommits(this.random.Next(15)); + BuildResults buildResult = await this.BuildAsync(); + this.AssertStandardProperties(subdirVersionSpec, buildResult, subdirectory); + } + + [Fact] + public async Task GetBuildVersion_In_Git_With_Version_File_In_Root_And_Project_In_Root_Works() + { + var rootVersionSpec = new VersionOptions + { + Version = SemanticVersion.Parse("14.1"), + AssemblyVersion = new VersionOptions.AssemblyVersionOptions(new Version(14, 0)), + }; + + this.WriteVersionFile(rootVersionSpec); + this.InitializeSourceControl(); + this.AddCommits(this.random.Next(15)); + this.testProject = this.CreateProjectRootElement(this.RepoPath, "root.proj"); + BuildResults buildResult = await this.BuildAsync(); + this.AssertStandardProperties(rootVersionSpec, buildResult); + } + + [Fact] + public async Task GetBuildVersion_StablePreRelease() + { + const string majorMinorVersion = "5.8"; + const string prerelease = ""; + + this.WriteVersionFile(majorMinorVersion, prerelease); + this.InitializeSourceControl(); + this.AddCommits(this.random.Next(15)); + BuildResults buildResult = await this.BuildAsync(); + this.AssertStandardProperties(VersionOptions.FromVersion(new Version(majorMinorVersion)), buildResult); + } + + [Fact] + public async Task GetBuildVersion_StableRelease() + { + const string majorMinorVersion = "5.8"; + const string prerelease = ""; + + this.WriteVersionFile(majorMinorVersion, prerelease); + this.InitializeSourceControl(); + this.AddCommits(this.random.Next(15)); + this.globalProperties["PublicRelease"] = "true"; + BuildResults buildResult = await this.BuildAsync(); + this.AssertStandardProperties(VersionOptions.FromVersion(new Version(majorMinorVersion)), buildResult); + + Version version = this.GetVersion(); + Assert.Equal($"{version.Major}.{version.Minor}.{buildResult.GitVersionHeight}", buildResult.NuGetPackageVersion); + } + + [Fact] + public async Task GetBuildVersion_UnstablePreRelease() + { + const string majorMinorVersion = "5.8"; + const string prerelease = "-beta"; + + this.WriteVersionFile(majorMinorVersion, prerelease); + this.InitializeSourceControl(); + this.AddCommits(this.random.Next(15)); + BuildResults buildResult = await this.BuildAsync(); + this.AssertStandardProperties(VersionOptions.FromVersion(new Version(majorMinorVersion), prerelease), buildResult); + } + + [Fact] + public async Task GetBuildVersion_UnstableRelease() + { + const string majorMinorVersion = "5.8"; + const string prerelease = "-beta"; + + this.WriteVersionFile(majorMinorVersion, prerelease); + this.InitializeSourceControl(); + this.AddCommits(this.random.Next(15)); + this.globalProperties["PublicRelease"] = "true"; + BuildResults buildResult = await this.BuildAsync(); + this.AssertStandardProperties(VersionOptions.FromVersion(new Version(majorMinorVersion), prerelease), buildResult); + } + + [Fact] + public async Task GetBuildVersion_CustomAssemblyVersion() + { + this.WriteVersionFile("14.0"); + this.InitializeSourceControl(); + var versionOptions = new VersionOptions + { + Version = new SemanticVersion(new Version(14, 1)), + AssemblyVersion = new VersionOptions.AssemblyVersionOptions(new Version(14, 0)), + }; + this.WriteVersionFile(versionOptions); + BuildResults buildResult = await this.BuildAsync(); + this.AssertStandardProperties(versionOptions, buildResult); + } + + [Theory] + [InlineData(VersionOptions.VersionPrecision.Major)] + [InlineData(VersionOptions.VersionPrecision.Build)] + [InlineData(VersionOptions.VersionPrecision.Revision)] + public async Task GetBuildVersion_CustomAssemblyVersionWithPrecision(VersionOptions.VersionPrecision precision) + { + var versionOptions = new VersionOptions + { + Version = new SemanticVersion("14.1"), + AssemblyVersion = new VersionOptions.AssemblyVersionOptions + { + Version = new Version("15.2"), + Precision = precision, + }, + }; + this.WriteVersionFile(versionOptions); + this.InitializeSourceControl(); + BuildResults buildResult = await this.BuildAsync(); + this.AssertStandardProperties(versionOptions, buildResult); + } + + [Theory] + [InlineData(VersionOptions.VersionPrecision.Major)] + [InlineData(VersionOptions.VersionPrecision.Build)] + [InlineData(VersionOptions.VersionPrecision.Revision)] + public async Task GetBuildVersion_CustomAssemblyVersionPrecision(VersionOptions.VersionPrecision precision) + { + var versionOptions = new VersionOptions + { + Version = new SemanticVersion("14.1"), + AssemblyVersion = new VersionOptions.AssemblyVersionOptions + { + Precision = precision, + }, + }; + this.WriteVersionFile(versionOptions); + this.InitializeSourceControl(); + BuildResults buildResult = await this.BuildAsync(); + this.AssertStandardProperties(versionOptions, buildResult); + } + + [Fact] + public async Task GetBuildVersion_CustomBuildNumberOffset() + { + this.WriteVersionFile("14.0"); + this.InitializeSourceControl(); + var versionOptions = new VersionOptions + { + Version = new SemanticVersion(new Version(14, 1)), + VersionHeightOffset = 5, + }; + this.WriteVersionFile(versionOptions); + BuildResults buildResult = await this.BuildAsync(); + this.AssertStandardProperties(versionOptions, buildResult); + } + + [Fact] + public async Task GetBuildVersion_OverrideBuildNumberOffset() + { + this.WriteVersionFile("14.0"); + this.InitializeSourceControl(); + var versionOptions = new VersionOptions + { + Version = new SemanticVersion(new Version(14, 1)), + }; + this.WriteVersionFile(versionOptions); + this.testProject.AddProperty("OverrideBuildNumberOffset", "10"); + BuildResults buildResult = await this.BuildAsync(); + Assert.StartsWith("14.1.11.", buildResult.AssemblyFileVersion); + } + + [Fact] + public async Task GetBuildVersion_Minus1BuildOffset_NotYetCommitted() + { + this.WriteVersionFile("14.0"); + this.InitializeSourceControl(); + var versionOptions = new VersionOptions + { + Version = new SemanticVersion(new Version(14, 1)), + VersionHeightOffset = -1, + }; + this.Context.VersionFile.SetVersion(this.RepoPath, versionOptions); + BuildResults buildResult = await this.BuildAsync(); + this.AssertStandardProperties(versionOptions, buildResult); + } + + [Theory] + [InlineData(0)] + [InlineData(21)] + public async Task GetBuildVersion_BuildNumberSpecifiedInVersionJson(int buildNumber) + { + var versionOptions = new VersionOptions + { + Version = SemanticVersion.Parse("14.0." + buildNumber), + }; + this.WriteVersionFile(versionOptions); + this.InitializeSourceControl(); + BuildResults buildResult = await this.BuildAsync(); + this.AssertStandardProperties(versionOptions, buildResult); + } + + [Fact] + public async Task PublicRelease_RegEx_Unsatisfied() + { + var versionOptions = new VersionOptions + { + Version = SemanticVersion.Parse("1.0"), + PublicReleaseRefSpec = new string[] { "^refs/heads/release$" }, + }; + this.WriteVersionFile(versionOptions); + this.InitializeSourceControl(); + + // Just build "master", which doesn't conform to the regex. + BuildResults buildResult = await this.BuildAsync(); + Assert.False(buildResult.PublicRelease); + this.AssertStandardProperties(versionOptions, buildResult); + } + + [Theory] + [MemberData(nameof(CloudBuildOfBranch), "release")] + public async Task PublicRelease_RegEx_SatisfiedByCI(IReadOnlyDictionary serverProperties) + { + var versionOptions = new VersionOptions + { + Version = SemanticVersion.Parse("1.0"), + PublicReleaseRefSpec = new string[] + { + "^refs/heads/release$", + "^refs/tags/release$", + }, + }; + this.WriteVersionFile(versionOptions); + this.InitializeSourceControl(); + + // Don't actually switch the checked out branch in git. CI environment variables + // should take precedence over actual git configuration. (Why? because these variables may + // retain information about which tag was checked out on a detached head). + using (ApplyEnvironmentVariables(serverProperties)) + { + BuildResults buildResult = await this.BuildAsync(); + Assert.True(buildResult.PublicRelease); + this.AssertStandardProperties(versionOptions, buildResult); + } + } + + [Theory] + [Trait("TestCategory", "FailsInCloudTest")] + [MemberData(nameof(CloudBuildVariablesData))] + public async Task CloudBuildVariables_SetInCI(IReadOnlyDictionary properties, string expectedMessage, bool setAllVariables) + { + using (ApplyEnvironmentVariables(properties)) + { + string keyName = "n1"; + string value = "v1"; + this.testProject.AddItem("CloudBuildVersionVars", keyName, new Dictionary { { "Value", value } }); + + string alwaysExpectedMessage = UnitTestCloudBuildPrefix + expectedMessage + .Replace("{NAME}", keyName) + .Replace("{VALUE}", value); + + var versionOptions = new VersionOptions + { + Version = SemanticVersion.Parse("1.0"), + CloudBuild = new VersionOptions.CloudBuildOptions { SetAllVariables = setAllVariables, SetVersionVariables = true }, + }; + this.WriteVersionFile(versionOptions); + this.InitializeSourceControl(); + + BuildResults buildResult = await this.BuildAsync(); + this.AssertStandardProperties(versionOptions, buildResult); + + // Assert GitBuildVersion was set + string conditionallyExpectedMessage = UnitTestCloudBuildPrefix + expectedMessage + .Replace("{NAME}", "GitBuildVersion") + .Replace("{VALUE}", buildResult.BuildVersion); + Assert.Contains(alwaysExpectedMessage, buildResult.LoggedEvents.Select(e => e.Message.TrimEnd())); + Assert.Contains(conditionallyExpectedMessage, buildResult.LoggedEvents.Select(e => e.Message.TrimEnd())); + + // Assert GitBuildVersionSimple was set + conditionallyExpectedMessage = UnitTestCloudBuildPrefix + expectedMessage + .Replace("{NAME}", "GitBuildVersionSimple") + .Replace("{VALUE}", buildResult.BuildVersionSimple); + Assert.Contains(alwaysExpectedMessage, buildResult.LoggedEvents.Select(e => e.Message.TrimEnd())); + Assert.Contains(conditionallyExpectedMessage, buildResult.LoggedEvents.Select(e => e.Message.TrimEnd())); + + // Assert that project properties are also set. + Assert.Equal(buildResult.BuildVersion, buildResult.GitBuildVersion); + Assert.Equal(buildResult.BuildVersionSimple, buildResult.GitBuildVersionSimple); + Assert.Equal(buildResult.AssemblyInformationalVersion, buildResult.GitAssemblyInformationalVersion); + + if (setAllVariables) + { + // Assert that some project properties were set as build properties prefaced with "NBGV_". + Assert.Equal(buildResult.GitCommitIdShort, buildResult.NBGV_GitCommitIdShort); + Assert.Equal(buildResult.NuGetPackageVersion, buildResult.NBGV_NuGetPackageVersion); + } + else + { + // Assert that the NBGV_ prefixed properties are *not* set. + Assert.Equal(string.Empty, buildResult.NBGV_GitCommitIdShort); + Assert.Equal(string.Empty, buildResult.NBGV_NuGetPackageVersion); + } + + // Assert that env variables were also set in context of the build. + 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); + this.SetContextToHead(); + buildResult = await this.BuildAsync(); + this.AssertStandardProperties(versionOptions, buildResult); + + // Assert GitBuildVersion was not set + conditionallyExpectedMessage = UnitTestCloudBuildPrefix + expectedMessage + .Replace("{NAME}", "GitBuildVersion") + .Replace("{VALUE}", buildResult.BuildVersion); + Assert.Contains(alwaysExpectedMessage, buildResult.LoggedEvents.Select(e => e.Message.TrimEnd())); + Assert.DoesNotContain(conditionallyExpectedMessage, buildResult.LoggedEvents.Select(e => e.Message.TrimEnd())); + Assert.NotEqual(buildResult.BuildVersion, buildResult.BuildResult.ProjectStateAfterBuild.GetPropertyValue("GitBuildVersion")); + + // Assert GitBuildVersionSimple was not set + conditionallyExpectedMessage = UnitTestCloudBuildPrefix + expectedMessage + .Replace("{NAME}", "GitBuildVersionSimple") + .Replace("{VALUE}", buildResult.BuildVersionSimple); + Assert.Contains(alwaysExpectedMessage, buildResult.LoggedEvents.Select(e => e.Message.TrimEnd())); + Assert.DoesNotContain(conditionallyExpectedMessage, buildResult.LoggedEvents.Select(e => e.Message.TrimEnd())); + Assert.NotEqual(buildResult.BuildVersionSimple, buildResult.BuildResult.ProjectStateAfterBuild.GetPropertyValue("GitBuildVersionSimple")); + } + } + + [Theory] + [MemberData(nameof(BuildNumberData))] + public async Task BuildNumber_SetInCI(VersionOptions versionOptions, IReadOnlyDictionary properties, string expectedBuildNumberMessage) + { + this.WriteVersionFile(versionOptions); + this.InitializeSourceControl(); + using (ApplyEnvironmentVariables(properties)) + { + BuildResults buildResult = await this.BuildAsync(); + this.AssertStandardProperties(versionOptions, buildResult); + expectedBuildNumberMessage = expectedBuildNumberMessage.Replace("{CLOUDBUILDNUMBER}", buildResult.CloudBuildNumber); + Assert.Contains(UnitTestCloudBuildPrefix + expectedBuildNumberMessage, buildResult.LoggedEvents.Select(e => e.Message.TrimEnd())); + } + + versionOptions.CloudBuild.BuildNumber.Enabled = false; + this.WriteVersionFile(versionOptions); + using (ApplyEnvironmentVariables(properties)) + { + BuildResults buildResult = await this.BuildAsync(); + this.AssertStandardProperties(versionOptions, buildResult); + expectedBuildNumberMessage = expectedBuildNumberMessage.Replace("{CLOUDBUILDNUMBER}", buildResult.CloudBuildNumber); + Assert.DoesNotContain(UnitTestCloudBuildPrefix + expectedBuildNumberMessage, buildResult.LoggedEvents.Select(e => e.Message.TrimEnd())); + } + } + + [Theory] + [PairwiseData] + public async Task BuildNumber_VariousOptions(bool isPublic, VersionOptions.CloudBuildNumberCommitWhere where, VersionOptions.CloudBuildNumberCommitWhen when, [CombinatorialValues(0, 1, 2)] int extraBuildMetadataCount, [CombinatorialValues(1, 2)] int semVer) + { + VersionOptions versionOptions = BuildNumberVersionOptionsBasis; + versionOptions.CloudBuild.BuildNumber.IncludeCommitId.Where = where; + versionOptions.CloudBuild.BuildNumber.IncludeCommitId.When = when; + versionOptions.NuGetPackageVersion = new VersionOptions.NuGetPackageVersionOptions + { + SemVer = semVer, + }; + this.WriteVersionFile(versionOptions); + this.InitializeSourceControl(); + + this.globalProperties["PublicRelease"] = isPublic.ToString(); + for (int i = 0; i < extraBuildMetadataCount; i++) + { + this.testProject.AddItem("BuildMetadata", $"A{i}"); + } + + BuildResults buildResult = await this.BuildAsync(); + this.AssertStandardProperties(versionOptions, buildResult); + } + + [Fact] + public void GitLab_BuildTag() + { + // Based on the values defined in https://docs.gitlab.com/ee/ci/variables/#syntax-of-environment-variables-in-job-scripts + using (ApplyEnvironmentVariables( + CloudBuild.SuppressEnvironment.SetItems( + new Dictionary() + { + { "CI_COMMIT_TAG", "1.0.0" }, + { "CI_COMMIT_SHA", "1ecfd275763eff1d6b4844ea3168962458c9f27a" }, + { "GITLAB_CI", "true" }, + { "SYSTEM_TEAMPROJECTID", string.Empty }, + }))) + { + ICloudBuild activeCloudBuild = Nerdbank.GitVersioning.CloudBuild.Active; + Assert.NotNull(activeCloudBuild); + Assert.Null(activeCloudBuild.BuildingBranch); + Assert.Equal("refs/tags/1.0.0", activeCloudBuild.BuildingTag); + Assert.Equal("1ecfd275763eff1d6b4844ea3168962458c9f27a", activeCloudBuild.GitCommitId); + Assert.True(activeCloudBuild.IsApplicable); + Assert.False(activeCloudBuild.IsPullRequest); + } + } + + [Fact] + public void GitLab_BuildBranch() + { + // Based on the values defined in https://docs.gitlab.com/ee/ci/variables/#syntax-of-environment-variables-in-job-scripts + using (ApplyEnvironmentVariables( + CloudBuild.SuppressEnvironment.SetItems( + new Dictionary() + { + { "CI_COMMIT_REF_NAME", "master" }, + { "CI_COMMIT_SHA", "1ecfd275763eff1d6b4844ea3168962458c9f27a" }, + { "GITLAB_CI", "true" }, + }))) + { + ICloudBuild activeCloudBuild = Nerdbank.GitVersioning.CloudBuild.Active; + Assert.NotNull(activeCloudBuild); + Assert.Equal("refs/heads/master", activeCloudBuild.BuildingBranch); + Assert.Null(activeCloudBuild.BuildingTag); + Assert.Equal("1ecfd275763eff1d6b4844ea3168962458c9f27a", activeCloudBuild.GitCommitId); + Assert.True(activeCloudBuild.IsApplicable); + Assert.False(activeCloudBuild.IsPullRequest); + } + } + + [Fact] + public async Task PublicRelease_RegEx_SatisfiedByCheckedOutBranch() + { + var versionOptions = new VersionOptions + { + Version = SemanticVersion.Parse("1.0"), + PublicReleaseRefSpec = new string[] { "^refs/heads/release$" }, + }; + this.WriteVersionFile(versionOptions); + this.InitializeSourceControl(); + + using (ApplyEnvironmentVariables(CloudBuild.SuppressEnvironment)) + { + // Check out a branch that conforms. + Branch releaseBranch = this.LibGit2Repository.CreateBranch("release"); + Commands.Checkout(this.LibGit2Repository, releaseBranch); + BuildResults buildResult = await this.BuildAsync(); + Assert.True(buildResult.PublicRelease); + this.AssertStandardProperties(versionOptions, buildResult); + } + } + + // This test builds projects using 'classic' MSBuild projects, which target net45. + // This is not supported on Linux. + [WindowsTheory] + [PairwiseData] + public async Task AssemblyInfo(bool isVB, bool includeNonVersionAttributes, bool gitRepo, bool isPrerelease, bool isPublicRelease) + { + this.WriteVersionFile(prerelease: isPrerelease ? "-beta" : string.Empty); + if (gitRepo) + { + this.InitializeSourceControl(); + } + + if (isVB) + { + this.MakeItAVBProject(); + } + + if (includeNonVersionAttributes) + { + this.testProject.AddProperty("NBGV_EmitNonVersionCustomAttributes", "true"); + } + + this.globalProperties["PublicRelease"] = isPublicRelease ? "true" : "false"; + + BuildResults result = await this.BuildAsync("Build", logVerbosity: LoggerVerbosity.Minimal); + string assemblyPath = result.BuildResult.ProjectStateAfterBuild.GetPropertyValue("TargetPath"); + string versionFileContent = File.ReadAllText(Path.Combine(this.projectDirectory, result.BuildResult.ProjectStateAfterBuild.GetPropertyValue("VersionSourceFile"))); + this.Logger.WriteLine(versionFileContent); + + var assembly = Assembly.LoadFile(assemblyPath); + + AssemblyFileVersionAttribute assemblyFileVersion = assembly.GetCustomAttribute(); + AssemblyInformationalVersionAttribute assemblyInformationalVersion = assembly.GetCustomAttribute(); + AssemblyTitleAttribute assemblyTitle = assembly.GetCustomAttribute(); + AssemblyProductAttribute assemblyProduct = assembly.GetCustomAttribute(); + AssemblyCompanyAttribute assemblyCompany = assembly.GetCustomAttribute(); + AssemblyCopyrightAttribute assemblyCopyright = assembly.GetCustomAttribute(); + Type thisAssemblyClass = assembly.GetType("ThisAssembly") ?? assembly.GetType("TestNamespace.ThisAssembly"); + Assert.NotNull(thisAssemblyClass); + + Assert.Equal(new Version(result.AssemblyVersion), assembly.GetName().Version); + Assert.Equal(result.AssemblyFileVersion, assemblyFileVersion.Version); + Assert.Equal(result.AssemblyInformationalVersion, assemblyInformationalVersion.InformationalVersion); + if (includeNonVersionAttributes) + { + Assert.Equal(result.AssemblyTitle, assemblyTitle.Title); + Assert.Equal(result.AssemblyProduct, assemblyProduct.Product); + Assert.Equal(result.AssemblyCompany, assemblyCompany.Company); + Assert.Equal(result.AssemblyCopyright, assemblyCopyright.Copyright); + } + else + { + Assert.Null(assemblyTitle); + Assert.Null(assemblyProduct); + Assert.Null(assemblyCompany); + Assert.Null(assemblyCopyright); + } + + const BindingFlags fieldFlags = BindingFlags.Static | BindingFlags.NonPublic; + Assert.Equal(result.AssemblyVersion, thisAssemblyClass.GetField("AssemblyVersion", fieldFlags).GetValue(null)); + Assert.Equal(result.AssemblyFileVersion, thisAssemblyClass.GetField("AssemblyFileVersion", fieldFlags).GetValue(null)); + Assert.Equal(result.AssemblyInformationalVersion, thisAssemblyClass.GetField("AssemblyInformationalVersion", fieldFlags).GetValue(null)); + Assert.Equal(result.AssemblyName, thisAssemblyClass.GetField("AssemblyName", fieldFlags).GetValue(null)); + Assert.Equal(result.RootNamespace, thisAssemblyClass.GetField("RootNamespace", fieldFlags).GetValue(null)); + Assert.Equal(result.AssemblyConfiguration, thisAssemblyClass.GetField("AssemblyConfiguration", fieldFlags).GetValue(null)); + Assert.Equal(result.AssemblyTitle, thisAssemblyClass.GetField("AssemblyTitle", fieldFlags)?.GetValue(null)); + Assert.Equal(result.AssemblyProduct, thisAssemblyClass.GetField("AssemblyProduct", fieldFlags)?.GetValue(null)); + Assert.Equal(result.AssemblyCompany, thisAssemblyClass.GetField("AssemblyCompany", fieldFlags)?.GetValue(null)); + Assert.Equal(result.AssemblyCopyright, thisAssemblyClass.GetField("AssemblyCopyright", fieldFlags)?.GetValue(null)); + Assert.Equal(result.GitCommitId, thisAssemblyClass.GetField("GitCommitId", fieldFlags)?.GetValue(null) ?? string.Empty); + Assert.Equal(result.PublicRelease, thisAssemblyClass.GetField("IsPublicRelease", fieldFlags)?.GetValue(null)); + Assert.Equal(!string.IsNullOrEmpty(result.PrereleaseVersion), thisAssemblyClass.GetField("IsPrerelease", fieldFlags)?.GetValue(null)); + + if (gitRepo) + { + Assert.True(long.TryParse(result.GitCommitDateTicks, out _), $"Invalid value for GitCommitDateTicks: '{result.GitCommitDateTicks}'"); + var gitCommitDate = new DateTime(long.Parse(result.GitCommitDateTicks), DateTimeKind.Utc); + Assert.Equal(gitCommitDate, thisAssemblyClass.GetProperty("GitCommitDate", fieldFlags)?.GetValue(null) ?? thisAssemblyClass.GetField("GitCommitDate", fieldFlags)?.GetValue(null) ?? string.Empty); + } + else + { + Assert.Empty(result.GitCommitDateTicks); + Assert.Null(thisAssemblyClass.GetProperty("GitCommitDate", fieldFlags)); + } + + // Verify that it doesn't have key fields + Assert.Null(thisAssemblyClass.GetField("PublicKey", fieldFlags)); + Assert.Null(thisAssemblyClass.GetField("PublicKeyToken", fieldFlags)); + } + + [Fact] + [Trait("TestCategory", "FailsInCloudTest")] + public async Task AssemblyInfo_IncrementalBuild() + { + this.WriteVersionFile(prerelease: "-beta"); + await this.BuildAsync("Build", logVerbosity: LoggerVerbosity.Minimal); + this.WriteVersionFile(prerelease: "-rc"); // two characters SHORTER, to test file truncation. + await this.BuildAsync("Build", logVerbosity: LoggerVerbosity.Minimal); + } + +#if !NETCOREAPP + /// + /// Create a native resource .dll and verify that its version + /// information is set correctly. + /// + [Fact] + public async Task NativeVersionInfo_CreateNativeResourceDll() + { + this.testProject = this.CreateNativeProjectRootElement(this.projectDirectory, "test.vcxproj"); + this.WriteVersionFile(); + BuildResults result = await this.BuildAsync(Targets.Build, logVerbosity: LoggerVerbosity.Minimal); + Assert.Empty(result.LoggedEvents.OfType()); + + string targetFile = Path.Combine(this.projectDirectory, result.BuildResult.ProjectStateAfterBuild.GetPropertyValue("TargetPath")); + Assert.True(File.Exists(targetFile)); + + var fileInfo = FileVersionInfo.GetVersionInfo(targetFile); + 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($"Copyright (c) {DateTime.Now.Year}. All rights reserved.", fileInfo.LegalCopyright); + } +#endif + + /// + protected override GitContext CreateGitContext(string path, string committish = null) => throw new NotImplementedException(); +} diff --git a/test/Nerdbank.GitVersioning.Tests/VersionFileTests.cs b/test/Nerdbank.GitVersioning.Tests/VersionFileTests.cs index 071a22871..745c83df3 100644 --- a/test/Nerdbank.GitVersioning.Tests/VersionFileTests.cs +++ b/test/Nerdbank.GitVersioning.Tests/VersionFileTests.cs @@ -27,7 +27,7 @@ public VersionFileManagedTests(ITestOutputHelper logger) /// protected override GitContext CreateGitContext(string path, string committish = null) - => GitContext.Create(path, committish, writable: false); + => GitContext.Create(path, committish, engine: GitContext.Engine.ReadOnly); } [Trait("Engine", "LibGit2")] @@ -40,7 +40,7 @@ public VersionFileLibGit2Tests(ITestOutputHelper logger) /// protected override GitContext CreateGitContext(string path, string committish = null) - => GitContext.Create(path, committish, writable: true); + => GitContext.Create(path, committish, engine: GitContext.Engine.ReadWrite); } public abstract class VersionFileTests : RepoTestBase diff --git a/test/Nerdbank.GitVersioning.Tests/VersionOracleTests.cs b/test/Nerdbank.GitVersioning.Tests/VersionOracleTests.cs index 16fd63d74..8098be4c3 100644 --- a/test/Nerdbank.GitVersioning.Tests/VersionOracleTests.cs +++ b/test/Nerdbank.GitVersioning.Tests/VersionOracleTests.cs @@ -24,7 +24,7 @@ public VersionOracleManagedTests(ITestOutputHelper logger) /// protected override GitContext CreateGitContext(string path, string committish = null) - => GitContext.Create(path, committish, writable: false); + => GitContext.Create(path, committish, engine: GitContext.Engine.ReadOnly); } [Trait("Engine", "LibGit2")] @@ -37,7 +37,7 @@ public VersionOracleLibGit2Tests(ITestOutputHelper logger) /// protected override GitContext CreateGitContext(string path, string committish = null) - => GitContext.Create(path, committish, writable: true); + => GitContext.Create(path, committish, engine: GitContext.Engine.ReadWrite); } public abstract class VersionOracleTests : RepoTestBase