From 3700f2bbb24b904fdefc72e28857a3a73c12cf9e Mon Sep 17 00:00:00 2001 From: Artur Stolear Date: Sun, 3 May 2020 11:04:00 +0300 Subject: [PATCH 1/3] added output file option --- src/GitVersionCore/Core/GitVersionTool.cs | 2 +- src/GitVersionCore/Model/GitVersionOptions.cs | 1 + src/GitVersionCore/Model/OutputType.cs | 4 ++-- .../VersionConverters/OutputGenerator/OutputContext.cs | 4 +++- .../VersionConverters/OutputGenerator/OutputGenerator.cs | 8 +++++++- src/GitVersionExe/ArgumentParser.cs | 9 ++++++++- src/GitVersionExe/Arguments.cs | 2 ++ 7 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/GitVersionCore/Core/GitVersionTool.cs b/src/GitVersionCore/Core/GitVersionTool.cs index 7d67ed94dc..041f79a520 100644 --- a/src/GitVersionCore/Core/GitVersionTool.cs +++ b/src/GitVersionCore/Core/GitVersionTool.cs @@ -85,7 +85,7 @@ public void OutputVariables(VersionVariables variables) using (outputGenerator) { - outputGenerator.Execute(variables, new OutputContext(gitVersionOptions.WorkingDirectory)); + outputGenerator.Execute(variables, new OutputContext(gitVersionOptions.WorkingDirectory, gitVersionOptions.OutputFile)); } } diff --git a/src/GitVersionCore/Model/GitVersionOptions.cs b/src/GitVersionCore/Model/GitVersionOptions.cs index 4e616b3101..2463c839ee 100644 --- a/src/GitVersionCore/Model/GitVersionOptions.cs +++ b/src/GitVersionCore/Model/GitVersionOptions.cs @@ -39,6 +39,7 @@ public GitVersionOptions() public string LogFilePath; public string ShowVariable; + public string OutputFile; public ISet Output = new HashSet(); public Verbosity Verbosity = Verbosity.Normal; diff --git a/src/GitVersionCore/Model/OutputType.cs b/src/GitVersionCore/Model/OutputType.cs index 4a05b0b4ab..03497d7e48 100644 --- a/src/GitVersionCore/Model/OutputType.cs +++ b/src/GitVersionCore/Model/OutputType.cs @@ -3,7 +3,7 @@ namespace GitVersion.Model public enum OutputType { BuildServer, - - Json + Json, + File } } diff --git a/src/GitVersionCore/VersionConverters/OutputGenerator/OutputContext.cs b/src/GitVersionCore/VersionConverters/OutputGenerator/OutputContext.cs index da1b5aa202..4dbab4f862 100644 --- a/src/GitVersionCore/VersionConverters/OutputGenerator/OutputContext.cs +++ b/src/GitVersionCore/VersionConverters/OutputGenerator/OutputContext.cs @@ -2,11 +2,13 @@ namespace GitVersion.VersionConverters.OutputGenerator { public readonly struct OutputContext : IConverterContext { - public OutputContext(string workingDirectory) + public OutputContext(string workingDirectory, string outputFile) { WorkingDirectory = workingDirectory; + OutputFile = outputFile; } public string WorkingDirectory { get; } + public string OutputFile { get; } } } diff --git a/src/GitVersionCore/VersionConverters/OutputGenerator/OutputGenerator.cs b/src/GitVersionCore/VersionConverters/OutputGenerator/OutputGenerator.cs index 9328d8fc10..60ff934471 100644 --- a/src/GitVersionCore/VersionConverters/OutputGenerator/OutputGenerator.cs +++ b/src/GitVersionCore/VersionConverters/OutputGenerator/OutputGenerator.cs @@ -13,12 +13,14 @@ public interface IOutputGenerator : IVersionConverter public class OutputGenerator : IOutputGenerator { private readonly IConsole console; + private readonly IFileSystem fileSystem; private readonly IOptions options; private readonly ICurrentBuildAgent buildAgent; - public OutputGenerator(ICurrentBuildAgent buildAgent, IConsole console, IOptions options) + public OutputGenerator(ICurrentBuildAgent buildAgent, IConsole console, IFileSystem fileSystem, IOptions options) { this.console = console ?? throw new ArgumentNullException(nameof(console)); + this.fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem)); this.options = options ?? throw new ArgumentNullException(nameof(options)); this.buildAgent = buildAgent; } @@ -30,6 +32,10 @@ public void Execute(VersionVariables variables, OutputContext context) { buildAgent?.WriteIntegration(console.WriteLine, variables); } + if (gitVersionOptions.Output.Contains(OutputType.File)) + { + fileSystem.WriteAllText(context.OutputFile, variables.ToString()); + } if (gitVersionOptions.Output.Contains(OutputType.Json)) { switch (gitVersionOptions.ShowVariable) diff --git a/src/GitVersionExe/ArgumentParser.cs b/src/GitVersionExe/ArgumentParser.cs index 98e6959679..4f2845184b 100644 --- a/src/GitVersionExe/ArgumentParser.cs +++ b/src/GitVersionExe/ArgumentParser.cs @@ -223,6 +223,13 @@ private static bool ParseSwitches(Arguments arguments, string name, string[] val return true; } + if (name.IsSwitch("outputfile")) + { + EnsureArgumentValueCount(values); + arguments.OutputFile = value; + return true; + } + if (name.IsSwitch("nofetch")) { arguments.NoFetch = true; @@ -417,7 +424,7 @@ private static void ParseOutput(Arguments arguments, string[] values) { if (!Enum.TryParse(v, true, out OutputType outputType)) { - throw new WarningException($"Value '{v}' cannot be parsed as output type, please use 'json' or 'buildserver'"); + throw new WarningException($"Value '{v}' cannot be parsed as output type, please use 'json', 'file' or 'buildserver'"); } arguments.Output.Add(outputType); diff --git a/src/GitVersionExe/Arguments.cs b/src/GitVersionExe/Arguments.cs index 04723025cb..9c9afd22f7 100644 --- a/src/GitVersionExe/Arguments.cs +++ b/src/GitVersionExe/Arguments.cs @@ -34,6 +34,7 @@ public class Arguments public string LogFilePath; public string ShowVariable; + public string OutputFile; public ISet Output = new HashSet(); public Verbosity Verbosity = Verbosity.Normal; @@ -108,6 +109,7 @@ public GitVersionOptions ToOptions() ShowVariable = ShowVariable, Verbosity = Verbosity, Output = Output, + OutputFile = OutputFile, // TODO obsolete to be removed in version 6.0.0 Proj = Proj, From baa55fd0b55c9765057a08722d681d2845a432af Mon Sep 17 00:00:00 2001 From: Artur Stolear Date: Sun, 3 May 2020 10:28:08 +0300 Subject: [PATCH 2/3] added output file tests --- .../ArgumentParserTests.cs | 46 ++++++++++++++++++- src/GitVersionExe.Tests/HelpWriterTests.cs | 1 + src/GitVersionExe/ArgumentParser.cs | 6 +++ src/GitVersionExe/HelpWriter.cs | 3 +- 4 files changed, 54 insertions(+), 2 deletions(-) diff --git a/src/GitVersionExe.Tests/ArgumentParserTests.cs b/src/GitVersionExe.Tests/ArgumentParserTests.cs index 8bc78343fa..9891f57e35 100644 --- a/src/GitVersionExe.Tests/ArgumentParserTests.cs +++ b/src/GitVersionExe.Tests/ArgumentParserTests.cs @@ -155,7 +155,7 @@ public void UsernameAndPasswordCanBeParsed() public void UnknownOutputShouldThrow() { var exception = Assert.Throws(() => argumentParser.ParseArguments("targetDirectoryPath -output invalid_value")); - exception.Message.ShouldBe("Value 'invalid_value' cannot be parsed as output type, please use 'json' or 'buildserver'"); + exception.Message.ShouldBe("Value 'invalid_value' cannot be parsed as output type, please use 'json', 'file' or 'buildserver'"); } [Test] @@ -163,6 +163,8 @@ public void OutputDefaultsToJson() { var arguments = argumentParser.ParseArguments("targetDirectoryPath"); arguments.Output.ShouldContain(OutputType.Json); + arguments.Output.ShouldNotContain(OutputType.BuildServer); + arguments.Output.ShouldNotContain(OutputType.File); } [Test] @@ -171,6 +173,7 @@ public void OutputJsonCanBeParsed() var arguments = argumentParser.ParseArguments("targetDirectoryPath -output json"); arguments.Output.ShouldContain(OutputType.Json); arguments.Output.ShouldNotContain(OutputType.BuildServer); + arguments.Output.ShouldNotContain(OutputType.File); } [Test] @@ -179,6 +182,7 @@ public void MultipleOutputJsonCanBeParsed() var arguments = argumentParser.ParseArguments("targetDirectoryPath -output json -output json"); arguments.Output.ShouldContain(OutputType.Json); arguments.Output.ShouldNotContain(OutputType.BuildServer); + arguments.Output.ShouldNotContain(OutputType.File); } [Test] @@ -187,6 +191,7 @@ public void OutputBuildserverCanBeParsed() var arguments = argumentParser.ParseArguments("targetDirectoryPath -output buildserver"); arguments.Output.ShouldContain(OutputType.BuildServer); arguments.Output.ShouldNotContain(OutputType.Json); + arguments.Output.ShouldNotContain(OutputType.File); } [Test] @@ -195,6 +200,25 @@ public void MultipleOutputBuildserverCanBeParsed() var arguments = argumentParser.ParseArguments("targetDirectoryPath -output buildserver -output buildserver"); arguments.Output.ShouldContain(OutputType.BuildServer); arguments.Output.ShouldNotContain(OutputType.Json); + arguments.Output.ShouldNotContain(OutputType.File); + } + + [Test] + public void OutputFileCanBeParsed() + { + var arguments = argumentParser.ParseArguments("targetDirectoryPath -output file"); + arguments.Output.ShouldContain(OutputType.File); + arguments.Output.ShouldNotContain(OutputType.BuildServer); + arguments.Output.ShouldNotContain(OutputType.Json); + } + + [Test] + public void MultipleOutputFileCanBeParsed() + { + var arguments = argumentParser.ParseArguments("targetDirectoryPath -output file -output file"); + arguments.Output.ShouldContain(OutputType.File); + arguments.Output.ShouldNotContain(OutputType.BuildServer); + arguments.Output.ShouldNotContain(OutputType.Json); } [Test] @@ -203,6 +227,16 @@ public void OutputBuildserverAndJsonCanBeParsed() var arguments = argumentParser.ParseArguments("targetDirectoryPath -output buildserver -output json"); arguments.Output.ShouldContain(OutputType.BuildServer); arguments.Output.ShouldContain(OutputType.Json); + arguments.Output.ShouldNotContain(OutputType.File); + } + + [Test] + public void OutputBuildserverAndJsonAndFileCanBeParsed() + { + var arguments = argumentParser.ParseArguments("targetDirectoryPath -output buildserver -output json -output file"); + arguments.Output.ShouldContain(OutputType.BuildServer); + arguments.Output.ShouldContain(OutputType.Json); + arguments.Output.ShouldContain(OutputType.File); } [Test] @@ -212,6 +246,16 @@ public void MultipleArgsAndFlag() arguments.Output.ShouldContain(OutputType.BuildServer); } + [TestCase("-output file", "GitVersion.json")] + [TestCase("-output file -outputfile version.json", "version.json")] + public void OutputFileArgumentCanBeParsed(string args, string outputFile) + { + var arguments = argumentParser.ParseArguments(args); + + arguments.Output.ShouldContain(OutputType.File); + arguments.OutputFile.ShouldBe(outputFile); + } + [Test] public void UrlAndBranchNameCanBeParsed() { diff --git a/src/GitVersionExe.Tests/HelpWriterTests.cs b/src/GitVersionExe.Tests/HelpWriterTests.cs index 6fa82bd879..98778a194b 100644 --- a/src/GitVersionExe.Tests/HelpWriterTests.cs +++ b/src/GitVersionExe.Tests/HelpWriterTests.cs @@ -31,6 +31,7 @@ public void AllArgsAreInHelp() { nameof(Arguments.Init), "init" }, { nameof(Arguments.TargetBranch), "/b" }, { nameof(Arguments.LogFilePath) , "/l" }, + { nameof(Arguments.OutputFile) , "/outputfile" }, { nameof(Arguments.DynamicRepositoryClonePath), "/dynamicRepoLocation" }, { nameof(Arguments.IsHelp), "/?" }, { nameof(Arguments.IsVersion), "/version" }, diff --git a/src/GitVersionExe/ArgumentParser.cs b/src/GitVersionExe/ArgumentParser.cs index 4f2845184b..2c8c777222 100644 --- a/src/GitVersionExe/ArgumentParser.cs +++ b/src/GitVersionExe/ArgumentParser.cs @@ -17,6 +17,7 @@ public class ArgumentParser : IArgumentParser private readonly ICurrentBuildAgent buildAgent; private readonly IConsole console; private readonly IGlobbingResolver globbingResolver; + private const string defaultOutputFileName = "GitVersion.json"; public ArgumentParser(IEnvironment environment, ICurrentBuildAgent buildAgent, IConsole console, IGlobbingResolver globbingResolver) { @@ -91,6 +92,11 @@ public Arguments ParseArguments(string[] commandLineArguments) arguments.Output.Add(OutputType.Json); } + if (arguments.Output.Contains(OutputType.File) && arguments.OutputFile == null) + { + arguments.OutputFile = defaultOutputFileName; + } + // If the first argument is a switch, it should already have been consumed in the above loop, // or else a WarningException should have been thrown and we wouldn't end up here. arguments.TargetPath ??= firstArgumentIsSwitch diff --git a/src/GitVersionExe/HelpWriter.cs b/src/GitVersionExe/HelpWriter.cs index e4dc4692bd..4dd030aa77 100644 --- a/src/GitVersionExe/HelpWriter.cs +++ b/src/GitVersionExe/HelpWriter.cs @@ -38,7 +38,8 @@ path The directory containing .git. If not defined current directory /h or /? Shows Help /targetpath Same as 'path', but not positional - /output Determines the output to the console. Can be either 'json' or 'buildserver', will default to 'json'. + /output Determines the output to the console. Can be either 'json', 'file' or 'buildserver', will default to 'json'. + /outputfile Path to output file. It is used in combination with /output 'file'. /showvariable Used in conjuntion with /output json, will output just a particular variable. eg /output json /showvariable SemVer - will output `1.2.3+beta.4` /l Path to logfile. From d755bf2ac3bd595b0e6d1c43717526214c31a737 Mon Sep 17 00:00:00 2001 From: Artur Stolear Date: Mon, 4 May 2020 14:03:40 +0300 Subject: [PATCH 3/3] added output file integration tests --- .../JsonOutputOnBuildServerTest.cs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/GitVersionExe.Tests/JsonOutputOnBuildServerTest.cs b/src/GitVersionExe.Tests/JsonOutputOnBuildServerTest.cs index ae5fcbcef9..990caad2bb 100644 --- a/src/GitVersionExe.Tests/JsonOutputOnBuildServerTest.cs +++ b/src/GitVersionExe.Tests/JsonOutputOnBuildServerTest.cs @@ -1,6 +1,9 @@ using System.Collections.Generic; +using System.IO; using GitTools.Testing; using GitVersion.BuildAgents; +using GitVersion.OutputVariables; +using Newtonsoft.Json; using NUnit.Framework; using Shouldly; @@ -41,5 +44,31 @@ public void BeingOnBuildServerWithOutputJsonDoesNotFail() result.OutputVariables.ShouldNotBeNull(); result.OutputVariables.FullSemVer.ShouldBeEquivalentTo(version); } + + [TestCase("", "GitVersion.json")] + [TestCase("version.json", "version.json")] + public void BeingOnBuildServerWithOutputJsonAndOutputFileDoesNotFail(string outputFile, string fileName) + { + using var fixture = new RemoteRepositoryFixture(); + fixture.Repository.MakeATaggedCommit("1.2.3"); + fixture.Repository.MakeACommit(); + + var env = new KeyValuePair(TeamCity.EnvironmentVariableName, "8.0.0"); + + var result = GitVersionHelper.ExecuteIn(fixture.LocalRepositoryFixture.RepositoryPath, arguments: $" /output json /output buildserver /output file /outputfile {outputFile}", environments: env); + + result.ExitCode.ShouldBe(0); + const string version = "0.1.0+4"; + result.Output.ShouldContain($"##teamcity[buildNumber '{version}']"); + result.OutputVariables.ShouldNotBeNull(); + result.OutputVariables.FullSemVer.ShouldBeEquivalentTo(version); + + var filePath = Path.Combine(fixture.LocalRepositoryFixture.RepositoryPath, fileName); + var json = File.ReadAllText(filePath); + + var outputVariables = VersionVariables.FromDictionary(JsonConvert.DeserializeObject>(json)); + outputVariables.ShouldNotBeNull(); + outputVariables.FullSemVer.ShouldBeEquivalentTo(version); + } } }