Skip to content

Commit 6b2d022

Browse files
lbussellCopilot
andcommitted
Upgrade System.CommandLine from 2.0.0-beta1 to 2.0.5
- Eliminate ~43 CliOptionsBuilder classes by merging into Options classes - Simplify Command<TOptions, TOptionsBuilder> to Command<TOptions> - Replace CommandLineBuilder/UseDefaults/UseMiddleware/ModelBinder pipeline with rootCommand.Parse(args).InvokeAsync() - Remove CliHelper factory methods (CreateOption, CreateMultiOption, etc.) - Update validators from ValidateSymbol<CommandResult> to Action<CommandResult> - Keep GitOptionsBuilder, ServiceConnectionOptionsBuilder, RegistryOptionsBuilder as separate helpers (dynamic/parameterized behavior) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 83282b4 commit 6b2d022

81 files changed

Lines changed: 1601 additions & 1070 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/ImageBuilder.Tests/QueueBuildCommandTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -698,7 +698,7 @@ private static bool FilterBuildToParameters(string buildParametersJson, string p
698698
IList<string> paths = pathString
699699
.Split(" ", StringSplitOptions.RemoveEmptyEntries)
700700
.Select(p => p.Trim().Trim('\''))
701-
.Except([ CliHelper.FormatAlias(DockerfileFilterOptionsBuilder.PathOptionName) ])
701+
.Except([ CliHelper.FormatAlias(DockerfileFilterOptions.PathOptionName) ])
702702
.ToList();
703703
return CompareLists(expectedPaths, paths);
704704
}

