[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:
stuartmorgan
2021-07-13 13:25:41 -07:00
committed by GitHub
parent 5f7735d16c
commit ca5e753486
3 changed files with 175 additions and 98 deletions

View File

@ -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 }