Skip to content

[flutter_tools] Implement Templates slice and flutter create integration - #191748

Merged
auto-submit[bot] merged 14 commits into
flutter:masterfrom
bkonyi:ft-ext-step05-templates-slice
Sep 1, 2026
Merged

auto-submit[bot] merged 14 commits into
flutter:masterfrom
bkonyi:ft-ext-step05-templates-slice

Conversation

@bkonyi

@bkonyi bkonyi commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Description

This PR implements Step 5 of Flutter Tools Extensibility: the Templates extension slice and flutter create dynamic template integration.

Architectural Overview

  1. package:flutter_tools_core:
    • Defines core, platform-agnostic template models: ProjectTemplate and ExtensionProjectTemplate with JSON serialization, equality, and unordered set hashing.
  2. package:flutter_tools_extension:
    • Defines the TemplateService RPC interface and handlers for template.getAppTemplates, template.getPluginTemplates, template.getProjectTemplates, and template.generateTemplateParameters.
  3. package:flutter_tools_extension_linux_prototype:
    • Implements LinuxTemplateService and LinuxProjectTemplate declaring custom template 'custom-linux-app' with templateDependencies: {'app'}.
    • Adds prototype template assets for 'custom-linux-app'.
  4. packages/flutter_tools:
    • Implements ExtensionTemplateManager to discover custom templates over RPC concurrently, cache them, resolve directories, and delegate parameter generation.
    • Updates Template.fromDirectories to merge directory sources over base template dependencies.
    • Integrates dynamic --template CLI options and help text into CreateCommand using ExtensionArgParserMixin.
    • Supports ExtensionProjectTemplateType in FlutterProjectMetadata and ParsedFlutterTemplateType.
    • Wires ExtensionTemplateManager through executable.dart into CreateCommand.

Related Issues

Part of #190692

Tests

  • Added packages/flutter_tools/packages/flutter_tools_core/test/templates_test.dart
  • Added packages/flutter_tools/packages/flutter_tools_extension_linux_prototype/test/linux_template_test.dart
  • Added packages/flutter_tools/test/general.shard/extension_protocol/template_service_test.dart
  • Updated packages/flutter_tools/test/general.shard/flutter_project_metadata_test.dart
  • Updated packages/flutter_tools/test/integration.shard/tool_extensions_test.dart

@github-actions github-actions Bot added tool Affects the "flutter" command-line tool. See also t: labels. team-ios Owned by iOS platform team team-macos Owned by the macOS platform team team-linux Owned by the Linux platform team labels Aug 25, 2026
@bkonyi bkonyi added the CICD Run CI/CD label Aug 25, 2026
Implements the Templates extension service and integrates dynamic custom template support into `flutter create` and `package:flutter_tools_core`.

- `package:flutter_tools_core`:
  - Adds `ProjectTemplate` and `ExtensionProjectTemplate` domain models with JSON serialization, hashing, and equality in `lib/src/templates.dart`.
  - Exports template models from `lib/flutter_tools_core.dart`.
- `package:flutter_tools_extension`:
  - Defines `TemplateService` RPC interface and handlers for `template.getAppTemplates`, `template.getPluginTemplates`, `template.getProjectTemplates`, and `template.generateTemplateParameters` in `lib/src/templates.dart`.
- `package:flutter_tools_extension_linux_prototype`:
  - Implements `LinuxTemplateService` and `LinuxProjectTemplate` declaring custom template `'custom-linux-app'` with `templateDependencies: {'app'}`.
  - Adds prototype template assets for `'custom-linux-app'`.
- `packages/flutter_tools`:
  - Adds `ExtensionTemplateManager` in `lib/src/experimental/templates.dart` to discover custom templates over RPC, cache them, resolve directories, and delegate parameter generation.
  - Updates `Template.fromDirectories` in `lib/src/template.dart` to merge directory sources with base template dependencies.
  - Updates `CreateCommand` and `ExtensionArgParserMixin` to dynamically populate `--template` CLI options and help entries.
  - Updates `FlutterProjectMetadata` and `ParsedFlutterTemplateType` to support `ExtensionProjectTemplateType`.
  - Wires `ExtensionTemplateManager` through `executable.dart` into `CreateCommand`.
  - Adds unit, hermetic usage, and integration test coverage across all layers.
