Closes https://github.com/flutter/flutter/issues/163767.
Closes https://github.com/flutter/flutter/issues/163706.

It just works after, but added more test cases.
This commit is contained in:
Matan Lurey 2025-02-20 19:35:14 -08:00 committed by GitHub
parent dec3b1e20e
commit 178749b970
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 178 additions and 3 deletions

View File

@ -239,9 +239,8 @@ bool _writeFlutterPluginsList(
final String? oldPluginsFileStringContent = _readFileContent(pluginsFile);
bool pluginsChanged = true;
if (oldPluginsFileStringContent != null) {
Object? decodedJson;
try {
decodedJson = jsonDecode(oldPluginsFileStringContent);
final Object? decodedJson = jsonDecode(oldPluginsFileStringContent);
if (decodedJson is Map<String, Object?>) {
final String jsonOfNewPluginsMap = jsonEncode(pluginsMap);
final String jsonOfOldPluginsMap = jsonEncode(decodedJson[_kFlutterPluginsPluginListKey]);
@ -1095,6 +1094,11 @@ void _createPlatformPluginSymlinks(
/// dependencies declared in `pubspec.yaml`.
///
/// Assumes `pub get` has been executed since last change to `pubspec.yaml`.
///
/// Unless explicitly specified, [determineDevDependencies] is disabled by
/// default; if set to `true`, plugins that are development-only dependencies
/// may be labeled or, depending on the platform, omitted from metadata or
/// platform-specific artifacts.
Future<void> refreshPluginsList(
FlutterProject project, {
bool iosPlatform = false,

View File

@ -31,6 +31,17 @@ import '../src/fake_pub_deps.dart';
import '../src/fakes.dart';
void main() {
// TODO(matanlurey): Remove after `explicit-package-dependencies` is enabled by default.
// See https://github.com/flutter/flutter/issues/160257 for details.
FeatureFlags enableExplicitPackageDependencies() {
return TestFeatureFlags(isExplicitPackageDependenciesEnabled: true);
}
FeatureFlags disableExplicitPackageDependencies() {
// ignore: avoid_redundant_argument_values
return TestFeatureFlags(isExplicitPackageDependenciesEnabled: false);
}
// TODO(zanderso): remove once FlutterProject is fully refactored.
// this is safe since no tests have expectations on the test logger.
final BufferLogger logger = BufferLogger.test();
@ -272,6 +283,107 @@ void main() {
await project.regeneratePlatformSpecificTooling(releaseMode: false);
expectExists(project.android.hostAppGradleRoot.childFile('local.properties'));
});
testUsingContext(
'--no-explicit-package-dependencies does not determine dev dependencies',
() async {
// Create a plugin.
await aPluginProject(legacy: false);
// Create a project that depends on that plugin.
final FlutterProject project = await projectWithPluginDependency();
// Don't bother with Android, we just want the manifest.
project.directory.childDirectory('android').deleteSync(recursive: true);
await project.regeneratePlatformSpecificTooling(releaseMode: false);
expect(
project.flutterPluginsDependenciesFile.readAsStringSync(),
isNot(contains('"dev_dependency":true')),
);
},
overrides: <Type, Generator>{
FeatureFlags: disableExplicitPackageDependencies,
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
Pub: () => FakePubWithPrimedDeps(devDependencies: <String>{'my_plugin'}),
FlutterProjectFactory:
() => FlutterProjectFactory(logger: logger, fileSystem: globals.fs),
},
);
testUsingContext(
'--explicit-package-dependencies determines dev dependencies',
() async {
// Create a plugin.
await aPluginProject(legacy: false);
// Create a project that depends on that plugin.
final FlutterProject project = await projectWithPluginDependency();
// Don't bother with Android, we just want the manifest.
project.directory.childDirectory('android').deleteSync(recursive: true);
await project.regeneratePlatformSpecificTooling(releaseMode: false);
expect(
project.flutterPluginsDependenciesFile.readAsStringSync(),
contains('"dev_dependency":true'),
);
},
overrides: <Type, Generator>{
FeatureFlags: enableExplicitPackageDependencies,
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
Pub: () => FakePubWithPrimedDeps(devDependencies: <String>{'my_plugin'}),
FlutterProjectFactory:
() => FlutterProjectFactory(logger: logger, fileSystem: globals.fs),
},
);
testUsingContext(
'--explicit-package-dependencies with releaseMode: false retains dev plugins',
() async {
// Create a plugin.
await aPluginProject(includeAndroidMain: true, legacy: false);
// Create a project that depends on that plugin.
final FlutterProject project = await projectWithPluginDependency();
await project.regeneratePlatformSpecificTooling(releaseMode: false);
expect(
project.android.generatedPluginRegistrantFile.readAsStringSync(),
contains('MyPlugin'),
);
},
overrides: <Type, Generator>{
FeatureFlags: enableExplicitPackageDependencies,
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
Pub: () => FakePubWithPrimedDeps(devDependencies: <String>{'my_plugin'}),
FlutterProjectFactory:
() => FlutterProjectFactory(logger: logger, fileSystem: globals.fs),
},
);
testUsingContext(
'--explicit-package-dependencies with releaseMode: true omits dev plugins',
() async {
// Create a plugin.
await aPluginProject(includeAndroidMain: true, legacy: false);
// Create a project that depends on that plugin.
final FlutterProject project = await projectWithPluginDependency();
await project.regeneratePlatformSpecificTooling(releaseMode: true);
expect(
project.android.generatedPluginRegistrantFile.readAsStringSync(),
isNot(contains('MyPlugin')),
);
},
overrides: <Type, Generator>{
FeatureFlags: enableExplicitPackageDependencies,
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
Pub: () => FakePubWithPrimedDeps(devDependencies: <String>{'my_plugin'}),
FlutterProjectFactory:
() => FlutterProjectFactory(logger: logger, fileSystem: globals.fs),
},
);
testUsingContext(
'injects plugins for macOS',
() async {
@ -1730,7 +1842,41 @@ Future<FlutterProject> someProject({
return FlutterProject.fromDirectory(directory);
}
Future<FlutterProject> aPluginProject({bool legacy = true}) async {
Future<FlutterProject> projectWithPluginDependency() async {
final Directory directory = globals.fs.directory('some_project');
directory.childDirectory('.dart_tool').childFile('package_config.json')
..createSync(recursive: true)
..writeAsStringSync('''
{
"configVersion": 2,
"packages": [
{
"name": "my_plugin",
"rootUri": "/plugin_project",
"packageUri": "lib/",
"languageVersion": "2.12"
}
]
}
''');
directory.childFile('pubspec.yaml')
..createSync(recursive: true)
..writeAsStringSync('''
name: app_name
flutter:
dependencies:
my_plugin:
sdk: flutter
''');
directory.childDirectory('ios').createSync(recursive: true);
final Directory androidDirectory = directory.childDirectory('android')
..createSync(recursive: true);
androidDirectory.childFile('AndroidManifest.xml').writeAsStringSync('<manifest></manifest>');
return FlutterProject.fromDirectory(directory);
}
Future<FlutterProject> aPluginProject({bool legacy = true, bool includeAndroidMain = false}) async {
final Directory directory = globals.fs.directory('plugin_project');
directory.childDirectory('ios').createSync(recursive: true);
directory.childDirectory('android').createSync(recursive: true);
@ -1765,6 +1911,16 @@ flutter:
''';
}
directory.childFile('pubspec.yaml').writeAsStringSync(pluginPubSpec);
if (includeAndroidMain) {
directory
.childDirectory('android')
.childFile(globals.fs.path.join('src', 'main', 'java', 'com', 'example', 'MyPlugin.java'))
..createSync(recursive: true)
..writeAsStringSync('''
import io.flutter.embedding.engine.plugins.FlutterPlugin;
class MyPlugin extends FluttPlugin { /* ... */ }
''');
}
return FlutterProject.fromDirectory(directory);
}

View File

@ -5,6 +5,7 @@
import 'package:file_testing/file_testing.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/features.dart';
import '../integration.shard/test_utils.dart';
import '../src/common.dart';
@ -14,6 +15,20 @@ void main() {
setUpAll(() {
processManager.runSync(<String>[flutterBin, 'config', '--enable-macos-desktop']);
// TODO(matanlurey): Remove after `explicit-package-dependencies` is enabled by default.
// See https://github.com/flutter/flutter/issues/160257 for details.
if (!explicitPackageDependencies.master.enabledByDefault) {
processManager.runSync(<String>[flutterBin, 'config', '--explicit-package-dependencies']);
}
});
tearDownAll(() {
// TODO(matanlurey): Remove after `explicit-package-dependencies` is enabled by default.
// See https://github.com/flutter/flutter/issues/160257 for details.
if (!explicitPackageDependencies.master.enabledByDefault) {
processManager.runSync(<String>[flutterBin, 'config', '--no-explicit-package-dependencies']);
}
});
for (final String buildMode in <String>['Debug', 'Release']) {