Skip to content

Commit bc746f7

Browse files
paulomorgadodevlead
authored andcommitted
Implement dotnet tool command aliases
Add typed aliases and settings for dotnet tool subcommands, including install, list, restore, run, search, uninstall, update, and execute. Model command-specific options with dedicated settings classes, keep forwarded tool arguments as explicit ProcessArgumentBuilder parameters for execute/run, and add docs links for each alias. Add unit coverage for command rendering, overloads, settings, forwarded arguments, validation, working directory behavior, and failure handling.
1 parent 0caade2 commit bc746f7

14 files changed

Lines changed: 2514 additions & 293 deletions

build.cake

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -379,13 +379,14 @@ Task("Frosting-Integration-Tests")
379379
},
380380
(parameters, test, context) =>
381381
{
382+
string defaultVerbosity = EnvironmentVariable("RUNNER_DEBUG", "0") == "1" ? "diagnostic" : "quiet";
382383
try
383384
{
384385
Information("Testing: {0}", test.Framework);
385386

386387
DotNetRun(test.Project.FullPath,
387388
new ProcessArgumentBuilder()
388-
.AppendSwitchQuoted("--verbosity", "=", Argument("integration-tests-verbosity", "quiet"))
389+
.AppendSwitchQuoted("--verbosity", "=", Argument("integration-tests-verbosity", defaultVerbosity))
389390
.AppendSwitchQuoted("--name", "=", "World")
390391
.AppendSwitchQuoted("--IntegrationTest_Argument", "=", bool.TrueString),
391392
new DotNetRunSettings
@@ -414,16 +415,21 @@ Task("Run-Integration-Tests")
414415
.IsDependentOn("Prepare-Integration-Tests")
415416
.IsDependentOn("Frosting-Integration-Tests")
416417
.DeferOnError()
417-
.DoesForEach<BuildParameters, FilePath>(
418-
parameters => new[] {
419-
GetFiles($"{parameters.Paths.Directories.IntegrationTestsBinTool.FullPath}/**/net8.0/**/Cake.dll").Single(),
420-
GetFiles($"{parameters.Paths.Directories.IntegrationTestsBinTool.FullPath}/**/net9.0/**/Cake.dll").Single(),
421-
GetFiles($"{parameters.Paths.Directories.IntegrationTestsBinTool.FullPath}/**/net10.0/**/Cake.dll").Single()
418+
.DoesForEach<BuildParameters, (FilePath CakeAssembly, string Verbosity)>(
419+
parameters => {
420+
string defaultVerbosity = EnvironmentVariable("RUNNER_DEBUG", "0") == "1" ? "diagnostic" : "quiet";
421+
return [
422+
(GetFiles($"{parameters.Paths.Directories.IntegrationTestsBinTool.FullPath}/**/net8.0/**/Cake.dll").Single(), defaultVerbosity),
423+
(GetFiles($"{parameters.Paths.Directories.IntegrationTestsBinTool.FullPath}/**/net9.0/**/Cake.dll").Single(), defaultVerbosity),
424+
(GetFiles($"{parameters.Paths.Directories.IntegrationTestsBinTool.FullPath}/**/net10.0/**/Cake.dll").Single(), defaultVerbosity)
425+
];
422426
},
423-
(parameters, cakeAssembly, context) =>
427+
(parameters, test, context) =>
424428
{
429+
var (cakeAssembly, verbosity) = test;
425430
try
426431
{
432+
427433
Information("Testing: {0}", cakeAssembly);
428434
CakeExecuteScript("./tests/integration/build.cake",
429435
new CakeSettings {
@@ -434,7 +440,7 @@ Task("Run-Integration-Tests")
434440
},
435441
ArgumentCustomization = args => args
436442
.AppendSwitchQuoted("--target", " ", Argument("integration-tests-target", "Run-All-Tests"))
437-
.AppendSwitchQuoted("--verbosity", " ", Argument("integration-tests-verbosity", "quiet"))
443+
.AppendSwitchQuoted("--verbosity", " ", Argument("integration-tests-verbosity", verbosity))
438444
.AppendSwitchQuoted("--platform", " ", parameters.IsRunningOnWindows ? "windows" : "posix")
439445
.AppendSwitchQuoted("--customarg", " ", "hello")
440446
.AppendSwitchQuoted("--multipleargs", "=", "a")

build/paths.cake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public record BuildPaths(
4040
integrationTestsBinTool);
4141

4242
FilePath signClientPath = null;
43-
if (context.IsRunningOnWindows())
43+
if (context.IsRunningOnWindows() && context.GitHubActions().IsRunningOnGitHubActions)
4444
{
4545
signClientPath = context.Tools.Resolve("sign.exe");
4646

src/Cake.Common.Tests/Unit/Tools/DotNet/Tool/DotNetToolCommandTests.cs

Lines changed: 677 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 308 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,308 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using System.Collections.Generic;
7+
using Cake.Common.Tools.DotNet.Tool;
8+
using Cake.Core;
9+
using Cake.Core.Configuration;
10+
using Cake.Core.IO;
11+
12+
namespace Cake.Common.Tools.DotNet
13+
{
14+
/// <summary>
15+
/// <para>Contains functionality related to <see href="https://github.com/dotnet/cli">.NET CLI</see>.</para>
16+
/// <para>
17+
/// In order to use the commands for this alias, the .NET CLI tools will need to be installed on the machine where
18+
/// the Cake script is being executed. See this <see href="https://www.microsoft.com/net/core">page</see> for information
19+
/// on how to install.
20+
/// </para>
21+
/// </summary>
22+
public static partial class DotNetAliases
23+
{
24+
private static void RunDotNetToolCommand(
25+
ICakeContext context,
26+
FilePath projectPath,
27+
ProcessArgumentBuilder arguments,
28+
DotNetToolSettings settings)
29+
{
30+
ArgumentNullException.ThrowIfNull(context);
31+
ArgumentNullException.ThrowIfNull(arguments);
32+
ArgumentNullException.ThrowIfNull(settings);
33+
34+
context.DotNetTool(projectPath, "tool", arguments, settings);
35+
}
36+
37+
private static void RunDotNetToolCommandWithoutVerbosity(
38+
ICakeContext context,
39+
FilePath projectPath,
40+
ProcessArgumentBuilder arguments,
41+
DotNetToolSettings settings)
42+
{
43+
ArgumentNullException.ThrowIfNull(context);
44+
ArgumentNullException.ThrowIfNull(arguments);
45+
ArgumentNullException.ThrowIfNull(settings);
46+
47+
var verbosity = settings.Verbosity;
48+
settings.Verbosity = null;
49+
50+
try
51+
{
52+
context.DotNetTool(projectPath, "tool", arguments, settings);
53+
}
54+
finally
55+
{
56+
settings.Verbosity = verbosity;
57+
}
58+
}
59+
60+
private static void RunDotNetToolCommandWithForwardedArguments(
61+
ICakeContext context,
62+
FilePath projectPath,
63+
ProcessArgumentBuilder arguments,
64+
ProcessArgumentBuilder forwardedArguments,
65+
DotNetToolSettings settings)
66+
{
67+
ArgumentNullException.ThrowIfNull(context);
68+
ArgumentNullException.ThrowIfNull(arguments);
69+
ArgumentNullException.ThrowIfNull(settings);
70+
71+
if (forwardedArguments.IsNullOrEmpty())
72+
{
73+
context.DotNetTool(projectPath, "tool", arguments, settings);
74+
return;
75+
}
76+
77+
var argumentCustomization = settings.ArgumentCustomization;
78+
settings.ArgumentCustomization = dotnetArguments =>
79+
{
80+
var customizedArguments = argumentCustomization?.Invoke(dotnetArguments) ?? dotnetArguments;
81+
customizedArguments.Append("--");
82+
forwardedArguments.CopyTo(customizedArguments);
83+
return customizedArguments;
84+
};
85+
86+
try
87+
{
88+
context.DotNetTool(projectPath, "tool", arguments, settings);
89+
}
90+
finally
91+
{
92+
settings.ArgumentCustomization = argumentCustomization;
93+
}
94+
}
95+
96+
private static void RunDotNetToolCommandWithForwardedArgumentsWithoutVerbosity(
97+
ICakeContext context,
98+
FilePath projectPath,
99+
ProcessArgumentBuilder arguments,
100+
ProcessArgumentBuilder forwardedArguments,
101+
DotNetToolSettings settings)
102+
{
103+
ArgumentNullException.ThrowIfNull(context);
104+
ArgumentNullException.ThrowIfNull(arguments);
105+
ArgumentNullException.ThrowIfNull(settings);
106+
107+
var verbosity = settings.Verbosity;
108+
settings.Verbosity = null;
109+
110+
try
111+
{
112+
RunDotNetToolCommandWithForwardedArguments(context, projectPath, arguments, forwardedArguments, settings);
113+
}
114+
finally
115+
{
116+
settings.Verbosity = verbosity;
117+
}
118+
}
119+
120+
private static void AppendToolExecuteSettings(ProcessArgumentBuilder builder, DotNetToolExecuteSettings settings, ICakeEnvironment environment)
121+
{
122+
AppendPackageResolutionSettings(builder, settings.Version, settings.ConfigFile, settings.Source, settings.AddSource, settings.Prerelease, environment);
123+
AppendSwitch(builder, "--allow-roll-forward", settings.AllowRollForward);
124+
AppendRestoreSettings(builder, settings.DisableParallel, settings.IgnoreFailedSources, settings.NoHttpCache, settings.Interactive);
125+
}
126+
127+
private static void AppendToolInstallSettings(ProcessArgumentBuilder builder, DotNetToolInstallSettings settings, ICakeConfiguration configuration, ICakeEnvironment environment)
128+
{
129+
AppendInstallationScope(builder, settings.InstallationScope, settings.ToolInstallationPath, settings.WorkingDirectory, configuration, environment);
130+
AppendPackageResolutionSettings(builder, settings.Version, settings.ConfigFile, settings.Source, settings.AddSource, settings.Prerelease, environment);
131+
AppendFilePath(builder, "--tool-manifest", settings.ToolManifest, environment);
132+
AppendString(builder, "--framework", settings.Framework);
133+
AppendRestoreSettings(builder, settings.DisableParallel, settings.IgnoreFailedSources, settings.NoHttpCache, settings.Interactive);
134+
AppendSwitch(builder, "--allow-downgrade", settings.AllowDowngrade);
135+
AppendString(builder, "--arch", settings.Architecture);
136+
AppendSwitch(builder, "--create-manifest-if-needed", settings.CreateManifestIfNeeded);
137+
AppendSwitch(builder, "--allow-roll-forward", settings.AllowRollForward);
138+
}
139+
140+
private static void AppendToolListSettings(ProcessArgumentBuilder builder, DotNetToolListSettings settings, ICakeConfiguration configuration, ICakeEnvironment environment)
141+
{
142+
AppendInstallationScope(builder, settings.InstallationScope, settings.ToolInstallationPath, settings.WorkingDirectory, configuration, environment);
143+
144+
if (settings.Format.HasValue)
145+
{
146+
builder.AppendSwitch("--format", settings.Format.Value == DotNetToolListFormat.Json ? "json" : "table");
147+
}
148+
}
149+
150+
private static void AppendToolRestoreSettings(ProcessArgumentBuilder builder, DotNetToolRestoreSettings settings, ICakeEnvironment environment)
151+
{
152+
AppendFilePath(builder, "--configfile", settings.ConfigFile, environment);
153+
AppendSources(builder, "--add-source", settings.AddSource);
154+
AppendFilePath(builder, "--tool-manifest", settings.ToolManifest, environment);
155+
AppendRestoreSettings(builder, settings.DisableParallel, settings.IgnoreFailedSources, settings.NoHttpCache, settings.Interactive);
156+
}
157+
158+
private static void AppendToolRunSettings(ProcessArgumentBuilder builder, DotNetToolRunSettings settings)
159+
{
160+
AppendSwitch(builder, "--allow-roll-forward", settings.AllowRollForward);
161+
}
162+
163+
private static void AppendToolSearchSettings(ProcessArgumentBuilder builder, DotNetToolSearchSettings settings)
164+
{
165+
AppendSwitch(builder, "--detail", settings.Detail);
166+
167+
if (settings.Skip.HasValue)
168+
{
169+
builder.AppendSwitch("--skip", settings.Skip.Value.ToString());
170+
}
171+
172+
if (settings.Take.HasValue)
173+
{
174+
builder.AppendSwitch("--take", settings.Take.Value.ToString());
175+
}
176+
177+
AppendSwitch(builder, "--prerelease", settings.Prerelease);
178+
}
179+
180+
private static void AppendToolUninstallSettings(ProcessArgumentBuilder builder, DotNetToolUninstallSettings settings, ICakeConfiguration configuration, ICakeEnvironment environment)
181+
{
182+
AppendInstallationScope(builder, settings.InstallationScope, settings.ToolInstallationPath, settings.WorkingDirectory, configuration, environment);
183+
AppendFilePath(builder, "--tool-manifest", settings.ToolManifest, environment);
184+
}
185+
186+
private static void AppendToolUpdateSettings(ProcessArgumentBuilder builder, DotNetToolUpdateSettings settings, ICakeConfiguration configuration, ICakeEnvironment environment)
187+
{
188+
AppendInstallationScope(builder, settings.InstallationScope, settings.ToolInstallationPath, settings.WorkingDirectory, configuration, environment);
189+
AppendPackageResolutionSettings(builder, settings.Version, settings.ConfigFile, settings.Source, settings.AddSource, settings.Prerelease, environment);
190+
AppendFilePath(builder, "--tool-manifest", settings.ToolManifest, environment);
191+
AppendString(builder, "--framework", settings.Framework);
192+
AppendRestoreSettings(builder, settings.DisableParallel, settings.IgnoreFailedSources, settings.NoHttpCache, settings.Interactive);
193+
AppendSwitch(builder, "--allow-downgrade", settings.AllowDowngrade);
194+
AppendSwitch(builder, "--all", settings.All);
195+
}
196+
197+
private static void AppendInstallationScope(
198+
ProcessArgumentBuilder builder,
199+
DotNetToolInstallationScope scope,
200+
DirectoryPath toolInstallationPath,
201+
DirectoryPath settingsWorkingDirectory,
202+
ICakeConfiguration configuration,
203+
ICakeEnvironment environment)
204+
{
205+
switch (scope)
206+
{
207+
case DotNetToolInstallationScope.Global:
208+
builder.Append("--global");
209+
break;
210+
case DotNetToolInstallationScope.Local:
211+
builder.Append("--local");
212+
break;
213+
case DotNetToolInstallationScope.ToolPath:
214+
var root = settingsWorkingDirectory ?? environment.WorkingDirectory;
215+
var path = toolInstallationPath ?? configuration.GetToolPath(root, environment);
216+
AppendDirectoryPath(builder, "--tool-path", path, environment);
217+
break;
218+
}
219+
}
220+
221+
private static void AppendPackageResolutionSettings(
222+
ProcessArgumentBuilder builder,
223+
string version,
224+
FilePath configFile,
225+
ICollection<string> source,
226+
ICollection<string> addSource,
227+
bool prerelease,
228+
ICakeEnvironment environment)
229+
{
230+
AppendString(builder, "--version", version);
231+
AppendFilePath(builder, "--configfile", configFile, environment);
232+
AppendSources(builder, "--source", source);
233+
AppendSources(builder, "--add-source", addSource);
234+
AppendSwitch(builder, "--prerelease", prerelease);
235+
}
236+
237+
private static void AppendRestoreSettings(ProcessArgumentBuilder builder, bool disableParallel, bool ignoreFailedSources, bool noHttpCache, bool interactive)
238+
{
239+
AppendSwitch(builder, "--disable-parallel", disableParallel);
240+
AppendSwitch(builder, "--ignore-failed-sources", ignoreFailedSources);
241+
AppendSwitch(builder, "--no-http-cache", noHttpCache);
242+
AppendSwitch(builder, "--interactive", interactive);
243+
}
244+
245+
private static void AppendRequiredArgument(ProcessArgumentBuilder builder, string argument, string parameterName)
246+
{
247+
if (string.IsNullOrWhiteSpace(argument))
248+
{
249+
throw new ArgumentNullException(parameterName);
250+
}
251+
252+
builder.Append(argument);
253+
}
254+
255+
private static void AppendOptionalArgument(ProcessArgumentBuilder builder, string argument)
256+
{
257+
if (!string.IsNullOrWhiteSpace(argument))
258+
{
259+
builder.Append(argument);
260+
}
261+
}
262+
263+
private static void AppendSwitch(ProcessArgumentBuilder builder, string switchName, bool value)
264+
{
265+
if (value)
266+
{
267+
builder.Append(switchName);
268+
}
269+
}
270+
271+
private static void AppendString(ProcessArgumentBuilder builder, string switchName, string value)
272+
{
273+
if (!string.IsNullOrWhiteSpace(value))
274+
{
275+
builder.AppendSwitchQuoted(switchName, value);
276+
}
277+
}
278+
279+
private static void AppendFilePath(ProcessArgumentBuilder builder, string switchName, FilePath value, ICakeEnvironment environment)
280+
{
281+
if (value != null)
282+
{
283+
builder.AppendSwitchQuoted(switchName, value.MakeAbsolute(environment).FullPath);
284+
}
285+
}
286+
287+
private static void AppendDirectoryPath(ProcessArgumentBuilder builder, string switchName, DirectoryPath value, ICakeEnvironment environment)
288+
{
289+
if (value != null)
290+
{
291+
builder.AppendSwitchQuoted(switchName, value.MakeAbsolute(environment).FullPath);
292+
}
293+
}
294+
295+
private static void AppendSources(ProcessArgumentBuilder builder, string switchName, ICollection<string> sources)
296+
{
297+
if (sources == null)
298+
{
299+
return;
300+
}
301+
302+
foreach (var source in sources)
303+
{
304+
AppendString(builder, switchName, source);
305+
}
306+
}
307+
}
308+
}

0 commit comments

Comments
 (0)