Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit 714339b

Browse files
Migrate command, add failure test, remove skip (#4106)
Switches `podspec` to the new base command that handles the boilerplate of looping over target packages. Includes test improvements: - Adds failure tests; previously no failure cases were covered. - Captures output using the standard mechanism instead of using a custom `_print`, simplifying the command code. Also removes `--skip`, which is redundant with `--exclude`. Part of flutter/flutter#83413
1 parent bc4ac59 commit 714339b

File tree

4 files changed

+87
-70
lines changed

4 files changed

+87
-70
lines changed

script/tool/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
- **Breaking change**: it now requires an `--ios` and/or `--macos` flag.
88
- The tooling now runs in strong null-safe mode.
99
- `publish plugins` check against pub.dev to determine if a release should happen.
10-
- Modified the output format of `pubspec-check` and `xctest`
10+
- Modified the output format of many commands
11+
- Removed `podspec`'s `--skip` in favor of `--ignore` using the new structure.
1112

1213
## 0.2.0
1314

script/tool/lib/src/common/plugin_command.dart

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,10 +250,16 @@ abstract class PluginCommand extends Command<void> {
250250
/// Returns the files contained, recursively, within the plugins
251251
/// involved in this command execution.
252252
Stream<File> getFiles() {
253-
return getPlugins().asyncExpand<File>((Directory folder) => folder
253+
return getPlugins()
254+
.asyncExpand<File>((Directory folder) => getFilesForPackage(folder));
255+
}
256+
257+
/// Returns the files contained, recursively, within [package].
258+
Stream<File> getFilesForPackage(Directory package) {
259+
return package
254260
.list(recursive: true, followLinks: false)
255261
.where((FileSystemEntity entity) => entity is File)
256-
.cast<File>());
262+
.cast<File>();
257263
}
258264

259265
/// Returns whether the specified entity is a directory containing a

script/tool/lib/src/lint_podspecs_command.dart

Lines changed: 26 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -10,29 +10,26 @@ import 'package:path/path.dart' as p;
1010
import 'package:platform/platform.dart';
1111

1212
import 'common/core.dart';
13-
import 'common/plugin_command.dart';
13+
import 'common/package_looping_command.dart';
1414
import 'common/process_runner.dart';
1515

16+
const int _exitUnsupportedPlatform = 2;
17+
1618
/// Lint the CocoaPod podspecs and run unit tests.
1719
///
1820
/// See https://guides.cocoapods.org/terminal/commands.html#pod_lib_lint.
19-
class LintPodspecsCommand extends PluginCommand {
21+
class LintPodspecsCommand extends PackageLoopingCommand {
2022
/// Creates an instance of the linter command.
2123
LintPodspecsCommand(
2224
Directory packagesDir, {
2325
ProcessRunner processRunner = const ProcessRunner(),
2426
Platform platform = const LocalPlatform(),
25-
Print print = print,
2627
}) : _platform = platform,
27-
_print = print,
2828
super(packagesDir, processRunner: processRunner) {
29-
argParser.addMultiOption('skip',
30-
help:
31-
'Skip all linting for podspecs with this basename (example: federated plugins with placeholder podspecs)',
32-
valueHelp: 'podspec_file_name');
3329
argParser.addMultiOption('ignore-warnings',
3430
help:
35-
'Do not pass --allow-warnings flag to "pod lib lint" for podspecs with this basename (example: plugins with known warnings)',
31+
'Do not pass --allow-warnings flag to "pod lib lint" for podspecs '
32+
'with this basename (example: plugins with known warnings)',
3633
valueHelp: 'podspec_file_name');
3734
}
3835

@@ -49,13 +46,11 @@ class LintPodspecsCommand extends PluginCommand {
4946

5047
final Platform _platform;
5148

52-
final Print _print;
53-
5449
@override
55-
Future<void> run() async {
50+
Future<void> initializeRun() async {
5651
if (!_platform.isMacOS) {
57-
_print('Detected platform is not macOS, skipping podspec lint');
58-
return;
52+
printError('This command is only supported on macOS');
53+
throw ToolExit(_exitUnsupportedPlatform);
5954
}
6055

6156
await processRunner.run(
@@ -65,32 +60,24 @@ class LintPodspecsCommand extends PluginCommand {
6560
exitOnError: true,
6661
logOnError: true,
6762
);
63+
}
6864

69-
_print('Starting podspec lint test');
70-
71-
final List<String> failingPlugins = <String>[];
72-
for (final File podspec in await _podspecsToLint()) {
65+
@override
66+
Future<List<String>> runForPackage(Directory package) async {
67+
final List<String> errors = <String>[];
68+
for (final File podspec in await _podspecsToLint(package)) {
7369
if (!await _lintPodspec(podspec)) {
74-
failingPlugins.add(p.basenameWithoutExtension(podspec.path));
75-
}
76-
}
77-
78-
_print('\n\n');
79-
if (failingPlugins.isNotEmpty) {
80-
_print('The following plugins have podspec errors (see above):');
81-
for (final String plugin in failingPlugins) {
82-
_print(' * $plugin');
70+
errors.add(p.basename(podspec.path));
8371
}
84-
throw ToolExit(1);
8572
}
73+
return errors;
8674
}
8775

88-
Future<List<File>> _podspecsToLint() async {
89-
final List<File> podspecs = await getFiles().where((File entity) {
76+
Future<List<File>> _podspecsToLint(Directory package) async {
77+
final List<File> podspecs =
78+
await getFilesForPackage(package).where((File entity) {
9079
final String filePath = entity.path;
91-
return p.extension(filePath) == '.podspec' &&
92-
!getStringListArg('skip')
93-
.contains(p.basenameWithoutExtension(filePath));
80+
return p.extension(filePath) == '.podspec';
9481
}).toList();
9582

9683
podspecs.sort(
@@ -103,19 +90,19 @@ class LintPodspecsCommand extends PluginCommand {
10390
final String podspecPath = podspec.path;
10491

10592
final String podspecBasename = p.basename(podspecPath);
106-
_print('Linting $podspecBasename');
93+
print('Linting $podspecBasename');
10794

10895
// Lint plugin as framework (use_frameworks!).
10996
final ProcessResult frameworkResult =
11097
await _runPodLint(podspecPath, libraryLint: true);
111-
_print(frameworkResult.stdout);
112-
_print(frameworkResult.stderr);
98+
print(frameworkResult.stdout);
99+
print(frameworkResult.stderr);
113100

114101
// Lint plugin as library.
115102
final ProcessResult libraryResult =
116103
await _runPodLint(podspecPath, libraryLint: false);
117-
_print(libraryResult.stdout);
118-
_print(libraryResult.stderr);
104+
print(libraryResult.stdout);
105+
print(libraryResult.stderr);
119106

120107
return frameworkResult.exitCode == 0 && libraryResult.exitCode == 0;
121108
}
@@ -135,7 +122,7 @@ class LintPodspecsCommand extends PluginCommand {
135122
if (libraryLint) '--use-libraries'
136123
];
137124

138-
_print('Running "pod ${arguments.join(' ')}"');
125+
print('Running "pod ${arguments.join(' ')}"');
139126
return processRunner.run('pod', arguments,
140127
workingDir: packagesDir, stdoutEncoding: utf8, stderrEncoding: utf8);
141128
}

script/tool/test/lint_podspecs_command_test.dart

Lines changed: 51 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import 'package:args/command_runner.dart';
66
import 'package:file/file.dart';
77
import 'package:file/memory.dart';
8+
import 'package:flutter_plugin_tools/src/common/core.dart';
89
import 'package:flutter_plugin_tools/src/lint_podspecs_command.dart';
910
import 'package:path/path.dart' as p;
1011
import 'package:test/test.dart';
@@ -19,20 +20,17 @@ void main() {
1920
late CommandRunner<void> runner;
2021
late MockPlatform mockPlatform;
2122
late RecordingProcessRunner processRunner;
22-
late List<String> printedMessages;
2323

2424
setUp(() {
2525
fileSystem = MemoryFileSystem();
2626
packagesDir = createPackagesDirectory(fileSystem: fileSystem);
2727

28-
printedMessages = <String>[];
2928
mockPlatform = MockPlatform(isMacOS: true);
3029
processRunner = RecordingProcessRunner();
3130
final LintPodspecsCommand command = LintPodspecsCommand(
3231
packagesDir,
3332
processRunner: processRunner,
3433
platform: mockPlatform,
35-
print: (Object? message) => printedMessages.add(message.toString()),
3634
);
3735

3836
runner =
@@ -47,14 +45,26 @@ void main() {
4745
test('only runs on macOS', () async {
4846
createFakePlugin('plugin1', packagesDir,
4947
extraFiles: <String>['plugin1.podspec']);
50-
5148
mockPlatform.isMacOS = false;
52-
await runner.run(<String>['podspecs']);
49+
50+
Error? commandError;
51+
final List<String> output = await runCapturingPrint(
52+
runner, <String>['podspecs'], errorHandler: (Error e) {
53+
commandError = e;
54+
});
55+
56+
expect(commandError, isA<ToolExit>());
5357

5458
expect(
5559
processRunner.recordedCalls,
5660
equals(<ProcessCall>[]),
5761
);
62+
63+
expect(
64+
output,
65+
containsAllInOrder(
66+
<Matcher>[contains('only supported on macOS')],
67+
));
5868
});
5969

6070
test('runs pod lib lint on a podspec', () async {
@@ -70,7 +80,8 @@ void main() {
7080
processRunner.resultStdout = 'Foo';
7181
processRunner.resultStderr = 'Bar';
7282

73-
await runner.run(<String>['podspecs']);
83+
final List<String> output =
84+
await runCapturingPrint(runner, <String>['podspecs']);
7485

7586
expect(
7687
processRunner.recordedCalls,
@@ -102,33 +113,17 @@ void main() {
102113
]),
103114
);
104115

105-
expect(printedMessages, contains('Linting plugin1.podspec'));
106-
expect(printedMessages, contains('Foo'));
107-
expect(printedMessages, contains('Bar'));
108-
});
109-
110-
test('skips podspecs with known issues', () async {
111-
createFakePlugin('plugin1', packagesDir,
112-
extraFiles: <String>['plugin1.podspec']);
113-
createFakePlugin('plugin2', packagesDir,
114-
extraFiles: <String>['plugin2.podspec']);
115-
116-
await runner
117-
.run(<String>['podspecs', '--skip=plugin1', '--skip=plugin2']);
118-
119-
expect(
120-
processRunner.recordedCalls,
121-
orderedEquals(<ProcessCall>[
122-
ProcessCall('which', const <String>['pod'], packagesDir.path),
123-
]),
124-
);
116+
expect(output, contains('Linting plugin1.podspec'));
117+
expect(output, contains('Foo'));
118+
expect(output, contains('Bar'));
125119
});
126120

127121
test('allow warnings for podspecs with known warnings', () async {
128122
final Directory plugin1Dir = createFakePlugin('plugin1', packagesDir,
129123
extraFiles: <String>['plugin1.podspec']);
130124

131-
await runner.run(<String>['podspecs', '--ignore-warnings=plugin1']);
125+
final List<String> output = await runCapturingPrint(
126+
runner, <String>['podspecs', '--ignore-warnings=plugin1']);
132127

133128
expect(
134129
processRunner.recordedCalls,
@@ -162,7 +157,35 @@ void main() {
162157
]),
163158
);
164159

165-
expect(printedMessages, contains('Linting plugin1.podspec'));
160+
expect(output, contains('Linting plugin1.podspec'));
161+
});
162+
163+
test('fails if linting fails', () async {
164+
createFakePlugin('plugin1', packagesDir,
165+
extraFiles: <String>['plugin1.podspec']);
166+
167+
// Simulate failure from `pod`.
168+
final MockProcess mockDriveProcess = MockProcess();
169+
mockDriveProcess.exitCodeCompleter.complete(1);
170+
processRunner.processToReturn = mockDriveProcess;
171+
172+
Error? commandError;
173+
final List<String> output = await runCapturingPrint(
174+
runner, <String>['podspecs'], errorHandler: (Error e) {
175+
commandError = e;
176+
});
177+
178+
expect(commandError, isA<ToolExit>());
179+
180+
expect(
181+
output,
182+
containsAllInOrder(
183+
<Matcher>[
184+
contains('The following packages had errors:'),
185+
contains('plugin1:\n'
186+
' plugin1.podspec')
187+
],
188+
));
166189
});
167190
});
168191
}

0 commit comments

Comments
 (0)