Skip to content

Commit 09a13ca

Browse files
committed
Move implementation of the "cloud" command out of Program.cs into the "CloudCommand" class
1 parent 2e44aa4 commit 09a13ca

File tree

2 files changed

+199
-55
lines changed

2 files changed

+199
-55
lines changed
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
namespace Nerdbank.GitVersioning
2+
{
3+
using System;
4+
using System.Collections.Generic;
5+
using System.IO;
6+
using System.Linq;
7+
using Validation;
8+
9+
/// <summary>
10+
/// Implementation of the "nbgv cloud" command that updates the build environments variables with version variables
11+
/// </summary>
12+
public class CloudCommand
13+
{
14+
/// <summary>
15+
/// Defines the possible errors of the "cloud" command
16+
/// </summary>
17+
public enum CloudCommandError
18+
{
19+
/// <summary>
20+
/// Teh specified CI system was not found
21+
/// </summary>
22+
NoCloudBuildProviderMatch,
23+
24+
/// <summary>
25+
/// A cloud variable was defined multiple times
26+
/// </summary>
27+
DuplicateCloudVariable,
28+
29+
/// <summary>
30+
/// No supported cloud build environment could be detected
31+
/// </summary>
32+
NoCloudBuildEnvDetected
33+
}
34+
35+
/// <summary>
36+
/// Exception indicating an error while setting build variables
37+
/// </summary>
38+
public class CloudCommandException : Exception
39+
{
40+
/// <summary>
41+
/// Gets the error that occurred.
42+
/// </summary>
43+
public CloudCommandError Error { get; }
44+
45+
/// <summary>
46+
/// Initializes a new instance of <see cref="CloudCommandException"/>
47+
/// </summary>
48+
/// <param name="message">The message that describes the error.</param>
49+
/// <param name="error">The error that occurred.</param>
50+
public CloudCommandException(string message, CloudCommandError error) : base(message) => this.Error = error;
51+
}
52+
53+
private readonly TextWriter stdout;
54+
private readonly TextWriter stderr;
55+
56+
/// <summary>
57+
/// Initializes a new instance of <see cref="CloudCommand"/>.
58+
/// </summary>
59+
/// <param name="outputWriter">The <see cref="TextWriter"/> to write output to (e.g. <see cref="Console.Out" />).</param>
60+
/// <param name="errorWriter">The <see cref="TextWriter"/> to write error messages to (e.g. <see cref="Console.Error" />).</param>
61+
public CloudCommand(TextWriter outputWriter = null, TextWriter errorWriter = null)
62+
{
63+
this.stdout = outputWriter ?? TextWriter.Null;
64+
this.stderr = errorWriter ?? TextWriter.Null;
65+
}
66+
67+
68+
/// <summary>
69+
/// Adds version variables to the the current cloud build environment.
70+
/// </summary>
71+
/// <exception cref="CloudCommandException">Thrown when the build environment could not be updated.</exception>
72+
/// <param name="projectDirectory">
73+
/// The path to the directory which may (or its ancestors may) define the version file.
74+
/// </param>
75+
/// <param name="metadata">
76+
/// Optionally adds an identifier to the build metadata part of a semantic version.
77+
/// </param>
78+
/// <param name="version">
79+
/// The string to use for the cloud build number. If not specified, the computed version will be used.
80+
/// </param>
81+
/// <param name="ciSystem">
82+
/// The CI system to activate. If not specified, auto-detection will be used.
83+
/// </param>
84+
/// <param name="allVars">
85+
/// Controls whether to define all version variables as cloud build variables.
86+
/// </param>
87+
/// <param name="commonVars">
88+
/// Controls whether to define common version variables as cloud build variables.
89+
/// </param>
90+
/// <param name="additionalVariables">
91+
/// Additional cloud build variables to define.
92+
/// </param>
93+
/// <param name="alwaysUseLibGit2">
94+
/// Force usage of LibGit2 for accessing the git repository.
95+
/// </param>
96+
public void SetBuildVariables(string projectDirectory, IEnumerable<string> metadata, string version, string ciSystem, bool allVars, bool commonVars, IEnumerable<KeyValuePair<string, string>> additionalVariables, bool alwaysUseLibGit2)
97+
{
98+
Requires.NotNull(projectDirectory, nameof(projectDirectory));
99+
Requires.NotNull(additionalVariables, nameof(additionalVariables));
100+
101+
ICloudBuild activeCloudBuild = CloudBuild.Active;
102+
if (!string.IsNullOrEmpty(ciSystem))
103+
{
104+
int matchingIndex = Array.FindIndex(CloudProviderNames, m => string.Equals(m, ciSystem, StringComparison.OrdinalIgnoreCase));
105+
if (matchingIndex == -1)
106+
{
107+
throw new CloudCommandException(
108+
$"No cloud provider found by the name: \"{ciSystem}\"",
109+
CloudCommandError.NoCloudBuildProviderMatch);
110+
}
111+
112+
activeCloudBuild = CloudBuild.SupportedCloudBuilds[matchingIndex];
113+
}
114+
115+
using var context = GitContext.Create(projectDirectory, writable: alwaysUseLibGit2);
116+
var oracle = new VersionOracle(context, cloudBuild: activeCloudBuild);
117+
if (metadata is not null)
118+
{
119+
oracle.BuildMetadata.AddRange(metadata);
120+
}
121+
122+
var variables = new Dictionary<string, string>();
123+
if (allVars)
124+
{
125+
foreach (var pair in oracle.CloudBuildAllVars)
126+
{
127+
variables.Add(pair.Key, pair.Value);
128+
}
129+
}
130+
131+
if (commonVars)
132+
{
133+
foreach (var pair in oracle.CloudBuildVersionVars)
134+
{
135+
variables.Add(pair.Key, pair.Value);
136+
}
137+
}
138+
139+
foreach (var kvp in additionalVariables)
140+
{
141+
if (variables.ContainsKey(kvp.Key))
142+
{
143+
throw new CloudCommandException(
144+
$"Cloud build variable \"{kvp.Key}\" specified more than once.",
145+
CloudCommandError.DuplicateCloudVariable);
146+
}
147+
148+
variables[kvp.Key] = kvp.Value;
149+
}
150+
151+
if (activeCloudBuild is not null)
152+
{
153+
if (string.IsNullOrEmpty(version))
154+
{
155+
version = oracle.CloudBuildNumber;
156+
}
157+
158+
activeCloudBuild.SetCloudBuildNumber(version, this.stdout, this.stderr);
159+
160+
foreach (var pair in variables)
161+
{
162+
activeCloudBuild.SetCloudBuildVariable(pair.Key, pair.Value, this.stdout, this.stderr);
163+
}
164+
}
165+
else
166+
{
167+
throw new CloudCommandException(
168+
"No cloud build detected.",
169+
CloudCommandError.NoCloudBuildEnvDetected);
170+
}
171+
}
172+
173+
174+
private static string[] CloudProviderNames => CloudBuild.SupportedCloudBuilds.Select(cb => cb.GetType().Name).ToArray();
175+
}
176+
}