@bkonyi
bkonyi force-pushed the ft-ext-step05-templates-slice branch from c69e665 to 1106827 Compare August 26, 2026 01:37
@github-actions github-actions Bot removed team-ios Owned by iOS platform team team-macos Owned by the macOS platform team labels Aug 26, 2026
@bkonyi
bkonyi marked this pull request as ready for review August 26, 2026 03:26
@bkonyi
bkonyi requested a review from a team as a code owner August 26, 2026 03:26
@bkonyi
bkonyi removed the request for review from a team August 26, 2026 03:26

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces support for custom project templates provided dynamically by tool extensions in flutter create. It adds ExtensionTemplateManager to query templates over RPC, updates CreateCommand to dynamically rebuild its argument parser, and integrates custom template rendering. The review feedback suggests wrapping asynchronous RPC calls to getProjectTemplates() in try-catch blocks to prevent potential tool crashes if extensions fail to initialize. Additionally, it recommends adding a fallback mechanism when parsing custom template names from .metadata files to handle scenarios where the extension manager is not active.

Comment thread packages/flutter_tools/lib/src/commands/create.dart
Comment thread packages/flutter_tools/lib/src/commands/create.dart
Comment thread packages/flutter_tools/lib/src/flutter_project_metadata.dart
Comment thread packages/flutter_tools/lib/src/flutter_project_metadata.dart
@bkonyi
bkonyi requested a review from loic-sharma August 26, 2026 15:34
bkonyi added 2 commits August 28, 2026 14:36
…plates-slice

