From 46a41585ebb0bdf22f881325ceb584b38bdc20a7 Mon Sep 17 00:00:00 2001 From: Camille Simon <43054281+camsim99@users.noreply.github.com> Date: Thu, 14 Nov 2024 10:08:09 -0800 Subject: [PATCH] Add `dev_dependency` attribute to plugins in `.flutter-plugins-dependencies` (#158009) Adds whether or not the plugins in `.flutter-plugins-dependencies` are dev dependencies or not (as the `dev_dependency` attribute). Fixes https://github.com/flutter/flutter/issues/157948. --- .../lib/src/flutter_plugins.dart | 2 + .../test/general.shard/plugins_test.dart | 15 +- .../flutter_plugins_dependencies_test.dart | 140 ++++++++++++++++++ 3 files changed, 153 insertions(+), 4 deletions(-) create mode 100644 packages/flutter_tools/test/integration.shard/flutter_plugins_dependencies_test.dart diff --git a/packages/flutter_tools/lib/src/flutter_plugins.dart b/packages/flutter_tools/lib/src/flutter_plugins.dart index 5bed044b59..478baf57cf 100644 --- a/packages/flutter_tools/lib/src/flutter_plugins.dart +++ b/packages/flutter_tools/lib/src/flutter_plugins.dart @@ -143,6 +143,7 @@ const String _kFlutterPluginsPathKey = 'path'; const String _kFlutterPluginsDependenciesKey = 'dependencies'; const String _kFlutterPluginsHasNativeBuildKey = 'native_build'; const String _kFlutterPluginsSharedDarwinSource = 'shared_darwin_source'; +const String _kFlutterPluginsDevDependencyKey = 'dev_dependency'; /// Writes the .flutter-plugins-dependencies file based on the list of plugins. /// If there aren't any plugins, then the files aren't written to disk. The resulting @@ -270,6 +271,7 @@ List> _createPluginMapOfPlatform( if (platformPlugin is NativeOrDartPlugin) _kFlutterPluginsHasNativeBuildKey: (platformPlugin as NativeOrDartPlugin).hasMethodChannel() || (platformPlugin as NativeOrDartPlugin).hasFfi(), _kFlutterPluginsDependenciesKey: [...plugin.dependencies.where(pluginNames.contains)], + _kFlutterPluginsDevDependencyKey: plugin.isDevDependency, }); } return pluginInfo; diff --git a/packages/flutter_tools/test/general.shard/plugins_test.dart b/packages/flutter_tools/test/general.shard/plugins_test.dart index 443d94980f..6d96f15416 100644 --- a/packages/flutter_tools/test/general.shard/plugins_test.dart +++ b/packages/flutter_tools/test/general.shard/plugins_test.dart @@ -508,6 +508,7 @@ dependencies: 'plugin-b', 'plugin-c', ], + 'dev_dependency': false, }, { 'name': 'plugin-b', @@ -516,12 +517,14 @@ dependencies: 'dependencies': [ 'plugin-c', ], + 'dev_dependency': false, }, { 'name': 'plugin-c', 'path': '${pluginC.path}/', 'native_build': true, 'dependencies': [], + 'dev_dependency': false, }, ]; expect(plugins['ios'], expectedPlugins); @@ -614,7 +617,8 @@ dependencies: 'path': '/.tmp_rand0/flutter_plugin.rand0/', 'shared_darwin_source': true, 'native_build': true, - 'dependencies': [] + 'dependencies': [], + 'dev_dependency': false, } ], 'android': >[ @@ -622,7 +626,8 @@ dependencies: 'name': 'plugin-a', 'path': '/.tmp_rand0/flutter_plugin.rand0/', 'native_build': true, - 'dependencies': [] + 'dependencies': [], + 'dev_dependency': false, } ], 'macos': >[], @@ -632,14 +637,16 @@ dependencies: 'name': 'plugin-a', 'path': '/.tmp_rand0/flutter_plugin.rand0/', 'native_build': false, - 'dependencies': [] + 'dependencies': [], + 'dev_dependency': false, } ], 'web': >[ { 'name': 'plugin-a', 'path': '/.tmp_rand0/flutter_plugin.rand0/', - 'dependencies': [] + 'dependencies': [], + 'dev_dependency': false, } ] }; diff --git a/packages/flutter_tools/test/integration.shard/flutter_plugins_dependencies_test.dart b/packages/flutter_tools/test/integration.shard/flutter_plugins_dependencies_test.dart new file mode 100644 index 0000000000..5939b0aa01 --- /dev/null +++ b/packages/flutter_tools/test/integration.shard/flutter_plugins_dependencies_test.dart @@ -0,0 +1,140 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:convert'; +import 'package:file/file.dart'; + +import '../src/common.dart'; +import 'test_utils.dart'; + +void main() { + late Directory tempProjectDir; + late Directory tempPluginADir; + late Directory tempPluginBDir; + + setUp(() { + tempProjectDir = createResolvedTempDirectorySync( + 'flutter_plugins_dependencies_test_project.'); + tempPluginADir = createResolvedTempDirectorySync( + 'flutter_plugins_dependencies_test_plugin_a.'); + tempPluginBDir = createResolvedTempDirectorySync( + 'flutter_plugins_dependencies_test_plugin_b.'); + }); + + tearDown(() { + tryToDelete(tempProjectDir); + }); + + test( + '.flutter-plugins-dependencies correctly denotes project dev dependencies on all default platforms', + () async { + // Create Flutter project. + final String flutterBin = + fileSystem.path.join(getFlutterRoot(), 'bin', 'flutter'); + + await processManager.run([ + flutterBin, + 'create', + tempProjectDir.path, + '--project-name=testapp', + ], workingDirectory: tempProjectDir.path); + + final File pubspecFile = tempProjectDir.childFile('pubspec.yaml'); + expect(pubspecFile.existsSync(), true); + + // Create Flutter plugins to add as dependencies to Flutter project. + final String pluginAPath = '${tempPluginADir.path}/plugin_a_real_dependency'; + final String pluginBPath = '${tempPluginBDir.path}/plugin_b_dev_dependency'; + + await processManager.run([ + flutterBin, + 'create', + pluginAPath, + '--template=plugin', + '--project-name=plugin_a_real_dependency', + ], workingDirectory: tempPluginADir.path); + + await processManager.run([ + flutterBin, + 'create', + pluginBPath, + '--template=plugin', + '--project-name=plugin_b_dev_dependency', + ], workingDirectory: tempPluginBDir.path); + + // Add dependency on two plugin: one dependency, one dev dependency. + await processManager.run([ + flutterBin, + 'pub', + 'add', + 'plugin_a_real_dependency', + '--path', + pluginAPath, + ], workingDirectory: tempProjectDir.path); + + await processManager.run([ + flutterBin, + 'pub', + 'add', + 'dev:plugin_b_dev_dependency', + '--path', + pluginBPath, + ], workingDirectory: tempProjectDir.path); + + // Run `flutter pub get` to generate .flutter-plugins-dependencies. + await processManager.run([ + flutterBin, + '--no-implicit-pubspec-resolution', + 'pub', + 'get', + ], workingDirectory: tempProjectDir.path); + + final File flutterPluginsDependenciesFile = + tempProjectDir.childFile('.flutter-plugins-dependencies'); + expect(flutterPluginsDependenciesFile.existsSync(), true); + + // Check that .flutter-plugin-dependencies denotes the dependency and + // dev dependency as expected. + final String pluginsString = + flutterPluginsDependenciesFile.readAsStringSync(); + final Map jsonContent = + json.decode(pluginsString) as Map; + final Map plugins = + jsonContent['plugins'] as Map; + + // Loop through all platforms supported by default to verify that the + // dependency and dev dependency are handled appropriately. + final List platformsToVerify = [ + 'ios', + 'android', + 'windows', + 'linux', + 'macos', + 'web', + ]; + + for (final String platform in platformsToVerify) { + final List pluginsForPlatform = + plugins[platform] as List; + + for (final dynamic plugin in pluginsForPlatform) { + final Map pluginProperties = + plugin as Map; + final String pluginName = pluginProperties['name'] as String; + final bool pluginIsDevDependency = + pluginProperties['dev_dependency'] as bool; + + // Check camera dependencies are not marked as dev dependencies. + if (pluginName.startsWith('plugin_a_real_dependency')) { + expect(pluginIsDevDependency, isFalse); + } + + // Check video_player dependencies are marked as dev dependencies. + if (pluginName.startsWith('plugin_b_dev_dependency')) { + expect(pluginIsDevDependency, isTrue); + } + } + } + }); +}