From ab8bc00e2cda21d6e9011ea5dbf5d29de8115f8d Mon Sep 17 00:00:00 2001 From: Navaron Bracke Date: Wed, 3 Jul 2024 18:28:27 +0200 Subject: [PATCH] Fix project name fallback (#150614) This PR changes the project name logic for `flutter create` to look for the name in the pubspec.yaml `name` field, before falling back to the directory name. Fixes https://github.com/flutter/flutter/issues/53106 *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* --- .../lib/src/commands/create_base.dart | 41 +++++++++++++++++-- .../commands.shard/permeable/create_test.dart | 24 +++++++++++ 2 files changed, 61 insertions(+), 4 deletions(-) diff --git a/packages/flutter_tools/lib/src/commands/create_base.dart b/packages/flutter_tools/lib/src/commands/create_base.dart index c57a24ffa7c..dc9e60d529a 100644 --- a/packages/flutter_tools/lib/src/commands/create_base.dart +++ b/packages/flutter_tools/lib/src/commands/create_base.dart @@ -4,6 +4,7 @@ import 'package:meta/meta.dart'; import 'package:uuid/uuid.dart'; +import 'package:yaml/yaml.dart'; import '../android/android.dart' as android_common; import '../android/android_workflow.dart'; @@ -319,13 +320,45 @@ abstract class CreateBase extends FlutterCommand { } } - /// Gets the project name based. + /// Gets the project name. /// - /// Use the current directory path name if the `--project-name` is not specified explicitly. + /// If the `--project-name` is not specified explicitly, + /// the `name` field from the pubspec.yaml file is used. + /// + /// If the pubspec.yaml file does not exist, + /// the current directory path name is used. @protected String get projectName { - final String projectName = - stringArg('project-name') ?? globals.fs.path.basename(projectDirPath); + String? projectName = stringArg('project-name'); + + if (projectName == null) { + final File pubspec = globals.fs + .directory(projectDirPath) + .childFile('pubspec.yaml'); + + if (pubspec.existsSync()) { + final String pubspecContents = pubspec.readAsStringSync(); + + try { + final Object? pubspecYaml = loadYaml(pubspecContents); + + if (pubspecYaml is YamlMap) { + final Object? pubspecName = pubspecYaml['name']; + + if (pubspecName is String) { + projectName = pubspecName; + } + } + } on YamlException { + // If the pubspec is malformed, fallback to using the directory name. + } + } + + final String projectDirName = globals.fs.path.basename(projectDirPath); + + projectName ??= projectDirName; + } + if (!boolArg('skip-name-checks')) { final String? error = _validateProjectName(projectName); if (error != null) { diff --git a/packages/flutter_tools/test/commands.shard/permeable/create_test.dart b/packages/flutter_tools/test/commands.shard/permeable/create_test.dart index 9c0e086ab92..90043c0fdd3 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/create_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/create_test.dart @@ -824,6 +824,30 @@ void main() { ); }); + testUsingContext('recreating project uses pubspec name as project name fallback', () async { + final Directory outputDirectory = tempDir.childDirectory('invalid-name'); + + // Create the new project with a valid project name, + // but with a directory name that would be an invalid project name. + await _createProject( + outputDirectory, + ['--no-pub', '--template=app', '--project-name', 'valid_name', '--platforms' , 'android'], + [] + ); + + // Now amend a new platform to the project, but omit the project name, so the fallback project name is used. + await _createProject( + outputDirectory, + ['--no-pub', '--template=app', '--platforms', 'web'], + [] + ); + + // Verify that the pubspec name was used as project name for the web project. + final File webOutputFile = outputDirectory.childDirectory('web').childFile('index.html'); + + expect(webOutputFile.readAsStringSync(), contains('valid_name')); + }); + testUsingContext('module project with pub', () async { return _createProject(projectDir, [ '--template=module',