From 70ff6821af9a0673ba913beec3e3aecd7cb239d8 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Wed, 28 Sep 2022 16:51:15 -0400 Subject: [PATCH] [tool] Adds a `fix` command (#6512) --- script/tool/CHANGELOG.md | 4 ++ script/tool/lib/src/fix_command.dart | 51 +++++++++++++++++ script/tool/lib/src/main.dart | 2 + script/tool/test/fix_command_test.dart | 78 ++++++++++++++++++++++++++ 4 files changed, 135 insertions(+) create mode 100644 script/tool/lib/src/fix_command.dart create mode 100644 script/tool/test/fix_command_test.dart diff --git a/script/tool/CHANGELOG.md b/script/tool/CHANGELOG.md index 830d3ca931..bf549d4e79 100644 --- a/script/tool/CHANGELOG.md +++ b/script/tool/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.11.1 + +* Adds a `fix` command to run `dart fix --apply` in target packages. + ## 0.11 * Renames `publish-plugin` to `publish`. diff --git a/script/tool/lib/src/fix_command.dart b/script/tool/lib/src/fix_command.dart new file mode 100644 index 0000000000..2819609eab --- /dev/null +++ b/script/tool/lib/src/fix_command.dart @@ -0,0 +1,51 @@ +// Copyright 2013 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:async'; + +import 'package:file/file.dart'; +import 'package:platform/platform.dart'; + +import 'common/core.dart'; +import 'common/package_looping_command.dart'; +import 'common/process_runner.dart'; +import 'common/repository_package.dart'; + +/// A command to run Dart's "fix" command on packages. +class FixCommand extends PackageLoopingCommand { + /// Creates a fix command instance. + FixCommand( + Directory packagesDir, { + ProcessRunner processRunner = const ProcessRunner(), + Platform platform = const LocalPlatform(), + }) : super(packagesDir, processRunner: processRunner, platform: platform); + + @override + final String name = 'fix'; + + @override + final String description = 'Fixes packages using dart fix.\n\n' + 'This command requires "dart" and "flutter" to be in your path, and ' + 'assumes that dependencies have already been fetched (e.g., by running ' + 'the analyze command first).'; + + @override + final bool hasLongOutput = false; + + @override + PackageLoopingType get packageLoopingType => + PackageLoopingType.includeAllSubpackages; + + @override + Future runForPackage(RepositoryPackage package) async { + final int exitCode = await processRunner.runAndStream( + 'dart', ['fix', '--apply'], + workingDir: package.directory); + if (exitCode != 0) { + printError('Unable to automatically fix package.'); + return PackageResult.fail(); + } + return PackageResult.success(); + } +} diff --git a/script/tool/lib/src/main.dart b/script/tool/lib/src/main.dart index 078976d973..414ca7f303 100644 --- a/script/tool/lib/src/main.dart +++ b/script/tool/lib/src/main.dart @@ -17,6 +17,7 @@ import 'dependabot_check_command.dart'; import 'drive_examples_command.dart'; import 'federation_safety_check_command.dart'; import 'firebase_test_lab_command.dart'; +import 'fix_command.dart'; import 'format_command.dart'; import 'license_check_command.dart'; import 'lint_android_command.dart'; @@ -61,6 +62,7 @@ void main(List args) { ..addCommand(DriveExamplesCommand(packagesDir)) ..addCommand(FederationSafetyCheckCommand(packagesDir)) ..addCommand(FirebaseTestLabCommand(packagesDir)) + ..addCommand(FixCommand(packagesDir)) ..addCommand(FormatCommand(packagesDir)) ..addCommand(LicenseCheckCommand(packagesDir)) ..addCommand(LintAndroidCommand(packagesDir)) diff --git a/script/tool/test/fix_command_test.dart b/script/tool/test/fix_command_test.dart new file mode 100644 index 0000000000..16061d2206 --- /dev/null +++ b/script/tool/test/fix_command_test.dart @@ -0,0 +1,78 @@ +// Copyright 2013 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:io' as io; + +import 'package:args/command_runner.dart'; +import 'package:file/file.dart'; +import 'package:file/memory.dart'; +import 'package:flutter_plugin_tools/src/common/core.dart'; +import 'package:flutter_plugin_tools/src/fix_command.dart'; +import 'package:test/test.dart'; + +import 'mocks.dart'; +import 'util.dart'; + +void main() { + late FileSystem fileSystem; + late MockPlatform mockPlatform; + late Directory packagesDir; + late RecordingProcessRunner processRunner; + late CommandRunner runner; + + setUp(() { + fileSystem = MemoryFileSystem(); + mockPlatform = MockPlatform(); + packagesDir = createPackagesDirectory(fileSystem: fileSystem); + processRunner = RecordingProcessRunner(); + final FixCommand command = FixCommand( + packagesDir, + processRunner: processRunner, + platform: mockPlatform, + ); + + runner = CommandRunner('fix_command', 'Test for fix_command'); + runner.addCommand(command); + }); + + test('runs fix in top-level packages and subpackages', () async { + final RepositoryPackage package = createFakePackage('a', packagesDir); + final RepositoryPackage plugin = createFakePlugin('b', packagesDir); + + await runCapturingPrint(runner, ['fix']); + + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('dart', const ['fix', '--apply'], package.path), + ProcessCall('dart', const ['fix', '--apply'], + package.getExamples().first.path), + ProcessCall('dart', const ['fix', '--apply'], plugin.path), + ProcessCall('dart', const ['fix', '--apply'], + plugin.getExamples().first.path), + ])); + }); + + test('fails if "dart fix" fails', () async { + createFakePlugin('foo', packagesDir); + + processRunner.mockProcessesForExecutable['dart'] = [ + MockProcess(exitCode: 1), + ]; + + Error? commandError; + final List output = await runCapturingPrint(runner, ['fix'], + errorHandler: (Error e) { + commandError = e; + }); + + expect(commandError, isA()); + expect( + output, + containsAllInOrder([ + contains('Unable to automatically fix package.'), + ]), + ); + }); +}