src/nbgv/Program.cs

Lines changed: 23 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -583,43 +583,7 @@ private static int OnCloudCommand(string project, IReadOnlyList<string> metadata
583583
return (int)ExitCodes.NoGitRepo;
584584
}
585585

586-
ICloudBuild activeCloudBuild = CloudBuild.Active;
587-
if (!string.IsNullOrEmpty(ciSystem))
588-
{
589-
int matchingIndex = Array.FindIndex(CloudProviderNames, m => string.Equals(m, ciSystem, StringComparison.OrdinalIgnoreCase));
590-
if (matchingIndex == -1)
591-
{
592-
Console.Error.WriteLine("No cloud provider found by the name: \"{0}\"", ciSystem);
593-
return (int)ExitCodes.NoCloudBuildProviderMatch;
594-
}
595-
596-
activeCloudBuild = CloudBuild.SupportedCloudBuilds[matchingIndex];
597-
}
598-
599-
using var context = GitContext.Create(searchPath, writable: AlwaysUseLibGit2);
600-
var oracle = new VersionOracle(context, cloudBuild: activeCloudBuild);
601-
if (metadata is not null)
602-
{
603-
oracle.BuildMetadata.AddRange(metadata);
604-
}
605-
606-
var variables = new Dictionary<string, string>();
607-
if (allVars)
608-
{
609-
foreach (var pair in oracle.CloudBuildAllVars)
610-
{
611-
variables.Add(pair.Key, pair.Value);
612-
}
613-
}
614-
615-
if (commonVars)
616-
{
617-
foreach (var pair in oracle.CloudBuildVersionVars)
618-
{
619-
variables.Add(pair.Key, pair.Value);
620-
}
621-
}
622-
586+
var additionalVariables = new Dictionary<string, string>();
623587
if (define is not null)
624588
{
625589
foreach (string def in define)
@@ -631,37 +595,41 @@ private static int OnCloudCommand(string project, IReadOnlyList<string> metadata
631595
return (int)ExitCodes.BadCloudVariable;
632596
}
633597

634-
if (variables.ContainsKey(split[0]))
598+
if (additionalVariables.ContainsKey(split[0]))
635599
{
636600
Console.Error.WriteLine($"Cloud build variable \"{split[0]}\" specified more than once.");
637601
return (int)ExitCodes.DuplicateCloudVariable;
638602
}
639603

640-
variables[split[0]] = split[1];
604+
additionalVariables[split[0]] = split[1];
641605
}
642606
}
643607

