Skip to content

Add git template system spec, feature flag, and command stubs (Phase 1)#16927

Open
mitchdenny wants to merge 1 commit into
mainfrom
mitchdenny/git-template-system
Open

Add git template system spec, feature flag, and command stubs (Phase 1)#16927
mitchdenny wants to merge 1 commit into
mainfrom
mitchdenny/git-template-system

Conversation

@mitchdenny
Copy link
Copy Markdown
Member

Description

This is the first slice of resuming the git-based template work originally spiked in #14763. The goal is to let users (and downstream catalogs) install Aspire project/item templates straight from git repositories, instead of being limited to NuGet template packs.

The architectural change vs. the spike is that template discovery is delegated to a single aspire.dev HTTP endpoint instead of a federated walk of aspire-template-index.json files in user-owned repos. This keeps the CLI thin and lets the catalog evolve server-side.

That means:

  • No per-repo aspire-template-index.json schema (collapsed into a service-response schema in spec §3).
  • No includes federation, cycle detection, depth limits, or gh-based personal/org auto-discovery.
  • No aspire template new-index command (end users do not author indexes; the catalog is owned by the aspire.dev service).
  • Configuration collapses to templates.serviceUrl + templates.cacheTtlMinutes.

This PR is foundation only. There is no real implementation behind the commands yet, the work is gated behind a feature flag that defaults to false, and end users see no behavior change. Subsequent phases (HTTP catalog client, repo cache, list/search/refresh, template new, polyglot engine) ship in their own PRs as outlined in spec §15.

What this PR contains

  • docs/specs/git-templates.md: full architecture spec, revised for the service-delegated discovery model. Section 15 lays out the phased rollout.
  • KnownFeatures.GitTemplatesEnabled feature flag (default false).
  • The aspire template command group with four stub subcommands behind the feature flag:
    • aspire template list
    • aspire template search <keyword>
    • aspire template refresh
    • aspire template new [path]
  • Wiring into RootCommand and DI in Program.cs and CliTestHelper.cs.
  • TemplateCommandStrings.resx + Designer + 13 generated XLFs.
  • Parse and feature-flag-gating tests (15 cases, all passing).

Notes for reviewers

  • All new C# class names use a Git prefix (GitTemplateCommand, etc.) to avoid a type-name collision with the existing Aspire.Cli.Commands.TemplateCommand, which is the per-template wrapper used by NewCommand. The user-facing CLI verb is unchanged: aspire template.
  • Stubs print "not yet implemented" via IInteractionService.DisplayMessage and return Success so they exercise the wiring without pretending to do work.
  • Enable for local smoke testing with:
    aspire config set features.gitTemplatesEnabled true
    aspire template --help
    
  • The spec's §10 Security section is intentionally marked TODO pending input from the security team. The catalog endpoint host (aspire.dev) and exact JSON shape in §3 are placeholders subject to change as the service team finalizes the contract.

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
      • If yes, did you have an API Review for it?
        • Yes
        • No
      • Did you add <remarks /> and <code /> elements on your triple slash comments?
        • Yes
        • No
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
      • If yes, have you done a threat model and had a security review?
        • Yes
        • No
    • No

Copilot AI review requested due to automatic review settings May 11, 2026 00:39
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 11, 2026

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 16927

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 16927"

Copy link
Copy Markdown
Contributor

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 lays the foundation for a git-based Aspire template system by adding a detailed architecture spec plus a feature-flagged aspire template command group (stubs only), with wiring, localization resources, and unit tests to validate parsing and feature-flag gating.

Changes:

  • Added the gitTemplatesEnabled feature flag (default false) and gated registration of the new aspire template command group behind it.
  • Introduced aspire template + list/search/refresh/new stub subcommands (return success with a “not yet implemented” message) and wired them into DI and RootCommand.
  • Added localized command strings resources (RESX + generated designer + XLF set) and unit tests covering command registration and invocation behavior.
Show a summary per file
File Description
tests/Aspire.Cli.Tests/Utils/CliTestHelper.cs Registers git template command stubs in the test DI container.
tests/Aspire.Cli.Tests/Commands/Template/GitTemplateCommandsTests.cs Adds feature-flag gating + parsing/exit-code tests for the new command group and subcommands.
src/Aspire.Cli/Resources/xlf/TemplateCommandStrings.zh-Hant.xlf Adds localization file for new template command strings (zh-Hant).
src/Aspire.Cli/Resources/xlf/TemplateCommandStrings.zh-Hans.xlf Adds localization file for new template command strings (zh-Hans).
src/Aspire.Cli/Resources/xlf/TemplateCommandStrings.tr.xlf Adds localization file for new template command strings (tr).
src/Aspire.Cli/Resources/xlf/TemplateCommandStrings.ru.xlf Adds localization file for new template command strings (ru).
src/Aspire.Cli/Resources/xlf/TemplateCommandStrings.pt-BR.xlf Adds localization file for new template command strings (pt-BR).
src/Aspire.Cli/Resources/xlf/TemplateCommandStrings.pl.xlf Adds localization file for new template command strings (pl).
src/Aspire.Cli/Resources/xlf/TemplateCommandStrings.ko.xlf Adds localization file for new template command strings (ko).
src/Aspire.Cli/Resources/xlf/TemplateCommandStrings.ja.xlf Adds localization file for new template command strings (ja).
src/Aspire.Cli/Resources/xlf/TemplateCommandStrings.it.xlf Adds localization file for new template command strings (it).
src/Aspire.Cli/Resources/xlf/TemplateCommandStrings.fr.xlf Adds localization file for new template command strings (fr).
src/Aspire.Cli/Resources/xlf/TemplateCommandStrings.es.xlf Adds localization file for new template command strings (es).
src/Aspire.Cli/Resources/xlf/TemplateCommandStrings.de.xlf Adds localization file for new template command strings (de).
src/Aspire.Cli/Resources/xlf/TemplateCommandStrings.cs.xlf Adds localization file for new template command strings (cs).
src/Aspire.Cli/Resources/TemplateCommandStrings.resx Adds base (en) resource strings for aspire template commands.
src/Aspire.Cli/Resources/TemplateCommandStrings.Designer.cs Adds generated strongly-typed resource wrapper for template command strings.
src/Aspire.Cli/Program.cs Registers git template command stubs in the CLI DI container.
src/Aspire.Cli/KnownFeatures.cs Adds KnownFeatures.GitTemplatesEnabled with metadata and default false.
src/Aspire.Cli/Commands/Template/GitTemplateSearchCommand.cs Adds stub aspire template search <keyword> command.
src/Aspire.Cli/Commands/Template/GitTemplateRefreshCommand.cs Adds stub aspire template refresh command.
src/Aspire.Cli/Commands/Template/GitTemplateNewCommand.cs Adds stub aspire template new [path] command.
src/Aspire.Cli/Commands/Template/GitTemplateListCommand.cs Adds stub aspire template list command.
src/Aspire.Cli/Commands/Template/GitTemplateCommand.cs Adds parent aspire template command and subcommand wiring.
src/Aspire.Cli/Commands/RootCommand.cs Gates registration of aspire template on gitTemplatesEnabled.
src/Aspire.Cli/Aspire.Cli.csproj Adds RESX + Designer integration for the new TemplateCommandStrings resources.
docs/specs/git-templates.md Adds the git template system architecture spec and phased implementation plan.

Copilot's findings

Files not reviewed (1)
  • src/Aspire.Cli/Resources/TemplateCommandStrings.Designer.cs: Language not supported
  • Files reviewed: 26/27 changed files
  • Comments generated: 0

This is the first slice of resuming the git-based template work originally
spiked in #14763. The architectural change vs. the spike is that template
discovery is delegated to a single `aspire.dev` HTTP endpoint instead of a
federated walk of `aspire-template-index.json` files in user-owned repos.
That means:

