mirror of
https://github.com/flutter/packages.git
synced 2025-07-02 08:34:31 +08:00
[ci] Run Swift formatter and linter during CI formatting (#5928)
Make `swift-format` CIPD package available on the `PATH` https://flutter-review.googlesource.com/c/recipes/+/54020 Run `format --no-clang-format --no-java --no-kotlin --no-dart` on the macOS builder so it doesn't duplicate same `format` call run on Linux. Filter out generated files until https://github.com/flutter/flutter/issues/141799 is done. Also add `swift-format lint` call during `format` command. Fix the one casing issue it found in a test file. Failing run: https://logs.chromium.org/logs/flutter/buildbucket/cr-buildbucket/8758535881172004177/+/u/Run_package_tests/Swift_format/stdout Successful run: https://logs.chromium.org/logs/flutter/buildbucket/cr-buildbucket/8758492350529121249/+/u/Run_package_tests/Swift_format/stdout Fixes https://github.com/flutter/flutter/issues/41129
This commit is contained in:
@ -54,7 +54,8 @@ class FormatCommand extends PackageCommand {
|
||||
argParser.addFlag(_kotlinArg,
|
||||
help: 'Format Kotlin files', defaultsTo: true);
|
||||
argParser.addFlag(_javaArg, help: 'Format Java files', defaultsTo: true);
|
||||
argParser.addFlag(_swiftArg, help: 'Format Swift files');
|
||||
argParser.addFlag(_swiftArg,
|
||||
help: 'Format and lint Swift files', defaultsTo: true);
|
||||
argParser.addOption(_clangFormatPathArg,
|
||||
defaultsTo: 'clang-format', help: 'Path to "clang-format" executable.');
|
||||
argParser.addOption(_javaPathArg,
|
||||
@ -105,7 +106,7 @@ class FormatCommand extends PackageCommand {
|
||||
await _formatCppAndObjectiveC(files);
|
||||
}
|
||||
if (getBoolArg(_swiftArg)) {
|
||||
await _formatSwift(files);
|
||||
await _formatAndLintSwift(files);
|
||||
}
|
||||
|
||||
if (getBoolArg('fail-on-change')) {
|
||||
@ -177,16 +178,32 @@ class FormatCommand extends PackageCommand {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _formatSwift(Iterable<String> files) async {
|
||||
final String swiftFormat = await _findValidSwiftFormat();
|
||||
final Iterable<String> swiftFiles =
|
||||
_getPathsWithExtensions(files, <String>{'.swift'});
|
||||
Future<void> _formatAndLintSwift(Iterable<String> files) async {
|
||||
// TODO(jmagman): Remove generated file filter when pigeon Swift generation matches swift-format.
|
||||
// https://github.com/flutter/flutter/issues/141799
|
||||
final Iterable<String> swiftFiles = _filterGeneratedFiles(
|
||||
_getPathsWithExtensions(files, <String>{'.swift'}));
|
||||
if (swiftFiles.isNotEmpty) {
|
||||
final String swiftFormat = await _findValidSwiftFormat();
|
||||
print('Formatting .swift files...');
|
||||
final int exitCode =
|
||||
final int formatExitCode =
|
||||
await _runBatched(swiftFormat, <String>['-i'], files: swiftFiles);
|
||||
if (exitCode != 0) {
|
||||
printError('Failed to format Swift files: exit code $exitCode.');
|
||||
if (formatExitCode != 0) {
|
||||
printError('Failed to format Swift files: exit code $formatExitCode.');
|
||||
throw ToolExit(_exitSwiftFormatFailed);
|
||||
}
|
||||
|
||||
print('Linting .swift files...');
|
||||
final int lintExitCode = await _runBatched(
|
||||
swiftFormat,
|
||||
<String>[
|
||||
'lint',
|
||||
'--parallel',
|
||||
'--strict',
|
||||
],
|
||||
files: swiftFiles);
|
||||
if (lintExitCode != 0) {
|
||||
printError('Failed to lint Swift files: exit code $lintExitCode.');
|
||||
throw ToolExit(_exitSwiftFormatFailed);
|
||||
}
|
||||
}
|
||||
@ -342,6 +359,13 @@ class FormatCommand extends PackageCommand {
|
||||
(String filePath) => extensions.contains(path.extension(filePath)));
|
||||
}
|
||||
|
||||
Iterable<String> _filterGeneratedFiles(Iterable<String> files) {
|
||||
return files.where((String filePath) {
|
||||
final String basename = path.basename(filePath);
|
||||
return !basename.contains('.gen.') && !basename.contains('.g.');
|
||||
});
|
||||
}
|
||||
|
||||
Future<String> _getJavaFormatterPath() async {
|
||||
final String javaFormatterPath = path.join(
|
||||
path.dirname(path.fromUri(platform.script)),
|
||||
|
@ -551,15 +551,45 @@ void main() {
|
||||
processRunner.recordedCalls,
|
||||
orderedEquals(<ProcessCall>[
|
||||
const ProcessCall(
|
||||
'/path/to/swift-format', <String>['--version'], null),
|
||||
'/path/to/swift-format',
|
||||
<String>['--version'],
|
||||
null,
|
||||
),
|
||||
ProcessCall(
|
||||
'/path/to/swift-format',
|
||||
<String>['-i', ...getPackagesDirRelativePaths(plugin, files)],
|
||||
packagesDir.path),
|
||||
'/path/to/swift-format',
|
||||
<String>['-i', ...getPackagesDirRelativePaths(plugin, files)],
|
||||
packagesDir.path,
|
||||
),
|
||||
ProcessCall(
|
||||
'/path/to/swift-format',
|
||||
<String>[
|
||||
'lint',
|
||||
'--parallel',
|
||||
'--strict',
|
||||
...getPackagesDirRelativePaths(plugin, files),
|
||||
],
|
||||
packagesDir.path,
|
||||
),
|
||||
]));
|
||||
});
|
||||
|
||||
test('skips Swift if --swift flag is not provided', () async {
|
||||
test('skips generated Swift files', () async {
|
||||
const List<String> files = <String>[
|
||||
'macos/foo.gen.swift',
|
||||
'macos/foo.g.swift',
|
||||
];
|
||||
createFakePlugin(
|
||||
'a_plugin',
|
||||
packagesDir,
|
||||
extraFiles: files,
|
||||
);
|
||||
|
||||
await runCapturingPrint(runner, <String>['format', '--swift']);
|
||||
|
||||
expect(processRunner.recordedCalls, orderedEquals(<ProcessCall>[]));
|
||||
});
|
||||
|
||||
test('skips Swift if --no-swift flag is provided', () async {
|
||||
const List<String> files = <String>[
|
||||
'macos/foo.swift',
|
||||
];
|
||||
@ -569,7 +599,7 @@ void main() {
|
||||
extraFiles: files,
|
||||
);
|
||||
|
||||
await runCapturingPrint(runner, <String>['format']);
|
||||
await runCapturingPrint(runner, <String>['format', '--no-swift']);
|
||||
|
||||
expect(processRunner.recordedCalls, orderedEquals(<ProcessCall>[]));
|
||||
});
|
||||
@ -601,6 +631,40 @@ void main() {
|
||||
]));
|
||||
});
|
||||
|
||||
test('fails if swift-format lint fails', () async {
|
||||
const List<String> files = <String>[
|
||||
'macos/foo.swift',
|
||||
];
|
||||
createFakePlugin('a_plugin', packagesDir, extraFiles: files);
|
||||
|
||||
processRunner.mockProcessesForExecutable['swift-format'] =
|
||||
<FakeProcessInfo>[
|
||||
FakeProcessInfo(MockProcess(),
|
||||
<String>['--version']), // check for working swift-format
|
||||
FakeProcessInfo(MockProcess(), <String>['-i']),
|
||||
FakeProcessInfo(MockProcess(exitCode: 1), <String>[
|
||||
'lint',
|
||||
'--parallel',
|
||||
'--strict',
|
||||
]),
|
||||
];
|
||||
Error? commandError;
|
||||
final List<String> output = await runCapturingPrint(runner, <String>[
|
||||
'format',
|
||||
'--swift',
|
||||
'--swift-format-path=swift-format'
|
||||
], errorHandler: (Error e) {
|
||||
commandError = e;
|
||||
});
|
||||
|
||||
expect(commandError, isA<ToolExit>());
|
||||
expect(
|
||||
output,
|
||||
containsAllInOrder(<Matcher>[
|
||||
contains('Failed to lint Swift files: exit code 1.'),
|
||||
]));
|
||||
});
|
||||
|
||||
test('fails if swift-format fails', () async {
|
||||
const List<String> files = <String>[
|
||||
'macos/foo.swift',
|
||||
|
Reference in New Issue
Block a user