Skip to content

real structures around package input formats for dotnet new commands #48892

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

baronfel
Copy link
Member

@baronfel baronfel commented May 9, 2025

This is a refactoring for the template engine around the allowed inputs for the package-to-install argument. It also changes some user-facing strings to unify on the package@version syntax where appropriate.

@Copilot Copilot AI review requested due to automatic review settings May 9, 2025 17:41
@baronfel baronfel requested a review from a team as a code owner May 9, 2025 17:41
Comment on lines +9 to +18
internal interface ITemplateIdentifierArgument;

#pragma warning disable CS9113 // Parameter is unread.
internal record FileBasedTemplateIdentifier(FileInfo File) : ITemplateIdentifierArgument;
#pragma warning restore CS9113 // Parameter is unread.

#pragma warning disable CS9113 // Parameter is unread.
internal record PackageIdentifier(PackageIdentity Package) : ITemplateIdentifierArgument;
#pragma warning restore CS9113 // Parameter is unread.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the core logical change - introducing structures to represent the allowed variants of input for package identifiers.
With these defined, we have to then change parsing to create these structures, and change execution to handle the structures potentially-differently.

Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR refactors the template engine’s handling of package install inputs to use a unified package@version syntax while updating related user‐facing messages and argument names.

  • Updated argument name from NameArgument to PackageIdentifierArgument throughout the codebase.
  • Modified string formatting and command examples to replace "::" with "@" for specifying package versions.
  • Introduced new parsing logic for template package identifiers, supporting both file paths and package identities.

Reviewed Changes

Copilot reviewed 22 out of 22 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/Cli/Microsoft.TemplateEngine.Cli/TemplateSearch/CliTemplateSearchCoordinator.cs Updated command example argument from NameArgument to PackageIdentifierArgument.
src/Cli/Microsoft.TemplateEngine.Cli/TemplatePackageDisplay.cs Changed the string format for package identifiers in display methods.
src/Cli/Microsoft.TemplateEngine.Cli/TemplatePackageCoordinator.cs Removed deprecated methods and updated package identifier formatting.
src/Cli/Microsoft.TemplateEngine.Cli/TemplateInvoker.cs Updated example usage to reflect the new PackageIdentifierArgument.
Several xlf files Updated instruction texts in localized resource files from "::" to "@" with target state changed to needs-review-translation.
src/Cli/Microsoft.TemplateEngine.Cli/Commands/install/InstallCommandArgs.cs Modified command argument extraction to use PackageIdentifierArgument and adjusted filtering for LegacyInstallCommand.
src/Cli/Microsoft.TemplateEngine.Cli/Commands/install/BaseInstallCommand.cs Replaced NameArgument with PackageIdentifierArgument and added custom parsing logic for template identifiers.
src/Cli/Microsoft.TemplateEngine.Cli/Commands/SymbolStrings.resx Updated install command string to use the new package version separator.

};

private static ITemplateIdentifierArgument[]? ParseTemplateIdentifierArguments(ArgumentResult result)
Copy link
Preview

Copilot AI May 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider refactoring the inline creation of EngineEnvironmentSettings (line 48–53) by injecting it as a dependency to improve testability and ensure consistency across invocations.

Copilot uses AI. Check for mistakes.


//workaround for --install source1 --install source2 case
if (installCommand is LegacyInstallCommand && (TemplatePackages.Contains(installCommand.Name) || installCommand.Aliases.Any(alias => TemplatePackages.Contains(alias))))
if (installCommand is LegacyInstallCommand)
Copy link
Preview

Copilot AI May 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Review the filtering logic for LegacyInstallCommand to ensure that valid file-based identifiers are not unintentionally filtered out, as the current check only applies to PackageIdentifier types.

Copilot uses AI. Check for mistakes.