- No per-repo `aspire-template-index.json` schema (collapsed in §3 of the
  spec into a service-response schema).
- No `includes` federation, cycle detection, depth limits, or `gh`-based
  personal/org auto-discovery.
- No `aspire template new-index` command (end users don't author indexes;
  the catalog is owned by the aspire.dev service).
- Configuration collapses to `templates.serviceUrl` +
  `templates.cacheTtlMinutes`.

What this PR contains (foundation only — no real implementation yet):

- `docs/specs/git-templates.md` — full architecture spec, revised for the
  service-delegated discovery model.
- `KnownFeatures.GitTemplatesEnabled` feature flag (default `false`).
- The `aspire template` command group with four stub subcommands behind
  the feature flag:
  - `aspire template list`  - `aspire template search <keyword>`
  - `aspire template refresh`  - `aspire template new [path]`
- Wiring into `RootCommand` and DI in `Program.cs` /`CliTestHelper.cs`.
- `TemplateCommandStrings.resx` + Designer + 13 generated XLFs.
- Parse + feature-flag-gating tests.

All new C# class names use a `Git` prefix (`GitTemplateCommand`, etc.) to
avoid type-name collision with the existing `Aspire.Cli.Commands.TemplateCommand`,
which is the per-template wrapper used by `NewCommand`. The user-facing CLI
verb is unchanged: `aspire template`.

Enable for local testing with`:`

    aspire config set features.gitTemplatesEnabled true

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@mitchdenny mitchdenny force-pushed the mitchdenny/git-template-system branch from 6863a7a to f2ff0bc Compare May 11, 2026 02:00
@github-actions
Copy link
Copy Markdown
Contributor

🎬 CLI E2E Test Recordings — 77 recordings uploaded (commit f2ff0bc)