# Conflicts:
#	packages/flutter_tools/lib/src/experimental/extension_arg_parser.dart
Comment thread packages/flutter_tools/packages/flutter_tools_core/lib/src/templates.dart Outdated
@bkonyi
bkonyi requested a review from loic-sharma September 1, 2026 02:05
return ExtensionArgParserMixin.cloneParser(
baseArgParser,
optionCloner: (ArgParser newParser, Option opt) {
if (opt.name == 'template') {

@loic-sharma loic-sharma Sep 1, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit: Consider inverting this to improve readability. Something like:

if (opt.name != 'template') {
  ExtensionArgParserMixin.copyOption(newParser, opt);
  return;
}

// Template logic here...

I don't feel strongly, feel free to skip.

);
if (parsedTemplate == null) {
throwToolExit(
'Expected one of ${ParsedFlutterTemplateType.enabledValues(featureFlags, extensionTemplateManager: _extensionTemplateManager).map((ParsedFlutterTemplateType t) => t.cliName).join(', ')} '

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit: consider splitting this into two lines, it's quite long

if (depTemplate != null) {
templateSources.add(manager.resolveTemplateDirectory(depTemplate.templatePath));
} else {
// Fallback to internal templates.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should we make internal templates have higher priority than extension templates? I suspect allowing extensions to override internal templates is not a scenario we want to support?

static ParsedFlutterTemplateType? fromCliName(
String cliName, {
required ExtensionTemplateManager? extensionTemplateManager,
bool fallbackToCustom = false,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

FYI this appears to be unused currently, other than in tests. Is it still needed?

Comment thread packages/flutter_tools/packages/flutter_tools_core/lib/src/templates.dart Outdated
import 'doctor.dart';
import 'emulator.dart';
import 'features.dart';

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This looks like an unintentional change :)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Probably had some changes here before... 😅

throw UnimplementedError(
'ExtensionProjectTemplate.generateTemplateParameters should not be called directly on host representation.',
);
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

(Sorry for re-litigating 😂)

I still don't love this pattern. Over time, I expect we'll have lots of methods that the host should not call, but if we make a mistake in the host it'll be non-obvious from the call site. I'm OK with landing this, but this pattern is something I think we should reconsider after we've landed more of the prototype.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Completely agree!

'ExtensionProjectTemplate(name: $name, hidden: $hidden, templateDependencies: $templateDependencies, templateSources: $templateSources, templatePath: $templatePath)';

@override
bool operator ==(Object other) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Just curious, why do we need to override == and hashCode for the host side models again?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Mainly for unit test assertions so we can do expect(actual, expected).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Ah OK sounds good 👍

@loic-sharma loic-sharma left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This looks good to me! All feedback is minor nitpicks :)

@bkonyi bkonyi added the autosubmit Merge PR when tree becomes green via auto submit App label Sep 1, 2026
@auto-submit auto-submit Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Sep 1, 2026
@auto-submit

auto-submit Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

autosubmit label was removed for flutter/flutter/191748, because - The status or check suite Dashboard Checks has failed. Please fix the issues identified (or deflake) before re-applying this label.

@bkonyi bkonyi added the autosubmit Merge PR when tree becomes green via auto submit App label Sep 1, 2026
@auto-submit
auto-submit Bot added this pull request to the merge queue Sep 1, 2026
Merged via the queue into flutter:master with commit 453cb46 Sep 1, 2026
29 checks passed
@flutter-dashboard flutter-dashboard Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Sep 1, 2026
auto-submit Bot pushed a commit to flutter/packages that referenced this pull request Sep 4, 2026
flutter/flutter@0cbd1a4...70797e1

2026-09-02 [email protected] [analysis] Upgrade package:analyzer to 14.3.0 and enable custom plugin compilation (flutter/flutter#191590)
2026-09-02 [email protected] Roll Dart SDK from d8d7869d8031 to 9a8fbde80f6c (1 revision) (flutter/flutter#192179)
2026-09-02 [email protected] Roll Skia from dec311244db4 to ae22da2e8308 (1 revision) (flutter/flutter#192177)
2026-09-02 [email protected] [tool] Migrate DoctorCommand to modular dependency injection (flutter/flutter#190758)
2026-09-02 [email protected] Roll Skia from 482b7e285244 to dec311244db4 (3 revisions) (flutter/flutter#192161)
2026-09-02 [email protected] Roll Skia from 28447e9fb8d5 to 482b7e285244 (3 revisions) (flutter/flutter#192157)
2026-09-02 [email protected] feat: Add placeholder to DecorationImage (flutter/flutter#191528)
2026-09-02 [email protected] [Android] Do not schedule engine frames on a detached FlutterJNI (flutter/flutter#191204)
2026-09-02 [email protected] Roll Skia from 3a242fb7cdb3 to 28447e9fb8d5 (1 revision) (flutter/flutter#192145)
2026-09-02 [email protected] Roll Dart SDK from 9164def35347 to d8d7869d8031 (2 revisions) (flutter/flutter#192144)
2026-09-02 [email protected] Add FadeInImageTransition.fadeInOver to fade the image in over the placeholder (flutter/flutter#186246)
2026-09-02 [email protected] Roll Skia from 63d13ec4df6d to 3a242fb7cdb3 (9 revisions) (flutter/flutter#192138)
2026-09-02 [email protected] [flutter_tools] Add --no-plugins flag and disable plugins for benchmark (flutter/flutter#192129)
2026-09-02 [email protected] [tool] Migrate ChannelCommand to modular dependency injection (flutter/flutter#190751)
2026-09-01 [email protected] Add mouseCursor to RawScrollbar (flutter/flutter#185750)
2026-09-01 [email protected] Fix self-comparison and assert typos in TestSemantics (flutter/flutter#191938)
2026-09-01 [email protected] [Linux] Wait for frames to be rendered before using them in another context (flutter/flutter#192094)
2026-09-01 [email protected] [wimp] Turn on multithreading for wimp. (flutter/flutter#191747)
2026-09-01 [email protected] Roll Skia from 3911a1fe7f7a to 63d13ec4df6d (6 revisions) (flutter/flutter#192125)
2026-09-01 [email protected] Remove the redundant flutter/shell/platform/android:robolectric_tests build target (flutter/flutter#192117)
2026-09-01 [email protected] [iOS] Preserve semantics parents after reparenting (flutter/flutter#189686)
2026-09-01 [email protected] [flutter_tools] Report preview reload timing analytics in LspPreviewDetector (flutter/flutter#192120)
2026-09-01 [email protected] [flutter_tools] Implement Templates slice and flutter create integration (flutter/flutter#191748)
2026-09-01 [email protected] Uiscene migrate add2app hosts (flutter/flutter#191847)
2026-09-01 [email protected] Roll Packages from d642322 to 7a7912f (8 revisions) (flutter/flutter#192119)
2026-09-01 [email protected] [web] Anchor flt-semantics-host at 0,0 to fix WebKit semantics offset (flutter/flutter#190486)
2026-09-01 [email protected] Replace Shell::WaitForFirstFrame with an asynchronous API that matches the Shell threading model (flutter/flutter#191841)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC [email protected] on the revert to ensure that a human
is aware of the problem.

To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
victorsanni pushed a commit to victorsanni/packages that referenced this pull request Sep 9, 2026
…r#12727)

flutter/flutter@0cbd1a4...70797e1

2026-09-02 [email protected] [analysis] Upgrade package:analyzer to 14.3.0 and enable custom plugin compilation (flutter/flutter#191590)
2026-09-02 [email protected] Roll Dart SDK from d8d7869d8031 to 9a8fbde80f6c (1 revision) (flutter/flutter#192179)
2026-09-02 [email protected] Roll Skia from dec311244db4 to ae22da2e8308 (1 revision) (flutter/flutter#192177)
2026-09-02 [email protected] [tool] Migrate DoctorCommand to modular dependency injection (flutter/flutter#190758)
2026-09-02 [email protected] Roll Skia from 482b7e285244 to dec311244db4 (3 revisions) (flutter/flutter#192161)
2026-09-02 [email protected] Roll Skia from 28447e9fb8d5 to 482b7e285244 (3 revisions) (flutter/flutter#192157)
2026-09-02 [email protected] feat: Add placeholder to DecorationImage (flutter/flutter#191528)
2026-09-02 [email protected] [Android] Do not schedule engine frames on a detached FlutterJNI (flutter/flutter#191204)
2026-09-02 [email protected] Roll Skia from 3a242fb7cdb3 to 28447e9fb8d5 (1 revision) (flutter/flutter#192145)
2026-09-02 [email protected] Roll Dart SDK from 9164def35347 to d8d7869d8031 (2 revisions) (flutter/flutter#192144)
2026-09-02 [email protected] Add FadeInImageTransition.fadeInOver to fade the image in over the placeholder (flutter/flutter#186246)
2026-09-02 [email protected] Roll Skia from 63d13ec4df6d to 3a242fb7cdb3 (9 revisions) (flutter/flutter#192138)
2026-09-02 [email protected] [flutter_tools] Add --no-plugins flag and disable plugins for benchmark (flutter/flutter#192129)
2026-09-02 [email protected] [tool] Migrate ChannelCommand to modular dependency injection (flutter/flutter#190751)
2026-09-01 [email protected] Add mouseCursor to RawScrollbar (flutter/flutter#185750)
2026-09-01 [email protected] Fix self-comparison and assert typos in TestSemantics (flutter/flutter#191938)
2026-09-01 [email protected] [Linux] Wait for frames to be rendered before using them in another context (flutter/flutter#192094)
2026-09-01 [email protected] [wimp] Turn on multithreading for wimp. (flutter/flutter#191747)
2026-09-01 [email protected] Roll Skia from 3911a1fe7f7a to 63d13ec4df6d (6 revisions) (flutter/flutter#192125)
2026-09-01 [email protected] Remove the redundant flutter/shell/platform/android:robolectric_tests build target (flutter/flutter#192117)
2026-09-01 [email protected] [iOS] Preserve semantics parents after reparenting (flutter/flutter#189686)
2026-09-01 [email protected] [flutter_tools] Report preview reload timing analytics in LspPreviewDetector (flutter/flutter#192120)
2026-09-01 [email protected] [flutter_tools] Implement Templates slice and flutter create integration (flutter/flutter#191748)
2026-09-01 [email protected] Uiscene migrate add2app hosts (flutter/flutter#191847)
2026-09-01 [email protected] Roll Packages from d642322 to 7a7912f (8 revisions) (flutter/flutter#192119)
2026-09-01 [email protected] [web] Anchor flt-semantics-host at 0,0 to fix WebKit semantics offset (flutter/flutter#190486)
2026-09-01 [email protected] Replace Shell::WaitForFirstFrame with an asynchronous API that matches the Shell threading model (flutter/flutter#191841)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC [email protected] on the revert to ensure that a human
is aware of the problem.

To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
victorsanni pushed a commit to victorsanni/packages that referenced this pull request Sep 9, 2026
…r#12727)

flutter/flutter@0cbd1a4...70797e1

2026-09-02 [email protected] [analysis] Upgrade package:analyzer to 14.3.0 and enable custom plugin compilation (flutter/flutter#191590)
2026-09-02 [email protected] Roll Dart SDK from d8d7869d8031 to 9a8fbde80f6c (1 revision) (flutter/flutter#192179)
2026-09-02 [email protected] Roll Skia from dec311244db4 to ae22da2e8308 (1 revision) (flutter/flutter#192177)
2026-09-02 [email protected] [tool] Migrate DoctorCommand to modular dependency injection (flutter/flutter#190758)
2026-09-02 [email protected] Roll Skia from 482b7e285244 to dec311244db4 (3 revisions) (flutter/flutter#192161)
2026-09-02 [email protected] Roll Skia from 28447e9fb8d5 to 482b7e285244 (3 revisions) (flutter/flutter#192157)
2026-09-02 [email protected] feat: Add placeholder to DecorationImage (flutter/flutter#191528)
2026-09-02 [email protected] [Android] Do not schedule engine frames on a detached FlutterJNI (flutter/flutter#191204)
2026-09-02 [email protected] Roll Skia from 3a242fb7cdb3 to 28447e9fb8d5 (1 revision) (flutter/flutter#192145)
2026-09-02 [email protected] Roll Dart SDK from 9164def35347 to d8d7869d8031 (2 revisions) (flutter/flutter#192144)
2026-09-02 [email protected] Add FadeInImageTransition.fadeInOver to fade the image in over the placeholder (flutter/flutter#186246)
2026-09-02 [email protected] Roll Skia from 63d13ec4df6d to 3a242fb7cdb3 (9 revisions) (flutter/flutter#192138)
2026-09-02 [email protected] [flutter_tools] Add --no-plugins flag and disable plugins for benchmark (flutter/flutter#192129)
2026-09-02 [email protected] [tool] Migrate ChannelCommand to modular dependency injection (flutter/flutter#190751)
2026-09-01 [email protected] Add mouseCursor to RawScrollbar (flutter/flutter#185750)
2026-09-01 [email protected] Fix self-comparison and assert typos in TestSemantics (flutter/flutter#191938)
2026-09-01 [email protected] [Linux] Wait for frames to be rendered before using them in another context (flutter/flutter#192094)
2026-09-01 [email protected] [wimp] Turn on multithreading for wimp. (flutter/flutter#191747)
2026-09-01 [email protected] Roll Skia from 3911a1fe7f7a to 63d13ec4df6d (6 revisions) (flutter/flutter#192125)
2026-09-01 [email protected] Remove the redundant flutter/shell/platform/android:robolectric_tests build target (flutter/flutter#192117)
2026-09-01 [email protected] [iOS] Preserve semantics parents after reparenting (flutter/flutter#189686)
2026-09-01 [email protected] [flutter_tools] Report preview reload timing analytics in LspPreviewDetector (flutter/flutter#192120)
2026-09-01 [email protected] [flutter_tools] Implement Templates slice and flutter create integration (flutter/flutter#191748)
2026-09-01 [email protected] Uiscene migrate add2app hosts (flutter/flutter#191847)
2026-09-01 [email protected] Roll Packages from d642322 to 7a7912f (8 revisions) (flutter/flutter#192119)
2026-09-01 [email protected] [web] Anchor flt-semantics-host at 0,0 to fix WebKit semantics offset (flutter/flutter#190486)
2026-09-01 [email protected] Replace Shell::WaitForFirstFrame with an asynchronous API that matches the Shell threading model (flutter/flutter#191841)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC [email protected] on the revert to ensure that a human
is aware of the problem.

To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CICD Run CI/CD team-linux Owned by the Linux platform team tool Affects the "flutter" command-line tool. See also t: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants