mirror of
https://github.com/flutter/packages.git
synced 2025-06-05 19:17:51 +08:00
Fix cosmetic variations in copyrights and license files (#3730)
- Replaces "the Flutter project authors" with the repo-standard version "The Flutter Authors" - Updates the license check not to allow "the Flutter project authors" in the future - Fixes a few minor cosmetic variations that had crept back into LICENSE files since my mass-standardization of those files. - Updates the license check to validate those to prevent such drift in the future.
This commit is contained in:
@ -66,9 +66,40 @@ final List<String> _firstPartyAuthors = <String>[
|
||||
'The Chromium Authors',
|
||||
'the Chromium project authors',
|
||||
'The Flutter Authors',
|
||||
'the Flutter project authors',
|
||||
];
|
||||
|
||||
// The exact format of the BSD license that our license files should contain.
|
||||
// Slight variants are not accepted because they may prevent consolidation in
|
||||
// tools that assemble all licenses used in distributed applications.
|
||||
//
|
||||
// TODO(stuartmorgan): Add the copyright string here once that's completely
|
||||
// standardized.
|
||||
final String _fullBsdLicenseText = '''
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
''';
|
||||
|
||||
/// Validates that code files have copyright and license blocks.
|
||||
class LicenseCheckCommand extends PluginCommand {
|
||||
/// Creates a new license check command for [packagesDir].
|
||||
@ -90,13 +121,19 @@ class LicenseCheckCommand extends PluginCommand {
|
||||
|
||||
@override
|
||||
Future<Null> run() async {
|
||||
Iterable<File> codeFiles = (await _getAllFiles()).where((File file) =>
|
||||
final Iterable<File> codeFiles = (await _getAllFiles()).where((File file) =>
|
||||
_codeFileExtensions.contains(p.extension(file.path)) &&
|
||||
!_shouldIgnoreFile(file));
|
||||
final Iterable<File> firstPartyLicenseFiles = (await _getAllFiles()).where(
|
||||
(File file) =>
|
||||
p.basename(file.basename) == 'LICENSE' && !_isThirdParty(file));
|
||||
|
||||
bool succeeded = await _checkLicenses(codeFiles);
|
||||
final bool copyrightCheckSucceeded = await _checkCodeLicenses(codeFiles);
|
||||
print('\n=======================================\n');
|
||||
final bool licenseCheckSucceeded =
|
||||
await _checkLicenseFiles(firstPartyLicenseFiles);
|
||||
|
||||
if (!succeeded) {
|
||||
if (!copyrightCheckSucceeded || !licenseCheckSucceeded) {
|
||||
throw ToolExit(1);
|
||||
}
|
||||
}
|
||||
@ -110,7 +147,7 @@ class LicenseCheckCommand extends PluginCommand {
|
||||
|
||||
// Checks all license blocks for [codeFiles], returning false if any of them
|
||||
// fail validation.
|
||||
Future<bool> _checkLicenses(Iterable<File> codeFiles) async {
|
||||
Future<bool> _checkCodeLicenses(Iterable<File> codeFiles) async {
|
||||
final List<File> filesWithoutDetectedCopyright = <File>[];
|
||||
final List<File> filesWithoutDetectedLicense = <File>[];
|
||||
final List<File> misplacedThirdPartyFiles = <File>[];
|
||||
@ -133,8 +170,7 @@ class LicenseCheckCommand extends PluginCommand {
|
||||
continue;
|
||||
}
|
||||
final String author = copyright.group(1);
|
||||
if (!_firstPartyAuthors.contains(author) &&
|
||||
!p.split(file.path).contains('third_party')) {
|
||||
if (!_firstPartyAuthors.contains(author) && !_isThirdParty(file)) {
|
||||
misplacedThirdPartyFiles.add(file);
|
||||
}
|
||||
|
||||
@ -146,7 +182,7 @@ class LicenseCheckCommand extends PluginCommand {
|
||||
filesWithoutDetectedLicense.add(file);
|
||||
}
|
||||
}
|
||||
_print('\n\n');
|
||||
_print('\n');
|
||||
|
||||
// Sort by path for more usable output.
|
||||
final pathCompare = (File a, File b) => a.path.compareTo(b.path);
|
||||
@ -188,7 +224,35 @@ class LicenseCheckCommand extends PluginCommand {
|
||||
filesWithoutDetectedLicense.isEmpty &&
|
||||
misplacedThirdPartyFiles.isEmpty;
|
||||
if (succeeded) {
|
||||
_print('All files passed validation!');
|
||||
_print('All source files passed validation!');
|
||||
}
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
// Checks all provide LICENSE files, returning false if any of them
|
||||
// fail validation.
|
||||
Future<bool> _checkLicenseFiles(Iterable<File> files) async {
|
||||
final List<File> incorrectLicenseFiles = <File>[];
|
||||
|
||||
for (final File file in files) {
|
||||
_print('Checking ${file.path}');
|
||||
if (!file.readAsStringSync().contains(_fullBsdLicenseText)) {
|
||||
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');
|
||||
}
|
||||
|
||||
bool succeeded = incorrectLicenseFiles.isEmpty;
|
||||
if (succeeded) {
|
||||
_print('All LICENSE files passed validation!');
|
||||
}
|
||||
return succeeded;
|
||||
}
|
||||
@ -201,6 +265,10 @@ class LicenseCheckCommand extends PluginCommand {
|
||||
_ignoredFullBasenameList.contains(p.basename(path)));
|
||||
}
|
||||
|
||||
bool _isThirdParty(File file) {
|
||||
return p.split(file.path).contains('third_party');
|
||||
}
|
||||
|
||||
Future<List<File>> _getAllFiles() => packagesDir.parent
|
||||
.list(recursive: true, followLinks: false)
|
||||
.where((FileSystemEntity entity) => entity is File)
|
||||
|
@ -134,7 +134,7 @@ void main() {
|
||||
|
||||
// Sanity check that the test did actually check a file.
|
||||
expect(printedMessages, contains('Checking checked.cc'));
|
||||
expect(printedMessages, contains('All files passed validation!'));
|
||||
expect(printedMessages, contains('All source files passed validation!'));
|
||||
});
|
||||
|
||||
test('handles the comment styles for all supported languages', () async {
|
||||
@ -154,7 +154,7 @@ void main() {
|
||||
expect(printedMessages, contains('Checking file_a.cc'));
|
||||
expect(printedMessages, contains('Checking file_b.sh'));
|
||||
expect(printedMessages, contains('Checking file_c.html'));
|
||||
expect(printedMessages, contains('All files passed validation!'));
|
||||
expect(printedMessages, contains('All source files passed validation!'));
|
||||
});
|
||||
|
||||
test('fails if any checked files are missing license blocks', () async {
|
||||
@ -176,7 +176,8 @@ void main() {
|
||||
expect(printedMessages, contains(' bad.cc'));
|
||||
expect(printedMessages, contains(' bad.h'));
|
||||
// Failure shouldn't print the success message.
|
||||
expect(printedMessages, isNot(contains('All files passed validation!')));
|
||||
expect(printedMessages,
|
||||
isNot(contains('All source files passed validation!')));
|
||||
});
|
||||
|
||||
test('fails if any checked files are missing just the copyright', () async {
|
||||
@ -195,7 +196,8 @@ void main() {
|
||||
contains('No copyright line was found for the following files:'));
|
||||
expect(printedMessages, contains(' bad.cc'));
|
||||
// Failure shouldn't print the success message.
|
||||
expect(printedMessages, isNot(contains('All files passed validation!')));
|
||||
expect(printedMessages,
|
||||
isNot(contains('All source files passed validation!')));
|
||||
});
|
||||
|
||||
test('fails if any checked files are missing just the license', () async {
|
||||
@ -214,7 +216,8 @@ void main() {
|
||||
contains('No recognized license was found for the following files:'));
|
||||
expect(printedMessages, contains(' bad.cc'));
|
||||
// Failure shouldn't print the success message.
|
||||
expect(printedMessages, isNot(contains('All files passed validation!')));
|
||||
expect(printedMessages,
|
||||
isNot(contains('All source files passed validation!')));
|
||||
});
|
||||
|
||||
test('fails if any third-party code is not in a third_party directory',
|
||||
@ -234,7 +237,8 @@ void main() {
|
||||
'but are not in a "third_party/" directory:'));
|
||||
expect(printedMessages, contains(' third_party.cc'));
|
||||
// Failure shouldn't print the success message.
|
||||
expect(printedMessages, isNot(contains('All files passed validation!')));
|
||||
expect(printedMessages,
|
||||
isNot(contains('All source files passed validation!')));
|
||||
});
|
||||
|
||||
test('succeeds for third-party code in a third_party directory', () async {
|
||||
@ -252,7 +256,7 @@ void main() {
|
||||
// Sanity check that the test did actually check the file.
|
||||
expect(printedMessages,
|
||||
contains('Checking a_plugin/lib/src/third_party/file.cc'));
|
||||
expect(printedMessages, contains('All files passed validation!'));
|
||||
expect(printedMessages, contains('All source files passed validation!'));
|
||||
});
|
||||
|
||||
test('fails for licenses that the tool does not expect', () async {
|
||||
@ -274,7 +278,8 @@ void main() {
|
||||
contains('No recognized license was found for the following files:'));
|
||||
expect(printedMessages, contains(' third_party/bad.cc'));
|
||||
// Failure shouldn't print the success message.
|
||||
expect(printedMessages, isNot(contains('All files passed validation!')));
|
||||
expect(printedMessages,
|
||||
isNot(contains('All source files passed validation!')));
|
||||
});
|
||||
|
||||
test('Apache is not recognized for new authors without validation changes',
|
||||
@ -300,7 +305,107 @@ void main() {
|
||||
contains('No recognized license was found for the following files:'));
|
||||
expect(printedMessages, contains(' third_party/bad.cc'));
|
||||
// Failure shouldn't print the success message.
|
||||
expect(printedMessages, isNot(contains('All files passed validation!')));
|
||||
expect(printedMessages,
|
||||
isNot(contains('All source files passed validation!')));
|
||||
});
|
||||
|
||||
test('passes if all first-party LICENSE files are correctly formatted',
|
||||
() async {
|
||||
File license = root.childFile('LICENSE');
|
||||
license.createSync();
|
||||
license.writeAsStringSync(_correctLicenseFileText);
|
||||
|
||||
await runner.run(<String>['license-check']);
|
||||
|
||||
// Sanity check that the test did actually check the file.
|
||||
expect(printedMessages, contains('Checking LICENSE'));
|
||||
expect(printedMessages, contains('All LICENSE files passed validation!'));
|
||||
});
|
||||
|
||||
test('fails if any first-party LICENSE files are incorrectly formatted',
|
||||
() async {
|
||||
File license = root.childFile('LICENSE');
|
||||
license.createSync();
|
||||
license.writeAsStringSync(_incorrectLicenseFileText);
|
||||
|
||||
await expectLater(() => runner.run(<String>['license-check']),
|
||||
throwsA(const TypeMatcher<ToolExit>()));
|
||||
|
||||
expect(printedMessages,
|
||||
isNot(contains('All LICENSE files passed validation!')));
|
||||
});
|
||||
|
||||
test('ignores third-party LICENSE format',
|
||||
() async {
|
||||
File license = root.childDirectory('third_party').childFile('LICENSE');
|
||||
license.createSync(recursive: true);
|
||||
license.writeAsStringSync(_incorrectLicenseFileText);
|
||||
|
||||
await runner.run(<String>['license-check']);
|
||||
|
||||
// The file shouldn't be checked.
|
||||
expect(printedMessages, isNot(contains('Checking third_party/LICENSE')));
|
||||
expect(printedMessages, contains('All LICENSE files passed validation!'));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const String _correctLicenseFileText =
|
||||
'''Copyright 2017 The Flutter Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
''';
|
||||
|
||||
// A common incorrect version created by copying text intended for a code file,
|
||||
// with comment markers.
|
||||
const String _incorrectLicenseFileText =
|
||||
'''// Copyright 2017 The Flutter Authors. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
''';
|
||||
|
Reference in New Issue
Block a user