From d17489c62fed52e07381cb1762cd23e62dec93d5 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Thu, 22 Jul 2021 14:26:44 -0700 Subject: [PATCH] [flutter_plugin_tools] Support YAML exception lists (#4183) Currently the tool accepts `--custom-analysis` to allow a list of packages for which custom `analysis_options.yaml` are allowed, and `--exclude` to exclude a set of packages when running a command against all, or all changed, packages. This results in these exception lists being embedded into CI configuration files (e.g., .cirrus.yaml) or scripts, which makes them harder to maintain, and harder to re-use in other contexts (local runs, new CI systems). This adds support for both flags to accept paths to YAML files that contain the lists, so that they can be maintained separately, and with inline comments about the reasons things are on the lists. Also updates the CI to use this new support, eliminating those lists from `.cirrus.yaml` and `tool_runner.sh` Fixes https://github.com/flutter/flutter/issues/86799 --- script/tool/CHANGELOG.md | 4 ++++ script/tool/lib/src/analyze_command.dart | 21 +++++++++++++++++-- .../tool/lib/src/common/plugin_command.dart | 17 +++++++++++++-- script/tool/test/analyze_command_test.dart | 19 +++++++++++++++++ .../tool/test/common/plugin_command_test.dart | 13 ++++++++++++ 5 files changed, 70 insertions(+), 4 deletions(-) diff --git a/script/tool/CHANGELOG.md b/script/tool/CHANGELOG.md index dc30c05f79..7d1eac01b7 100644 --- a/script/tool/CHANGELOG.md +++ b/script/tool/CHANGELOG.md @@ -1,5 +1,9 @@ ## NEXT +- `--exclude` and `--custom-analysis` now accept paths to YAML files that + contain lists of packages to exclude, in addition to just package names, + so that exclude lists can be maintained separately from scripts and CI + configuration. - Added an `xctest` flag to select specific test targets, to allow running only unit tests or integration tests. - **Breaking change**: Split Xcode analysis out of `xctest` and into a new diff --git a/script/tool/lib/src/analyze_command.dart b/script/tool/lib/src/analyze_command.dart index e56b95d88e..4fd15f027f 100644 --- a/script/tool/lib/src/analyze_command.dart +++ b/script/tool/lib/src/analyze_command.dart @@ -6,6 +6,7 @@ import 'dart:async'; import 'package:file/file.dart'; import 'package:platform/platform.dart'; +import 'package:yaml/yaml.dart'; import 'common/core.dart'; import 'common/package_looping_command.dart'; @@ -23,7 +24,10 @@ class AnalyzeCommand extends PackageLoopingCommand { }) : super(packagesDir, processRunner: processRunner, platform: platform) { argParser.addMultiOption(_customAnalysisFlag, help: - 'Directories (comma separated) that are allowed to have their own analysis options.', + 'Directories (comma separated) that are allowed to have their own ' + 'analysis options.\n\n' + 'Alternately, a list of one or more YAML files that contain a list ' + 'of allowed directories.', defaultsTo: []); argParser.addOption(_analysisSdk, valueHelp: 'dart-sdk', @@ -37,6 +41,8 @@ class AnalyzeCommand extends PackageLoopingCommand { late String _dartBinaryPath; + Set _allowedCustomAnalysisDirectories = const {}; + @override final String name = 'analyze'; @@ -56,7 +62,7 @@ class AnalyzeCommand extends PackageLoopingCommand { continue; } - final bool allowed = (getStringListArg(_customAnalysisFlag)).any( + final bool allowed = _allowedCustomAnalysisDirectories.any( (String directory) => directory.isNotEmpty && path.isWithin( @@ -107,6 +113,17 @@ class AnalyzeCommand extends PackageLoopingCommand { throw ToolExit(_exitPackagesGetFailed); } + _allowedCustomAnalysisDirectories = + getStringListArg(_customAnalysisFlag).expand((String item) { + if (item.endsWith('.yaml')) { + final File file = packagesDir.fileSystem.file(item); + return (loadYaml(file.readAsStringSync()) as YamlList) + .toList() + .cast(); + } + return [item]; + }).toSet(); + // Use the Dart SDK override if one was passed in. final String? dartSdk = argResults![_analysisSdk] as String?; _dartBinaryPath = diff --git a/script/tool/lib/src/common/plugin_command.dart b/script/tool/lib/src/common/plugin_command.dart index ecdcb0565d..7781eee0d9 100644 --- a/script/tool/lib/src/common/plugin_command.dart +++ b/script/tool/lib/src/common/plugin_command.dart @@ -9,6 +9,7 @@ import 'package:file/file.dart'; import 'package:git/git.dart'; import 'package:path/path.dart' as p; import 'package:platform/platform.dart'; +import 'package:yaml/yaml.dart'; import 'core.dart'; import 'git_version_finder.dart'; @@ -48,7 +49,9 @@ abstract class PluginCommand extends Command { argParser.addMultiOption( _excludeArg, abbr: 'e', - help: 'Exclude packages from this command.', + help: 'A list of packages to exclude from from this command.\n\n' + 'Alternately, a list of one or more YAML files that contain a list ' + 'of packages to exclude.', defaultsTo: [], ); argParser.addFlag(_runOnChangedPackagesArg, @@ -214,8 +217,18 @@ abstract class PluginCommand extends Command { /// of packages in the flutter/packages repository. Stream _getAllPlugins() async* { Set plugins = Set.from(getStringListArg(_packagesArg)); + final Set excludedPlugins = - Set.from(getStringListArg(_excludeArg)); + getStringListArg(_excludeArg).expand((String item) { + if (item.endsWith('.yaml')) { + final File file = packagesDir.fileSystem.file(item); + return (loadYaml(file.readAsStringSync()) as YamlList) + .toList() + .cast(); + } + return [item]; + }).toSet(); + final bool runOnChangedPackages = getBoolArg(_runOnChangedPackagesArg); if (plugins.isEmpty && runOnChangedPackages && diff --git a/script/tool/test/analyze_command_test.dart b/script/tool/test/analyze_command_test.dart index 69a2c4f955..9dc8b6a3fc 100644 --- a/script/tool/test/analyze_command_test.dart +++ b/script/tool/test/analyze_command_test.dart @@ -176,6 +176,25 @@ void main() { ])); }); + test('takes an allow config file', () async { + final Directory pluginDir = createFakePlugin('foo', packagesDir, + extraFiles: ['analysis_options.yaml']); + final File allowFile = packagesDir.childFile('custom.yaml'); + allowFile.writeAsStringSync('- foo'); + + await runCapturingPrint( + runner, ['analyze', '--custom-analysis', allowFile.path]); + + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall( + 'flutter', const ['packages', 'get'], pluginDir.path), + ProcessCall('dart', const ['analyze', '--fatal-infos'], + pluginDir.path), + ])); + }); + // See: https://github.com/flutter/flutter/issues/78994 test('takes an empty allow list', () async { createFakePlugin('foo', packagesDir, diff --git a/script/tool/test/common/plugin_command_test.dart b/script/tool/test/common/plugin_command_test.dart index fdab9612be..7f67acfb2d 100644 --- a/script/tool/test/common/plugin_command_test.dart +++ b/script/tool/test/common/plugin_command_test.dart @@ -172,6 +172,19 @@ void main() { expect(plugins, unorderedEquals([plugin2.path])); }); + test('exclude accepts config files', () async { + createFakePlugin('plugin1', packagesDir); + final File configFile = packagesDir.childFile('exclude.yaml'); + configFile.writeAsStringSync('- plugin1'); + + await runCapturingPrint(runner, [ + 'sample', + '--packages=plugin1', + '--exclude=${configFile.path}' + ]); + expect(plugins, unorderedEquals([])); + }); + group('test run-on-changed-packages', () { test('all plugins should be tested if there are no changes.', () async { final Directory plugin1 = createFakePlugin('plugin1', packagesDir);