diff --git a/docs/input/docs/usage/msbuild.md b/docs/input/docs/usage/msbuild.md index 64e06e9b9b..b91d38f17a 100644 --- a/docs/input/docs/usage/msbuild.md +++ b/docs/input/docs/usage/msbuild.md @@ -258,14 +258,26 @@ For SDK-style projects, `UpdateVersionProperties` controls setting the default variables: `Version`, `VersionPrefix`, `VersionSuffix`, `PackageVersion`, `InformationalVersion`, `AssemblyVersion` and `FileVersion`. +### Namespace generation + +You can configure GitVersion to generate the `GitVersionInformation` class in a namespace that matches the current assembly. By default this class is created in the global namespace. If `UseProjectNamespaceForGitVersionInformation` is set to true, the `GitVersionInfomation` class will instead be generated in a namespace matching the current project. If the property `` is set that value will be used, otherwise the name of the project file is used. + +```xml + + ... + true + ... + +``` + ## Extra properties -There are properties that correspont to certain +There are properties that correspont to certain [command line arguments](/docs/usage/cli/arguments) for GetVersion task. -In particular, setting `GitVersion_NoFetchEnabled` to `true` disables `git fetch` -during version calculation, setting `GitVersion_NoNormalizeEnabled` to `true` disables +In particular, setting `GitVersion_NoFetchEnabled` to `true` disables `git fetch` +during version calculation, setting `GitVersion_NoNormalizeEnabled` to `true` disables normalize step on a build server, setting `GitVersion_NoCacheEnabled` to `true` -makes GetVersion ignore cache. All the rest command line arguments can be passed via +makes GetVersion ignore cache. All the rest command line arguments can be passed via `GitVersion_CommandLineArguments` variable. ## My Git repository requires authentication. What should I do? diff --git a/src/GitVersion.Core/Options/GitVersionOptions.cs b/src/GitVersion.Core/Options/GitVersionOptions.cs index 42feb102a7..0a26d69ef2 100644 --- a/src/GitVersion.Core/Options/GitVersionOptions.cs +++ b/src/GitVersion.Core/Options/GitVersionOptions.cs @@ -13,6 +13,8 @@ public class GitVersionOptions public WixInfo WixInfo { get; } = new(); public Settings Settings { get; } = new(); + + public bool Init; public bool Diag; public bool IsVersion; diff --git a/src/GitVersion.MsBuild.Tests/Tasks/GenerateGitVersionInformationTest.cs b/src/GitVersion.MsBuild.Tests/Tasks/GenerateGitVersionInformationTest.cs index 3c6a143d51..871c22176e 100644 --- a/src/GitVersion.MsBuild.Tests/Tasks/GenerateGitVersionInformationTest.cs +++ b/src/GitVersion.MsBuild.Tests/Tasks/GenerateGitVersionInformationTest.cs @@ -218,12 +218,133 @@ public void GenerateGitVersionInformationTaskShouldCreateFileWhenRunWithMsBuildA fileContent.ShouldMatch(string.Format(regexPattern, nameof(GitVersionVariables.FullSemVer), "1.0.1-1")); } - private static void AddGenerateGitVersionInformationTask(ProjectCreator project, string targetToRun, string taskName, + [TestCaseSource(nameof(Languages))] + public void GenerateGitVersionInformationTaskShouldCreateFileWhenRunWithMsBuildAndUseProjectNamespaceIsSpecifiedAndRootNamespaceIsSet(string language) + { + const string taskName = nameof(GenerateGitVersionInformation); + const string outputProperty = nameof(GenerateGitVersionInformation.GitVersionInformationFilePath); + var randDir = Guid.NewGuid().ToString("N"); + + var extension = FileHelper.GetFileExtension(language); + using var result = ExecuteMsBuildExe(project => + { + var intermediateOutputPath = Path.Combine("$(MSBuildProjectDirectory)", randDir); + AddGenerateGitVersionInformationTask(project, taskName, taskName, outputProperty, language, intermediateOutputPath).Property("UseProjectNamespaceForGitVersionInformation", "True").Property("RootNamespace", "Test.Root"); + }, language); + + result.ProjectPath.ShouldNotBeNullOrWhiteSpace(); + result.MsBuild.Count.ShouldBeGreaterThan(0); + result.MsBuild.OverallSuccess.ShouldBe(true); + result.MsBuild.ShouldAllBe(x => x.Succeeded); + result.Output.ShouldNotBeNullOrWhiteSpace(); + + var generatedFilePath = PathHelper.Combine(Path.GetDirectoryName(result.ProjectPath), randDir, $"GitVersionInformation.g.{extension}"); + result.Output.ShouldContain($"{outputProperty}: {generatedFilePath}"); + + var fileContent = File.ReadAllText(generatedFilePath); + TestContext.WriteLine(fileContent); + fileContent.ShouldMatch(string.Format(regexPattern, nameof(GitVersionVariables.Major), "1")); + fileContent.ShouldMatch(string.Format(regexPattern, nameof(GitVersionVariables.Minor), "2")); + fileContent.ShouldMatch(string.Format(regexPattern, nameof(GitVersionVariables.Patch), "4")); + fileContent.ShouldMatch(string.Format(regexPattern, nameof(GitVersionVariables.MajorMinorPatch), "1.2.4")); + fileContent.ShouldMatch(string.Format(regexPattern, nameof(GitVersionVariables.FullSemVer), "1.2.4-1")); + fileContent.ShouldContain("namespace Test.Root", Case.Insensitive); + + } + + [TestCaseSource(nameof(Languages))] + public void GenerateGitVersionInformationTaskShouldCreateFileWhenRunWithMsBuildAndUseProjectNamespaceIsSpecifiedAndRootNamespaceIsNotSet(string language) + { + const string taskName = nameof(GenerateGitVersionInformation); + const string outputProperty = nameof(GenerateGitVersionInformation.GitVersionInformationFilePath); + var randDir = Guid.NewGuid().ToString("N"); + + var extension = FileHelper.GetFileExtension(language); + using var result = ExecuteMsBuildExeInAzurePipeline(project => + { + var intermediateOutputPath = Path.Combine("$(MSBuildProjectDirectory)", randDir); + AddGenerateGitVersionInformationTask(project, taskName, taskName, outputProperty, language, intermediateOutputPath).Property("UseProjectNamespaceForGitVersionInformation", "True"); + }, language); + + result.ProjectPath.ShouldNotBeNullOrWhiteSpace(); + result.MsBuild.Count.ShouldBeGreaterThan(0); + result.MsBuild.OverallSuccess.ShouldBe(true); + result.MsBuild.ShouldAllBe(x => x.Succeeded); + result.Output.ShouldNotBeNullOrWhiteSpace(); + + var generatedFilePath = PathHelper.Combine(Path.GetDirectoryName(result.ProjectPath), randDir, $"GitVersionInformation.g.{extension}"); + result.Output.ShouldContain($"{outputProperty}: {generatedFilePath}"); + + var fileContent = File.ReadAllText(generatedFilePath); + fileContent.ShouldMatch(string.Format(regexPattern, nameof(GitVersionVariables.Major), "1")); + fileContent.ShouldMatch(string.Format(regexPattern, nameof(GitVersionVariables.Minor), "0")); + fileContent.ShouldMatch(string.Format(regexPattern, nameof(GitVersionVariables.Patch), "1")); + fileContent.ShouldMatch(string.Format(regexPattern, nameof(GitVersionVariables.MajorMinorPatch), "1.0.1")); + fileContent.ShouldMatch(string.Format(regexPattern, nameof(GitVersionVariables.FullSemVer), "1.0.1-1")); + fileContent.ShouldContain("namespace App", Case.Insensitive); + } + + [TestCaseSource(nameof(Languages))] + public void GenerateGitVersionInformationTaskShouldCreateFileWithUseProjectNamespaceSetAndRootNamespaceUnSet(string language) + { + var extension = FileHelper.GetFileExtension(language); + var task = new GenerateGitVersionInformation + { + Language = language, + UseProjectNamespaceForGitVersionInformation = "true", + ProjectFile = "App.Project.csproj", + }; + using var result = ExecuteMsBuildTask(task); + + result.Success.ShouldBe(true); + result.Errors.ShouldBe(0); + result.Task.GitVersionInformationFilePath.ShouldNotBeNull(); + result.Task.GitVersionInformationFilePath.ShouldMatch($@"GitVersionInformation.*\.g\.{extension}"); + + var fileContent = File.ReadAllText(result.Task.GitVersionInformationFilePath); + fileContent.ShouldMatch(string.Format(regexPattern, nameof(GitVersionVariables.Major), "1")); + fileContent.ShouldMatch(string.Format(regexPattern, nameof(GitVersionVariables.Minor), "2")); + fileContent.ShouldMatch(string.Format(regexPattern, nameof(GitVersionVariables.Patch), "4")); + fileContent.ShouldMatch(string.Format(regexPattern, nameof(GitVersionVariables.MajorMinorPatch), "1.2.4")); + fileContent.ShouldMatch(string.Format(regexPattern, nameof(GitVersionVariables.FullSemVer), "1.2.4-1")); + fileContent.ShouldContain("namespace App.Project", Case.Insensitive); + } + + [TestCaseSource(nameof(Languages))] + public void GenerateGitVersionInformationTaskShouldCreateFileWithUseProjectNamespaceSetAndRootNamespaceIsSet(string language) + { + + var extension = FileHelper.GetFileExtension(language); + var task = new GenerateGitVersionInformation + { + Language = language, + UseProjectNamespaceForGitVersionInformation = "true", + ProjectFile = "App.Project.csproj", + RootNamespace = "App.Project.RootNamespace", + }; + using var result = ExecuteMsBuildTask(task); + + result.Success.ShouldBe(true); + result.Errors.ShouldBe(0); + result.Task.GitVersionInformationFilePath.ShouldNotBeNull(); + result.Task.GitVersionInformationFilePath.ShouldMatch($@"GitVersionInformation.*\.g\.{extension}"); + + var fileContent = File.ReadAllText(result.Task.GitVersionInformationFilePath); + fileContent.ShouldMatch(string.Format(regexPattern, nameof(GitVersionVariables.Major), "1")); + fileContent.ShouldMatch(string.Format(regexPattern, nameof(GitVersionVariables.Minor), "2")); + fileContent.ShouldMatch(string.Format(regexPattern, nameof(GitVersionVariables.Patch), "4")); + fileContent.ShouldMatch(string.Format(regexPattern, nameof(GitVersionVariables.MajorMinorPatch), "1.2.4")); + fileContent.ShouldMatch(string.Format(regexPattern, nameof(GitVersionVariables.FullSemVer), "1.2.4-1")); + + fileContent.ShouldContain("namespace App.Project.RootNamespace"); + } + + private static ProjectCreator AddGenerateGitVersionInformationTask(ProjectCreator project, string targetToRun, string taskName, string outputProperty, string language, string intermediateOutputPath = "$(MSBuildProjectDirectory)") { var assemblyFileLocation = typeof(GitVersionTaskBase).Assembly.Location; - project.UsingTaskAssemblyFile(taskName, assemblyFileLocation) + return project.UsingTaskAssemblyFile(taskName, assemblyFileLocation) .Property("ManagePackageVersionsCentrally", "false") .Property("GenerateAssemblyInfo", "false") .Property("Language", language) @@ -235,6 +356,8 @@ private static void AddGenerateGitVersionInformationTask(ProjectCreator project, { "ProjectFile", "$(MSBuildProjectFullPath)" }, { "Language", "$(Language)" }, { "IntermediateOutputPath", intermediateOutputPath }, + { "UseProjectNamespaceForGitVersionInformation", "$(UseProjectNamespaceForGitVersionInformation)" }, + { "RootNamespace", "$(RootNamespace)" }, }) .TaskOutputProperty(outputProperty, outputProperty) .ItemGroup() diff --git a/src/GitVersion.MsBuild/GitVersionTaskExecutor.cs b/src/GitVersion.MsBuild/GitVersionTaskExecutor.cs index dc28c41b76..6e4ff9dc03 100644 --- a/src/GitVersion.MsBuild/GitVersionTaskExecutor.cs +++ b/src/GitVersion.MsBuild/GitVersionTaskExecutor.cs @@ -72,8 +72,23 @@ public void GenerateGitVersionInformation(GenerateGitVersionInformation task) var gitVersionOptions = this.options.Value; gitVersionOptions.WorkingDirectory = fileWriteInfo.WorkingDirectory; + var targetNamespace = getTargetNamespace(task); + gitVersionOutputTool.GenerateGitVersionInformation(versionVariables, fileWriteInfo, targetNamespace); - gitVersionOutputTool.GenerateGitVersionInformation(versionVariables, fileWriteInfo); + static string? getTargetNamespace(GenerateGitVersionInformation task) + { + string? targetNamespace = null; + if (string.Equals(task.UseProjectNamespaceForGitVersionInformation, "true", StringComparison.OrdinalIgnoreCase)) + { + targetNamespace = task.RootNamespace; + if (string.IsNullOrWhiteSpace(targetNamespace)) + { + targetNamespace = Path.GetFileNameWithoutExtension(task.ProjectFile); + } + } + + return targetNamespace; + } } public void WriteVersionInfoToBuildLog(WriteVersionInfoToBuildLog task) diff --git a/src/GitVersion.MsBuild/PublicAPI.Unshipped.txt b/src/GitVersion.MsBuild/PublicAPI.Unshipped.txt index 4735527d08..56f89d7613 100644 --- a/src/GitVersion.MsBuild/PublicAPI.Unshipped.txt +++ b/src/GitVersion.MsBuild/PublicAPI.Unshipped.txt @@ -98,3 +98,7 @@ override GitVersion.MsBuild.Tasks.GenerateGitVersionInformation.OnExecute() -> b override GitVersion.MsBuild.Tasks.GetVersion.OnExecute() -> bool override GitVersion.MsBuild.Tasks.UpdateAssemblyInfo.OnExecute() -> bool override GitVersion.MsBuild.Tasks.WriteVersionInfoToBuildLog.OnExecute() -> bool +GitVersion.MsBuild.Tasks.GenerateGitVersionInformation.UseProjectNamespaceForGitVersionInformation.get -> string? +GitVersion.MsBuild.Tasks.GenerateGitVersionInformation.UseProjectNamespaceForGitVersionInformation.set -> void +GitVersion.MsBuild.Tasks.GenerateGitVersionInformation.RootNamespace.get -> string! +GitVersion.MsBuild.Tasks.GenerateGitVersionInformation.RootNamespace.set -> void diff --git a/src/GitVersion.MsBuild/Tasks/GenerateGitVersionInformation.cs b/src/GitVersion.MsBuild/Tasks/GenerateGitVersionInformation.cs index 2a4cddcc23..92c0fb95af 100644 --- a/src/GitVersion.MsBuild/Tasks/GenerateGitVersionInformation.cs +++ b/src/GitVersion.MsBuild/Tasks/GenerateGitVersionInformation.cs @@ -13,6 +13,10 @@ public class GenerateGitVersionInformation : GitVersionTaskBase [Required] public string Language { get; set; } = "C#"; + public string? UseProjectNamespaceForGitVersionInformation { get; set; } + + public string RootNamespace { get; set; } + [Output] public string GitVersionInformationFilePath { get; set; } diff --git a/src/GitVersion.MsBuild/msbuild/tools/GitVersion.MsBuild.targets b/src/GitVersion.MsBuild/msbuild/tools/GitVersion.MsBuild.targets index 668e19e261..e7d1a30e58 100644 --- a/src/GitVersion.MsBuild/msbuild/tools/GitVersion.MsBuild.targets +++ b/src/GitVersion.MsBuild/msbuild/tools/GitVersion.MsBuild.targets @@ -100,7 +100,9 @@ + Language="$(Language)" + UseProjectNamespaceForGitVersionInformation="$(UseProjectNamespaceForGitVersionInformation)" + RootNamespace="$(RootNamespace)"> diff --git a/src/GitVersion.Output/GitVersionInfo/GitVersionInfoContext.cs b/src/GitVersion.Output/GitVersionInfo/GitVersionInfoContext.cs index 87c779261d..d3a09c0e57 100644 --- a/src/GitVersion.Output/GitVersionInfo/GitVersionInfoContext.cs +++ b/src/GitVersion.Output/GitVersionInfo/GitVersionInfoContext.cs @@ -2,14 +2,20 @@ namespace GitVersion.Output.GitVersionInfo; internal readonly struct GitVersionInfoContext : IConverterContext { - public GitVersionInfoContext(string workingDirectory, string fileName, string fileExtension) + public GitVersionInfoContext(string workingDirectory, string fileName, string fileExtension) : this(workingDirectory, fileName, fileExtension, null) + { + } + + public GitVersionInfoContext(string workingDirectory, string fileName, string fileExtension, string? targetNamespace = null) { WorkingDirectory = workingDirectory; FileName = fileName; FileExtension = fileExtension; + TargetNamespace = targetNamespace; } public string WorkingDirectory { get; } public string FileName { get; } public string FileExtension { get; } + public string? TargetNamespace { get; } } diff --git a/src/GitVersion.Output/GitVersionInfo/GitVersionInfoGenerator.cs b/src/GitVersion.Output/GitVersionInfo/GitVersionInfoGenerator.cs index ae925b51a5..97970f5a1e 100644 --- a/src/GitVersion.Output/GitVersionInfo/GitVersionInfoGenerator.cs +++ b/src/GitVersion.Output/GitVersionInfo/GitVersionInfoGenerator.cs @@ -10,6 +10,7 @@ internal interface IGitVersionInfoGenerator : IVersionConverter x.Key).Select(v => string.Format(indentation + addFormat, v.Key, v.Value)); var members = string.Join(System.Environment.NewLine, lines); - var fileContents = string.Format(template, members); + + var fileContents = string.Format(template, members, targetNamespace, openBracket, closeBracket, indent); if (fileContents != originalFileContents) { this.fileSystem.WriteAllText(filePath, fileContents); } + + string getTargetNamespace(string fileExtension) => fileExtension switch + { + ".vb" => context.TargetNamespace ?? "Global", + ".cs" => context.TargetNamespace != null ? $"{System.Environment.NewLine}namespace {context.TargetNamespace};" : "", + ".fs" => context.TargetNamespace ?? "global", + _ => targetNamespaceSentinelValue, + }; } public void Dispose() diff --git a/src/GitVersion.Output/GitVersionInfo/Templates/GitVersionInformation.cs b/src/GitVersion.Output/GitVersionInfo/Templates/GitVersionInformation.cs index 53e9b35ead..12deef9fa3 100644 --- a/src/GitVersion.Output/GitVersionInfo/Templates/GitVersionInformation.cs +++ b/src/GitVersion.Output/GitVersionInfo/Templates/GitVersionInformation.cs @@ -23,10 +23,10 @@ namespace System.Diagnostics.CodeAnalysis internal sealed class ExcludeFromCodeCoverageAttribute : global::System.Attribute {{ }} }} #endif - -[global::System.Runtime.CompilerServices.CompilerGenerated] -[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] -static class GitVersionInformation -{{ +{1}{2} +{4}[global::System.Runtime.CompilerServices.CompilerGenerated] +{4}[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] +{4}static class GitVersionInformation +{4}{{ {0} -}} +{4}}}{3} diff --git a/src/GitVersion.Output/GitVersionInfo/Templates/GitVersionInformation.fs b/src/GitVersion.Output/GitVersionInfo/Templates/GitVersionInformation.fs index 561bc56f75..0862986636 100644 --- a/src/GitVersion.Output/GitVersionInfo/Templates/GitVersionInformation.fs +++ b/src/GitVersion.Output/GitVersionInfo/Templates/GitVersionInformation.fs @@ -24,7 +24,7 @@ namespace System.Diagnostics.CodeAnalysis type ExcludeFromCodeCoverageAttribute() = inherit global.System.Attribute() #endif -namespace global +namespace {1} [] [] diff --git a/src/GitVersion.Output/GitVersionInfo/Templates/GitVersionInformation.vb b/src/GitVersion.Output/GitVersionInfo/Templates/GitVersionInformation.vb index d9cd68db27..b7f3b7b923 100644 --- a/src/GitVersion.Output/GitVersionInfo/Templates/GitVersionInformation.vb +++ b/src/GitVersion.Output/GitVersionInfo/Templates/GitVersionInformation.vb @@ -24,7 +24,7 @@ Namespace Global.System.Diagnostics.CodeAnalysis End Namespace #End If -Namespace Global +Namespace {1} diff --git a/src/GitVersion.Output/GitVersionOutputTool.cs b/src/GitVersion.Output/GitVersionOutputTool.cs index 246ed81b60..6d19222437 100644 --- a/src/GitVersion.Output/GitVersionOutputTool.cs +++ b/src/GitVersion.Output/GitVersionOutputTool.cs @@ -71,11 +71,13 @@ public void UpdateWixVersionFile(GitVersionVariables variables) } } - public void GenerateGitVersionInformation(GitVersionVariables variables, FileWriteInfo fileWriteInfo) + public void GenerateGitVersionInformation(GitVersionVariables variables, FileWriteInfo fileWriteInfo, string? targetNamespace = null) { using (this.gitVersionInfoGenerator) { - this.gitVersionInfoGenerator.Execute(variables, new GitVersionInfoContext(gitVersionOptions.WorkingDirectory, fileWriteInfo.FileName, fileWriteInfo.FileExtension)); + this.gitVersionInfoGenerator.Execute(variables, new GitVersionInfoContext(gitVersionOptions.WorkingDirectory, fileWriteInfo.FileName, fileWriteInfo.FileExtension, targetNamespace)); } } + + public void GenerateGitVersionInformation(GitVersionVariables variables, FileWriteInfo fileWriteInfo) => GenerateGitVersionInformation(variables, fileWriteInfo, null); } diff --git a/src/GitVersion.Output/IGitVersionOutputTool.cs b/src/GitVersion.Output/IGitVersionOutputTool.cs index 514c878150..f56248fe5e 100644 --- a/src/GitVersion.Output/IGitVersionOutputTool.cs +++ b/src/GitVersion.Output/IGitVersionOutputTool.cs @@ -8,4 +8,5 @@ public interface IGitVersionOutputTool void UpdateAssemblyInfo(GitVersionVariables variables); void UpdateWixVersionFile(GitVersionVariables variables); void GenerateGitVersionInformation(GitVersionVariables variables, FileWriteInfo fileWriteInfo); + void GenerateGitVersionInformation(GitVersionVariables variables, FileWriteInfo fileWriteInfo, string? targetNamespace = null); } diff --git a/src/GitVersion.Output/PublicAPI.Unshipped.txt b/src/GitVersion.Output/PublicAPI.Unshipped.txt index 5a492ac2d7..4920c0a9cc 100644 --- a/src/GitVersion.Output/PublicAPI.Unshipped.txt +++ b/src/GitVersion.Output/PublicAPI.Unshipped.txt @@ -1,6 +1,7 @@ #nullable enable GitVersion.IGitVersionOutputTool GitVersion.IGitVersionOutputTool.GenerateGitVersionInformation(GitVersion.OutputVariables.GitVersionVariables! variables, GitVersion.FileWriteInfo! fileWriteInfo) -> void +GitVersion.IGitVersionOutputTool.GenerateGitVersionInformation(GitVersion.OutputVariables.GitVersionVariables! variables, GitVersion.FileWriteInfo! fileWriteInfo, string? targetNamespace = null) -> void GitVersion.IGitVersionOutputTool.OutputVariables(GitVersion.OutputVariables.GitVersionVariables! variables, bool updateBuildNumber) -> void GitVersion.IGitVersionOutputTool.UpdateAssemblyInfo(GitVersion.OutputVariables.GitVersionVariables! variables) -> void GitVersion.IGitVersionOutputTool.UpdateWixVersionFile(GitVersion.OutputVariables.GitVersionVariables! variables) -> void