View all recordings
Status Test Recording
AddPackageInteractiveWhileAppHostRunningDetached ▶️ View Recording
AddPackageWhileAppHostRunningDetached ▶️ View Recording
AgentCommands_AllHelpOutputs_AreCorrect ▶️ View Recording
AgentInitCommand_DefaultSelection_InstallsSkillOnly ▶️ View Recording
AgentInitCommand_MigratesDeprecatedConfig ▶️ View Recording
AspireAddPackageVersionToDirectoryPackagesProps ▶️ View Recording
AspireInitSingleFileAppHostRunsViaDotnetRunAppHost ▶️ View Recording
AspireUpdateRemovesAppHostPackageVersionFromDirectoryPackagesProps ▶️ View Recording
Banner_DisplayedOnFirstRun ▶️ View Recording
Banner_DisplayedWithExplicitFlag ▶️ View Recording
Banner_NotDisplayedWithNoLogoFlag ▶️ View Recording
CertificatesClean_RemovesCertificates ▶️ View Recording
CertificatesTrust_WithNoCert_CreatesAndTrustsCertificate ▶️ View Recording
CertificatesTrust_WithUntrustedCert_TrustsCertificate ▶️ View Recording
ConfigSetGet_CreatesNestedJsonFormat ▶️ View Recording
CreateAndRunAspireStarterProject ▶️ View Recording
CreateAndRunAspireStarterProjectWithBundle ▶️ View Recording
CreateAndRunEmptyAppHostProject ▶️ View Recording
CreateAndRunJavaEmptyAppHostProject ▶️ View Recording
CreateAndRunJsReactProject ▶️ View Recording
CreateAndRunPythonReactProject ▶️ View Recording
CreateAndRunTypeScriptEmptyAppHostProject ▶️ View Recording
CreateAndRunTypeScriptStarterProject ▶️ View Recording
CreateJavaAppHostWithViteApp ▶️ View Recording
CreateTypeScriptAppHostWithViteApp_UsesConfiguredToolchain ▶️ View Recording
DashboardRunWithOtelTracesReturnsNoTraces ▶️ View Recording
DeployK8sBasicApiService ▶️ View Recording
DeployK8sWithGarnet ▶️ View Recording
DeployK8sWithMongoDB ▶️ View Recording
DeployK8sWithMySql ▶️ View Recording
DeployK8sWithPostgres ▶️ View Recording
DeployK8sWithRabbitMQ ▶️ View Recording
DeployK8sWithRedis ▶️ View Recording
DeployK8sWithSqlServer ▶️ View Recording
DeployK8sWithValkey ▶️ View Recording
DeployTypeScriptAppToKubernetes ▶️ View Recording
DescribeCommandResolvesReplicaNames ▶️ View Recording
DescribeCommandShowsRunningResources ▶️ View Recording
DetachFormatJsonProducesValidJson ▶️ View Recording
DetachFormatJsonProducesValidJsonWhenRestartingExistingInstance ▶️ View Recording
DoListStepsShowsPipelineSteps ▶️ View Recording
DocsCommand_RendersInteractiveMarkdownFromLocalSource ▶️ View Recording
DoctorCommand_DetectsDeprecatedAgentConfig ▶️ View Recording
DoctorCommand_TypeScriptAppHostReportsMissingConfiguredToolchain ▶️ View Recording
DoctorCommand_WithSslCertDir_ShowsTrusted ▶️ View Recording
DoctorCommand_WithoutSslCertDir_ShowsPartiallyTrusted ▶️ View Recording
GlobalMigration_HandlesCommentsAndTrailingCommas ▶️ View Recording
GlobalMigration_HandlesMalformedLegacyJson ▶️ View Recording
GlobalMigration_PreservesAllValueTypes ▶️ View Recording
GlobalMigration_SkipsWhenNewConfigExists ▶️ View Recording
GlobalSettings_MigratedFromLegacyFormat ▶️ View Recording
InitTypeScriptAppHost_AugmentsExistingViteRepoAtRoot ▶️ View Recording
InteractiveCSharpInitCreatesExpectedFiles ▶️ View Recording
InvalidAppHostPathWithComments_IsHealedOnRun ▶️ View Recording
LatestCliCanStartStableChannelAppHost ▶️ View Recording
LatestCliCanStartStableChannelTypeScriptAppHost ▶️ View Recording
LegacySettingsMigration_AdjustsRelativeAppHostPath ▶️ View Recording
LogsCommandShowsResourceLogs ▶️ View Recording
OtelLogsReturnsStructuredLogsFromStarterAppCore ▶️ View Recording
PsCommandListsRunningAppHost ▶️ View Recording
PsFormatJsonOutputsOnlyJsonToStdout ▶️ View Recording
PublishWithConfigureEnvFileUpdatesEnvOutput ▶️ View Recording
PublishWithDockerComposeServiceCallbackSucceeds ▶️ View Recording
PublishWithoutOutputPathUsesAppHostDirectoryDefault ▶️ View Recording
RestoreGeneratesSdkFiles ▶️ View Recording
RestoreGeneratesSdkFiles_WithConfiguredToolchain ▶️ View Recording
RestoreRefreshesGeneratedSdkAfterAddingIntegration ▶️ View Recording
RestoreSupportsConfigOnlyHelperPackageAndCrossPackageTypes ▶️ View Recording
RunFromParentDirectory_UsesExistingConfigNearAppHost ▶️ View Recording
SecretCrudOnDotNetAppHost ▶️ View Recording
SecretCrudOnTypeScriptAppHost ▶️ View Recording
StagingChannel_ConfigureAndVerifySettings_ThenSwitchChannels ▶️ View Recording
StartAndWaitForTypeScriptSqlServerAppHostWithNativeAssets ▶️ View Recording
StopAllAppHostsFromAppHostDirectory ▶️ View Recording
StopNonInteractiveSingleAppHost ▶️ View Recording
StopWithNoRunningAppHostExitsSuccessfully ▶️ View Recording
UnAwaitedChainsCompileWithAutoResolvePromises ▶️ View Recording

📹 Recordings uploaded automatically from CI run #25646413155

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.

2 participants