644-
if (activeCloudBuild is not null)
608+
try
609+
{
610+
var cloudCommand = new CloudCommand(Console.Out, Console.Error);
611+
cloudCommand.SetBuildVariables(searchPath, metadata, version, ciSystem, allVars, commonVars, additionalVariables, AlwaysUseLibGit2);
612+
}
613+
catch (CloudCommand.CloudCommandException ex)
645614
{
646-
if (string.IsNullOrEmpty(version))
615+
Console.Error.WriteLine(ex.Message);
616+
// map error codes
617+
switch (ex.Error)
647618
{
648-
version = oracle.CloudBuildNumber;
619+
case CloudCommand.CloudCommandError.NoCloudBuildProviderMatch:
620+
return (int)ExitCodes.NoCloudBuildProviderMatch;
621+
case CloudCommand.CloudCommandError.DuplicateCloudVariable:
622+
return (int)ExitCodes.DuplicateCloudVariable;
623+
case CloudCommand.CloudCommandError.NoCloudBuildEnvDetected:
624+
return (int)ExitCodes.NoCloudBuildEnvDetected;
625+
default:
626+
Report.Fail($"{nameof(CloudCommand.CloudCommandError)}: {ex.Error}");
627+
return -1;
649628
}
629+
}
650630

651-
activeCloudBuild.SetCloudBuildNumber(version, Console.Out, Console.Error);
652-
653-
foreach (var pair in variables)
654-
{
655-
activeCloudBuild.SetCloudBuildVariable(pair.Key, pair.Value, Console.Out, Console.Error);
656-
}
631+
return (int)ExitCodes.OK;
657632

658-
return (int)ExitCodes.OK;
659-
}
660-
else
661-
{
662-
Console.Error.WriteLine("No cloud build detected.");
663-
return (int)ExitCodes.NoCloudBuildEnvDetected;
664-
}
665633
}
666634

667635
private static int OnPrepareReleaseCommand(string project, string nextVersion, string versionIncrement, string format, string tag)

0 commit comments

Comments
 (0)