src/ImageBuilder/Commands/AnnotateEolDigestsCommand.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
namespace Microsoft.DotNet.ImageBuilder.Commands
1818
{
19-
public class AnnotateEolDigestsCommand : Command<AnnotateEolDigestsOptions, AnnotateEolDigestsOptionsBuilder>
19+
public class AnnotateEolDigestsCommand : Command<AnnotateEolDigestsOptions>
2020
{
2121
private readonly ILogger<AnnotateEolDigestsCommand> _logger;
2222
private readonly ILifecycleMetadataService _lifecycleMetadataService;

src/ImageBuilder/Commands/AnnotateEolDigestsOptions.cs

Lines changed: 51 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,41 +4,62 @@
44

55
using System.Collections.Generic;
66
using System.CommandLine;
7+
using System.CommandLine.Parsing;
78

8-
namespace Microsoft.DotNet.ImageBuilder.Commands
9+
namespace Microsoft.DotNet.ImageBuilder.Commands;
10+
11+
public class AnnotateEolDigestsOptions : Options
912
{
10-
public class AnnotateEolDigestsOptions : Options
13+
public RegistryCredentialsOptions CredentialsOptions { get; set; } = new();
14+
15+
public string EolDigestsListPath { get; set; } = string.Empty;
16+
public string AcrName { get; set; } = string.Empty;
17+
public string RepoPrefix { get; set; } = string.Empty;
18+
public string AnnotationDigestsOutputPath { get; set; } = string.Empty;
19+
20+
private static readonly Argument<string> EolDigestsListPathArgument = new(nameof(EolDigestsListPath))
1121
{
12-
public RegistryCredentialsOptions CredentialsOptions { get; set; } = new();
22+
Description = "EOL annotations digests list path"
23+
};
1324

14-
public string EolDigestsListPath { get; set; } = string.Empty;
15-
public string AcrName { get; set; } = string.Empty;
16-
public string RepoPrefix { get; set; } = string.Empty;
17-
public string AnnotationDigestsOutputPath { get; set; } = string.Empty;
18-
}
25+
private static readonly Argument<string> AcrNameArgument = new(nameof(AcrName))
26+
{
27+
Description = "Azure registry name"
28+
};
29+
30+
private static readonly Argument<string> RepoPrefixArgument = new(nameof(RepoPrefix))
31+
{
32+
Description = "Publish prefix of the repo names"
33+
};
34+
35+
private static readonly Argument<string> AnnotationDigestsOutputPathArgument = new(nameof(AnnotationDigestsOutputPath))
36+
{
37+
Description = "Output path of file containing the list of annotation digests that were created"
38+
};
39+
40+
public override IEnumerable<Option> GetCliOptions() =>
41+
[
42+
..base.GetCliOptions(),
43+
..CredentialsOptions.GetCliOptions(),
44+
];
45+
46+
public override IEnumerable<Argument> GetCliArguments() =>
47+
[
48+
..base.GetCliArguments(),
49+
..CredentialsOptions.GetCliArguments(),
50+
EolDigestsListPathArgument,
51+
AcrNameArgument,
52+
RepoPrefixArgument,
53+
AnnotationDigestsOutputPathArgument,
54+
];
1955

20-
public class AnnotateEolDigestsOptionsBuilder : CliOptionsBuilder
56+
public override void Bind(ParseResult result)
2157
{
22-
private readonly RegistryCredentialsOptionsBuilder _registryCredentialsOptionsBuilder = new();
23-
24-
public override IEnumerable<Option> GetCliOptions() =>
25-
[
26-
..base.GetCliOptions(),
27-
.._registryCredentialsOptionsBuilder.GetCliOptions(),
28-
];
29-
30-
public override IEnumerable<Argument> GetCliArguments() =>
31-
[
32-
..base.GetCliArguments(),
33-
.._registryCredentialsOptionsBuilder.GetCliArguments(),
34-
new Argument<string>(nameof(AnnotateEolDigestsOptions.EolDigestsListPath),
35-
"EOL annotations digests list path"),
36-
new Argument<string>(nameof(AnnotateEolDigestsOptions.AcrName),
37-
"Azure registry name"),
38-
new Argument<string>(nameof(AnnotateEolDigestsOptions.RepoPrefix),
39-
"Publish prefix of the repo names"),
40-
new Argument<string>(nameof(AnnotateEolDigestsOptions.AnnotationDigestsOutputPath),
41-
"Output path of file containing the list of annotation digests that were created"),
42-
];
58+
base.Bind(result);
59+
CredentialsOptions.Bind(result);
60+
EolDigestsListPath = result.GetValue(EolDigestsListPathArgument) ?? string.Empty;
61+
AcrName = result.GetValue(AcrNameArgument) ?? string.Empty;
62+
RepoPrefix = result.GetValue(RepoPrefixArgument) ?? string.Empty;
63+
AnnotationDigestsOutputPath = result.GetValue(AnnotationDigestsOutputPathArgument) ?? string.Empty;
4364
}
4465
}

src/ImageBuilder/Commands/AzdoOptions.cs

Lines changed: 55 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,45 +4,72 @@
44
using System;
55
using System.Collections.Generic;
66
using System.CommandLine;
7+
using System.CommandLine.Parsing;
78
using Microsoft.VisualStudio.Services.Common;
8-
using static Microsoft.DotNet.ImageBuilder.Commands.CliHelper;
99

10-
namespace Microsoft.DotNet.ImageBuilder.Commands
10+
namespace Microsoft.DotNet.ImageBuilder.Commands;
11+
12+
public class AzdoOptions
1113
{
12-
public class AzdoOptions
14+
public string AccessToken { get; set; } = string.Empty;
15+
16+
public string Organization { get; set; } = string.Empty;
17+
18+
public string Project { get; set; } = string.Empty;
19+
20+
public string? AzdoRepo { get; set; }
21+
22+
public string? AzdoBranch { get; set; }
23+
24+
public string? AzdoPath { get; set; }
25+
26+
private static readonly Argument<string> AccessTokenArgument = new(nameof(AccessToken))
1327
{
14-
public string AccessToken { get; set; } = string.Empty;
28+
Description = "Azure DevOps PAT"
29+
};
1530

16-
public string Organization { get; set; } = string.Empty;
31+
private static readonly Argument<string> OrganizationArgument = new(nameof(Organization))
32+
{
33+
Description = "Azure DevOps organization"
34+
};
1735

18-
public string Project { get; set; } = string.Empty;
36+
private static readonly Argument<string> ProjectArgument = new(nameof(Project))
37+
{
38+
Description = "Azure DevOps project"
39+
};
1940

20-
public string? AzdoRepo { get; set; }
41+
private static readonly Option<string?> AzdoRepoOption = new(CliHelper.FormatAlias("azdo-repo"))
42+
{
43+
Description = "Azure DevOps repo"
44+
};
2145

22-
public string? AzdoBranch { get; set; }
46+
private static readonly Option<string?> AzdoBranchOption = new(CliHelper.FormatAlias("azdo-branch"))
47+
{
48+
Description = "Azure DevOps branch (default: main)",
49+
DefaultValueFactory = _ => "main"
50+
};
2351

24-
public string? AzdoPath { get; set; }
52+
private static readonly Option<string?> AzdoPathOption = new(CliHelper.FormatAlias("azdo-path"))
53+
{
54+
Description = "Azure DevOps path"
55+
};
2556

26-
public (Uri BaseUrl, VssCredentials Credentials) GetConnectionDetails() =>
27-
(new Uri($"https://dev.azure.com/{Organization}"), new VssBasicCredential(string.Empty, AccessToken));
28-
}
57+
public IEnumerable<Argument> GetCliArguments() =>
58+
[AccessTokenArgument, OrganizationArgument, ProjectArgument];
59+
60+
public IEnumerable<Option> GetCliOptions() =>
61+
[AzdoRepoOption, AzdoBranchOption, AzdoPathOption];
2962

30-
public class AzdoOptionsBuilder
63+
public void Bind(ParseResult result)
3164
{
32-
public IEnumerable<Argument> GetCliArguments() =>
33-
new Argument[]
34-
{
35-
new Argument<string>(nameof(AzdoOptions.AccessToken), "Azure DevOps PAT"),
36-
new Argument<string>(nameof(AzdoOptions.Organization), "Azure DevOps organization"),
37-
new Argument<string>(nameof(AzdoOptions.Project), "Azure DevOps project")
38-
};
39-
40-
public IEnumerable<Option> GetCliOptions() =>
41-
new Option[]
42-
{
43-
CreateOption<string?>("azdo-repo", nameof(AzdoOptions.AzdoRepo), "Azure DevOps repo"),
44-
CreateOption<string?>("azdo-branch", nameof(AzdoOptions.AzdoBranch), "Azure DevOps branch (default: main)", "main"),
45-
CreateOption<string?>("azdo-path", nameof(AzdoOptions.AzdoPath), "Azure DevOps path"),
46-
};
65+
AccessToken = result.GetValue(AccessTokenArgument) ?? string.Empty;
66+
Organization = result.GetValue(OrganizationArgument) ?? string.Empty;
67+
Project = result.GetValue(ProjectArgument) ?? string.Empty;
68+
AzdoRepo = result.GetValue(AzdoRepoOption);
69+
AzdoBranch = result.GetValue(AzdoBranchOption);
70+
AzdoPath = result.GetValue(AzdoPathOption);
4771
}
72+
73+
public (Uri BaseUrl, VssCredentials Credentials) GetConnectionDetails() =>
74+
(new Uri($"https://dev.azure.com/{Organization}"), new VssBasicCredential(string.Empty, AccessToken));
4875
}

