mirror of
https://github.com/flutter/packages.git
synced 2025-08-16 04:30:37 +08:00
[flutter_plugin_tools] Improve license-check output (#4154)
Currently each type of check handles its output in isolation, which creates confusing output when the last check succeeds but an earlier check fails, since the end of the output will just be a success message. This makes the output follow the same basic approach as the package looper commands, where all failures are collected, and then a final summary is presented at the end, so the last message will always reflect the important details. It also adopts the colorized output now used by most other commands.
This commit is contained in:
@ -107,21 +107,65 @@ class LicenseCheckCommand extends PluginCommand {
|
||||
|
||||
@override
|
||||
Future<void> run() async {
|
||||
final Iterable<File> codeFiles = (await _getAllFiles()).where((File file) =>
|
||||
final Iterable<File> allFiles = await _getAllFiles();
|
||||
|
||||
final Iterable<File> codeFiles = allFiles.where((File file) =>
|
||||
_codeFileExtensions.contains(p.extension(file.path)) &&
|
||||
!_shouldIgnoreFile(file));
|
||||
final Iterable<File> firstPartyLicenseFiles = (await _getAllFiles()).where(
|
||||
(File file) =>
|
||||
path.basename(file.basename) == 'LICENSE' && !_isThirdParty(file));
|
||||
final Iterable<File> firstPartyLicenseFiles = allFiles.where((File file) =>
|
||||
path.basename(file.basename) == 'LICENSE' && !_isThirdParty(file));
|
||||
|
||||
final bool copyrightCheckSucceeded = await _checkCodeLicenses(codeFiles);
|
||||
print('\n=======================================\n');
|
||||
final bool licenseCheckSucceeded =
|
||||
final List<File> licenseFileFailures =
|
||||
await _checkLicenseFiles(firstPartyLicenseFiles);
|
||||
final Map<_LicenseFailureType, List<File>> codeFileFailures =
|
||||
await _checkCodeLicenses(codeFiles);
|
||||
|
||||
if (!copyrightCheckSucceeded || !licenseCheckSucceeded) {
|
||||
bool passed = true;
|
||||
|
||||
print('\n=======================================\n');
|
||||
|
||||
if (licenseFileFailures.isNotEmpty) {
|
||||
passed = false;
|
||||
printError(
|
||||
'The following LICENSE files do not follow the expected format:');
|
||||
for (final File file in licenseFileFailures) {
|
||||
printError(' ${file.path}');
|
||||
}
|
||||
printError('Please ensure that they use the exact format used in this '
|
||||
'repository".\n');
|
||||
}
|
||||
|
||||
if (codeFileFailures[_LicenseFailureType.incorrectFirstParty]!.isNotEmpty) {
|
||||
passed = false;
|
||||
printError('The license block for these files is missing or incorrect:');
|
||||
for (final File file
|
||||
in codeFileFailures[_LicenseFailureType.incorrectFirstParty]!) {
|
||||
printError(' ${file.path}');
|
||||
}
|
||||
printError(
|
||||
'If this third-party code, move it to a "third_party/" directory, '
|
||||
'otherwise ensure that you are using the exact copyright and license '
|
||||
'text used by all first-party files in this repository.\n');
|
||||
}
|
||||
|
||||
if (codeFileFailures[_LicenseFailureType.unknownThirdParty]!.isNotEmpty) {
|
||||
passed = false;
|
||||
printError(
|
||||
'No recognized license was found for the following third-party files:');
|
||||
for (final File file
|
||||
in codeFileFailures[_LicenseFailureType.unknownThirdParty]!) {
|
||||
printError(' ${file.path}');
|
||||
}
|
||||
print('Please check that they have a license at the top of the file. '
|
||||
'If they do, the license check needs to be updated to recognize '
|
||||
'the new third-party license block.\n');
|
||||
}
|
||||
|
||||
if (!passed) {
|
||||
throw ToolExit(1);
|
||||
}
|
||||
|
||||
printSuccess('All files passed validation!');
|
||||
}
|
||||
|
||||
// Creates the expected copyright+license block for first-party code.
|
||||
@ -135,9 +179,10 @@ class LicenseCheckCommand extends PluginCommand {
|
||||
'${comment}found in the LICENSE file.$suffix\n';
|
||||
}
|
||||
|
||||
// Checks all license blocks for [codeFiles], returning false if any of them
|
||||
// fail validation.
|
||||
Future<bool> _checkCodeLicenses(Iterable<File> codeFiles) async {
|
||||
/// Checks all license blocks for [codeFiles], returning any that fail
|
||||
/// validation.
|
||||
Future<Map<_LicenseFailureType, List<File>>> _checkCodeLicenses(
|
||||
Iterable<File> codeFiles) async {
|
||||
final List<File> incorrectFirstPartyFiles = <File>[];
|
||||
final List<File> unrecognizedThirdPartyFiles = <File>[];
|
||||
|
||||
@ -171,7 +216,6 @@ class LicenseCheckCommand extends PluginCommand {
|
||||
}
|
||||
}
|
||||
}
|
||||
print('\n');
|
||||
|
||||
// Sort by path for more usable output.
|
||||
final int Function(File, File) pathCompare =
|
||||
@ -179,38 +223,14 @@ class LicenseCheckCommand extends PluginCommand {
|
||||
incorrectFirstPartyFiles.sort(pathCompare);
|
||||
unrecognizedThirdPartyFiles.sort(pathCompare);
|
||||
|
||||
if (incorrectFirstPartyFiles.isNotEmpty) {
|
||||
print('The license block for these files is missing or incorrect:');
|
||||
for (final File file in incorrectFirstPartyFiles) {
|
||||
print(' ${file.path}');
|
||||
}
|
||||
print('If this third-party code, move it to a "third_party/" directory, '
|
||||
'otherwise ensure that you are using the exact copyright and license '
|
||||
'text used by all first-party files in this repository.\n');
|
||||
}
|
||||
|
||||
if (unrecognizedThirdPartyFiles.isNotEmpty) {
|
||||
print(
|
||||
'No recognized license was found for the following third-party files:');
|
||||
for (final File file in unrecognizedThirdPartyFiles) {
|
||||
print(' ${file.path}');
|
||||
}
|
||||
print('Please check that they have a license at the top of the file. '
|
||||
'If they do, the license check needs to be updated to recognize '
|
||||
'the new third-party license block.\n');
|
||||
}
|
||||
|
||||
final bool succeeded =
|
||||
incorrectFirstPartyFiles.isEmpty && unrecognizedThirdPartyFiles.isEmpty;
|
||||
if (succeeded) {
|
||||
print('All source files passed validation!');
|
||||
}
|
||||
return succeeded;
|
||||
return <_LicenseFailureType, List<File>>{
|
||||
_LicenseFailureType.incorrectFirstParty: incorrectFirstPartyFiles,
|
||||
_LicenseFailureType.unknownThirdParty: unrecognizedThirdPartyFiles,
|
||||
};
|
||||
}
|
||||
|
||||
// Checks all provide LICENSE files, returning false if any of them
|
||||
// fail validation.
|
||||
Future<bool> _checkLicenseFiles(Iterable<File> files) async {
|
||||
/// Checks all provided LICENSE [files], returning any that fail validation.
|
||||
Future<List<File>> _checkLicenseFiles(Iterable<File> files) async {
|
||||
final List<File> incorrectLicenseFiles = <File>[];
|
||||
|
||||
for (final File file in files) {
|
||||
@ -219,22 +239,8 @@ class LicenseCheckCommand extends PluginCommand {
|
||||
incorrectLicenseFiles.add(file);
|
||||
}
|
||||
}
|
||||
print('\n');
|
||||
|
||||
if (incorrectLicenseFiles.isNotEmpty) {
|
||||
print('The following LICENSE files do not follow the expected format:');
|
||||
for (final File file in incorrectLicenseFiles) {
|
||||
print(' ${file.path}');
|
||||
}
|
||||
print(
|
||||
'Please ensure that they use the exact format used in this repository".\n');
|
||||
}
|
||||
|
||||
final bool succeeded = incorrectLicenseFiles.isEmpty;
|
||||
if (succeeded) {
|
||||
print('All LICENSE files passed validation!');
|
||||
}
|
||||
return succeeded;
|
||||
return incorrectLicenseFiles;
|
||||
}
|
||||
|
||||
bool _shouldIgnoreFile(File file) {
|
||||
@ -255,3 +261,5 @@ class LicenseCheckCommand extends PluginCommand {
|
||||
.map((FileSystemEntity file) => file as File)
|
||||
.toList();
|
||||
}
|
||||
|
||||
enum _LicenseFailureType { incorrectFirstParty, unknownThirdParty }
|
||||
|
Reference in New Issue
Block a user