Comment on lines +42 to +63
if (File.Exists(value))
{
templateIdentifierArguments.Add(new FileBasedTemplateIdentifier(new FileInfo(value)));
}
else if (Directory.Exists(value) || Directory.Exists(Path.GetDirectoryName(value)))
{
var environmentSettings = new EngineEnvironmentSettings(new Edge.DefaultTemplateEngineHost("dotnet", "1.0.0"), false, null, null, null, null);
// expand the value pattern to allow for globbing, etc:
foreach (var path in InstallRequestPathResolution.ExpandMaskedPath(value, environmentSettings))
{
templateIdentifierArguments.Add(new FileBasedTemplateIdentifier(new FileInfo(path)));
}
}
else if (value.Contains("::") && ParsePackageIdentityWithVersionSeparator(value, "::") is PackageIdentity packageIdentity)
{
Console.WriteLine(string.Format(LocalizableStrings.Colon_Separator_Deprecated, packageIdentity.Id, packageIdentity.Version is not null ? packageIdentity.Version : string.Empty));
templateIdentifierArguments.Add(new PackageIdentifier(packageIdentity));
}
else if (ParsePackageIdentityWithVersionSeparator(value, "@") is PackageIdentity packageIdentityWithAt)
{
templateIdentifierArguments.Add(new PackageIdentifier(packageIdentityWithAt));
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is us pivoting across the different variants - priority is important here to make sure we go 'most selective' to 'least selective'.

one interesting thing to call out is that we're 'expanding' the directory and wildcard scenarios to a list of packages to install directly here - this is a parsing-time operation and gives faster, actionable errors to the user


if (templateIdentifierArguments.Count == 0) // we have an arity of One or More, so code is expecting that we error before we call the command...
{
result.AddError("No packages were found for installation. Please provide a valid package identity or path to a template package.");
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs translation


if (string.IsNullOrEmpty(packageId))
{
throw new ArgumentException("package identity cannot be null or empty", nameof(packageId));
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs translation


if (!NuGetVersion.TryParse(versionString, out var version))
{
throw new ArgumentException($"Version {versionString} is not a valid Semantic Version");
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs translation

@@ -137,44 +136,6 @@ internal TemplatePackageCoordinator(
return default;
}

internal void DisplayUpdateCheckResult(CheckUpdateResult versionCheckResult, ICommandArgs args)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deleted because it was unused

Comment on lines +172 to 183
if (packageIdentifier is PackageIdentifier id)
{
Reporter.Output.WriteLine(string.Format(LocalizableStrings.Colon_Separator_Deprecated, split[0], split.Length > 1 ? split[1] : string.Empty).Yellow());
installRequests.Add(new InstallRequest(id.Package.Id, version: id.Package.Version?.ToString(), details: details, force: args.Force));
}

foreach (string expandedIdentifier in InstallRequestPathResolution.ExpandMaskedPath(identifier, _engineEnvironmentSettings))
else if (packageIdentifier is FileBasedTemplateIdentifier fileIdentifier)
{
installRequests.Add(new InstallRequest(fileIdentifier.File.FullName, version: null, details: details, force: args.Force));
}
else
{
installRequests.Add(new InstallRequest(expandedIdentifier, version, details: details, force: args.Force));
throw new ArgumentException($"Unknown template package identifier type: {packageIdentifier.GetType().Name}");
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here's the pivot on the different variants - note that since the C# compiler doesn't do exhaustivity-checks we need a catch-all clause. this clause can be unlocalized because we should only hit it during development time (we shouldn't introduce variants without expanding this)

@@ -314,7 +274,7 @@ internal async Task<NewCommandStatus> EnterUpdateFlowAsync(UpdateCommandArgs com
Reporter.Output.WriteLine(LocalizableStrings.TemplatePackageCoordinator_Update_Info_PackagesToBeUpdated);
foreach (CheckUpdateResult update in updatesToApply)
{
Reporter.Output.WriteLine($"{update.TemplatePackage!.Identifier}::{update.LatestVersion}".Indent());
Reporter.Output.WriteLine($"{update.TemplatePackage!.Identifier}@{update.LatestVersion}".Indent());
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lots of small updates to use the newer @-based syntax

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant