Skip to content

Commit e4fda47

Browse files
committed
Support for dotenv output format
closes #4174
1 parent 754e71c commit e4fda47

File tree

9 files changed

+175
-4
lines changed

9 files changed

+175
-4
lines changed

docs/input/docs/usage/cli/arguments.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ GitVersion [path]
3030

3131
/targetpath Same as 'path', but not positional
3232
/output Determines the output to the console. Can be either 'json',
33-
'file' or 'buildserver', will default to 'json'.
33+
'file', 'buildserver' or 'dotenv', will default to 'json'.
3434
/outputfile Path to output file. It is used in combination with /output
3535
'file'.
3636
/showvariable Used in conjunction with /output json, will output just a

docs/input/docs/usage/cli/output.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,10 @@ out the variables to whatever build server it is running in. You can then use
1414
those variables in your build scripts or run different tools to create versioned
1515
NuGet packages or whatever you would like to do. See [build
1616
servers](/docs/reference/build-servers) for more information about this.
17+
18+
You can even store the [variables](/docs/reference/variables) in a Dotenv file
19+
and load it to have the variables available in your environment.
20+
For that you have to run `GitVersion.exe /output dotenv` and store the output
21+
into e.g. a `gitversion.env` file. These files can also be passed around in CI environments
22+
like [GitHub](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables#passing-values-between-steps-and-jobs-in-a-workflow)
23+
or [GitLab](https://docs.gitlab.com/ee/ci/variables/#pass-an-environment-variable-to-another-job).

new-cli/command.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,18 @@ cat gitversion.json | gitversion output buildserver
5353
# Read version variables from stdin and write to Jenkins.
5454
cat gitversion.json | gitversion output buildserver --buildserver Jenkins
5555

56+
# Output version variables in Dotenv format
57+
gitversion /output dotenv
58+
59+
# Show only a subset of the version variables in Dotenv format (Unix syntax)
60+
gitversion /output dotenv | grep -i "prerelease"
61+
62+
# Show only a subset of the version variables that match the regex in Dotenv format (Unix syntax)
63+
gitversion /output dotenv | grep -iE "major|sha=|_prerelease"
64+
65+
# Write version variables in Dotenv format into a file
66+
gitversion /output dotenv > gitversion.env
67+
5668
# Read version variables from stdin and write to globbed .wxi files.
5769
cat gitversion.json | gitversion output wix --path ./**/*.wxi
5870

src/GitVersion.App.Tests/ArgumentParserTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ public void UnknownOutputShouldThrow()
102102
{
103103
var exception = Assert.Throws<WarningException>(() => this.argumentParser.ParseArguments("targetDirectoryPath -output invalid_value"));
104104
exception.ShouldNotBeNull();
105-
exception.Message.ShouldBe("Value 'invalid_value' cannot be parsed as output type, please use 'json', 'file' or 'buildserver'");
105+
exception.Message.ShouldBe("Value 'invalid_value' cannot be parsed as output type, please use 'json', 'file', 'buildserver' or 'dotenv'");
106106
}
107107

108108
[Test]

src/GitVersion.App/ArgumentParser.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ private static void ParseOutput(Arguments arguments, IEnumerable<string>? values
431431
{
432432
if (!Enum.TryParse(v, true, out OutputType outputType))
433433
{
434-
throw new WarningException($"Value '{v}' cannot be parsed as output type, please use 'json', 'file' or 'buildserver'");
434+
throw new WarningException($"Value '{v}' cannot be parsed as output type, please use 'json', 'file', 'buildserver' or 'dotenv'");
435435
}
436436

437437
arguments.Output.Add(outputType);

src/GitVersion.Core/Options/OutputType.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ public enum OutputType
44
{
55
BuildServer,
66
Json,
7-
File
7+
File,
8+
DotEnv
89
}

src/GitVersion.Core/PublicAPI.Shipped.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,7 @@ GitVersion.OutputType
435435
GitVersion.OutputType.BuildServer = 0 -> GitVersion.OutputType
436436
GitVersion.OutputType.File = 2 -> GitVersion.OutputType
437437
GitVersion.OutputType.Json = 1 -> GitVersion.OutputType
438+
GitVersion.OutputType.DotEnv = 3 -> GitVersion.OutputType
438439
GitVersion.OutputVariables.GitVersionVariables
439440
GitVersion.OutputVariables.GitVersionVariables.AssemblySemFileVer.get -> string?
440441
GitVersion.OutputVariables.GitVersionVariables.AssemblySemFileVer.init -> void

src/GitVersion.Output.Tests/Output/FormatArgumentTests.cs

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,126 @@ public void ShouldOutputFormatWithEnvironmentVariablesTests(string format, strin
6868
output.ShouldBeEquivalentTo(expectedValue);
6969
}
7070

71+
[TestCase("Major", "1")]
72+
[TestCase("MajorMinorPatch", "1.1.0")]
73+
[TestCase("SemVer", "1.1.0-foo.1")]
74+
[TestCase("PreReleaseTagWithDash", "-foo.1")]
75+
[TestCase("AssemblySemFileVer", "1.1.0.0")]
76+
[TestCase("BranchName", "feature/foo")]
77+
[TestCase("FullSemVer", "1.1.0-foo.1+1")]
78+
public void ShouldOutputDotEnvEntries(string variableName, string expectedValue)
79+
{
80+
var fixture = CreateTestRepository();
81+
82+
var consoleBuilder = new StringBuilder();
83+
IConsole consoleAdapter = new TestConsoleAdapter(consoleBuilder);
84+
85+
var sp = ConfigureServices(services =>
86+
{
87+
var options = Options.Create(new GitVersionOptions { WorkingDirectory = fixture.RepositoryPath, RepositoryInfo = { TargetBranch = fixture.Repository.Head.CanonicalName }, Output = { OutputType.DotEnv } });
88+
var repository = fixture.Repository.ToGitRepository();
89+
90+
services.AddSingleton(options);
91+
services.AddSingleton(repository);
92+
services.AddSingleton(consoleAdapter);
93+
});
94+
95+
var versionVariables = sp.GetRequiredService<IGitVersionCalculateTool>().CalculateVersionVariables();
96+
var outputGenerator = sp.GetRequiredService<IOutputGenerator>();
97+
98+
outputGenerator.Execute(versionVariables, new());
99+
var output = consoleBuilder.ToString();
100+
output.ShouldContain("GitVersion_" + variableName + "=" + expectedValue + "\n");
101+
}
102+
103+
[TestCase]
104+
public void ShouldOutputAllCalculatedVariablesAsDotEnvEntries()
105+
{
106+
var fixture = CreateTestRepository();
107+
108+
var consoleBuilder = new StringBuilder();
109+
IConsole consoleAdapter = new TestConsoleAdapter(consoleBuilder);
110+
111+
var sp = ConfigureServices(services =>
112+
{
113+
var options = Options.Create(new GitVersionOptions { WorkingDirectory = fixture.RepositoryPath, RepositoryInfo = { TargetBranch = fixture.Repository.Head.CanonicalName }, Output = { OutputType.DotEnv } });
114+
var repository = fixture.Repository.ToGitRepository();
115+
116+
services.AddSingleton(options);
117+
services.AddSingleton(repository);
118+
services.AddSingleton(consoleAdapter);
119+
});
120+
121+
var versionVariables = sp.GetRequiredService<IGitVersionCalculateTool>().CalculateVersionVariables();
122+
var outputGenerator = sp.GetRequiredService<IOutputGenerator>();
123+
124+
outputGenerator.Execute(versionVariables, new());
125+
var output = consoleBuilder.ToString();
126+
var totalOutputLines = output.Split("\n").Length - 1; // ignore last item that also ends with \n
127+
Assert.That(totalOutputLines, Is.EqualTo(versionVariables.Count()));
128+
}
129+
130+
[TestCase("Major", "0")]
131+
[TestCase("MajorMinorPatch", "0.0.1")]
132+
[TestCase("SemVer", "0.0.1-1")]
133+
[TestCase("BuildMetaData", "''")]
134+
[TestCase("AssemblySemVer", "0.0.1.0")]
135+
[TestCase("PreReleaseTagWithDash", "-1")]
136+
[TestCase("BranchName", "main")]
137+
[TestCase("PreReleaseLabel", "''")]
138+
[TestCase("PreReleaseLabelWithDash", "''")]
139+
public void ShouldOutputAllDotEnvEntriesEvenForMinimalRepositories(string variableName, string expectedValue)
140+
{
141+
var fixture = CreateMinimalTestRepository();
142+
143+
var consoleBuilder = new StringBuilder();
144+
IConsole consoleAdapter = new TestConsoleAdapter(consoleBuilder);
145+
146+
var sp = ConfigureServices(services =>
147+
{
148+
var options = Options.Create(new GitVersionOptions { WorkingDirectory = fixture.RepositoryPath, RepositoryInfo = { TargetBranch = fixture.Repository.Head.CanonicalName }, Output = { OutputType.DotEnv } });
149+
var repository = fixture.Repository.ToGitRepository();
150+
151+
services.AddSingleton(options);
152+
services.AddSingleton(repository);
153+
services.AddSingleton(consoleAdapter);
154+
});
155+
156+
var versionVariables = sp.GetRequiredService<IGitVersionCalculateTool>().CalculateVersionVariables();
157+
var outputGenerator = sp.GetRequiredService<IOutputGenerator>();
158+
159+
outputGenerator.Execute(versionVariables, new());
160+
var output = consoleBuilder.ToString();
161+
output.ShouldContain("GitVersion_" + variableName + "=" + expectedValue + "\n");
162+
}
163+
164+
[TestCase]
165+
public void ShouldOutputAllCalculatedVariablesAsDotEnvEntriesEvenForMinimalRepositories()
166+
{
167+
var fixture = CreateMinimalTestRepository();
168+
169+
var consoleBuilder = new StringBuilder();
170+
IConsole consoleAdapter = new TestConsoleAdapter(consoleBuilder);
171+
172+
var sp = ConfigureServices(services =>
173+
{
174+
var options = Options.Create(new GitVersionOptions { WorkingDirectory = fixture.RepositoryPath, RepositoryInfo = { TargetBranch = fixture.Repository.Head.CanonicalName }, Output = { OutputType.DotEnv } });
175+
var repository = fixture.Repository.ToGitRepository();
176+
177+
services.AddSingleton(options);
178+
services.AddSingleton(repository);
179+
services.AddSingleton(consoleAdapter);
180+
});
181+
182+
var versionVariables = sp.GetRequiredService<IGitVersionCalculateTool>().CalculateVersionVariables();
183+
var outputGenerator = sp.GetRequiredService<IOutputGenerator>();
184+
185+
outputGenerator.Execute(versionVariables, new());
186+
var output = consoleBuilder.ToString();
187+
var totalOutputLines = output.Split("\n").Length - 1; // ignore last item that also ends with \n
188+
Assert.That(totalOutputLines, Is.EqualTo(versionVariables.Count()));
189+
}
190+
71191
private static EmptyRepositoryFixture CreateTestRepository()
72192
{
73193
var fixture = new EmptyRepositoryFixture();
@@ -80,4 +200,11 @@ private static EmptyRepositoryFixture CreateTestRepository()
80200
_ = fixture.Repository.MakeACommit();
81201
return fixture;
82202
}
203+
204+
private static EmptyRepositoryFixture CreateMinimalTestRepository()
205+
{
206+
var fixture = new EmptyRepositoryFixture();
207+
_ = fixture.Repository.MakeACommit();
208+
return fixture;
209+
}
83210
}

src/GitVersion.Output/OutputGenerator/OutputGenerator.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,34 @@ internal sealed class OutputGenerator(
2727
public void Execute(GitVersionVariables variables, OutputContext context)
2828
{
2929
var gitVersionOptions = this.options.Value;
30+
3031
if (gitVersionOptions.Output.Contains(OutputType.BuildServer))
3132
{
3233
this.buildAgent.WriteIntegration(this.console.WriteLine, variables, context.UpdateBuildNumber ?? true);
3334
}
3435

36+
if (gitVersionOptions.Output.Contains(OutputType.DotEnv))
37+
{
38+
List<string> dotEnvEntries = [];
39+
foreach (var (key, value) in variables.OrderBy(x => x.Key))
40+
{
41+
string prefixedKey = "GitVersion_" + key;
42+
string environmentValue = "''";
43+
if (!value.IsNullOrEmpty())
44+
{
45+
environmentValue = value;
46+
}
47+
dotEnvEntries.Add(prefixedKey + "=" + environmentValue);
48+
}
49+
50+
foreach(var dotEnvEntry in dotEnvEntries)
51+
{
52+
this.console.WriteLine(dotEnvEntry);
53+
}
54+
55+
return;
56+
}
57+
3558
var json = this.serializer.ToJson(variables);
3659
if (gitVersionOptions.Output.Contains(OutputType.File))
3760
{

0 commit comments

Comments
 (0)