src/ImageBuilder/Commands/BaseImageOverrideOptions.cs

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,19 @@
44
using System;
55
using System.Collections.Generic;
66
using System.CommandLine;
7-
using System.Linq;
7+
using System.CommandLine.Parsing;
88
using System.Text.RegularExpressions;
9-
using static Microsoft.DotNet.ImageBuilder.Commands.CliHelper;
109

1110
namespace Microsoft.DotNet.ImageBuilder.Commands;
1211

1312
/// <summary>
1413
/// Defines options that allow the caller to configure whether and how base image tags defined in a Dockerfile
1514
/// are to be overriden.
1615
/// </summary>
16+
/// <remarks>
1717
/// This allows for images to be sourced from a different location than described in the Dockerfile.
1818
/// For example, the Build command implements this by pulling an image from the overriden location, retagging it with the
19-
/// tag used in the Dockerfile, and continue with the rest of the build.<remarks>
19+
/// tag used in the Dockerfile, and continue with the rest of the build.
2020
/// </remarks>
2121
public class BaseImageOverrideOptions
2222
{
@@ -27,6 +27,16 @@ public class BaseImageOverrideOptions
2727

2828
public string? Substitution { get; set; }
2929

30+
private static readonly Option<string?> RegexPatternOption = new(CliHelper.FormatAlias(BaseOverrideRegexName))
31+
{
32+
Description = $"Regular expression identifying base image tags to apply string substitution to (requires {BaseOverrideSubName} to be set)"
33+
};
34+
35+
private static readonly Option<string?> SubstitutionOption = new(CliHelper.FormatAlias(BaseOverrideSubName))
36+
{
37+
Description = $"Regular expression substitution that overrides a matching base image tag (requires {BaseOverrideRegexName} to be set)"
38+
};
39+
3040
public void Validate()
3141
{
3242
if ((RegexPattern is null) != (Substitution is null))
@@ -45,19 +55,15 @@ public string ApplyBaseImageOverride(string imageName)
4555

4656
return imageName;
4757
}
48-
}
4958

50-
public class BaseImageOverrideOptionsBuilder
51-
{
5259
public IEnumerable<Option> GetCliOptions() =>
53-
new Option[]
54-
{
55-
CreateOption<string?>(BaseImageOverrideOptions.BaseOverrideRegexName, nameof(BaseImageOverrideOptions.RegexPattern),
56-
$"Regular expression identifying base image tags to apply string substitution to (requires {BaseImageOverrideOptions.BaseOverrideSubName} to be set)"),
57-
CreateOption<string?>(BaseImageOverrideOptions.BaseOverrideSubName, nameof(BaseImageOverrideOptions.Substitution),
58-
$"Regular expression substitution that overrides a matching base image tag (requires {BaseImageOverrideOptions.BaseOverrideRegexName} to be set)")
59-
};
60+
[RegexPatternOption, SubstitutionOption];
6061

61-
public IEnumerable<Argument> GetCliArguments() => Enumerable.Empty<Argument>();
62-
}
62+
public IEnumerable<Argument> GetCliArguments() => [];
6363

64+
public void Bind(ParseResult result)
65+
{
66+
RegexPattern = result.GetValue(RegexPatternOption);
67+
Substitution = result.GetValue(SubstitutionOption);
68+
}
69+
}

src/ImageBuilder/Commands/BuildCommand.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
namespace Microsoft.DotNet.ImageBuilder.Commands
1717
{
18-
public class BuildCommand : ManifestCommand<BuildOptions, BuildOptionsBuilder>
18+
public class BuildCommand : ManifestCommand<BuildOptions>
1919
{
2020
private readonly IDockerService _dockerService;
2121
private readonly ILogger<BuildCommand> _logger;

0 commit comments

Comments
 (0)