From cbc6c9b27ba9f339d6c44817808a98c29084a85e Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Wed, 4 Oct 2023 14:41:30 +0100 Subject: [PATCH 01/69] feat: include hidden check licenses command --- .../packages/commands/check/check.dart | 38 +++++++++++++++++++ .../commands/check/commands/commands.dart | 1 + .../commands/check/commands/licenses.dart | 37 ++++++++++++++++++ lib/src/commands/packages/packages.dart | 2 + .../packages/commands/check/check_test.dart | 7 ++++ .../check/commands/licenses_test.dart | 7 ++++ 6 files changed, 92 insertions(+) create mode 100644 lib/src/commands/packages/commands/check/check.dart create mode 100644 lib/src/commands/packages/commands/check/commands/commands.dart create mode 100644 lib/src/commands/packages/commands/check/commands/licenses.dart create mode 100644 test/src/commands/packages/commands/check/check_test.dart create mode 100644 test/src/commands/packages/commands/check/commands/licenses_test.dart diff --git a/lib/src/commands/packages/commands/check/check.dart b/lib/src/commands/packages/commands/check/check.dart new file mode 100644 index 00000000..c831a546 --- /dev/null +++ b/lib/src/commands/packages/commands/check/check.dart @@ -0,0 +1,38 @@ +import 'package:args/args.dart'; +import 'package:args/command_runner.dart'; +import 'package:mason/mason.dart'; +import 'package:meta/meta.dart'; +import 'package:very_good_cli/src/commands/packages/commands/check/commands/commands.dart'; + +/// {@template packages_check_command} +/// `very_good packages check` command for checking packages. +/// {@endtemplate} +class PackagesCheckCommand extends Command { + /// {@macro packages_check_command} + PackagesCheckCommand({Logger? logger}) : _logger = logger ?? Logger() { + addSubcommand(PackagesCheckLicensesCommand(logger: _logger)); + } + + final Logger _logger; + + @override + String get description => 'Check packages in a Dart or Flutter project.'; + + @override + String get name => 'check'; + + @override + bool get hidden => true; + + /// [ArgResults] which can be overridden for testing. + @visibleForTesting + ArgResults? argResultOverrides; + + // ignore: unused_element + ArgResults get _argResults => argResultOverrides ?? argResults!; + + @override + Future run() async { + return ExitCode.success.code; + } +} diff --git a/lib/src/commands/packages/commands/check/commands/commands.dart b/lib/src/commands/packages/commands/check/commands/commands.dart new file mode 100644 index 00000000..0c391a64 --- /dev/null +++ b/lib/src/commands/packages/commands/check/commands/commands.dart @@ -0,0 +1 @@ +export 'licenses.dart'; diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart new file mode 100644 index 00000000..78ac3438 --- /dev/null +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -0,0 +1,37 @@ +import 'package:args/args.dart'; +import 'package:args/command_runner.dart'; +import 'package:mason/mason.dart'; +import 'package:meta/meta.dart'; + +/// {@template packages_check_licenses_command} +/// `very_good packages check licenses` command for checking packages licenses. +/// {@endtemplate} +class PackagesCheckLicensesCommand extends Command { + /// {@macro packages_check_licenses_command} + PackagesCheckLicensesCommand({Logger? logger}) : _logger = logger ?? Logger(); + + // ignore: unused_field + final Logger _logger; + + @override + String get description => + 'Check packages licenses in a Dart or Flutter project.'; + + @override + String get name => 'licenses'; + + @override + bool get hidden => true; + + /// [ArgResults] which can be overridden for testing. + @visibleForTesting + ArgResults? argResultOverrides; + + // ignore: unused_element + ArgResults get _argResults => argResultOverrides ?? argResults!; + + @override + Future run() async { + return ExitCode.success.code; + } +} diff --git a/lib/src/commands/packages/packages.dart b/lib/src/commands/packages/packages.dart index 7d849dbe..7afeec60 100644 --- a/lib/src/commands/packages/packages.dart +++ b/lib/src/commands/packages/packages.dart @@ -1,5 +1,6 @@ import 'package:args/command_runner.dart'; import 'package:mason/mason.dart'; +import 'package:very_good_cli/src/commands/packages/commands/check/check.dart'; import 'package:very_good_cli/src/commands/packages/commands/commands.dart'; /// {@template packages_command} @@ -9,6 +10,7 @@ class PackagesCommand extends Command { /// {@macro packages_command} PackagesCommand({Logger? logger}) { addSubcommand(PackagesGetCommand(logger: logger)); + addSubcommand(PackagesCheckCommand(logger: logger)); } @override diff --git a/test/src/commands/packages/commands/check/check_test.dart b/test/src/commands/packages/commands/check/check_test.dart new file mode 100644 index 00000000..2af78da7 --- /dev/null +++ b/test/src/commands/packages/commands/check/check_test.dart @@ -0,0 +1,7 @@ +import 'package:test/test.dart'; + +void main() { + test('check ...', () async { + // TODO: Implement test + }); +} diff --git a/test/src/commands/packages/commands/check/commands/licenses_test.dart b/test/src/commands/packages/commands/check/commands/licenses_test.dart new file mode 100644 index 00000000..cd6d4413 --- /dev/null +++ b/test/src/commands/packages/commands/check/commands/licenses_test.dart @@ -0,0 +1,7 @@ +import 'package:test/test.dart'; + +void main() { + test('licenses ...', () async { + // TODO: Implement test + }); +} From bd6e631d85e80d52f31e418627d3c519fc87f162 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Thu, 5 Oct 2023 09:17:05 +0100 Subject: [PATCH 02/69] coverage --- .../packages/commands/check/check.dart | 12 ----- .../commands/check/commands/licenses.dart | 9 ---- .../packages/commands/check/check_test.dart | 48 ++++++++++++++++- .../check/commands/licenses_test.dart | 53 ++++++++++++++++++- 4 files changed, 97 insertions(+), 25 deletions(-) diff --git a/lib/src/commands/packages/commands/check/check.dart b/lib/src/commands/packages/commands/check/check.dart index c831a546..5204fd94 100644 --- a/lib/src/commands/packages/commands/check/check.dart +++ b/lib/src/commands/packages/commands/check/check.dart @@ -23,16 +23,4 @@ class PackagesCheckCommand extends Command { @override bool get hidden => true; - - /// [ArgResults] which can be overridden for testing. - @visibleForTesting - ArgResults? argResultOverrides; - - // ignore: unused_element - ArgResults get _argResults => argResultOverrides ?? argResults!; - - @override - Future run() async { - return ExitCode.success.code; - } } diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index 78ac3438..ef89e0c9 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -1,7 +1,5 @@ -import 'package:args/args.dart'; import 'package:args/command_runner.dart'; import 'package:mason/mason.dart'; -import 'package:meta/meta.dart'; /// {@template packages_check_licenses_command} /// `very_good packages check licenses` command for checking packages licenses. @@ -23,13 +21,6 @@ class PackagesCheckLicensesCommand extends Command { @override bool get hidden => true; - /// [ArgResults] which can be overridden for testing. - @visibleForTesting - ArgResults? argResultOverrides; - - // ignore: unused_element - ArgResults get _argResults => argResultOverrides ?? argResults!; - @override Future run() async { return ExitCode.success.code; diff --git a/test/src/commands/packages/commands/check/check_test.dart b/test/src/commands/packages/commands/check/check_test.dart index 2af78da7..5e03460f 100644 --- a/test/src/commands/packages/commands/check/check_test.dart +++ b/test/src/commands/packages/commands/check/check_test.dart @@ -1,7 +1,51 @@ +import 'dart:collection'; + +import 'package:mason_logger/mason_logger.dart'; import 'package:test/test.dart'; +import 'package:very_good_cli/src/commands/packages/commands/check/check.dart'; + +import '../../../../../helpers/helpers.dart'; + +const _expectedPackagesCheckUsage = [ + // ignore: no_adjacent_strings_in_list + 'Check packages in a Dart or Flutter project.\n' + '\n' + 'Usage: very_good packages check [arguments]\n' + '-h, --help Print this usage information.\n' + '\n' + 'Available subcommands:\n' + ' licenses Check packages licenses in a Dart or Flutter project.\n' + '\n' + 'Run "very_good help" to see global options.' +]; void main() { - test('check ...', () async { - // TODO: Implement test + group('packages check licenses', () { + final commandArguements = UnmodifiableListView( + ['packages', 'check'], + ); + + test( + 'help', + withRunner((commandRunner, logger, pubUpdater, printLogs) async { + final result = await commandRunner.run( + [...commandArguements, '--help'], + ); + expect(printLogs, equals(_expectedPackagesCheckUsage)); + expect(result, equals(ExitCode.success.code)); + + printLogs.clear(); + + final resultAbbr = + await commandRunner.run([...commandArguements, '-h']); + expect(printLogs, equals(_expectedPackagesCheckUsage)); + expect(resultAbbr, equals(ExitCode.success.code)); + }), + ); + + test('is hidden', () { + final command = PackagesCheckCommand(); + expect(command.hidden, isTrue); + }); }); } diff --git a/test/src/commands/packages/commands/check/commands/licenses_test.dart b/test/src/commands/packages/commands/check/commands/licenses_test.dart index cd6d4413..6d5eec9d 100644 --- a/test/src/commands/packages/commands/check/commands/licenses_test.dart +++ b/test/src/commands/packages/commands/check/commands/licenses_test.dart @@ -1,7 +1,56 @@ +import 'dart:collection'; + +import 'package:mason_logger/mason_logger.dart'; import 'package:test/test.dart'; +import 'package:very_good_cli/src/commands/packages/commands/check/commands/commands.dart'; + +import '../../../../../../helpers/helpers.dart'; + +const _expectedPackagesCheckLicensesUsage = [ + // ignore: no_adjacent_strings_in_list + 'Check packages licenses in a Dart or Flutter project.\n' + '\n' + 'Usage: very_good packages check licenses [arguments]\n' + '-h, --help Print this usage information.\n' + '\n' + 'Run "very_good help" to see global options.' +]; void main() { - test('licenses ...', () async { - // TODO: Implement test + group('packages check licenses', () { + final commandArguements = UnmodifiableListView( + ['packages', 'check', 'licenses'], + ); + + test( + 'help', + withRunner((commandRunner, logger, pubUpdater, printLogs) async { + final result = await commandRunner.run( + [...commandArguements, '--help'], + ); + expect(printLogs, equals(_expectedPackagesCheckLicensesUsage)); + expect(result, equals(ExitCode.success.code)); + + printLogs.clear(); + + final resultAbbr = + await commandRunner.run([...commandArguements, '-h']); + expect(printLogs, equals(_expectedPackagesCheckLicensesUsage)); + expect(resultAbbr, equals(ExitCode.success.code)); + }), + ); + + test( + 'returns exit code 0', + withRunner((commandRunner, logger, pubUpdater, printLogs) async { + final result = await commandRunner.run(commandArguements); + expect(result, equals(ExitCode.success.code)); + }), + ); + + test('is hidden', () { + final command = PackagesCheckLicensesCommand(); + expect(command.hidden, isTrue); + }); }); } From 9dfc476eca18808b257afe6eb467a6329b9456b9 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Thu, 5 Oct 2023 09:20:57 +0100 Subject: [PATCH 03/69] typo --- .../src/commands/packages/commands/check/check_test.dart | 7 +++---- .../packages/commands/check/commands/licenses_test.dart | 9 ++++----- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/test/src/commands/packages/commands/check/check_test.dart b/test/src/commands/packages/commands/check/check_test.dart index 5e03460f..22245e06 100644 --- a/test/src/commands/packages/commands/check/check_test.dart +++ b/test/src/commands/packages/commands/check/check_test.dart @@ -21,7 +21,7 @@ const _expectedPackagesCheckUsage = [ void main() { group('packages check licenses', () { - final commandArguements = UnmodifiableListView( + final commandArguments = UnmodifiableListView( ['packages', 'check'], ); @@ -29,15 +29,14 @@ void main() { 'help', withRunner((commandRunner, logger, pubUpdater, printLogs) async { final result = await commandRunner.run( - [...commandArguements, '--help'], + [...commandArguments, '--help'], ); expect(printLogs, equals(_expectedPackagesCheckUsage)); expect(result, equals(ExitCode.success.code)); printLogs.clear(); - final resultAbbr = - await commandRunner.run([...commandArguements, '-h']); + final resultAbbr = await commandRunner.run([...commandArguments, '-h']); expect(printLogs, equals(_expectedPackagesCheckUsage)); expect(resultAbbr, equals(ExitCode.success.code)); }), diff --git a/test/src/commands/packages/commands/check/commands/licenses_test.dart b/test/src/commands/packages/commands/check/commands/licenses_test.dart index 6d5eec9d..e5ed8c00 100644 --- a/test/src/commands/packages/commands/check/commands/licenses_test.dart +++ b/test/src/commands/packages/commands/check/commands/licenses_test.dart @@ -18,7 +18,7 @@ const _expectedPackagesCheckLicensesUsage = [ void main() { group('packages check licenses', () { - final commandArguements = UnmodifiableListView( + final commandArguments = UnmodifiableListView( ['packages', 'check', 'licenses'], ); @@ -26,15 +26,14 @@ void main() { 'help', withRunner((commandRunner, logger, pubUpdater, printLogs) async { final result = await commandRunner.run( - [...commandArguements, '--help'], + [...commandArguments, '--help'], ); expect(printLogs, equals(_expectedPackagesCheckLicensesUsage)); expect(result, equals(ExitCode.success.code)); printLogs.clear(); - final resultAbbr = - await commandRunner.run([...commandArguements, '-h']); + final resultAbbr = await commandRunner.run([...commandArguments, '-h']); expect(printLogs, equals(_expectedPackagesCheckLicensesUsage)); expect(resultAbbr, equals(ExitCode.success.code)); }), @@ -43,7 +42,7 @@ void main() { test( 'returns exit code 0', withRunner((commandRunner, logger, pubUpdater, printLogs) async { - final result = await commandRunner.run(commandArguements); + final result = await commandRunner.run(commandArguments); expect(result, equals(ExitCode.success.code)); }), ); From 2c416f7f7fa806f91e4bd406d82f6df22d511bb8 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Thu, 5 Oct 2023 09:23:35 +0100 Subject: [PATCH 04/69] analyzer --- lib/src/commands/packages/commands/check/check.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/src/commands/packages/commands/check/check.dart b/lib/src/commands/packages/commands/check/check.dart index 5204fd94..0072f247 100644 --- a/lib/src/commands/packages/commands/check/check.dart +++ b/lib/src/commands/packages/commands/check/check.dart @@ -1,7 +1,5 @@ -import 'package:args/args.dart'; import 'package:args/command_runner.dart'; import 'package:mason/mason.dart'; -import 'package:meta/meta.dart'; import 'package:very_good_cli/src/commands/packages/commands/check/commands/commands.dart'; /// {@template packages_check_command} From 5b9fe3657d9e6afe78d671152e1192b3a1dcdc6e Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Thu, 5 Oct 2023 14:18:01 +0100 Subject: [PATCH 05/69] feat: allow fetching licenses --- .../commands/check/commands/licenses.dart | 113 +++++++++++++++++- lib/src/pub_license/pub_license.dart | 4 +- pubspec.yaml | 1 + 3 files changed, 115 insertions(+), 3 deletions(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index ef89e0c9..c48bff50 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -1,16 +1,32 @@ +import 'dart:io'; + +import 'package:args/args.dart'; import 'package:args/command_runner.dart'; import 'package:mason/mason.dart'; +import 'package:meta/meta.dart'; +import 'package:path/path.dart' as path; +import 'package:pubspec_lock/pubspec_lock.dart'; +import 'package:very_good_cli/src/pub_license/pub_license.dart'; + +/// The basename of the pubspec lock file. +const _pubspecLockBasename = 'pubspec.lock'; /// {@template packages_check_licenses_command} /// `very_good packages check licenses` command for checking packages licenses. /// {@endtemplate} class PackagesCheckLicensesCommand extends Command { /// {@macro packages_check_licenses_command} - PackagesCheckLicensesCommand({Logger? logger}) : _logger = logger ?? Logger(); + PackagesCheckLicensesCommand({ + Logger? logger, + @visibleForTesting PubLicense? pubLicense, + }) : _logger = logger ?? Logger(), + _pubLicense = pubLicense ?? PubLicense(); // ignore: unused_field final Logger _logger; + final PubLicense _pubLicense; + @override String get description => 'Check packages licenses in a Dart or Flutter project.'; @@ -21,8 +37,103 @@ class PackagesCheckLicensesCommand extends Command { @override bool get hidden => true; + /// [ArgResults] which can be overridden for testing. + @visibleForTesting + ArgResults? argResultOverrides; + + ArgResults get _argResults => argResultOverrides ?? argResults!; + @override Future run() async { + final target = _argResults.rest.length == 1 ? _argResults.rest[0] : '.'; + final targetPath = path.normalize(Directory(target).absolute.path); + + final progress = _logger.progress('Checking licenses on $targetPath'); + + final pubspecLock = _tryParsePubspecLock(targetPath); + if (pubspecLock == null) { + progress.cancel(); + return ExitCode.usage.code; + } + + final filteredDependencies = + pubspecLock.packages.where(_filterHostedDirectDependency); + + final licenses = ?>{}; + for (final dependency in filteredDependencies) { + progress.update( + 'Collecting licenses of ${licenses.length}/${filteredDependencies.length} packages', + ); + + final packageName = dependency.package(); + Set? rawLicense; + try { + rawLicense = await _pubLicense.getLicense(packageName); + } on PubLicenseException catch (e) { + _logger.warn('[$packageName] ${e.message}'); + } catch (e) { + _logger.warn('[$packageName] Unexpected failure with error: $e'); + } + + licenses[packageName] = rawLicense; + } + + final licenseTypes = licenses.values.fold( + {}, + (previousValue, element) { + if (element == null) return previousValue; + return previousValue..addAll(element); + }, + ); + + if (licenseTypes.isEmpty) { + progress.cancel(); + _logger.err('No licenses found'); + return ExitCode.usage.code; + } + + progress.complete( + '''Retrieved ${licenses.length} licenses from ${filteredDependencies.length} packages of type: ${licenseTypes.toList().stringify()}''', + ); + return ExitCode.success.code; } + + /// Attempts to parse a [PubspecLock] file in the given [path]. + /// + /// If no [PubspecLock] file is found or is unable to be parsed, `null` is + /// returned and an error is logged accordingly. + PubspecLock? _tryParsePubspecLock(String targetPath) { + final pubspecLockFile = File(path.join(targetPath, _pubspecLockBasename)); + + if (!pubspecLockFile.existsSync()) { + _logger.err('Could not find a $_pubspecLockBasename in $targetPath'); + return null; + } + + try { + return pubspecLockFile.readAsStringSync().loadPubspecLockFromYaml(); + } catch (e) { + _logger.err('Could not parse $_pubspecLockBasename in $targetPath'); + return null; + } + } +} + +bool _filterHostedDirectDependency( + PackageDependency dependency, +) { + // ignore: invalid_use_of_protected_member + final isPubHostedDependency = dependency.hosted != null; + final isDirectDependency = dependency.type() == DependencyType.direct; + return isPubHostedDependency && isDirectDependency; +} + +extension on List { + String stringify() { + if (isEmpty) return ''; + if (length == 1) return first.toString(); + final last = removeLast(); + return '${join(', ')} and $last'; + } } diff --git a/lib/src/pub_license/pub_license.dart b/lib/src/pub_license/pub_license.dart index 7a0cf3bd..e31c2bb8 100644 --- a/lib/src/pub_license/pub_license.dart +++ b/lib/src/pub_license/pub_license.dart @@ -1,7 +1,7 @@ /// Enables checking a package's license from pub.dev. /// -/// This library is intented to be used by Very Good CLI to help extracting -/// license information. The existance of this library is likely to be +/// This library is intended to be used by Very Good CLI to help extracting +/// license information. The existence of this library is likely to be /// ephemeral. It may be obsolete once [pub.dev](https://pub.dev/) exposes /// stable license information in their official API; you may track the /// progress [here](https://github.com/dart-lang/pub-dev/issues/4717). diff --git a/pubspec.yaml b/pubspec.yaml index 5029fd53..003e4ede 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -23,6 +23,7 @@ dependencies: meta: ^1.3.0 path: ^1.8.0 pub_updater: ">=0.3.1 <0.5.0" + pubspec_lock: ^3.0.2 pubspec_parse: ^1.2.0 stack_trace: ^1.10.0 universal_io: ^2.0.4 From 31cc3a07bbe145b991378e2b04576d5b999f2a99 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Thu, 5 Oct 2023 14:48:58 +0100 Subject: [PATCH 06/69] full stop --- lib/src/commands/packages/commands/check/commands/licenses.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index c48bff50..f32489ea 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -93,7 +93,7 @@ class PackagesCheckLicensesCommand extends Command { } progress.complete( - '''Retrieved ${licenses.length} licenses from ${filteredDependencies.length} packages of type: ${licenseTypes.toList().stringify()}''', + '''Retrieved ${licenses.length} licenses from ${filteredDependencies.length} packages of type: ${licenseTypes.toList().stringify()}.''', ); return ExitCode.success.code; From d13d6dc393d2c864e5578eba5c3b40d3d4f3d22c Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Fri, 6 Oct 2023 09:39:21 +0100 Subject: [PATCH 07/69] _isHostedDirectDependency --- .../commands/packages/commands/check/commands/licenses.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index f32489ea..87d19604 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -57,7 +57,7 @@ class PackagesCheckLicensesCommand extends Command { } final filteredDependencies = - pubspecLock.packages.where(_filterHostedDirectDependency); + pubspecLock.packages.where(_isHostedDirectDependency); final licenses = ?>{}; for (final dependency in filteredDependencies) { @@ -120,7 +120,7 @@ class PackagesCheckLicensesCommand extends Command { } } -bool _filterHostedDirectDependency( +bool _isHostedDirectDependency( PackageDependency dependency, ) { // ignore: invalid_use_of_protected_member From fe5a5dda84aa3cf1390e7156577f0fb0d749d993 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Mon, 9 Oct 2023 13:03:02 +0100 Subject: [PATCH 08/69] testing --- .../commands/check/commands/licenses.dart | 40 ++-- test/helpers/command_helper.dart | 1 + .../check/commands/licenses_test.dart | 176 ++++++++++++++++++ 3 files changed, 198 insertions(+), 19 deletions(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index 20d823b8..dfaf8305 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -9,7 +9,8 @@ import 'package:pubspec_lock/pubspec_lock.dart'; import 'package:very_good_cli/src/pub_license/pub_license.dart'; /// The basename of the pubspec lock file. -const _pubspecLockBasename = 'pubspec.lock'; +@visibleForTesting +const pubspecLockBasename = 'pubspec.lock'; /// {@template packages_check_licenses_command} /// `very_good packages check licenses` command for checking packages licenses. @@ -53,26 +54,36 @@ class PackagesCheckLicensesCommand extends Command { final pubspecLock = _tryParsePubspecLock(targetPath); if (pubspecLock == null) { progress.cancel(); - return ExitCode.usage.code; + return ExitCode.noInput.code; } final filteredDependencies = pubspecLock.packages.where(_isHostedDirectDependency); - final licenses = ?>{}; + if (filteredDependencies.isEmpty) { + progress.cancel(); + _logger.err('No hosted direct dependencies found in $targetPath'); + return ExitCode.usage.code; + } + + final licenses = >{}; for (final dependency in filteredDependencies) { progress.update( 'Collecting licenses of ${licenses.length}/${filteredDependencies.length} packages', ); final packageName = dependency.package(); - Set? rawLicense; + Set rawLicense; try { rawLicense = await _pubLicense.getLicense(packageName); } on PubLicenseException catch (e) { - _logger.warn('[$packageName] ${e.message}'); + progress.cancel(); + _logger.err('[$packageName] ${e.message}'); + return ExitCode.unavailable.code; } catch (e) { - _logger.warn('[$packageName] Unexpected failure with error: $e'); + progress.cancel(); + _logger.err('[$packageName] Unexpected failure with error: $e'); + return ExitCode.software.code; } licenses[packageName] = rawLicense; @@ -80,18 +91,9 @@ class PackagesCheckLicensesCommand extends Command { final licenseTypes = licenses.values.fold( {}, - (previousValue, element) { - if (element == null) return previousValue; - return previousValue..addAll(element); - }, + (previousValue, element) => previousValue..addAll(element), ); - if (licenseTypes.isEmpty) { - progress.cancel(); - _logger.err('No licenses found'); - return ExitCode.usage.code; - } - progress.complete( '''Retrieved ${licenses.length} licenses from ${filteredDependencies.length} packages of type: ${licenseTypes.toList().stringify()}.''', ); @@ -104,17 +106,17 @@ class PackagesCheckLicensesCommand extends Command { /// If no [PubspecLock] file is found or is unable to be parsed, `null` is /// returned and an error is logged accordingly. PubspecLock? _tryParsePubspecLock(String targetPath) { - final pubspecLockFile = File(path.join(targetPath, _pubspecLockBasename)); + final pubspecLockFile = File(path.join(targetPath, pubspecLockBasename)); if (!pubspecLockFile.existsSync()) { - _logger.err('Could not find a $_pubspecLockBasename in $targetPath'); + _logger.err('Could not find a $pubspecLockBasename in $targetPath'); return null; } try { return pubspecLockFile.readAsStringSync().loadPubspecLockFromYaml(); } catch (e) { - _logger.err('Could not parse $_pubspecLockBasename in $targetPath'); + _logger.err('Could not parse $pubspecLockBasename in $targetPath'); return null; } } diff --git a/test/helpers/command_helper.dart b/test/helpers/command_helper.dart index bcb0da7b..94bc75dd 100644 --- a/test/helpers/command_helper.dart +++ b/test/helpers/command_helper.dart @@ -47,6 +47,7 @@ void Function() withRunner( final commandRunner = VeryGoodCommandRunner( logger: logger, pubUpdater: pubUpdater, + pubLicense: pubLicense, ); when(() => progress.complete(any())).thenAnswer((_) { diff --git a/test/src/commands/packages/commands/check/commands/licenses_test.dart b/test/src/commands/packages/commands/check/commands/licenses_test.dart index 4a0f7723..d8426c88 100644 --- a/test/src/commands/packages/commands/check/commands/licenses_test.dart +++ b/test/src/commands/packages/commands/check/commands/licenses_test.dart @@ -1,8 +1,12 @@ import 'dart:collection'; +import 'dart:io'; import 'package:mason_logger/mason_logger.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:path/path.dart' as path; import 'package:test/test.dart'; import 'package:very_good_cli/src/commands/packages/commands/check/commands/commands.dart'; +import 'package:very_good_cli/src/pub_license/pub_license.dart'; import '../../../../../../helpers/helpers.dart'; @@ -53,5 +57,177 @@ void main() { final command = PackagesCheckLicensesCommand(); expect(command.hidden, isTrue); }); + + group('exits with error', () { + // TODO(alestiago): Verify process is cancelled. + + test( + 'when it did not find a pubspec.lock file at the target path', + withRunner( + (commandRunner, logger, pubUpdater, pubLicense, printLogs) async { + final tempDirectory = Directory.systemTemp.createTempSync(); + addTearDown(() => tempDirectory.deleteSync(recursive: true)); + + final result = await commandRunner.run( + [...commandArguments, tempDirectory.path], + ); + + final errorMessage = + 'Could not find a $pubspecLockBasename in ${tempDirectory.path}'; + verify(() => logger.err(errorMessage)).called(1); + + expect(result, equals(ExitCode.noInput.code)); + }), + ); + + test( + 'when it failed to parse a pubspec.lock file at the target path', + withRunner( + (commandRunner, logger, pubUpdater, pubLicense, printLogs) async { + final tempDirectory = Directory.systemTemp.createTempSync(); + addTearDown(() => tempDirectory.deleteSync(recursive: true)); + + File(path.join(tempDirectory.path, pubspecLockBasename)) + .writeAsStringSync(''); + + final result = await commandRunner.run( + [...commandArguments, tempDirectory.path], + ); + + final errorMessage = + 'Could not parse $pubspecLockBasename in ${tempDirectory.path}'; + verify(() => logger.err(errorMessage)).called(1); + + expect(result, equals(ExitCode.noInput.code)); + }), + ); + + test( + 'when no hosted direct dependencies are found', + withRunner( + (commandRunner, logger, pubUpdater, pubLicense, printLogs) async { + final tempDirectory = Directory.systemTemp.createTempSync(); + addTearDown(() => tempDirectory.deleteSync(recursive: true)); + + File(path.join(tempDirectory.path, pubspecLockBasename)) + .writeAsStringSync(_emptyPubspecLockContent); + + final result = await commandRunner.run( + [...commandArguments, tempDirectory.path], + ); + + final errorMessage = + 'No hosted direct dependencies found in ${tempDirectory.path}'; + verify(() => logger.err(errorMessage)).called(1); + + expect(result, equals(ExitCode.usage.code)); + }), + ); + + test( + 'when PubLicense throws a PubLicenseException', + withRunner( + (commandRunner, logger, pubUpdater, pubLicense, printLogs) async { + final tempDirectory = Directory.systemTemp.createTempSync(); + addTearDown(() => tempDirectory.deleteSync(recursive: true)); + + File(path.join(tempDirectory.path, pubspecLockBasename)) + .writeAsStringSync(_validPubspecLockContent); + + const exception = PubLicenseException('message'); + when(() => pubLicense.getLicense('very_good_test_runner')) + .thenThrow(exception); + + final result = await commandRunner.run( + [...commandArguments, tempDirectory.path], + ); + + final packageName = verify(() => pubLicense.getLicense(captureAny())) + .captured + .cast() + .first; + + final errorMessage = '[$packageName] ${exception.message}'; + verify(() => logger.err(errorMessage)).called(1); + + expect(result, equals(ExitCode.unavailable.code)); + }), + ); + + test( + 'when PubLicense throws an unknown error', + withRunner( + (commandRunner, logger, pubUpdater, pubLicense, printLogs) async { + final tempDirectory = Directory.systemTemp.createTempSync(); + addTearDown(() => tempDirectory.deleteSync(recursive: true)); + + File(path.join(tempDirectory.path, pubspecLockBasename)) + .writeAsStringSync(_validPubspecLockContent); + + const error = 'error'; + when(() => pubLicense.getLicense('very_good_test_runner')) + .thenThrow(error); + + final result = await commandRunner.run( + [...commandArguments, tempDirectory.path], + ); + + final packageName = verify(() => pubLicense.getLicense(captureAny())) + .captured + .cast() + .first; + + final errorMessage = + '[$packageName] Unexpected failure with error: $error'; + verify(() => logger.err(errorMessage)).called(1); + + expect(result, equals(ExitCode.software.code)); + }), + ); + }); }); } + +/// A valid pubspec lock file. +/// +/// It has been artificially crafted to include a single: +/// - hosted direct dependency +/// - hosted direct dev dependency +/// - hosted transitive dependency +const _validPubspecLockContent = ''' +packages: + very_good_analysis: + dependency: "direct dev" + description: + name: very_good_analysis + sha256: "9ae7f3a3bd5764fb021b335ca28a34f040cd0ab6eec00a1b213b445dae58a4b8" + url: "https://pub.dev" + source: hosted + version: "5.1.0" + very_good_test_runner: + dependency: "direct main" + description: + name: very_good_test_runner + sha256: "4d41e5d7677d259b9a1599c78645ac2d36bc2bd6ff7773507bcb0bab41417fe2" + url: "https://pub.dev" + source: hosted + version: "0.1.2" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" +sdks: + dart: ">=3.1.0 <4.0.0" + +'''; + +/// A valid pubspec lock file with no dependencies. +const _emptyPubspecLockContent = ''' +sdks: + dart: ">=3.1.0 <4.0.0" + +'''; From 19414b1c2f6db62968c13bc9f4281d8ea2770037 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Mon, 9 Oct 2023 13:24:24 +0100 Subject: [PATCH 09/69] licenses and packages singular --- .../commands/check/commands/licenses.dart | 5 +- .../check/commands/licenses_test.dart | 128 ++++++++++++++++-- 2 files changed, 119 insertions(+), 14 deletions(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index dfaf8305..139cefd6 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -94,8 +94,11 @@ class PackagesCheckLicensesCommand extends Command { (previousValue, element) => previousValue..addAll(element), ); + final licenseWord = licenseTypes.length > 1 ? 'licenses' : 'license'; + final packageWord = + filteredDependencies.length > 1 ? 'packages' : 'package'; progress.complete( - '''Retrieved ${licenses.length} licenses from ${filteredDependencies.length} packages of type: ${licenseTypes.toList().stringify()}.''', + '''Retrieved ${licenses.length} $licenseWord from ${filteredDependencies.length} $packageWord of type: ${licenseTypes.toList().stringify()}.''', ); return ExitCode.success.code; diff --git a/test/src/commands/packages/commands/check/commands/licenses_test.dart b/test/src/commands/packages/commands/check/commands/licenses_test.dart index d8426c88..90c41e9b 100644 --- a/test/src/commands/packages/commands/check/commands/licenses_test.dart +++ b/test/src/commands/packages/commands/check/commands/licenses_test.dart @@ -44,20 +44,61 @@ void main() { }), ); - test( - 'returns exit code 0', - withRunner( - (commandRunner, logger, pubUpdater, pubLicense, printLogs) async { - final result = await commandRunner.run(commandArguments); - expect(result, equals(ExitCode.success.code)); - }), - ); - test('is hidden', () { final command = PackagesCheckLicensesCommand(); expect(command.hidden, isTrue); }); + group( + 'reports licenses', + () { + test( + '''correctly when there is a single hosted direct dependency and license''', + withRunner( + (commandRunner, logger, pubUpdater, pubLicense, printLogs) async { + final tempDirectory = Directory.systemTemp.createTempSync(); + addTearDown(() => tempDirectory.deleteSync(recursive: true)); + + File(path.join(tempDirectory.path, pubspecLockBasename)) + .writeAsStringSync(_validPubspecLockContent); + + final result = await commandRunner.run( + [...commandArguments, tempDirectory.path], + ); + + const report = + '''Retrieved 1 license from 1 package of type: MIT.'''; + + expect(result, equals(ExitCode.success.code)); + }), + ); + + test( + '''correctly when there are multiple hosted direct dependency and licenses''', + withRunner( + (commandRunner, logger, pubUpdater, pubLicense, printLogs) async { + final tempDirectory = Directory.systemTemp.createTempSync(); + addTearDown(() => tempDirectory.deleteSync(recursive: true)); + + File(path.join(tempDirectory.path, pubspecLockBasename)) + .writeAsStringSync(_validPubspecLockContent); + + when(() => pubLicense.getLicense(any())) + .thenAnswer((_) => Future.value({'MIT', 'BSD'})); + + final result = await commandRunner.run( + [...commandArguments, tempDirectory.path], + ); + + const report = + '''Retrieved 4 licenses from 2 package of type: MIT and BSD.'''; + + expect(result, equals(ExitCode.success.code)); + }), + ); + }, + ); + group('exits with error', () { // TODO(alestiago): Verify process is cancelled. @@ -190,10 +231,10 @@ void main() { /// A valid pubspec lock file. /// -/// It has been artificially crafted to include a single: -/// - hosted direct dependency -/// - hosted direct dev dependency -/// - hosted transitive dependency +/// It has been artificially crafted to include: +/// - one hosted direct dependency +/// - one hosted direct dev dependency +/// - one hosted transitive dependency const _validPubspecLockContent = ''' packages: very_good_analysis: @@ -225,6 +266,67 @@ sdks: '''; +/// A valid pubspec lock file. +/// +/// It has been artificially crafted to include: +/// - two hosted direct dependency +/// - two hosted direct dev dependency +/// - two hosted transitive dependency +const _validMultiplePubspecLockContent = ''' +packages: + very_good_analysis: + dependency: "direct dev" + description: + name: very_good_analysis + sha256: "9ae7f3a3bd5764fb021b335ca28a34f040cd0ab6eec00a1b213b445dae58a4b8" + url: "https://pub.dev" + source: hosted + version: "5.1.0" + build_runner: + dependency: "direct dev" + description: + name: build_runner + sha256: "10c6bcdbf9d049a0b666702cf1cee4ddfdc38f02a19d35ae392863b47519848b" + url: "https://pub.dev" + source: hosted + version: "2.4.6" + very_good_test_runner: + dependency: "direct main" + description: + name: very_good_test_runner + sha256: "4d41e5d7677d259b9a1599c78645ac2d36bc2bd6ff7773507bcb0bab41417fe2" + url: "https://pub.dev" + source: hosted + version: "0.1.2" + cli_completion: + dependency: "direct main" + description: + name: cli_completion + sha256: "1e87700c029c77041d836e57f9016b5c90d353151c43c2ca0c36deaadc05aa3a" + url: "https://pub.dev" + source: hosted + version: "0.4.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" + archive: + dependency: transitive + description: + name: archive + sha256: d4dc11707abb32ef756ab95678c0d6df54003d98277f7c9aeda14c48e7a38c2f + url: "https://pub.dev" + source: hosted + version: "3.4.3" +sdks: + dart: ">=3.1.0 <4.0.0" + +'''; + /// A valid pubspec lock file with no dependencies. const _emptyPubspecLockContent = ''' sdks: From 5f0af9dc4c0b8bff07e5d7e96d678494817b471a Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Mon, 9 Oct 2023 13:32:45 +0100 Subject: [PATCH 10/69] included TODOs --- .../packages/commands/check/commands/licenses_test.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/src/commands/packages/commands/check/commands/licenses_test.dart b/test/src/commands/packages/commands/check/commands/licenses_test.dart index 90c41e9b..2f6ae9ef 100644 --- a/test/src/commands/packages/commands/check/commands/licenses_test.dart +++ b/test/src/commands/packages/commands/check/commands/licenses_test.dart @@ -68,6 +68,7 @@ void main() { const report = '''Retrieved 1 license from 1 package of type: MIT.'''; + // TODO(alestiago): Check that the progress completes with report. expect(result, equals(ExitCode.success.code)); }), @@ -92,6 +93,7 @@ void main() { const report = '''Retrieved 4 licenses from 2 package of type: MIT and BSD.'''; + // TODO(alestiago): Check that the progress completes with report. expect(result, equals(ExitCode.success.code)); }), From d434f6f9509e74b6692818821b05a188b2790a8d Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 10 Oct 2023 09:37:41 +0100 Subject: [PATCH 11/69] test progress --- .../commands/check/commands/licenses.dart | 6 ++- .../check/commands/licenses_test.dart | 50 ++++++++++++++++--- 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index 139cefd6..906c8e9e 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -93,12 +93,16 @@ class PackagesCheckLicensesCommand extends Command { {}, (previousValue, element) => previousValue..addAll(element), ); + final licenseCount = licenses.values.fold( + 0, + (previousValue, element) => previousValue + element.length, + ); final licenseWord = licenseTypes.length > 1 ? 'licenses' : 'license'; final packageWord = filteredDependencies.length > 1 ? 'packages' : 'package'; progress.complete( - '''Retrieved ${licenses.length} $licenseWord from ${filteredDependencies.length} $packageWord of type: ${licenseTypes.toList().stringify()}.''', + '''Retrieved $licenseCount $licenseWord from ${filteredDependencies.length} $packageWord of type: ${licenseTypes.toList().stringify()}.''', ); return ExitCode.success.code; diff --git a/test/src/commands/packages/commands/check/commands/licenses_test.dart b/test/src/commands/packages/commands/check/commands/licenses_test.dart index 2f6ae9ef..7c63befc 100644 --- a/test/src/commands/packages/commands/check/commands/licenses_test.dart +++ b/test/src/commands/packages/commands/check/commands/licenses_test.dart @@ -10,6 +10,8 @@ import 'package:very_good_cli/src/pub_license/pub_license.dart'; import '../../../../../../helpers/helpers.dart'; +class _MockProgress extends Mock implements Progress {} + const _expectedPackagesCheckLicensesUsage = [ // ignore: no_adjacent_strings_in_list 'Check packages licenses in a Dart or Flutter project.\n' @@ -26,6 +28,20 @@ void main() { ['packages', 'check', 'licenses'], ); + late Progress progress; + + setUpAll(() { + registerFallbackValue(''); + }); + + setUp(() { + progress = _MockProgress(); + // when(() => progress.cancel()).thenReturn(null); + // when(() => progress.update(any())).thenReturn(null); + // when(() => progress.fail(any())).thenReturn(null); + // when(() => progress.complete(any())).thenReturn(null); + }); + test( 'help', withRunner( @@ -62,13 +78,15 @@ void main() { File(path.join(tempDirectory.path, pubspecLockBasename)) .writeAsStringSync(_validPubspecLockContent); + when(() => logger.progress(any())).thenReturn(progress); + final result = await commandRunner.run( [...commandArguments, tempDirectory.path], ); const report = '''Retrieved 1 license from 1 package of type: MIT.'''; - // TODO(alestiago): Check that the progress completes with report. + verify(() => progress.complete(report)).called(1); expect(result, equals(ExitCode.success.code)); }), @@ -82,7 +100,9 @@ void main() { addTearDown(() => tempDirectory.deleteSync(recursive: true)); File(path.join(tempDirectory.path, pubspecLockBasename)) - .writeAsStringSync(_validPubspecLockContent); + .writeAsStringSync(_validMultiplePubspecLockContent); + + when(() => logger.progress(any())).thenReturn(progress); when(() => pubLicense.getLicense(any())) .thenAnswer((_) => Future.value({'MIT', 'BSD'})); @@ -92,8 +112,8 @@ void main() { ); const report = - '''Retrieved 4 licenses from 2 package of type: MIT and BSD.'''; - // TODO(alestiago): Check that the progress completes with report. + '''Retrieved 4 licenses from 2 packages of type: MIT and BSD.'''; + verify(() => progress.complete(report)).called(1); expect(result, equals(ExitCode.success.code)); }), @@ -102,8 +122,6 @@ void main() { ); group('exits with error', () { - // TODO(alestiago): Verify process is cancelled. - test( 'when it did not find a pubspec.lock file at the target path', withRunner( @@ -111,6 +129,8 @@ void main() { final tempDirectory = Directory.systemTemp.createTempSync(); addTearDown(() => tempDirectory.deleteSync(recursive: true)); + when(() => logger.progress(any())).thenReturn(progress); + final result = await commandRunner.run( [...commandArguments, tempDirectory.path], ); @@ -119,6 +139,8 @@ void main() { 'Could not find a $pubspecLockBasename in ${tempDirectory.path}'; verify(() => logger.err(errorMessage)).called(1); + verify(() => progress.cancel()).called(1); + expect(result, equals(ExitCode.noInput.code)); }), ); @@ -133,6 +155,8 @@ void main() { File(path.join(tempDirectory.path, pubspecLockBasename)) .writeAsStringSync(''); + when(() => logger.progress(any())).thenReturn(progress); + final result = await commandRunner.run( [...commandArguments, tempDirectory.path], ); @@ -141,6 +165,8 @@ void main() { 'Could not parse $pubspecLockBasename in ${tempDirectory.path}'; verify(() => logger.err(errorMessage)).called(1); + verify(() => progress.cancel()).called(1); + expect(result, equals(ExitCode.noInput.code)); }), ); @@ -155,6 +181,8 @@ void main() { File(path.join(tempDirectory.path, pubspecLockBasename)) .writeAsStringSync(_emptyPubspecLockContent); + when(() => logger.progress(any())).thenReturn(progress); + final result = await commandRunner.run( [...commandArguments, tempDirectory.path], ); @@ -163,6 +191,8 @@ void main() { 'No hosted direct dependencies found in ${tempDirectory.path}'; verify(() => logger.err(errorMessage)).called(1); + verify(() => progress.cancel()).called(1); + expect(result, equals(ExitCode.usage.code)); }), ); @@ -177,6 +207,8 @@ void main() { File(path.join(tempDirectory.path, pubspecLockBasename)) .writeAsStringSync(_validPubspecLockContent); + when(() => logger.progress(any())).thenReturn(progress); + const exception = PubLicenseException('message'); when(() => pubLicense.getLicense('very_good_test_runner')) .thenThrow(exception); @@ -193,6 +225,8 @@ void main() { final errorMessage = '[$packageName] ${exception.message}'; verify(() => logger.err(errorMessage)).called(1); + verify(() => progress.cancel()).called(1); + expect(result, equals(ExitCode.unavailable.code)); }), ); @@ -211,6 +245,8 @@ void main() { when(() => pubLicense.getLicense('very_good_test_runner')) .thenThrow(error); + when(() => logger.progress(any())).thenReturn(progress); + final result = await commandRunner.run( [...commandArguments, tempDirectory.path], ); @@ -224,6 +260,8 @@ void main() { '[$packageName] Unexpected failure with error: $error'; verify(() => logger.err(errorMessage)).called(1); + verify(() => progress.cancel()).called(1); + expect(result, equals(ExitCode.software.code)); }), ); From 71c965b796c2b789d22f851323cdf8a3d1654e0b Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 10 Oct 2023 09:43:25 +0100 Subject: [PATCH 12/69] refactor to "dependencyName" --- .../packages/commands/check/commands/licenses.dart | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index 906c8e9e..2f5bb589 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -72,21 +72,21 @@ class PackagesCheckLicensesCommand extends Command { 'Collecting licenses of ${licenses.length}/${filteredDependencies.length} packages', ); - final packageName = dependency.package(); + final dependencyName = dependency.package(); Set rawLicense; try { - rawLicense = await _pubLicense.getLicense(packageName); + rawLicense = await _pubLicense.getLicense(dependencyName); } on PubLicenseException catch (e) { progress.cancel(); - _logger.err('[$packageName] ${e.message}'); + _logger.err('[$dependencyName] ${e.message}'); return ExitCode.unavailable.code; } catch (e) { progress.cancel(); - _logger.err('[$packageName] Unexpected failure with error: $e'); + _logger.err('[$dependencyName] Unexpected failure with error: $e'); return ExitCode.software.code; } - licenses[packageName] = rawLicense; + licenses[dependencyName] = rawLicense; } final licenseTypes = licenses.values.fold( From 754728b145ee6a467b32f120204e4897be78ca08 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 10 Oct 2023 09:46:43 +0100 Subject: [PATCH 13/69] refactor _tryParsePubspecLock --- .../commands/check/commands/licenses.dart | 37 +++++++++---------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index 2f5bb589..d206b0ca 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -51,8 +51,15 @@ class PackagesCheckLicensesCommand extends Command { final progress = _logger.progress('Checking licenses on $targetPath'); - final pubspecLock = _tryParsePubspecLock(targetPath); + final pubspecLockFile = File(path.join(targetPath, pubspecLockBasename)); + if (!pubspecLockFile.existsSync()) { + _logger.err('Could not find a $pubspecLockBasename in $targetPath'); + return ExitCode.noInput.code; + } + + final pubspecLock = _tryParsePubspecLock(pubspecLockFile); if (pubspecLock == null) { + _logger.err('Could not parse $pubspecLockBasename in $targetPath'); progress.cancel(); return ExitCode.noInput.code; } @@ -107,25 +114,17 @@ class PackagesCheckLicensesCommand extends Command { return ExitCode.success.code; } +} - /// Attempts to parse a [PubspecLock] file in the given [path]. - /// - /// If no [PubspecLock] file is found or is unable to be parsed, `null` is - /// returned and an error is logged accordingly. - PubspecLock? _tryParsePubspecLock(String targetPath) { - final pubspecLockFile = File(path.join(targetPath, pubspecLockBasename)); - - if (!pubspecLockFile.existsSync()) { - _logger.err('Could not find a $pubspecLockBasename in $targetPath'); - return null; - } - - try { - return pubspecLockFile.readAsStringSync().loadPubspecLockFromYaml(); - } catch (e) { - _logger.err('Could not parse $pubspecLockBasename in $targetPath'); - return null; - } +/// Attempts to parse a [PubspecLock] file in the given [path]. +/// +/// If no [PubspecLock] file is found or is unable to be parsed, `null` is +/// returned. +PubspecLock? _tryParsePubspecLock(File pubspecLockFile) { + try { + return pubspecLockFile.readAsStringSync().loadPubspecLockFromYaml(); + } catch (e) { + return null; } } From d88047d53214758618d958d746207b78ea668885 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 10 Oct 2023 09:54:46 +0100 Subject: [PATCH 14/69] remove old ignore --- lib/src/commands/packages/commands/check/commands/licenses.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index d206b0ca..1ed69e94 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -23,7 +23,6 @@ class PackagesCheckLicensesCommand extends Command { }) : _logger = logger ?? Logger(), _pubLicense = pubLicense ?? PubLicense(); - // ignore: unused_field final Logger _logger; final PubLicense _pubLicense; From ba9c2039a7b417c04f2160a39a68db1ab895cc62 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 10 Oct 2023 10:00:52 +0100 Subject: [PATCH 15/69] missing cancel --- .../commands/packages/commands/check/commands/licenses.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index 1ed69e94..933ccf92 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -52,14 +52,15 @@ class PackagesCheckLicensesCommand extends Command { final pubspecLockFile = File(path.join(targetPath, pubspecLockBasename)); if (!pubspecLockFile.existsSync()) { + progress.cancel(); _logger.err('Could not find a $pubspecLockBasename in $targetPath'); return ExitCode.noInput.code; } final pubspecLock = _tryParsePubspecLock(pubspecLockFile); if (pubspecLock == null) { - _logger.err('Could not parse $pubspecLockBasename in $targetPath'); progress.cancel(); + _logger.err('Could not parse $pubspecLockBasename in $targetPath'); return ExitCode.noInput.code; } From ad09a3ce16613e93cb689053f3e0283eebedb575 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 10 Oct 2023 10:01:18 +0100 Subject: [PATCH 16/69] remove commented code --- .../packages/commands/check/commands/licenses_test.dart | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/src/commands/packages/commands/check/commands/licenses_test.dart b/test/src/commands/packages/commands/check/commands/licenses_test.dart index 7c63befc..ae110ddf 100644 --- a/test/src/commands/packages/commands/check/commands/licenses_test.dart +++ b/test/src/commands/packages/commands/check/commands/licenses_test.dart @@ -36,10 +36,6 @@ void main() { setUp(() { progress = _MockProgress(); - // when(() => progress.cancel()).thenReturn(null); - // when(() => progress.update(any())).thenReturn(null); - // when(() => progress.fail(any())).thenReturn(null); - // when(() => progress.complete(any())).thenReturn(null); }); test( From 4da63068919383f4a48171d57d50a5cf35c552ba Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 10 Oct 2023 10:02:35 +0100 Subject: [PATCH 17/69] words --- .../commands/packages/commands/check/commands/licenses.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index 933ccf92..103c38d4 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -105,9 +105,9 @@ class PackagesCheckLicensesCommand extends Command { (previousValue, element) => previousValue + element.length, ); - final licenseWord = licenseTypes.length > 1 ? 'licenses' : 'license'; + final licenseWord = licenseCount != 1 ? 'licenses' : 'license'; final packageWord = - filteredDependencies.length > 1 ? 'packages' : 'package'; + filteredDependencies.length != 1 ? 'packages' : 'package'; progress.complete( '''Retrieved $licenseCount $licenseWord from ${filteredDependencies.length} $packageWord of type: ${licenseTypes.toList().stringify()}.''', ); From 6d5a23dc986c6a817f30c0a8f6b286102bd8fdaa Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 10 Oct 2023 10:03:10 +0100 Subject: [PATCH 18/69] words --- .../commands/packages/commands/check/commands/licenses.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index 103c38d4..5198aad1 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -105,9 +105,9 @@ class PackagesCheckLicensesCommand extends Command { (previousValue, element) => previousValue + element.length, ); - final licenseWord = licenseCount != 1 ? 'licenses' : 'license'; + final licenseWord = licenseCount == 1 ? 'license' : 'licenses'; final packageWord = - filteredDependencies.length != 1 ? 'packages' : 'package'; + filteredDependencies.length == 1 ? 'package' : 'packages'; progress.complete( '''Retrieved $licenseCount $licenseWord from ${filteredDependencies.length} $packageWord of type: ${licenseTypes.toList().stringify()}.''', ); From cf25b300ca065b85d604fdff307d46c75736ccee Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 10 Oct 2023 10:08:51 +0100 Subject: [PATCH 19/69] removed argResults override --- .../commands/packages/commands/check/commands/licenses.dart | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index 5198aad1..dd426a1b 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -37,11 +37,7 @@ class PackagesCheckLicensesCommand extends Command { @override bool get hidden => true; - /// [ArgResults] which can be overridden for testing. - @visibleForTesting - ArgResults? argResultOverrides; - - ArgResults get _argResults => argResultOverrides ?? argResults!; + ArgResults get _argResults => argResults!; @override Future run() async { From 94657b56312b7695e48e5197e0a080ee1fa854c3 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 10 Oct 2023 10:32:48 +0100 Subject: [PATCH 20/69] feat: allow ignoring failures when checking licenses --- .../commands/check/commands/licenses.dart | 39 +++++++++++++------ .../check/commands/licenses_test.dart | 3 +- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index dd426a1b..7df4f521 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -21,7 +21,13 @@ class PackagesCheckLicensesCommand extends Command { Logger? logger, PubLicense? pubLicense, }) : _logger = logger ?? Logger(), - _pubLicense = pubLicense ?? PubLicense(); + _pubLicense = pubLicense ?? PubLicense() { + argParser.addFlag( + 'ignore-failures', + help: 'Avoids terminating whenever a license fails to be retrieved.', + negatable: false, + ); + } final Logger _logger; @@ -41,6 +47,9 @@ class PackagesCheckLicensesCommand extends Command { @override Future run() async { + // TODO(alestiago): Usage exception when too many arguments. + final ignoreFailures = _argResults['ignore-failures'] as bool; + final target = _argResults.rest.length == 1 ? _argResults.rest[0] : '.'; final targetPath = path.normalize(Directory(target).absolute.path); @@ -76,20 +85,28 @@ class PackagesCheckLicensesCommand extends Command { ); final dependencyName = dependency.package(); - Set rawLicense; try { - rawLicense = await _pubLicense.getLicense(dependencyName); + licenses[dependencyName] = await _pubLicense.getLicense(dependencyName); } on PubLicenseException catch (e) { - progress.cancel(); - _logger.err('[$dependencyName] ${e.message}'); - return ExitCode.unavailable.code; + final errorMessage = '[$dependencyName] ${e.message}'; + if (!ignoreFailures) { + progress.cancel(); + _logger.err(errorMessage); + return ExitCode.unavailable.code; + } + + _logger.err(errorMessage); } catch (e) { - progress.cancel(); - _logger.err('[$dependencyName] Unexpected failure with error: $e'); - return ExitCode.software.code; + final errorMessage = + '[$dependencyName] Unexpected failure with error: $e'; + if (!ignoreFailures) { + progress.cancel(); + _logger.err(errorMessage); + return ExitCode.software.code; + } + + _logger.err(errorMessage); } - - licenses[dependencyName] = rawLicense; } final licenseTypes = licenses.values.fold( diff --git a/test/src/commands/packages/commands/check/commands/licenses_test.dart b/test/src/commands/packages/commands/check/commands/licenses_test.dart index ae110ddf..06508901 100644 --- a/test/src/commands/packages/commands/check/commands/licenses_test.dart +++ b/test/src/commands/packages/commands/check/commands/licenses_test.dart @@ -17,7 +17,8 @@ const _expectedPackagesCheckLicensesUsage = [ 'Check packages licenses in a Dart or Flutter project.\n' '\n' 'Usage: very_good packages check licenses [arguments]\n' - '-h, --help Print this usage information.\n' + '-h, --help Print this usage information.\n' + ''' --ignore-failures Avoids terminating whenever a license fails to be retrieved.\n''' '\n' 'Run "very_good help" to see global options.' ]; From 3a035312c9184ed8ab61543b971a0204125a876d Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 10 Oct 2023 10:44:04 +0100 Subject: [PATCH 21/69] used const --- .../packages/commands/check/commands/licenses_test.dart | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/test/src/commands/packages/commands/check/commands/licenses_test.dart b/test/src/commands/packages/commands/check/commands/licenses_test.dart index ae110ddf..bc9bc6a8 100644 --- a/test/src/commands/packages/commands/check/commands/licenses_test.dart +++ b/test/src/commands/packages/commands/check/commands/licenses_test.dart @@ -1,4 +1,3 @@ -import 'dart:collection'; import 'dart:io'; import 'package:mason_logger/mason_logger.dart'; @@ -24,9 +23,7 @@ const _expectedPackagesCheckLicensesUsage = [ void main() { group('packages check licenses', () { - final commandArguments = UnmodifiableListView( - ['packages', 'check', 'licenses'], - ); + const commandArguments = ['packages', 'check', 'licenses']; late Progress progress; From eec1abf09e1fc88d5d6db5b8eee6c319d64ccd77 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 10 Oct 2023 10:53:29 +0100 Subject: [PATCH 22/69] testing --- .../check/commands/licenses_test.dart | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/test/src/commands/packages/commands/check/commands/licenses_test.dart b/test/src/commands/packages/commands/check/commands/licenses_test.dart index 06508901..b446dc06 100644 --- a/test/src/commands/packages/commands/check/commands/licenses_test.dart +++ b/test/src/commands/packages/commands/check/commands/licenses_test.dart @@ -118,6 +118,84 @@ void main() { }, ); + group('ignore-failures', () { + const ignoreFailuresArgument = '--ignore-failures'; + + group('reports licenses', () { + test( + 'when a PubLicenseException is thrown', + withRunner( + (commandRunner, logger, pubUpdater, pubLicense, printLogs) async { + final tempDirectory = Directory.systemTemp.createTempSync(); + addTearDown(() => tempDirectory.deleteSync(recursive: true)); + + File(path.join(tempDirectory.path, pubspecLockBasename)) + .writeAsStringSync(_validMultiplePubspecLockContent); + + when(() => logger.progress(any())).thenReturn(progress); + + when(() => pubLicense.getLicense(any())).thenAnswer( + (_) => Future.value({'MIT'}), + ); + const failedDependencyName = 'very_good_test_runner'; + const exception = PubLicenseException('message'); + when(() => pubLicense.getLicense(failedDependencyName)) + .thenThrow(exception); + + final result = await commandRunner.run( + [...commandArguments, ignoreFailuresArgument, tempDirectory.path], + ); + + final errorMessage = + '''[$failedDependencyName] ${exception.message}'''; + verify(() => logger.err(errorMessage)).called(1); + + const report = + '''Retrieved 1 license from 2 packages of type: MIT.'''; + verify(() => progress.complete(report)).called(1); + + expect(result, equals(ExitCode.success.code)); + }), + ); + + test( + 'when an unknown error is thrown', + withRunner( + (commandRunner, logger, pubUpdater, pubLicense, printLogs) async { + final tempDirectory = Directory.systemTemp.createTempSync(); + addTearDown(() => tempDirectory.deleteSync(recursive: true)); + + File(path.join(tempDirectory.path, pubspecLockBasename)) + .writeAsStringSync(_validMultiplePubspecLockContent); + + when(() => logger.progress(any())).thenReturn(progress); + + when(() => pubLicense.getLicense(any())).thenAnswer( + (_) => Future.value({'MIT'}), + ); + const failedDependencyName = 'very_good_test_runner'; + const error = 'error'; + when(() => pubLicense.getLicense(failedDependencyName)) + .thenThrow(error); + + final result = await commandRunner.run( + [...commandArguments, ignoreFailuresArgument, tempDirectory.path], + ); + + const errorMessage = + '''[$failedDependencyName] Unexpected failure with error: $error'''; + verify(() => logger.err(errorMessage)).called(1); + + const report = + '''Retrieved 1 license from 2 packages of type: MIT.'''; + verify(() => progress.complete(report)).called(1); + + expect(result, equals(ExitCode.success.code)); + }), + ); + }); + }); + group('exits with error', () { test( 'when it did not find a pubspec.lock file at the target path', From 928e6997ac75abf19650dea869ffffca49bea11b Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 10 Oct 2023 11:28:12 +0100 Subject: [PATCH 23/69] more tests and fixes --- .../commands/check/commands/licenses.dart | 33 +++++--- .../check/commands/licenses_test.dart | 82 +++++++++++++++++-- 2 files changed, 94 insertions(+), 21 deletions(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index 7df4f521..58ebc2d6 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -78,15 +78,16 @@ class PackagesCheckLicensesCommand extends Command { return ExitCode.usage.code; } - final licenses = >{}; + final licenses = ?>{}; for (final dependency in filteredDependencies) { progress.update( 'Collecting licenses of ${licenses.length}/${filteredDependencies.length} packages', ); final dependencyName = dependency.package(); + Set? rawLicense; try { - licenses[dependencyName] = await _pubLicense.getLicense(dependencyName); + rawLicense = await _pubLicense.getLicense(dependencyName); } on PubLicenseException catch (e) { final errorMessage = '[$dependencyName] ${e.message}'; if (!ignoreFailures) { @@ -95,7 +96,7 @@ class PackagesCheckLicensesCommand extends Command { return ExitCode.unavailable.code; } - _logger.err(errorMessage); + _logger.err('\n$errorMessage'); } catch (e) { final errorMessage = '[$dependencyName] Unexpected failure with error: $e'; @@ -105,24 +106,30 @@ class PackagesCheckLicensesCommand extends Command { return ExitCode.software.code; } - _logger.err(errorMessage); + _logger.err('\n$errorMessage'); + } finally { + licenses[dependencyName] = rawLicense; } } - final licenseTypes = licenses.values.fold( - {}, - (previousValue, element) => previousValue..addAll(element), - ); - final licenseCount = licenses.values.fold( - 0, - (previousValue, element) => previousValue + element.length, - ); + final licenseTypes = + licenses.values.fold({}, (previousValue, element) { + if (element == null) return previousValue; + return previousValue..addAll(element); + }); + final licenseCount = licenses.values.fold(0, (previousValue, element) { + if (element == null) return previousValue; + return previousValue + element.length; + }); final licenseWord = licenseCount == 1 ? 'license' : 'licenses'; final packageWord = filteredDependencies.length == 1 ? 'package' : 'packages'; + final suffix = licenseTypes.isEmpty + ? '' + : ' of type: ${licenseTypes.toList().stringify()}'; progress.complete( - '''Retrieved $licenseCount $licenseWord from ${filteredDependencies.length} $packageWord of type: ${licenseTypes.toList().stringify()}.''', + '''Retrieved $licenseCount $licenseWord from ${filteredDependencies.length} $packageWord$suffix.''', ); return ExitCode.success.code; diff --git a/test/src/commands/packages/commands/check/commands/licenses_test.dart b/test/src/commands/packages/commands/check/commands/licenses_test.dart index b446dc06..7188958f 100644 --- a/test/src/commands/packages/commands/check/commands/licenses_test.dart +++ b/test/src/commands/packages/commands/check/commands/licenses_test.dart @@ -147,12 +147,20 @@ void main() { ); final errorMessage = - '''[$failedDependencyName] ${exception.message}'''; + '''\n[$failedDependencyName] ${exception.message}'''; verify(() => logger.err(errorMessage)).called(1); - const report = - '''Retrieved 1 license from 2 packages of type: MIT.'''; - verify(() => progress.complete(report)).called(1); + verify( + () => progress.update('Collecting licenses of 0/2 packages'), + ).called(1); + verify( + () => progress.update('Collecting licenses of 1/2 packages'), + ).called(1); + verify( + () => progress.complete( + 'Retrieved 1 license from 2 packages of type: MIT.', + ), + ).called(1); expect(result, equals(ExitCode.success.code)); }), @@ -183,17 +191,75 @@ void main() { ); const errorMessage = - '''[$failedDependencyName] Unexpected failure with error: $error'''; + '''\n[$failedDependencyName] Unexpected failure with error: $error'''; verify(() => logger.err(errorMessage)).called(1); - const report = - '''Retrieved 1 license from 2 packages of type: MIT.'''; - verify(() => progress.complete(report)).called(1); + verify( + () => progress.update('Collecting licenses of 0/2 packages'), + ).called(1); + verify( + () => progress.update('Collecting licenses of 1/2 packages'), + ).called(1); + verify( + () => progress.complete( + 'Retrieved 1 license from 2 packages of type: MIT.', + ), + ).called(1); expect(result, equals(ExitCode.success.code)); }), ); }); + + test( + 'when all licenses fail to be retrieved', + withRunner( + (commandRunner, logger, pubUpdater, pubLicense, printLogs) async { + final tempDirectory = Directory.systemTemp.createTempSync(); + addTearDown(() => tempDirectory.deleteSync(recursive: true)); + + File(path.join(tempDirectory.path, pubspecLockBasename)) + .writeAsStringSync(_validMultiplePubspecLockContent); + + when(() => logger.progress(any())).thenReturn(progress); + + const error = 'error'; + when(() => pubLicense.getLicense(any())).thenThrow(error); + + final result = await commandRunner.run( + [...commandArguments, ignoreFailuresArgument, tempDirectory.path], + ); + + final packageNames = verify(() => pubLicense.getLicense(captureAny())) + .captured + .cast(); + + verify( + () => logger.err( + '''\n[${packageNames[0]}] Unexpected failure with error: $error''', + ), + ).called(1); + verify( + () => logger.err( + '''\n[${packageNames[1]}] Unexpected failure with error: $error''', + ), + ).called(1); + + verify( + () => progress.update('Collecting licenses of 0/2 packages'), + ).called(1); + verify( + () => progress.update('Collecting licenses of 1/2 packages'), + ).called(1); + verify( + () => progress.complete( + 'Retrieved 0 licenses from 2 packages.', + ), + ).called(1); + + expect(result, equals(ExitCode.success.code)); + }), + ); }); group('exits with error', () { From 6fac91b6b14b985042c695840af634b11e894a9a Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 10 Oct 2023 11:31:54 +0100 Subject: [PATCH 24/69] test progress update --- .../check/commands/licenses_test.dart | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/test/src/commands/packages/commands/check/commands/licenses_test.dart b/test/src/commands/packages/commands/check/commands/licenses_test.dart index bc9bc6a8..9a6f19dd 100644 --- a/test/src/commands/packages/commands/check/commands/licenses_test.dart +++ b/test/src/commands/packages/commands/check/commands/licenses_test.dart @@ -77,9 +77,14 @@ void main() { [...commandArguments, tempDirectory.path], ); - const report = - '''Retrieved 1 license from 1 package of type: MIT.'''; - verify(() => progress.complete(report)).called(1); + verify( + () => progress.update('Collecting licenses of 0/1 packages'), + ).called(1); + verify( + () => progress.complete( + '''Retrieved 1 license from 1 package of type: MIT.''', + ), + ).called(1); expect(result, equals(ExitCode.success.code)); }), @@ -104,9 +109,17 @@ void main() { [...commandArguments, tempDirectory.path], ); - const report = - '''Retrieved 4 licenses from 2 packages of type: MIT and BSD.'''; - verify(() => progress.complete(report)).called(1); + verify( + () => progress.update('Collecting licenses of 0/2 packages'), + ).called(1); + verify( + () => progress.update('Collecting licenses of 1/2 packages'), + ).called(1); + verify( + () => progress.complete( + '''Retrieved 4 licenses from 2 packages of type: MIT and BSD.''', + ), + ).called(1); expect(result, equals(ExitCode.success.code)); }), From f75c0d585888dc9aaa86baa5498e50bd583dd2f4 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 10 Oct 2023 11:44:19 +0100 Subject: [PATCH 25/69] removed TODO --- lib/src/commands/packages/commands/check/commands/licenses.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index 58ebc2d6..c50636bd 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -47,7 +47,6 @@ class PackagesCheckLicensesCommand extends Command { @override Future run() async { - // TODO(alestiago): Usage exception when too many arguments. final ignoreFailures = _argResults['ignore-failures'] as bool; final target = _argResults.rest.length == 1 ? _argResults.rest[0] : '.'; From b1c49e4d38e9444bc3161d624c99e2d043938cbd Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 10 Oct 2023 11:51:02 +0100 Subject: [PATCH 26/69] refactor _composeReport --- .../commands/check/commands/licenses.dart | 42 ++++++++++--------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index c50636bd..a52b9462 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -111,25 +111,7 @@ class PackagesCheckLicensesCommand extends Command { } } - final licenseTypes = - licenses.values.fold({}, (previousValue, element) { - if (element == null) return previousValue; - return previousValue..addAll(element); - }); - final licenseCount = licenses.values.fold(0, (previousValue, element) { - if (element == null) return previousValue; - return previousValue + element.length; - }); - - final licenseWord = licenseCount == 1 ? 'license' : 'licenses'; - final packageWord = - filteredDependencies.length == 1 ? 'package' : 'packages'; - final suffix = licenseTypes.isEmpty - ? '' - : ' of type: ${licenseTypes.toList().stringify()}'; - progress.complete( - '''Retrieved $licenseCount $licenseWord from ${filteredDependencies.length} $packageWord$suffix.''', - ); + progress.complete(_composeReport(licenses)); return ExitCode.success.code; } @@ -156,6 +138,28 @@ bool _isHostedDirectDependency( return isPubHostedDependency && isDirectDependency; } +/// Composes a human friendly [String] to report the result of the retrieved +/// licenses. +String _composeReport(Map?> licenses) { + final licenseTypes = + licenses.values.fold({}, (previousValue, element) { + if (element == null) return previousValue; + return previousValue..addAll(element); + }); + final licenseCount = licenses.values.fold(0, (previousValue, element) { + if (element == null) return previousValue; + return previousValue + element.length; + }); + + final licenseWord = licenseCount == 1 ? 'license' : 'licenses'; + final packageWord = licenses.length == 1 ? 'package' : 'packages'; + final suffix = licenseTypes.isEmpty + ? '' + : ' of type: ${licenseTypes.toList().stringify()}'; + + return '''Retrieved $licenseCount $licenseWord from ${licenses.length} $packageWord$suffix.'''; +} + extension on List { String stringify() { if (isEmpty) return ''; From 3b97198c0c51626786e03eeaabe8bd3aeece6277 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 10 Oct 2023 12:06:27 +0100 Subject: [PATCH 27/69] usage exception --- .../packages/commands/check/commands/licenses.dart | 4 ++++ .../commands/check/commands/licenses_test.dart | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index dd426a1b..9bd83ba8 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -41,6 +41,10 @@ class PackagesCheckLicensesCommand extends Command { @override Future run() async { + if (_argResults.rest.length > 1) { + usageException('Too many arguments'); + } + final target = _argResults.rest.length == 1 ? _argResults.rest[0] : '.'; final targetPath = path.normalize(Directory(target).absolute.path); diff --git a/test/src/commands/packages/commands/check/commands/licenses_test.dart b/test/src/commands/packages/commands/check/commands/licenses_test.dart index 9a6f19dd..15bda6f9 100644 --- a/test/src/commands/packages/commands/check/commands/licenses_test.dart +++ b/test/src/commands/packages/commands/check/commands/licenses_test.dart @@ -58,6 +58,17 @@ void main() { expect(command.hidden, isTrue); }); + test( + '''throws usage exception when too many rest arguments are provided''', + withRunner( + (commandRunner, logger, pubUpdater, pubLicense, printLogs) async { + final result = await commandRunner.run( + [...commandArguments, 'arg1', 'arg2'], + ); + expect(result, equals(ExitCode.usage.code)); + }), + ); + group( 'reports licenses', () { From 8ce817c917a5834227eabca435bea9c28c068b05 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 10 Oct 2023 12:37:23 +0100 Subject: [PATCH 28/69] feat: add `dependency-type` to `check licenses` --- .../commands/check/commands/licenses.dart | 57 +++++++++++++------ 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index bad6f045..38d327f3 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -22,11 +22,27 @@ class PackagesCheckLicensesCommand extends Command { PubLicense? pubLicense, }) : _logger = logger ?? Logger(), _pubLicense = pubLicense ?? PubLicense() { - argParser.addFlag( - 'ignore-failures', - help: 'Avoids terminating whenever a license fails to be retrieved.', - negatable: false, - ); + argParser + ..addFlag( + 'ignore-failures', + help: 'Avoids terminating whenever a license fails to be retrieved.', + negatable: false, + ) + ..addMultiOption( + 'dependency-type', + help: 'The type of dependencies to check licenses for.', + allowed: [ + 'direct-main', + 'direct-dev', + 'transitive', + ], + allowedHelp: { + 'direct-main': 'Check for direct main dependencies.', + 'direct-dev': 'Check for direct dev dependencies.', + 'transitive': 'Check for transitive dependencies.', + }, + defaultsTo: ['direct-main'], + ); } final Logger _logger; @@ -50,8 +66,13 @@ class PackagesCheckLicensesCommand extends Command { if (_argResults.rest.length > 1) { usageException('Too many arguments'); } - + final ignoreFailures = _argResults['ignore-failures'] as bool; + final dependencyTypes = _argResults['dependency-type'] as List; + + if (dependencyTypes.isEmpty) { + usageException('No dependency types specified'); + } final target = _argResults.rest.length == 1 ? _argResults.rest[0] : '.'; final targetPath = path.normalize(Directory(target).absolute.path); @@ -72,8 +93,19 @@ class PackagesCheckLicensesCommand extends Command { return ExitCode.noInput.code; } - final filteredDependencies = - pubspecLock.packages.where(_isHostedDirectDependency); + final filteredDependencies = pubspecLock.packages.where((dependency) { + final dependencyType = dependency.type(); + // ignore: invalid_use_of_protected_member + final isPubHosted = dependency.hosted != null; + if (!isPubHosted) return false; + + return (dependencyTypes.contains('direct-main') && + dependencyType == DependencyType.direct) || + (dependencyTypes.contains('direct-dev') && + dependencyType == DependencyType.development) || + (dependencyTypes.contains('transitive') && + dependencyType == DependencyType.transitive); + }); if (filteredDependencies.isEmpty) { progress.cancel(); @@ -133,15 +165,6 @@ PubspecLock? _tryParsePubspecLock(File pubspecLockFile) { } } -bool _isHostedDirectDependency( - PackageDependency dependency, -) { - // ignore: invalid_use_of_protected_member - final isPubHostedDependency = dependency.hosted != null; - final isDirectDependency = dependency.type() == DependencyType.direct; - return isPubHostedDependency && isDirectDependency; -} - /// Composes a human friendly [String] to report the result of the retrieved /// licenses. String _composeReport(Map?> licenses) { From cd321ebb473ec3a5233f2c3484787b02aaf6d1dc Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 10 Oct 2023 12:38:26 +0100 Subject: [PATCH 29/69] format --- lib/src/commands/packages/commands/check/commands/licenses.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index bad6f045..1f655e3f 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -50,7 +50,7 @@ class PackagesCheckLicensesCommand extends Command { if (_argResults.rest.length > 1) { usageException('Too many arguments'); } - + final ignoreFailures = _argResults['ignore-failures'] as bool; final target = _argResults.rest.length == 1 ? _argResults.rest[0] : '.'; From 10a9c75d98864f7293a67059b23e7d9b80cd9981 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 10 Oct 2023 13:07:52 +0100 Subject: [PATCH 30/69] updated usage --- .../commands/check/commands/licenses_test.dart | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/test/src/commands/packages/commands/check/commands/licenses_test.dart b/test/src/commands/packages/commands/check/commands/licenses_test.dart index 6ea91005..ed34c981 100644 --- a/test/src/commands/packages/commands/check/commands/licenses_test.dart +++ b/test/src/commands/packages/commands/check/commands/licenses_test.dart @@ -16,8 +16,13 @@ const _expectedPackagesCheckLicensesUsage = [ 'Check packages licenses in a Dart or Flutter project.\n' '\n' 'Usage: very_good packages check licenses [arguments]\n' - '-h, --help Print this usage information.\n' - ''' --ignore-failures Avoids terminating whenever a license fails to be retrieved.\n''' + '-h, --help Print this usage information.\n' + ''' --ignore-failures Avoids terminating whenever a license fails to be retrieved.\n''' + ''' --dependency-type The type of dependencies to check licenses for.\n''' + '\n' + ''' [direct-dev] Check for direct dev dependencies.\n''' + ''' [direct-main] (default) Check for direct main dependencies.\n''' + ''' [transitive] Check for transitive dependencies.\n''' '\n' 'Run "very_good help" to see global options.' ]; @@ -283,6 +288,8 @@ void main() { ); }); + group('dependency-type', () {}); + group('exits with error', () { test( 'when it did not find a pubspec.lock file at the target path', From 097beaf0409b665b8c40a540674c276aa718341e Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 10 Oct 2023 13:16:57 +0100 Subject: [PATCH 31/69] started testing --- .../commands/check/commands/licenses.dart | 4 -- .../check/commands/licenses_test.dart | 41 ++++++++++++++++++- 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index 38d327f3..3af1eb85 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -70,10 +70,6 @@ class PackagesCheckLicensesCommand extends Command { final ignoreFailures = _argResults['ignore-failures'] as bool; final dependencyTypes = _argResults['dependency-type'] as List; - if (dependencyTypes.isEmpty) { - usageException('No dependency types specified'); - } - final target = _argResults.rest.length == 1 ? _argResults.rest[0] : '.'; final targetPath = path.normalize(Directory(target).absolute.path); diff --git a/test/src/commands/packages/commands/check/commands/licenses_test.dart b/test/src/commands/packages/commands/check/commands/licenses_test.dart index ed34c981..fdd97793 100644 --- a/test/src/commands/packages/commands/check/commands/licenses_test.dart +++ b/test/src/commands/packages/commands/check/commands/licenses_test.dart @@ -288,7 +288,46 @@ void main() { ); }); - group('dependency-type', () {}); + group('dependency-type', () { + const dependencyTypeArgument = '--dependency-type'; + const dependencyTypeMainDirectOption = 'direct-main'; + const dependencyTypeDevDirectOption = 'direct-dev'; + const dependencyTypeTransitiveOption = 'transitive'; + + group('throws usage exception', () { + test( + 'when no option is provided', + withRunner( + (commandRunner, logger, pubUpdater, pubLicense, printLogs) async { + final result = await commandRunner.run( + [...commandArguments, dependencyTypeArgument], + ); + expect(result, equals(ExitCode.usage.code)); + }), + ); + + test( + 'when invalid option is provided', + withRunner( + (commandRunner, logger, pubUpdater, pubLicense, printLogs) async { + final result = await commandRunner.run( + [...commandArguments, dependencyTypeArgument, 'invalid'], + ); + expect(result, equals(ExitCode.usage.code)); + }), + ); + + group('reports licenses', () { + test('on developer main dependencies only', () {}); + + test('on developer dev dependencies only', () {}); + + test('on transitive dependencies only', () {}); + + test('on all dependencies', () {}); + }); + }); + }); group('exits with error', () { test( From 56eb24bfc3e8077f666d5e590ff7313aef0f5a0b Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 10 Oct 2023 13:48:32 +0100 Subject: [PATCH 32/69] reach test coverage --- .../check/commands/licenses_test.dart | 198 ++++++++++++++++-- 1 file changed, 185 insertions(+), 13 deletions(-) diff --git a/test/src/commands/packages/commands/check/commands/licenses_test.dart b/test/src/commands/packages/commands/check/commands/licenses_test.dart index fdd97793..9e73a8e0 100644 --- a/test/src/commands/packages/commands/check/commands/licenses_test.dart +++ b/test/src/commands/packages/commands/check/commands/licenses_test.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:collection/collection.dart'; import 'package:mason_logger/mason_logger.dart'; import 'package:mocktail/mocktail.dart'; import 'package:path/path.dart' as path; @@ -318,13 +319,184 @@ void main() { ); group('reports licenses', () { - test('on developer main dependencies only', () {}); - - test('on developer dev dependencies only', () {}); + /// A map of dependencies by type from [_validPubspecLockContent]. + const dependenciesByType = { + dependencyTypeMainDirectOption: ['very_good_test_runner'], + dependencyTypeDevDirectOption: ['very_good_analysis'], + dependencyTypeTransitiveOption: ['yaml'], + }; + + group('on developer main dependencies only', () { + test('by default', () {}); + + test('when specified', () {}); + }); + + test( + 'on developer dev dependencies only', + withRunner(( + commandRunner, + logger, + pubUpdater, + pubLicense, + printLogs, + ) async { + final tempDirectory = Directory.systemTemp.createTempSync(); + addTearDown(() => tempDirectory.deleteSync(recursive: true)); + + File(path.join(tempDirectory.path, pubspecLockBasename)) + .writeAsStringSync(_validPubspecLockContent); + + when(() => logger.progress(any())).thenReturn(progress); + + when(() => pubLicense.getLicense(any())) + .thenAnswer((_) => Future.value({'MIT'})); + + final result = await commandRunner.run( + [ + ...commandArguments, + dependencyTypeArgument, + dependencyTypeDevDirectOption, + tempDirectory.path, + ], + ); + + final packageNames = + verify(() => pubLicense.getLicense(captureAny())) + .captured + .cast(); + + expect( + packageNames, + equals(dependenciesByType[dependencyTypeDevDirectOption]), + ); + + verify( + () => progress.update('Collecting licenses of 0/1 packages'), + ).called(1); + verify( + () => progress.complete( + 'Retrieved 1 license from 1 package of type: MIT.', + ), + ).called(1); + + expect(result, equals(ExitCode.success.code)); + }), + ); - test('on transitive dependencies only', () {}); + test( + 'on transitive dependencies only', + withRunner(( + commandRunner, + logger, + pubUpdater, + pubLicense, + printLogs, + ) async { + final tempDirectory = Directory.systemTemp.createTempSync(); + addTearDown(() => tempDirectory.deleteSync(recursive: true)); + + File(path.join(tempDirectory.path, pubspecLockBasename)) + .writeAsStringSync(_validPubspecLockContent); + + when(() => logger.progress(any())).thenReturn(progress); + + when(() => pubLicense.getLicense(any())) + .thenAnswer((_) => Future.value({'MIT'})); + + final result = await commandRunner.run( + [ + ...commandArguments, + dependencyTypeArgument, + dependencyTypeTransitiveOption, + tempDirectory.path, + ], + ); + + final packageNames = + verify(() => pubLicense.getLicense(captureAny())) + .captured + .cast(); + + expect( + packageNames, + equals(dependenciesByType[dependencyTypeTransitiveOption]), + ); + + verify( + () => progress.update('Collecting licenses of 0/1 packages'), + ).called(1); + verify( + () => progress.complete( + 'Retrieved 1 license from 1 package of type: MIT.', + ), + ).called(1); + + expect(result, equals(ExitCode.success.code)); + }), + ); - test('on all dependencies', () {}); + test( + 'on all dependencies', + withRunner(( + commandRunner, + logger, + pubUpdater, + pubLicense, + printLogs, + ) async { + final tempDirectory = Directory.systemTemp.createTempSync(); + addTearDown(() => tempDirectory.deleteSync(recursive: true)); + + File(path.join(tempDirectory.path, pubspecLockBasename)) + .writeAsStringSync(_validPubspecLockContent); + + when(() => logger.progress(any())).thenReturn(progress); + + when(() => pubLicense.getLicense(any())) + .thenAnswer((_) => Future.value({'MIT'})); + + final result = await commandRunner.run( + [ + ...commandArguments, + dependencyTypeArgument, + dependencyTypeDevDirectOption, + dependencyTypeArgument, + dependencyTypeTransitiveOption, + dependencyTypeArgument, + dependencyTypeMainDirectOption, + tempDirectory.path, + ], + ); + + final packageNames = + verify(() => pubLicense.getLicense(captureAny())) + .captured + .cast(); + + expect( + packageNames, + equals([...dependenciesByType.values].flattened), + ); + + verify( + () => progress.update('Collecting licenses of 0/3 packages'), + ).called(1); + verify( + () => progress.update('Collecting licenses of 1/3 packages'), + ).called(1); + verify( + () => progress.update('Collecting licenses of 2/3 packages'), + ).called(1); + verify( + () => progress.complete( + 'Retrieved 3 licenses from 3 packages of type: MIT.', + ), + ).called(1); + + expect(result, equals(ExitCode.success.code)); + }), + ); }); }); }); @@ -485,14 +657,6 @@ void main() { /// - one hosted transitive dependency const _validPubspecLockContent = ''' packages: - very_good_analysis: - dependency: "direct dev" - description: - name: very_good_analysis - sha256: "9ae7f3a3bd5764fb021b335ca28a34f040cd0ab6eec00a1b213b445dae58a4b8" - url: "https://pub.dev" - source: hosted - version: "5.1.0" very_good_test_runner: dependency: "direct main" description: @@ -501,6 +665,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.1.2" + very_good_analysis: + dependency: "direct dev" + description: + name: very_good_analysis + sha256: "9ae7f3a3bd5764fb021b335ca28a34f040cd0ab6eec00a1b213b445dae58a4b8" + url: "https://pub.dev" + source: hosted + version: "5.1.0" yaml: dependency: transitive description: From 8876d4e48209494e49e5ac948719ce3b07ce5ae1 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 10 Oct 2023 13:50:18 +0100 Subject: [PATCH 33/69] refactor dependencyType --- lib/src/commands/packages/commands/check/commands/licenses.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index 3af1eb85..5fd4d2cd 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -90,11 +90,11 @@ class PackagesCheckLicensesCommand extends Command { } final filteredDependencies = pubspecLock.packages.where((dependency) { - final dependencyType = dependency.type(); // ignore: invalid_use_of_protected_member final isPubHosted = dependency.hosted != null; if (!isPubHosted) return false; + final dependencyType = dependency.type(); return (dependencyTypes.contains('direct-main') && dependencyType == DependencyType.direct) || (dependencyTypes.contains('direct-dev') && From 461808ab9285931229adaa838fa6c067d529d9d5 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 10 Oct 2023 14:06:08 +0100 Subject: [PATCH 34/69] completed all tests --- .../check/commands/licenses_test.dart | 108 +++++++++++++++--- 1 file changed, 91 insertions(+), 17 deletions(-) diff --git a/test/src/commands/packages/commands/check/commands/licenses_test.dart b/test/src/commands/packages/commands/check/commands/licenses_test.dart index 9e73a8e0..d4e0b194 100644 --- a/test/src/commands/packages/commands/check/commands/licenses_test.dart +++ b/test/src/commands/packages/commands/check/commands/licenses_test.dart @@ -161,9 +161,6 @@ void main() { when(() => logger.progress(any())).thenReturn(progress); - when(() => pubLicense.getLicense(any())).thenAnswer( - (_) => Future.value({'MIT'}), - ); const failedDependencyName = 'very_good_test_runner'; const exception = PubLicenseException('message'); when(() => pubLicense.getLicense(failedDependencyName)) @@ -205,9 +202,6 @@ void main() { when(() => logger.progress(any())).thenReturn(progress); - when(() => pubLicense.getLicense(any())).thenAnswer( - (_) => Future.value({'MIT'}), - ); const failedDependencyName = 'very_good_test_runner'; const error = 'error'; when(() => pubLicense.getLicense(failedDependencyName)) @@ -327,9 +321,98 @@ void main() { }; group('on developer main dependencies only', () { - test('by default', () {}); + test( + 'by default', + withRunner(( + commandRunner, + logger, + pubUpdater, + pubLicense, + printLogs, + ) async { + final tempDirectory = Directory.systemTemp.createTempSync(); + addTearDown(() => tempDirectory.deleteSync(recursive: true)); + + File(path.join(tempDirectory.path, pubspecLockBasename)) + .writeAsStringSync(_validPubspecLockContent); + + when(() => logger.progress(any())).thenReturn(progress); + + final result = await commandRunner.run( + [...commandArguments, tempDirectory.path], + ); + + final packageNames = + verify(() => pubLicense.getLicense(captureAny())) + .captured + .cast(); + + expect( + packageNames, + equals(dependenciesByType[dependencyTypeMainDirectOption]), + ); + + verify( + () => progress.update('Collecting licenses of 0/1 packages'), + ).called(1); + verify( + () => progress.complete( + 'Retrieved 1 license from 1 package of type: MIT.', + ), + ).called(1); + + expect(result, equals(ExitCode.success.code)); + }), + ); - test('when specified', () {}); + test( + 'when specified', + withRunner(( + commandRunner, + logger, + pubUpdater, + pubLicense, + printLogs, + ) async { + final tempDirectory = Directory.systemTemp.createTempSync(); + addTearDown(() => tempDirectory.deleteSync(recursive: true)); + + File(path.join(tempDirectory.path, pubspecLockBasename)) + .writeAsStringSync(_validPubspecLockContent); + + when(() => logger.progress(any())).thenReturn(progress); + + final result = await commandRunner.run( + [ + ...commandArguments, + dependencyTypeArgument, + dependencyTypeMainDirectOption, + tempDirectory.path, + ], + ); + + final packageNames = + verify(() => pubLicense.getLicense(captureAny())) + .captured + .cast(); + + expect( + packageNames, + equals(dependenciesByType[dependencyTypeMainDirectOption]), + ); + + verify( + () => progress.update('Collecting licenses of 0/1 packages'), + ).called(1); + verify( + () => progress.complete( + 'Retrieved 1 license from 1 package of type: MIT.', + ), + ).called(1); + + expect(result, equals(ExitCode.success.code)); + }), + ); }); test( @@ -349,9 +432,6 @@ void main() { when(() => logger.progress(any())).thenReturn(progress); - when(() => pubLicense.getLicense(any())) - .thenAnswer((_) => Future.value({'MIT'})); - final result = await commandRunner.run( [ ...commandArguments, @@ -401,9 +481,6 @@ void main() { when(() => logger.progress(any())).thenReturn(progress); - when(() => pubLicense.getLicense(any())) - .thenAnswer((_) => Future.value({'MIT'})); - final result = await commandRunner.run( [ ...commandArguments, @@ -453,9 +530,6 @@ void main() { when(() => logger.progress(any())).thenReturn(progress); - when(() => pubLicense.getLicense(any())) - .thenAnswer((_) => Future.value({'MIT'})); - final result = await commandRunner.run( [ ...commandArguments, From 0b499493ae9bcead05e6fbd06b18ace90f8b465d Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Wed, 11 Oct 2023 09:20:08 +0100 Subject: [PATCH 35/69] update flag description --- lib/src/commands/packages/commands/check/commands/licenses.dart | 2 +- .../packages/commands/check/commands/licenses_test.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index 6ea505ed..439e83d4 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -24,7 +24,7 @@ class PackagesCheckLicensesCommand extends Command { _pubLicense = pubLicense ?? PubLicense() { argParser.addFlag( 'ignore-failures', - help: 'Avoids terminating whenever a license fails to be retrieved.', + help: 'Ignore any license that failed to be retrieved.', negatable: false, ); } diff --git a/test/src/commands/packages/commands/check/commands/licenses_test.dart b/test/src/commands/packages/commands/check/commands/licenses_test.dart index 6ea91005..226aad7a 100644 --- a/test/src/commands/packages/commands/check/commands/licenses_test.dart +++ b/test/src/commands/packages/commands/check/commands/licenses_test.dart @@ -17,7 +17,7 @@ const _expectedPackagesCheckLicensesUsage = [ '\n' 'Usage: very_good packages check licenses [arguments]\n' '-h, --help Print this usage information.\n' - ''' --ignore-failures Avoids terminating whenever a license fails to be retrieved.\n''' + ''' --ignore-failures Ignore any license that failed to be retrieved.\n''' '\n' 'Run "very_good help" to see global options.' ]; From 840d267b090e58a945601fc4b6413376776d9c98 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Wed, 11 Oct 2023 09:29:01 +0100 Subject: [PATCH 36/69] chore: generated spdx_license.gen.dart --- lib/src/pub_license/spdx_license.gen.dart | 645 ++++++++++++++++++++++ tool/spdx_license/CONTRIBUTING.md | 2 +- 2 files changed, 646 insertions(+), 1 deletion(-) create mode 100644 lib/src/pub_license/spdx_license.gen.dart diff --git a/lib/src/pub_license/spdx_license.gen.dart b/lib/src/pub_license/spdx_license.gen.dart new file mode 100644 index 00000000..eaa4e6e0 --- /dev/null +++ b/lib/src/pub_license/spdx_license.gen.dart @@ -0,0 +1,645 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// +// If you need to make changes, please refer to the SPDX License brick +// CONTRIBUTING file. + +// ignore_for_file: type=lint + +/// List of all SPDX licenses. +/// +/// This file was automatically generated with the SPDX License brick. +library spdx_license; + +/// {@template spdx_license} +/// A list of all 599 SPDX licenses. +/// +/// These have been automatically generated from the SPDX License brick. +/// {@endtemplate} +enum SpdxLicense { + $0BSD._('0BSD'), + $AAL._('AAL'), + $ADSL._('ADSL'), + $AFL_1_1._('AFL-1.1'), + $AFL_1_2._('AFL-1.2'), + $AFL_2_0._('AFL-2.0'), + $AFL_2_1._('AFL-2.1'), + $AFL_3_0._('AFL-3.0'), + $AGPL_1_0._('AGPL-1.0'), + $AGPL_1_0_only._('AGPL-1.0-only'), + $AGPL_1_0_or_later._('AGPL-1.0-or-later'), + $AGPL_3_0._('AGPL-3.0'), + $AGPL_3_0_only._('AGPL-3.0-only'), + $AGPL_3_0_or_later._('AGPL-3.0-or-later'), + $AMDPLPA._('AMDPLPA'), + $AML._('AML'), + $AMPAS._('AMPAS'), + $ANTLR_PD._('ANTLR-PD'), + $ANTLR_PD_fallback._('ANTLR-PD-fallback'), + $APAFML._('APAFML'), + $APL_1_0._('APL-1.0'), + $APSL_1_0._('APSL-1.0'), + $APSL_1_1._('APSL-1.1'), + $APSL_1_2._('APSL-1.2'), + $APSL_2_0._('APSL-2.0'), + $ASWF_Digital_Assets_1_0._('ASWF-Digital-Assets-1.0'), + $ASWF_Digital_Assets_1_1._('ASWF-Digital-Assets-1.1'), + $Abstyles._('Abstyles'), + $AdaCore_doc._('AdaCore-doc'), + $Adobe_2006._('Adobe-2006'), + $Adobe_Glyph._('Adobe-Glyph'), + $Adobe_Utopia._('Adobe-Utopia'), + $Afmparse._('Afmparse'), + $Aladdin._('Aladdin'), + $Apache_1_0._('Apache-1.0'), + $Apache_1_1._('Apache-1.1'), + $Apache_2_0._('Apache-2.0'), + $App_s2p._('App-s2p'), + $Arphic_1999._('Arphic-1999'), + $Artistic_1_0._('Artistic-1.0'), + $Artistic_1_0_Perl._('Artistic-1.0-Perl'), + $Artistic_1_0_cl8._('Artistic-1.0-cl8'), + $Artistic_2_0._('Artistic-2.0'), + $BSD_1_Clause._('BSD-1-Clause'), + $BSD_2_Clause._('BSD-2-Clause'), + $BSD_2_Clause_FreeBSD._('BSD-2-Clause-FreeBSD'), + $BSD_2_Clause_NetBSD._('BSD-2-Clause-NetBSD'), + $BSD_2_Clause_Patent._('BSD-2-Clause-Patent'), + $BSD_2_Clause_Views._('BSD-2-Clause-Views'), + $BSD_3_Clause._('BSD-3-Clause'), + $BSD_3_Clause_Attribution._('BSD-3-Clause-Attribution'), + $BSD_3_Clause_Clear._('BSD-3-Clause-Clear'), + $BSD_3_Clause_HP._('BSD-3-Clause-HP'), + $BSD_3_Clause_LBNL._('BSD-3-Clause-LBNL'), + $BSD_3_Clause_Modification._('BSD-3-Clause-Modification'), + $BSD_3_Clause_No_Military_License._('BSD-3-Clause-No-Military-License'), + $BSD_3_Clause_No_Nuclear_License._('BSD-3-Clause-No-Nuclear-License'), + $BSD_3_Clause_No_Nuclear_License_2014._('BSD-3-Clause-No-Nuclear-License-2014'), + $BSD_3_Clause_No_Nuclear_Warranty._('BSD-3-Clause-No-Nuclear-Warranty'), + $BSD_3_Clause_Open_MPI._('BSD-3-Clause-Open-MPI'), + $BSD_3_Clause_Sun._('BSD-3-Clause-Sun'), + $BSD_3_Clause_flex._('BSD-3-Clause-flex'), + $BSD_4_Clause._('BSD-4-Clause'), + $BSD_4_Clause_Shortened._('BSD-4-Clause-Shortened'), + $BSD_4_Clause_UC._('BSD-4-Clause-UC'), + $BSD_4_3RENO._('BSD-4.3RENO'), + $BSD_4_3TAHOE._('BSD-4.3TAHOE'), + $BSD_Advertising_Acknowledgement._('BSD-Advertising-Acknowledgement'), + $BSD_Attribution_HPND_disclaimer._('BSD-Attribution-HPND-disclaimer'), + $BSD_Inferno_Nettverk._('BSD-Inferno-Nettverk'), + $BSD_Protection._('BSD-Protection'), + $BSD_Source_Code._('BSD-Source-Code'), + $BSD_Systemics._('BSD-Systemics'), + $BSL_1_0._('BSL-1.0'), + $BUSL_1_1._('BUSL-1.1'), + $Baekmuk._('Baekmuk'), + $Bahyph._('Bahyph'), + $Barr._('Barr'), + $Beerware._('Beerware'), + $BitTorrent_1_0._('BitTorrent-1.0'), + $BitTorrent_1_1._('BitTorrent-1.1'), + $Bitstream_Charter._('Bitstream-Charter'), + $Bitstream_Vera._('Bitstream-Vera'), + $BlueOak_1_0_0._('BlueOak-1.0.0'), + $Boehm_GC._('Boehm-GC'), + $Borceux._('Borceux'), + $Brian_Gladman_3_Clause._('Brian-Gladman-3-Clause'), + $C_UDA_1_0._('C-UDA-1.0'), + $CAL_1_0._('CAL-1.0'), + $CAL_1_0_Combined_Work_Exception._('CAL-1.0-Combined-Work-Exception'), + $CATOSL_1_1._('CATOSL-1.1'), + $CC_BY_1_0._('CC-BY-1.0'), + $CC_BY_2_0._('CC-BY-2.0'), + $CC_BY_2_5._('CC-BY-2.5'), + $CC_BY_2_5_AU._('CC-BY-2.5-AU'), + $CC_BY_3_0._('CC-BY-3.0'), + $CC_BY_3_0_AT._('CC-BY-3.0-AT'), + $CC_BY_3_0_DE._('CC-BY-3.0-DE'), + $CC_BY_3_0_IGO._('CC-BY-3.0-IGO'), + $CC_BY_3_0_NL._('CC-BY-3.0-NL'), + $CC_BY_3_0_US._('CC-BY-3.0-US'), + $CC_BY_4_0._('CC-BY-4.0'), + $CC_BY_NC_1_0._('CC-BY-NC-1.0'), + $CC_BY_NC_2_0._('CC-BY-NC-2.0'), + $CC_BY_NC_2_5._('CC-BY-NC-2.5'), + $CC_BY_NC_3_0._('CC-BY-NC-3.0'), + $CC_BY_NC_3_0_DE._('CC-BY-NC-3.0-DE'), + $CC_BY_NC_4_0._('CC-BY-NC-4.0'), + $CC_BY_NC_ND_1_0._('CC-BY-NC-ND-1.0'), + $CC_BY_NC_ND_2_0._('CC-BY-NC-ND-2.0'), + $CC_BY_NC_ND_2_5._('CC-BY-NC-ND-2.5'), + $CC_BY_NC_ND_3_0._('CC-BY-NC-ND-3.0'), + $CC_BY_NC_ND_3_0_DE._('CC-BY-NC-ND-3.0-DE'), + $CC_BY_NC_ND_3_0_IGO._('CC-BY-NC-ND-3.0-IGO'), + $CC_BY_NC_ND_4_0._('CC-BY-NC-ND-4.0'), + $CC_BY_NC_SA_1_0._('CC-BY-NC-SA-1.0'), + $CC_BY_NC_SA_2_0._('CC-BY-NC-SA-2.0'), + $CC_BY_NC_SA_2_0_DE._('CC-BY-NC-SA-2.0-DE'), + $CC_BY_NC_SA_2_0_FR._('CC-BY-NC-SA-2.0-FR'), + $CC_BY_NC_SA_2_0_UK._('CC-BY-NC-SA-2.0-UK'), + $CC_BY_NC_SA_2_5._('CC-BY-NC-SA-2.5'), + $CC_BY_NC_SA_3_0._('CC-BY-NC-SA-3.0'), + $CC_BY_NC_SA_3_0_DE._('CC-BY-NC-SA-3.0-DE'), + $CC_BY_NC_SA_3_0_IGO._('CC-BY-NC-SA-3.0-IGO'), + $CC_BY_NC_SA_4_0._('CC-BY-NC-SA-4.0'), + $CC_BY_ND_1_0._('CC-BY-ND-1.0'), + $CC_BY_ND_2_0._('CC-BY-ND-2.0'), + $CC_BY_ND_2_5._('CC-BY-ND-2.5'), + $CC_BY_ND_3_0._('CC-BY-ND-3.0'), + $CC_BY_ND_3_0_DE._('CC-BY-ND-3.0-DE'), + $CC_BY_ND_4_0._('CC-BY-ND-4.0'), + $CC_BY_SA_1_0._('CC-BY-SA-1.0'), + $CC_BY_SA_2_0._('CC-BY-SA-2.0'), + $CC_BY_SA_2_0_UK._('CC-BY-SA-2.0-UK'), + $CC_BY_SA_2_1_JP._('CC-BY-SA-2.1-JP'), + $CC_BY_SA_2_5._('CC-BY-SA-2.5'), + $CC_BY_SA_3_0._('CC-BY-SA-3.0'), + $CC_BY_SA_3_0_AT._('CC-BY-SA-3.0-AT'), + $CC_BY_SA_3_0_DE._('CC-BY-SA-3.0-DE'), + $CC_BY_SA_3_0_IGO._('CC-BY-SA-3.0-IGO'), + $CC_BY_SA_4_0._('CC-BY-SA-4.0'), + $CC_PDDC._('CC-PDDC'), + $CC0_1_0._('CC0-1.0'), + $CDDL_1_0._('CDDL-1.0'), + $CDDL_1_1._('CDDL-1.1'), + $CDL_1_0._('CDL-1.0'), + $CDLA_Permissive_1_0._('CDLA-Permissive-1.0'), + $CDLA_Permissive_2_0._('CDLA-Permissive-2.0'), + $CDLA_Sharing_1_0._('CDLA-Sharing-1.0'), + $CECILL_1_0._('CECILL-1.0'), + $CECILL_1_1._('CECILL-1.1'), + $CECILL_2_0._('CECILL-2.0'), + $CECILL_2_1._('CECILL-2.1'), + $CECILL_B._('CECILL-B'), + $CECILL_C._('CECILL-C'), + $CERN_OHL_1_1._('CERN-OHL-1.1'), + $CERN_OHL_1_2._('CERN-OHL-1.2'), + $CERN_OHL_P_2_0._('CERN-OHL-P-2.0'), + $CERN_OHL_S_2_0._('CERN-OHL-S-2.0'), + $CERN_OHL_W_2_0._('CERN-OHL-W-2.0'), + $CFITSIO._('CFITSIO'), + $CMU_Mach._('CMU-Mach'), + $CNRI_Jython._('CNRI-Jython'), + $CNRI_Python._('CNRI-Python'), + $CNRI_Python_GPL_Compatible._('CNRI-Python-GPL-Compatible'), + $COIL_1_0._('COIL-1.0'), + $CPAL_1_0._('CPAL-1.0'), + $CPL_1_0._('CPL-1.0'), + $CPOL_1_02._('CPOL-1.02'), + $CUA_OPL_1_0._('CUA-OPL-1.0'), + $Caldera._('Caldera'), + $ClArtistic._('ClArtistic'), + $Clips._('Clips'), + $Community_Spec_1_0._('Community-Spec-1.0'), + $Condor_1_1._('Condor-1.1'), + $Cornell_Lossless_JPEG._('Cornell-Lossless-JPEG'), + $Cronyx._('Cronyx'), + $Crossword._('Crossword'), + $CrystalStacker._('CrystalStacker'), + $Cube._('Cube'), + $D_FSL_1_0._('D-FSL-1.0'), + $DL_DE_BY_2_0._('DL-DE-BY-2.0'), + $DL_DE_ZERO_2_0._('DL-DE-ZERO-2.0'), + $DOC._('DOC'), + $DRL_1_0._('DRL-1.0'), + $DSDP._('DSDP'), + $Dotseqn._('Dotseqn'), + $ECL_1_0._('ECL-1.0'), + $ECL_2_0._('ECL-2.0'), + $EFL_1_0._('EFL-1.0'), + $EFL_2_0._('EFL-2.0'), + $EPICS._('EPICS'), + $EPL_1_0._('EPL-1.0'), + $EPL_2_0._('EPL-2.0'), + $EUDatagrid._('EUDatagrid'), + $EUPL_1_0._('EUPL-1.0'), + $EUPL_1_1._('EUPL-1.1'), + $EUPL_1_2._('EUPL-1.2'), + $Elastic_2_0._('Elastic-2.0'), + $Entessa._('Entessa'), + $ErlPL_1_1._('ErlPL-1.1'), + $Eurosym._('Eurosym'), + $FBM._('FBM'), + $FDK_AAC._('FDK-AAC'), + $FSFAP._('FSFAP'), + $FSFUL._('FSFUL'), + $FSFULLR._('FSFULLR'), + $FSFULLRWD._('FSFULLRWD'), + $FTL._('FTL'), + $Fair._('Fair'), + $Ferguson_Twofish._('Ferguson-Twofish'), + $Frameworx_1_0._('Frameworx-1.0'), + $FreeBSD_DOC._('FreeBSD-DOC'), + $FreeImage._('FreeImage'), + $Furuseth._('Furuseth'), + $GD._('GD'), + $GFDL_1_1._('GFDL-1.1'), + $GFDL_1_1_invariants_only._('GFDL-1.1-invariants-only'), + $GFDL_1_1_invariants_or_later._('GFDL-1.1-invariants-or-later'), + $GFDL_1_1_no_invariants_only._('GFDL-1.1-no-invariants-only'), + $GFDL_1_1_no_invariants_or_later._('GFDL-1.1-no-invariants-or-later'), + $GFDL_1_1_only._('GFDL-1.1-only'), + $GFDL_1_1_or_later._('GFDL-1.1-or-later'), + $GFDL_1_2._('GFDL-1.2'), + $GFDL_1_2_invariants_only._('GFDL-1.2-invariants-only'), + $GFDL_1_2_invariants_or_later._('GFDL-1.2-invariants-or-later'), + $GFDL_1_2_no_invariants_only._('GFDL-1.2-no-invariants-only'), + $GFDL_1_2_no_invariants_or_later._('GFDL-1.2-no-invariants-or-later'), + $GFDL_1_2_only._('GFDL-1.2-only'), + $GFDL_1_2_or_later._('GFDL-1.2-or-later'), + $GFDL_1_3._('GFDL-1.3'), + $GFDL_1_3_invariants_only._('GFDL-1.3-invariants-only'), + $GFDL_1_3_invariants_or_later._('GFDL-1.3-invariants-or-later'), + $GFDL_1_3_no_invariants_only._('GFDL-1.3-no-invariants-only'), + $GFDL_1_3_no_invariants_or_later._('GFDL-1.3-no-invariants-or-later'), + $GFDL_1_3_only._('GFDL-1.3-only'), + $GFDL_1_3_or_later._('GFDL-1.3-or-later'), + $GL2PS._('GL2PS'), + $GLWTPL._('GLWTPL'), + $GPL_1_0._('GPL-1.0'), + $GPL_1_0plus._('GPL-1.0+'), + $GPL_1_0_only._('GPL-1.0-only'), + $GPL_1_0_or_later._('GPL-1.0-or-later'), + $GPL_2_0._('GPL-2.0'), + $GPL_2_0plus._('GPL-2.0+'), + $GPL_2_0_only._('GPL-2.0-only'), + $GPL_2_0_or_later._('GPL-2.0-or-later'), + $GPL_2_0_with_GCC_exception._('GPL-2.0-with-GCC-exception'), + $GPL_2_0_with_autoconf_exception._('GPL-2.0-with-autoconf-exception'), + $GPL_2_0_with_bison_exception._('GPL-2.0-with-bison-exception'), + $GPL_2_0_with_classpath_exception._('GPL-2.0-with-classpath-exception'), + $GPL_2_0_with_font_exception._('GPL-2.0-with-font-exception'), + $GPL_3_0._('GPL-3.0'), + $GPL_3_0plus._('GPL-3.0+'), + $GPL_3_0_only._('GPL-3.0-only'), + $GPL_3_0_or_later._('GPL-3.0-or-later'), + $GPL_3_0_with_GCC_exception._('GPL-3.0-with-GCC-exception'), + $GPL_3_0_with_autoconf_exception._('GPL-3.0-with-autoconf-exception'), + $Giftware._('Giftware'), + $Glide._('Glide'), + $Glulxe._('Glulxe'), + $Graphics_Gems._('Graphics-Gems'), + $HP_1986._('HP-1986'), + $HP_1989._('HP-1989'), + $HPND._('HPND'), + $HPND_DEC._('HPND-DEC'), + $HPND_Markus_Kuhn._('HPND-Markus-Kuhn'), + $HPND_Pbmplus._('HPND-Pbmplus'), + $HPND_UC._('HPND-UC'), + $HPND_doc._('HPND-doc'), + $HPND_doc_sell._('HPND-doc-sell'), + $HPND_export_US._('HPND-export-US'), + $HPND_export_US_modify._('HPND-export-US-modify'), + $HPND_sell_regexpr._('HPND-sell-regexpr'), + $HPND_sell_variant._('HPND-sell-variant'), + $HPND_sell_variant_MIT_disclaimer._('HPND-sell-variant-MIT-disclaimer'), + $HTMLTIDY._('HTMLTIDY'), + $HaskellReport._('HaskellReport'), + $Hippocratic_2_1._('Hippocratic-2.1'), + $IBM_pibs._('IBM-pibs'), + $ICU._('ICU'), + $IEC_Code_Components_EULA._('IEC-Code-Components-EULA'), + $IJG._('IJG'), + $IJG_short._('IJG-short'), + $IPA._('IPA'), + $IPL_1_0._('IPL-1.0'), + $ISC._('ISC'), + $ImageMagick._('ImageMagick'), + $Imlib2._('Imlib2'), + $Info_ZIP._('Info-ZIP'), + $Inner_Net_2_0._('Inner-Net-2.0'), + $Intel._('Intel'), + $Intel_ACPI._('Intel-ACPI'), + $Interbase_1_0._('Interbase-1.0'), + $JPL_image._('JPL-image'), + $JPNIC._('JPNIC'), + $JSON._('JSON'), + $Jam._('Jam'), + $JasPer_2_0._('JasPer-2.0'), + $Kastrup._('Kastrup'), + $Kazlib._('Kazlib'), + $Knuth_CTAN._('Knuth-CTAN'), + $LAL_1_2._('LAL-1.2'), + $LAL_1_3._('LAL-1.3'), + $LGPL_2_0._('LGPL-2.0'), + $LGPL_2_0plus._('LGPL-2.0+'), + $LGPL_2_0_only._('LGPL-2.0-only'), + $LGPL_2_0_or_later._('LGPL-2.0-or-later'), + $LGPL_2_1._('LGPL-2.1'), + $LGPL_2_1plus._('LGPL-2.1+'), + $LGPL_2_1_only._('LGPL-2.1-only'), + $LGPL_2_1_or_later._('LGPL-2.1-or-later'), + $LGPL_3_0._('LGPL-3.0'), + $LGPL_3_0plus._('LGPL-3.0+'), + $LGPL_3_0_only._('LGPL-3.0-only'), + $LGPL_3_0_or_later._('LGPL-3.0-or-later'), + $LGPLLR._('LGPLLR'), + $LOOP._('LOOP'), + $LPL_1_0._('LPL-1.0'), + $LPL_1_02._('LPL-1.02'), + $LPPL_1_0._('LPPL-1.0'), + $LPPL_1_1._('LPPL-1.1'), + $LPPL_1_2._('LPPL-1.2'), + $LPPL_1_3a._('LPPL-1.3a'), + $LPPL_1_3c._('LPPL-1.3c'), + $LZMA_SDK_9_11_to_9_20._('LZMA-SDK-9.11-to-9.20'), + $LZMA_SDK_9_22._('LZMA-SDK-9.22'), + $Latex2e._('Latex2e'), + $Latex2e_translated_notice._('Latex2e-translated-notice'), + $Leptonica._('Leptonica'), + $LiLiQ_P_1_1._('LiLiQ-P-1.1'), + $LiLiQ_R_1_1._('LiLiQ-R-1.1'), + $LiLiQ_Rplus_1_1._('LiLiQ-Rplus-1.1'), + $Libpng._('Libpng'), + $Linux_OpenIB._('Linux-OpenIB'), + $Linux_man_pages_1_para._('Linux-man-pages-1-para'), + $Linux_man_pages_copyleft._('Linux-man-pages-copyleft'), + $Linux_man_pages_copyleft_2_para._('Linux-man-pages-copyleft-2-para'), + $Linux_man_pages_copyleft_var._('Linux-man-pages-copyleft-var'), + $Lucida_Bitmap_Fonts._('Lucida-Bitmap-Fonts'), + $MIT._('MIT'), + $MIT_0._('MIT-0'), + $MIT_CMU._('MIT-CMU'), + $MIT_Festival._('MIT-Festival'), + $MIT_Modern_Variant._('MIT-Modern-Variant'), + $MIT_Wu._('MIT-Wu'), + $MIT_advertising._('MIT-advertising'), + $MIT_enna._('MIT-enna'), + $MIT_feh._('MIT-feh'), + $MIT_open_group._('MIT-open-group'), + $MIT_testregex._('MIT-testregex'), + $MITNFA._('MITNFA'), + $MMIXware._('MMIXware'), + $MPEG_SSG._('MPEG-SSG'), + $MPL_1_0._('MPL-1.0'), + $MPL_1_1._('MPL-1.1'), + $MPL_2_0._('MPL-2.0'), + $MPL_2_0_no_copyleft_exception._('MPL-2.0-no-copyleft-exception'), + $MS_LPL._('MS-LPL'), + $MS_PL._('MS-PL'), + $MS_RL._('MS-RL'), + $MTLL._('MTLL'), + $MakeIndex._('MakeIndex'), + $Martin_Birgmeier._('Martin-Birgmeier'), + $McPhee_slideshow._('McPhee-slideshow'), + $Minpack._('Minpack'), + $MirOS._('MirOS'), + $Motosoto._('Motosoto'), + $MulanPSL_1_0._('MulanPSL-1.0'), + $MulanPSL_2_0._('MulanPSL-2.0'), + $Multics._('Multics'), + $Mup._('Mup'), + $NAIST_2003._('NAIST-2003'), + $NASA_1_3._('NASA-1.3'), + $NBPL_1_0._('NBPL-1.0'), + $NCGL_UK_2_0._('NCGL-UK-2.0'), + $NCSA._('NCSA'), + $NGPL._('NGPL'), + $NICTA_1_0._('NICTA-1.0'), + $NIST_PD._('NIST-PD'), + $NIST_PD_fallback._('NIST-PD-fallback'), + $NIST_Software._('NIST-Software'), + $NLOD_1_0._('NLOD-1.0'), + $NLOD_2_0._('NLOD-2.0'), + $NLPL._('NLPL'), + $NOSL._('NOSL'), + $NPL_1_0._('NPL-1.0'), + $NPL_1_1._('NPL-1.1'), + $NPOSL_3_0._('NPOSL-3.0'), + $NRL._('NRL'), + $NTP._('NTP'), + $NTP_0._('NTP-0'), + $Naumen._('Naumen'), + $Net_SNMP._('Net-SNMP'), + $NetCDF._('NetCDF'), + $Newsletr._('Newsletr'), + $Nokia._('Nokia'), + $Noweb._('Noweb'), + $Nunit._('Nunit'), + $O_UDA_1_0._('O-UDA-1.0'), + $OCCT_PL._('OCCT-PL'), + $OCLC_2_0._('OCLC-2.0'), + $ODC_By_1_0._('ODC-By-1.0'), + $ODbL_1_0._('ODbL-1.0'), + $OFFIS._('OFFIS'), + $OFL_1_0._('OFL-1.0'), + $OFL_1_0_RFN._('OFL-1.0-RFN'), + $OFL_1_0_no_RFN._('OFL-1.0-no-RFN'), + $OFL_1_1._('OFL-1.1'), + $OFL_1_1_RFN._('OFL-1.1-RFN'), + $OFL_1_1_no_RFN._('OFL-1.1-no-RFN'), + $OGC_1_0._('OGC-1.0'), + $OGDL_Taiwan_1_0._('OGDL-Taiwan-1.0'), + $OGL_Canada_2_0._('OGL-Canada-2.0'), + $OGL_UK_1_0._('OGL-UK-1.0'), + $OGL_UK_2_0._('OGL-UK-2.0'), + $OGL_UK_3_0._('OGL-UK-3.0'), + $OGTSL._('OGTSL'), + $OLDAP_1_1._('OLDAP-1.1'), + $OLDAP_1_2._('OLDAP-1.2'), + $OLDAP_1_3._('OLDAP-1.3'), + $OLDAP_1_4._('OLDAP-1.4'), + $OLDAP_2_0._('OLDAP-2.0'), + $OLDAP_2_0_1._('OLDAP-2.0.1'), + $OLDAP_2_1._('OLDAP-2.1'), + $OLDAP_2_2._('OLDAP-2.2'), + $OLDAP_2_2_1._('OLDAP-2.2.1'), + $OLDAP_2_2_2._('OLDAP-2.2.2'), + $OLDAP_2_3._('OLDAP-2.3'), + $OLDAP_2_4._('OLDAP-2.4'), + $OLDAP_2_5._('OLDAP-2.5'), + $OLDAP_2_6._('OLDAP-2.6'), + $OLDAP_2_7._('OLDAP-2.7'), + $OLDAP_2_8._('OLDAP-2.8'), + $OLFL_1_3._('OLFL-1.3'), + $OML._('OML'), + $OPL_1_0._('OPL-1.0'), + $OPL_UK_3_0._('OPL-UK-3.0'), + $OPUBL_1_0._('OPUBL-1.0'), + $OSET_PL_2_1._('OSET-PL-2.1'), + $OSL_1_0._('OSL-1.0'), + $OSL_1_1._('OSL-1.1'), + $OSL_2_0._('OSL-2.0'), + $OSL_2_1._('OSL-2.1'), + $OSL_3_0._('OSL-3.0'), + $OpenPBS_2_3._('OpenPBS-2.3'), + $OpenSSL._('OpenSSL'), + $PADL._('PADL'), + $PDDL_1_0._('PDDL-1.0'), + $PHP_3_0._('PHP-3.0'), + $PHP_3_01._('PHP-3.01'), + $PSF_2_0._('PSF-2.0'), + $Parity_6_0_0._('Parity-6.0.0'), + $Parity_7_0_0._('Parity-7.0.0'), + $Plexus._('Plexus'), + $PolyForm_Noncommercial_1_0_0._('PolyForm-Noncommercial-1.0.0'), + $PolyForm_Small_Business_1_0_0._('PolyForm-Small-Business-1.0.0'), + $PostgreSQL._('PostgreSQL'), + $Python_2_0._('Python-2.0'), + $Python_2_0_1._('Python-2.0.1'), + $QPL_1_0._('QPL-1.0'), + $QPL_1_0_INRIA_2004._('QPL-1.0-INRIA-2004'), + $Qhull._('Qhull'), + $RHeCos_1_1._('RHeCos-1.1'), + $RPL_1_1._('RPL-1.1'), + $RPL_1_5._('RPL-1.5'), + $RPSL_1_0._('RPSL-1.0'), + $RSA_MD._('RSA-MD'), + $RSCPL._('RSCPL'), + $Rdisc._('Rdisc'), + $Ruby._('Ruby'), + $SAX_PD._('SAX-PD'), + $SCEA._('SCEA'), + $SGI_B_1_0._('SGI-B-1.0'), + $SGI_B_1_1._('SGI-B-1.1'), + $SGI_B_2_0._('SGI-B-2.0'), + $SGI_OpenGL._('SGI-OpenGL'), + $SGP4._('SGP4'), + $SHL_0_5._('SHL-0.5'), + $SHL_0_51._('SHL-0.51'), + $SISSL._('SISSL'), + $SISSL_1_2._('SISSL-1.2'), + $SL._('SL'), + $SMLNJ._('SMLNJ'), + $SMPPL._('SMPPL'), + $SNIA._('SNIA'), + $SPL_1_0._('SPL-1.0'), + $SSH_OpenSSH._('SSH-OpenSSH'), + $SSH_short._('SSH-short'), + $SSPL_1_0._('SSPL-1.0'), + $SWL._('SWL'), + $Saxpath._('Saxpath'), + $SchemeReport._('SchemeReport'), + $Sendmail._('Sendmail'), + $Sendmail_8_23._('Sendmail-8.23'), + $SimPL_2_0._('SimPL-2.0'), + $Sleepycat._('Sleepycat'), + $Soundex._('Soundex'), + $Spencer_86._('Spencer-86'), + $Spencer_94._('Spencer-94'), + $Spencer_99._('Spencer-99'), + $StandardML_NJ._('StandardML-NJ'), + $SugarCRM_1_1_3._('SugarCRM-1.1.3'), + $SunPro._('SunPro'), + $Symlinks._('Symlinks'), + $TAPR_OHL_1_0._('TAPR-OHL-1.0'), + $TCL._('TCL'), + $TCP_wrappers._('TCP-wrappers'), + $TMate._('TMate'), + $TORQUE_1_1._('TORQUE-1.1'), + $TOSL._('TOSL'), + $TPDL._('TPDL'), + $TPL_1_0._('TPL-1.0'), + $TTWL._('TTWL'), + $TTYP0._('TTYP0'), + $TU_Berlin_1_0._('TU-Berlin-1.0'), + $TU_Berlin_2_0._('TU-Berlin-2.0'), + $TermReadKey._('TermReadKey'), + $UCAR._('UCAR'), + $UCL_1_0._('UCL-1.0'), + $UPL_1_0._('UPL-1.0'), + $URT_RLE._('URT-RLE'), + $Unicode_DFS_2015._('Unicode-DFS-2015'), + $Unicode_DFS_2016._('Unicode-DFS-2016'), + $Unicode_TOU._('Unicode-TOU'), + $UnixCrypt._('UnixCrypt'), + $Unlicense._('Unlicense'), + $VOSTROM._('VOSTROM'), + $VSL_1_0._('VSL-1.0'), + $Vim._('Vim'), + $W3C._('W3C'), + $W3C_19980720._('W3C-19980720'), + $W3C_20150513._('W3C-20150513'), + $WTFPL._('WTFPL'), + $Watcom_1_0._('Watcom-1.0'), + $Widget_Workshop._('Widget-Workshop'), + $Wsuipa._('Wsuipa'), + $X11._('X11'), + $X11_distribute_modifications_variant._('X11-distribute-modifications-variant'), + $XFree86_1_1._('XFree86-1.1'), + $XSkat._('XSkat'), + $Xdebug_1_03._('Xdebug-1.03'), + $Xerox._('Xerox'), + $Xfig._('Xfig'), + $Xnet._('Xnet'), + $YPL_1_0._('YPL-1.0'), + $YPL_1_1._('YPL-1.1'), + $ZPL_1_1._('ZPL-1.1'), + $ZPL_2_0._('ZPL-2.0'), + $ZPL_2_1._('ZPL-2.1'), + $Zed._('Zed'), + $Zeeff._('Zeeff'), + $Zend_2_0._('Zend-2.0'), + $Zimbra_1_3._('Zimbra-1.3'), + $Zimbra_1_4._('Zimbra-1.4'), + $Zlib._('Zlib'), + $blessing._('blessing'), + $bzip2_1_0_5._('bzip2-1.0.5'), + $bzip2_1_0_6._('bzip2-1.0.6'), + $check_cvs._('check-cvs'), + $checkmk._('checkmk'), + $copyleft_next_0_3_0._('copyleft-next-0.3.0'), + $copyleft_next_0_3_1._('copyleft-next-0.3.1'), + $curl._('curl'), + $details._('details'), + $diffmark._('diffmark'), + $dtoa._('dtoa'), + $dvipdfm._('dvipdfm'), + $eCos_2_0._('eCos-2.0'), + $eGenix._('eGenix'), + $etalab_2_0._('etalab-2.0'), + $fwlw._('fwlw'), + $gSOAP_1_3b._('gSOAP-1.3b'), + $gnuplot._('gnuplot'), + $iMatix._('iMatix'), + $libpng_2_0._('libpng-2.0'), + $libselinux_1_0._('libselinux-1.0'), + $libtiff._('libtiff'), + $libutil_David_Nugent._('libutil-David-Nugent'), + $lsof._('lsof'), + $magaz._('magaz'), + $metamail._('metamail'), + $mpi_permissive._('mpi-permissive'), + $mpich2._('mpich2'), + $mplus._('mplus'), + $pnmstitch._('pnmstitch'), + $psfrag._('psfrag'), + $psutils._('psutils'), + $python_ldap._('python-ldap'), + $snprintf._('snprintf'), + $ssh_keyscan._('ssh-keyscan'), + $swrule._('swrule'), + $ulem._('ulem'), + $w3m._('w3m'), + $wxWindows._('wxWindows'), + $xinetd._('xinetd'), + $xlock._('xlock'), + $xpp._('xpp'), + $zlib_acknowledgement._('zlib-acknowledgement'), + $unknown._('unknown'); + + const SpdxLicense._(this.value); + + /// Parses a [String] into a [SpdxLicense]. + /// + /// If the [source] is not a valid [SpdxLicense], a [FormatException] is + /// thrown. + factory SpdxLicense.parse(String source) { + final result = SpdxLicense.tryParse(source); + if (result == null) { + throw FormatException('Failed to parse $source as SpdxLicense.'); + } + return result; + } + + /// Parse [source] into a possible [SpdxLicense]. + /// + /// Like [SpdxLicense.parse] except that it returns `null` where a similar + /// call to [SpdxLicense.parse] would throw a [FormatException]. + static SpdxLicense? tryParse(String source) => _valueMap[source]; + + static final Map _valueMap = SpdxLicense.values + .asNameMap() + .map((key, value) => MapEntry(value.value, value)); + + final String value; +} diff --git a/tool/spdx_license/CONTRIBUTING.md b/tool/spdx_license/CONTRIBUTING.md index 3b76d063..63fb6c35 100644 --- a/tool/spdx_license/CONTRIBUTING.md +++ b/tool/spdx_license/CONTRIBUTING.md @@ -46,7 +46,7 @@ mason get ```sh # ⚙️ Generate code using the spdx_license brick (from within project) -mason make spdx_license -o lib/src/models/ --on-conflict=overwrite +mason make spdx_license -o lib/src/pub_license/ --on-conflict=overwrite ``` If the licenses prompt is left empty the brick will fetch the [SPDX list](https://github.com/spdx/license-list-data/tree/main/json/details). Otherwise, the user specified licenses will be used and no SPDX List will be fetched. From 0dbb8f3e1420a36f9f0e1c6abc2c5b7fcc16f579 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Wed, 11 Oct 2023 10:40:38 +0100 Subject: [PATCH 37/69] license output --- .../commands/check/commands/licenses.dart | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index f4143088..6ed8a5e8 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -7,6 +7,7 @@ import 'package:meta/meta.dart'; import 'package:path/path.dart' as path; import 'package:pubspec_lock/pubspec_lock.dart'; import 'package:very_good_cli/src/pub_license/pub_license.dart'; +import 'package:very_good_cli/src/pub_license/spdx_license.gen.dart'; /// The basename of the pubspec lock file. @visibleForTesting @@ -42,6 +43,10 @@ class PackagesCheckLicensesCommand extends Command { 'transitive': 'Check for transitive dependencies.', }, defaultsTo: ['direct-main'], + ) + ..addMultiOption( + 'allowed', + help: 'Whitelist of allowed licenses.', ); } @@ -69,6 +74,16 @@ class PackagesCheckLicensesCommand extends Command { final ignoreFailures = _argResults['ignore-failures'] as bool; final dependencyTypes = _argResults['dependency-type'] as List; + final allowedLicenses = _argResults['allowed'] as List; + + final invalidLicenses = _invalidLicenses(allowedLicenses); + if (invalidLicenses.isNotEmpty) { + // TODO(alestiago): Link to documentation with a list of allowed license values. + _logger.err( + '''Some `allowed` licenses failed to be recognized: ${invalidLicenses.stringify()}.''', + ); + return ExitCode.usage.code; + } final target = _argResults.rest.length == 1 ? _argResults.rest[0] : '.'; final targetPath = path.normalize(Directory(target).absolute.path); @@ -140,6 +155,18 @@ class PackagesCheckLicensesCommand extends Command { _logger.err('\n$errorMessage'); } finally { licenses[dependencyName] = rawLicense; + + if (rawLicense != null && allowedLicenses.isNotEmpty) { + final bannedLicenses = rawLicense + .where((license) => !allowedLicenses.contains(license)) + .toList(); + + if (bannedLicenses.isNotEmpty) { + final errorMessage = + _composeShortBannedLicenseReport(bannedLicenses); + _logger.err('\n[$dependencyName] $errorMessage'); + } + } } } @@ -183,6 +210,34 @@ String _composeReport(Map?> licenses) { return '''Retrieved $licenseCount $licenseWord from ${licenses.length} $packageWord$suffix.'''; } +/// Composes a human friendly [String] to report the result of the recently +/// retrieved banned licenses. +String _composeShortBannedLicenseReport( + List bannedLicenses, +) { + final bannedLicenseWord = bannedLicenses.length == 1 ? 'license' : 'licenses'; + return '''Found ${bannedLicenses.length} banned $bannedLicenseWord: ${bannedLicenses.stringify()}.'''; +} + +/// Verifies that all [licenses] are valid license inputs. +/// +/// Valid license inputs are: +/// - [SpdxLicense] values. +/// +/// Returns a [List] of invalid licenses, if all licenses are valid the list +/// will be empty. +List _invalidLicenses(List licenses) { + final invalidLicenses = []; + for (final license in licenses) { + final parsedLicense = SpdxLicense.tryParse(license); + if (parsedLicense == null) { + invalidLicenses.add(license); + } + } + + return invalidLicenses; +} + extension on List { String stringify() { if (isEmpty) return ''; From 25d50db2509e564ac8c57e5260d523c4673110e2 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Wed, 11 Oct 2023 11:26:30 +0100 Subject: [PATCH 38/69] improved report --- .../commands/check/commands/licenses.dart | 64 +++++++++++-------- 1 file changed, 39 insertions(+), 25 deletions(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index 6ed8a5e8..142668cc 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -80,7 +80,7 @@ class PackagesCheckLicensesCommand extends Command { if (invalidLicenses.isNotEmpty) { // TODO(alestiago): Link to documentation with a list of allowed license values. _logger.err( - '''Some `allowed` licenses failed to be recognized: ${invalidLicenses.stringify()}.''', + '''Some ${styleItalic.wrap('allowed')} licenses failed to be recognized: ${invalidLicenses.stringify()}.''', ); return ExitCode.usage.code; } @@ -155,22 +155,30 @@ class PackagesCheckLicensesCommand extends Command { _logger.err('\n$errorMessage'); } finally { licenses[dependencyName] = rawLicense; + } + } - if (rawLicense != null && allowedLicenses.isNotEmpty) { - final bannedLicenses = rawLicense - .where((license) => !allowedLicenses.contains(license)) - .toList(); - - if (bannedLicenses.isNotEmpty) { - final errorMessage = - _composeShortBannedLicenseReport(bannedLicenses); - _logger.err('\n[$dependencyName] $errorMessage'); - } + final allowedLicenseSet = allowedLicenses.toSet(); + final bannedDependencies = >{}; + if (allowedLicenseSet.isNotEmpty) { + for (final dependency in licenses.entries) { + final name = dependency.key; + final license = dependency.value; + if (license == null) continue; + + final bannedLicenses = license.difference(allowedLicenseSet); + if (bannedLicenses.isNotEmpty) { + bannedDependencies[name] = bannedLicenses; } } } - progress.complete(_composeReport(licenses)); + progress.complete( + _composeReport( + licenses: licenses, + bannedDependencies: bannedDependencies, + ), + ); return ExitCode.success.code; } @@ -190,12 +198,27 @@ PubspecLock? _tryParsePubspecLock(File pubspecLockFile) { /// Composes a human friendly [String] to report the result of the retrieved /// licenses. -String _composeReport(Map?> licenses) { +String _composeReport({ + required Map?> licenses, + required Map> bannedDependencies, +}) { + final bannedLicenseTypes = + bannedDependencies.values.fold({}, (previousValue, licenses) { + if (licenses.isEmpty) return previousValue; + return previousValue..addAll(licenses); + }); final licenseTypes = - licenses.values.fold({}, (previousValue, element) { - if (element == null) return previousValue; - return previousValue..addAll(element); + licenses.values.fold({}, (previousValue, licenses) { + if (licenses == null) return previousValue; + final coloredLicenses = Set.from(licenses).map((license) { + if (bannedLicenseTypes.contains(license)) { + return red.wrap(license)!; + } + return green.wrap(license)!; + }); + return previousValue..addAll(coloredLicenses); }); + final licenseCount = licenses.values.fold(0, (previousValue, element) { if (element == null) return previousValue; return previousValue + element.length; @@ -210,15 +233,6 @@ String _composeReport(Map?> licenses) { return '''Retrieved $licenseCount $licenseWord from ${licenses.length} $packageWord$suffix.'''; } -/// Composes a human friendly [String] to report the result of the recently -/// retrieved banned licenses. -String _composeShortBannedLicenseReport( - List bannedLicenses, -) { - final bannedLicenseWord = bannedLicenses.length == 1 ? 'license' : 'licenses'; - return '''Found ${bannedLicenses.length} banned $bannedLicenseWord: ${bannedLicenses.stringify()}.'''; -} - /// Verifies that all [licenses] are valid license inputs. /// /// Valid license inputs are: From 2c64cc5516a0b9fb29348c260d9c93d9cdc6a403 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Wed, 11 Oct 2023 11:46:01 +0100 Subject: [PATCH 39/69] improve banned report --- .../commands/check/commands/licenses.dart | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index 142668cc..ce6f80e8 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -180,6 +180,11 @@ class PackagesCheckLicensesCommand extends Command { ), ); + if (bannedDependencies.isNotEmpty) { + _logger.err(_composeBannedReport(bannedDependencies)); + return ExitCode.config.code; + } + return ExitCode.success.code; } } @@ -233,6 +238,32 @@ String _composeReport({ return '''Retrieved $licenseCount $licenseWord from ${licenses.length} $packageWord$suffix.'''; } +String _composeBannedReport(Map> bannedDependencies) { + final bannedDependenciesList = bannedDependencies.entries.fold( + [], + (previousValue, element) { + final dependencyName = element.key; + final dependencyLicenses = element.value; + + final text = + '$dependencyName (${dependencyLicenses.toList().stringify()})'; + return previousValue..add(text); + }, + ); + final bannedLicenseTypes = + bannedDependencies.values.fold({}, (previousValue, licenses) { + if (licenses.isEmpty) return previousValue; + return previousValue..addAll(licenses); + }); + + final prefix = + bannedDependencies.length == 1 ? 'package has' : 'packages have'; + final suffix = + bannedLicenseTypes.length == 1 ? 'a banned license' : 'banned licenses'; + + return '''${bannedDependencies.length} $prefix $suffix: ${bannedDependenciesList.stringify()}'''; +} + /// Verifies that all [licenses] are valid license inputs. /// /// Valid license inputs are: From 49354b2cc585f7d8f4aa6b429a474b1ddcd28ac1 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Wed, 11 Oct 2023 11:51:39 +0100 Subject: [PATCH 40/69] refactor coloredLicenseTypes --- .../commands/check/commands/licenses.dart | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index ce6f80e8..12bbbcd3 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -215,13 +215,13 @@ String _composeReport({ final licenseTypes = licenses.values.fold({}, (previousValue, licenses) { if (licenses == null) return previousValue; - final coloredLicenses = Set.from(licenses).map((license) { - if (bannedLicenseTypes.contains(license)) { - return red.wrap(license)!; - } - return green.wrap(license)!; - }); - return previousValue..addAll(coloredLicenses); + return previousValue..addAll(licenses); + }); + final coloredLicenseTypes = licenseTypes.map((license) { + if (bannedLicenseTypes.contains(license)) { + return red.wrap(license)!; + } + return green.wrap(license)!; }); final licenseCount = licenses.values.fold(0, (previousValue, element) { @@ -231,9 +231,9 @@ String _composeReport({ final licenseWord = licenseCount == 1 ? 'license' : 'licenses'; final packageWord = licenses.length == 1 ? 'package' : 'packages'; - final suffix = licenseTypes.isEmpty + final suffix = coloredLicenseTypes.isEmpty ? '' - : ' of type: ${licenseTypes.toList().stringify()}'; + : ' of type: ${coloredLicenseTypes.toList().stringify()}'; return '''Retrieved $licenseCount $licenseWord from ${licenses.length} $packageWord$suffix.'''; } From 4fa86177ea96b20b6463a602d78e155cf7b0c2ba Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Wed, 11 Oct 2023 11:52:42 +0100 Subject: [PATCH 41/69] full stop --- lib/src/commands/packages/commands/check/commands/licenses.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index 12bbbcd3..ae9e7c34 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -261,7 +261,7 @@ String _composeBannedReport(Map> bannedDependencies) { final suffix = bannedLicenseTypes.length == 1 ? 'a banned license' : 'banned licenses'; - return '''${bannedDependencies.length} $prefix $suffix: ${bannedDependenciesList.stringify()}'''; + return '''${bannedDependencies.length} $prefix $suffix: ${bannedDependenciesList.stringify()}.'''; } /// Verifies that all [licenses] are valid license inputs. From 2a2e390f915430e2cf8d32588b8b8c9c7508a57f Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Wed, 11 Oct 2023 12:12:09 +0100 Subject: [PATCH 42/69] add uri --- .../packages/commands/check/commands/licenses.dart | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index ae9e7c34..b6fbe3af 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -13,6 +13,11 @@ import 'package:very_good_cli/src/pub_license/spdx_license.gen.dart'; @visibleForTesting const pubspecLockBasename = 'pubspec.lock'; +/// The URI for the pub.dev license page for the given [packageName]. +@visibleForTesting +Uri pubLicenseUri(String packageName) => + Uri.parse('https://pub.dev/packages/$packageName/license'); + /// {@template packages_check_licenses_command} /// `very_good packages check licenses` command for checking packages licenses. /// {@endtemplate} @@ -245,8 +250,10 @@ String _composeBannedReport(Map> bannedDependencies) { final dependencyName = element.key; final dependencyLicenses = element.value; - final text = - '$dependencyName (${dependencyLicenses.toList().stringify()})'; + final text = '$dependencyName (${link( + uri: pubLicenseUri(dependencyName), + message: dependencyLicenses.toList().stringify(), + )})'; return previousValue..add(text); }, ); From 1a3a50355287c4d65d3980c4860cecf8ecd44a98 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Wed, 11 Oct 2023 19:41:14 +0100 Subject: [PATCH 43/69] changed to warning --- .../packages/commands/check/commands/licenses.dart | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index b6fbe3af..0edeee89 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -84,10 +84,9 @@ class PackagesCheckLicensesCommand extends Command { final invalidLicenses = _invalidLicenses(allowedLicenses); if (invalidLicenses.isNotEmpty) { // TODO(alestiago): Link to documentation with a list of allowed license values. - _logger.err( - '''Some ${styleItalic.wrap('allowed')} licenses failed to be recognized: ${invalidLicenses.stringify()}.''', + _logger.warn( + '''Some ${styleItalic.wrap('allowed')} licenses failed to be recognized: ${invalidLicenses.stringify()}. Refer to the documentation for a list of valid licenses.''', ); - return ExitCode.usage.code; } final target = _argResults.rest.length == 1 ? _argResults.rest[0] : '.'; @@ -132,7 +131,7 @@ class PackagesCheckLicensesCommand extends Command { final licenses = ?>{}; for (final dependency in filteredDependencies) { progress.update( - 'Collecting licenses of ${licenses.length}/${filteredDependencies.length} packages', + 'Collecting licenses of ${licenses.length}/${filteredDependencies.length} packages.', ); final dependencyName = dependency.package(); From beb5178046b8e887c304dd2de67131900643aa1c Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Fri, 13 Oct 2023 09:49:11 +0100 Subject: [PATCH 44/69] update _expectedPackagesCheckLicensesUsage --- .../packages/commands/check/commands/licenses_test.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/src/commands/packages/commands/check/commands/licenses_test.dart b/test/src/commands/packages/commands/check/commands/licenses_test.dart index c5439fa6..dbd60b91 100644 --- a/test/src/commands/packages/commands/check/commands/licenses_test.dart +++ b/test/src/commands/packages/commands/check/commands/licenses_test.dart @@ -25,6 +25,8 @@ const _expectedPackagesCheckLicensesUsage = [ ''' [direct-main] (default) Check for direct main dependencies.\n''' ''' [transitive] Check for transitive dependencies.\n''' '\n' + ' --allowed Whitelist of allowed licenses.\n' + '\n' 'Run "very_good help" to see global options.' ]; From 122cee2895725d34214e9d1ed82aa88b34bd404a Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Fri, 13 Oct 2023 09:58:10 +0100 Subject: [PATCH 45/69] updated tests --- .../check/commands/licenses_test.dart | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/test/src/commands/packages/commands/check/commands/licenses_test.dart b/test/src/commands/packages/commands/check/commands/licenses_test.dart index dbd60b91..82aaa9ba 100644 --- a/test/src/commands/packages/commands/check/commands/licenses_test.dart +++ b/test/src/commands/packages/commands/check/commands/licenses_test.dart @@ -98,7 +98,7 @@ void main() { ); verify( - () => progress.update('Collecting licenses of 0/1 packages'), + () => progress.update('Collecting licenses of 0/1 packages.'), ).called(1); verify( () => progress.complete( @@ -130,10 +130,10 @@ void main() { ); verify( - () => progress.update('Collecting licenses of 0/2 packages'), + () => progress.update('Collecting licenses of 0/2 packages.'), ).called(1); verify( - () => progress.update('Collecting licenses of 1/2 packages'), + () => progress.update('Collecting licenses of 1/2 packages.'), ).called(1); verify( () => progress.complete( @@ -177,10 +177,10 @@ void main() { verify(() => logger.err(errorMessage)).called(1); verify( - () => progress.update('Collecting licenses of 0/2 packages'), + () => progress.update('Collecting licenses of 0/2 packages.'), ).called(1); verify( - () => progress.update('Collecting licenses of 1/2 packages'), + () => progress.update('Collecting licenses of 1/2 packages.'), ).called(1); verify( () => progress.complete( @@ -218,10 +218,10 @@ void main() { verify(() => logger.err(errorMessage)).called(1); verify( - () => progress.update('Collecting licenses of 0/2 packages'), + () => progress.update('Collecting licenses of 0/2 packages.'), ).called(1); verify( - () => progress.update('Collecting licenses of 1/2 packages'), + () => progress.update('Collecting licenses of 1/2 packages.'), ).called(1); verify( () => progress.complete( @@ -269,10 +269,10 @@ void main() { ).called(1); verify( - () => progress.update('Collecting licenses of 0/2 packages'), + () => progress.update('Collecting licenses of 0/2 packages.'), ).called(1); verify( - () => progress.update('Collecting licenses of 1/2 packages'), + () => progress.update('Collecting licenses of 1/2 packages.'), ).called(1); verify( () => progress.complete( @@ -355,7 +355,7 @@ void main() { ); verify( - () => progress.update('Collecting licenses of 0/1 packages'), + () => progress.update('Collecting licenses of 0/1 packages.'), ).called(1); verify( () => progress.complete( @@ -404,7 +404,7 @@ void main() { ); verify( - () => progress.update('Collecting licenses of 0/1 packages'), + () => progress.update('Collecting licenses of 0/1 packages.'), ).called(1); verify( () => progress.complete( @@ -454,7 +454,7 @@ void main() { ); verify( - () => progress.update('Collecting licenses of 0/1 packages'), + () => progress.update('Collecting licenses of 0/1 packages.'), ).called(1); verify( () => progress.complete( @@ -503,7 +503,7 @@ void main() { ); verify( - () => progress.update('Collecting licenses of 0/1 packages'), + () => progress.update('Collecting licenses of 0/1 packages.'), ).called(1); verify( () => progress.complete( @@ -556,13 +556,13 @@ void main() { ); verify( - () => progress.update('Collecting licenses of 0/3 packages'), + () => progress.update('Collecting licenses of 0/3 packages.'), ).called(1); verify( - () => progress.update('Collecting licenses of 1/3 packages'), + () => progress.update('Collecting licenses of 1/3 packages.'), ).called(1); verify( - () => progress.update('Collecting licenses of 2/3 packages'), + () => progress.update('Collecting licenses of 2/3 packages.'), ).called(1); verify( () => progress.complete( From ac0beebdd9b221d17b33d593351e6962eaead606 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Fri, 13 Oct 2023 10:23:39 +0100 Subject: [PATCH 46/69] test for invalid warning --- .../check/commands/licenses_test.dart | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/test/src/commands/packages/commands/check/commands/licenses_test.dart b/test/src/commands/packages/commands/check/commands/licenses_test.dart index 82aaa9ba..a2c232aa 100644 --- a/test/src/commands/packages/commands/check/commands/licenses_test.dart +++ b/test/src/commands/packages/commands/check/commands/licenses_test.dart @@ -577,6 +577,48 @@ void main() { }); }); + group('allowed', () { + const allowedArgument = '--allowed'; + + test( + 'warns when a license is not recognized', + withRunner( + (commandRunner, logger, pubUpdater, pubLicense, printLogs) async { + final tempDirectory = Directory.systemTemp.createTempSync(); + addTearDown(() => tempDirectory.deleteSync(recursive: true)); + + File(path.join(tempDirectory.path, pubspecLockBasename)) + .writeAsStringSync(_validPubspecLockContent); + + when(() => logger.progress(any())).thenReturn(progress); + + const invalidLicense = 'not_a_valid_license'; + await commandRunner.run( + [ + ...commandArguments, + allowedArgument, + invalidLicense, + tempDirectory.path, + ], + ); + + const warningMessage = + '''Some allowed licenses failed to be recognized: $invalidLicense. Refer to the documentation for a list of valid licenses.'''; + verify( + () => logger.warn(warningMessage), + ).called(1); + }), + ); + + test('exits when a license is not allowed', () {}); + + group('reports', () { + test('when a single license is not allowed', () {}); + + test('when more than a single license is allowed', () {}); + }); + }); + group('exits with error', () { test( 'when it did not find a pubspec.lock file at the target path', From 9bb6af96499f82777465fd6fd3face9e898eb4a8 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Fri, 13 Oct 2023 10:59:17 +0100 Subject: [PATCH 47/69] coverage --- .../commands/check/commands/licenses.dart | 2 +- .../check/commands/licenses_test.dart | 116 +++++++++++++++++- 2 files changed, 114 insertions(+), 4 deletions(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index 0edeee89..0fb78c2e 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -263,7 +263,7 @@ String _composeBannedReport(Map> bannedDependencies) { }); final prefix = - bannedDependencies.length == 1 ? 'package has' : 'packages have'; + bannedDependencies.length == 1 ? 'dependency has' : 'dependencies have'; final suffix = bannedLicenseTypes.length == 1 ? 'a banned license' : 'banned licenses'; diff --git a/test/src/commands/packages/commands/check/commands/licenses_test.dart b/test/src/commands/packages/commands/check/commands/licenses_test.dart index a2c232aa..edeb70ef 100644 --- a/test/src/commands/packages/commands/check/commands/licenses_test.dart +++ b/test/src/commands/packages/commands/check/commands/licenses_test.dart @@ -610,12 +610,122 @@ void main() { }), ); - test('exits when a license is not allowed', () {}); + test( + 'exits when a license is not allowed', + withRunner( + (commandRunner, logger, pubUpdater, pubLicense, printLogs) async { + final tempDirectory = Directory.systemTemp.createTempSync(); + addTearDown(() => tempDirectory.deleteSync(recursive: true)); + + File(path.join(tempDirectory.path, pubspecLockBasename)) + .writeAsStringSync(_validPubspecLockContent); + + when(() => logger.progress(any())).thenReturn(progress); + + when(() => pubLicense.getLicense(any())) + .thenAnswer((_) => Future.value({'MIT'})); + + final result = await commandRunner.run( + [ + ...commandArguments, + allowedArgument, + 'BSD', + tempDirectory.path, + ], + ); + + expect(result, ExitCode.config.code); + }), + ); group('reports', () { - test('when a single license is not allowed', () {}); + test( + 'when a single license is not allowed', + withRunner( + (commandRunner, logger, pubUpdater, pubLicense, printLogs) async { + final tempDirectory = Directory.systemTemp.createTempSync(); + addTearDown(() => tempDirectory.deleteSync(recursive: true)); + + File(path.join(tempDirectory.path, pubspecLockBasename)) + .writeAsStringSync(_validMultiplePubspecLockContent); + + when(() => logger.progress(any())).thenReturn(progress); + + const dependency1Name = 'very_good_test_runner'; + when(() => pubLicense.getLicense(dependency1Name)) + .thenAnswer((_) => Future.value({'MIT'})); + final license1LinkedMessage = link( + uri: pubLicenseUri(dependency1Name), + message: 'MIT', + ); + + const dependency2Name = 'cli_completion'; + when(() => pubLicense.getLicense(dependency2Name)) + .thenAnswer((_) => Future.value({'BSD'})); + + await commandRunner.run( + [ + ...commandArguments, + allowedArgument, + 'BSD', + tempDirectory.path, + ], + ); + + final errorMessage = + '''1 dependency has a banned license: $dependency1Name ($license1LinkedMessage).'''; - test('when more than a single license is allowed', () {}); + verify( + () => logger.err(errorMessage), + ).called(1); + }), + ); + + test( + 'when more than a single license is not allowed', + withRunner( + (commandRunner, logger, pubUpdater, pubLicense, printLogs) async { + final tempDirectory = Directory.systemTemp.createTempSync(); + addTearDown(() => tempDirectory.deleteSync(recursive: true)); + + File(path.join(tempDirectory.path, pubspecLockBasename)) + .writeAsStringSync(_validMultiplePubspecLockContent); + + when(() => logger.progress(any())).thenReturn(progress); + + const dependency1Name = 'very_good_test_runner'; + when(() => pubLicense.getLicense(dependency1Name)) + .thenAnswer((_) => Future.value({'MIT'})); + final license1LinkedMessage = link( + uri: pubLicenseUri(dependency1Name), + message: 'MIT', + ); + + const dependency2Name = 'cli_completion'; + when(() => pubLicense.getLicense(dependency2Name)) + .thenAnswer((_) => Future.value({'BSD'})); + final license2LinkedMessage = link( + uri: pubLicenseUri(dependency2Name), + message: 'BSD', + ); + + await commandRunner.run( + [ + ...commandArguments, + allowedArgument, + 'Apache-2.0', + tempDirectory.path, + ], + ); + + final errorMessage = + '''2 dependencies have banned licenses: $dependency1Name ($license1LinkedMessage) and $dependency2Name ($license2LinkedMessage).'''; + + verify( + () => logger.err(errorMessage), + ).called(1); + }), + ); }); }); From 84b085856cca3dde793bb2e537ff7513d5fb780d Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Fri, 13 Oct 2023 11:01:07 +0100 Subject: [PATCH 48/69] exclude gen files --- .github/workflows/very_good_cli.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/very_good_cli.yaml b/.github/workflows/very_good_cli.yaml index f0ff7c11..ab81eef2 100644 --- a/.github/workflows/very_good_cli.yaml +++ b/.github/workflows/very_good_cli.yaml @@ -46,6 +46,8 @@ jobs: - name: Check Code Coverage uses: VeryGoodOpenSource/very_good_coverage@v2.1.0 + with: + exclude: "**/*.gen.dart" pana: runs-on: ubuntu-latest From 7a5d5643a455cf465c402c03ebd51556e6624288 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Fri, 13 Oct 2023 11:13:32 +0100 Subject: [PATCH 49/69] dart format . --- lib/src/pub_license/spdx_license.gen.dart | 14 ++++++++------ tool/spdx_license/test/spdx_license.gen.dart | 14 ++++++++------ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/lib/src/pub_license/spdx_license.gen.dart b/lib/src/pub_license/spdx_license.gen.dart index eaa4e6e0..33ce5550 100644 --- a/lib/src/pub_license/spdx_license.gen.dart +++ b/lib/src/pub_license/spdx_license.gen.dart @@ -1,6 +1,6 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -// -// If you need to make changes, please refer to the SPDX License brick +// +// If you need to make changes, please refer to the SPDX License brick // CONTRIBUTING file. // ignore_for_file: type=lint @@ -73,7 +73,8 @@ enum SpdxLicense { $BSD_3_Clause_Modification._('BSD-3-Clause-Modification'), $BSD_3_Clause_No_Military_License._('BSD-3-Clause-No-Military-License'), $BSD_3_Clause_No_Nuclear_License._('BSD-3-Clause-No-Nuclear-License'), - $BSD_3_Clause_No_Nuclear_License_2014._('BSD-3-Clause-No-Nuclear-License-2014'), + $BSD_3_Clause_No_Nuclear_License_2014._( + 'BSD-3-Clause-No-Nuclear-License-2014'), $BSD_3_Clause_No_Nuclear_Warranty._('BSD-3-Clause-No-Nuclear-Warranty'), $BSD_3_Clause_Open_MPI._('BSD-3-Clause-Open-MPI'), $BSD_3_Clause_Sun._('BSD-3-Clause-Sun'), @@ -554,7 +555,8 @@ enum SpdxLicense { $Widget_Workshop._('Widget-Workshop'), $Wsuipa._('Wsuipa'), $X11._('X11'), - $X11_distribute_modifications_variant._('X11-distribute-modifications-variant'), + $X11_distribute_modifications_variant._( + 'X11-distribute-modifications-variant'), $XFree86_1_1._('XFree86-1.1'), $XSkat._('XSkat'), $Xdebug_1_03._('Xdebug-1.03'), @@ -638,8 +640,8 @@ enum SpdxLicense { static SpdxLicense? tryParse(String source) => _valueMap[source]; static final Map _valueMap = SpdxLicense.values - .asNameMap() - .map((key, value) => MapEntry(value.value, value)); + .asNameMap() + .map((key, value) => MapEntry(value.value, value)); final String value; } diff --git a/tool/spdx_license/test/spdx_license.gen.dart b/tool/spdx_license/test/spdx_license.gen.dart index eaa4e6e0..33ce5550 100644 --- a/tool/spdx_license/test/spdx_license.gen.dart +++ b/tool/spdx_license/test/spdx_license.gen.dart @@ -1,6 +1,6 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -// -// If you need to make changes, please refer to the SPDX License brick +// +// If you need to make changes, please refer to the SPDX License brick // CONTRIBUTING file. // ignore_for_file: type=lint @@ -73,7 +73,8 @@ enum SpdxLicense { $BSD_3_Clause_Modification._('BSD-3-Clause-Modification'), $BSD_3_Clause_No_Military_License._('BSD-3-Clause-No-Military-License'), $BSD_3_Clause_No_Nuclear_License._('BSD-3-Clause-No-Nuclear-License'), - $BSD_3_Clause_No_Nuclear_License_2014._('BSD-3-Clause-No-Nuclear-License-2014'), + $BSD_3_Clause_No_Nuclear_License_2014._( + 'BSD-3-Clause-No-Nuclear-License-2014'), $BSD_3_Clause_No_Nuclear_Warranty._('BSD-3-Clause-No-Nuclear-Warranty'), $BSD_3_Clause_Open_MPI._('BSD-3-Clause-Open-MPI'), $BSD_3_Clause_Sun._('BSD-3-Clause-Sun'), @@ -554,7 +555,8 @@ enum SpdxLicense { $Widget_Workshop._('Widget-Workshop'), $Wsuipa._('Wsuipa'), $X11._('X11'), - $X11_distribute_modifications_variant._('X11-distribute-modifications-variant'), + $X11_distribute_modifications_variant._( + 'X11-distribute-modifications-variant'), $XFree86_1_1._('XFree86-1.1'), $XSkat._('XSkat'), $Xdebug_1_03._('Xdebug-1.03'), @@ -638,8 +640,8 @@ enum SpdxLicense { static SpdxLicense? tryParse(String source) => _valueMap[source]; static final Map _valueMap = SpdxLicense.values - .asNameMap() - .map((key, value) => MapEntry(value.value, value)); + .asNameMap() + .map((key, value) => MapEntry(value.value, value)); final String value; } From 03d9ff4b0e191c8fa722cc41da214d409a219d64 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Fri, 13 Oct 2023 12:12:44 +0100 Subject: [PATCH 50/69] comment --- lib/src/commands/packages/commands/check/commands/licenses.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index 0fb78c2e..f9498fc9 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -83,7 +83,6 @@ class PackagesCheckLicensesCommand extends Command { final invalidLicenses = _invalidLicenses(allowedLicenses); if (invalidLicenses.isNotEmpty) { - // TODO(alestiago): Link to documentation with a list of allowed license values. _logger.warn( '''Some ${styleItalic.wrap('allowed')} licenses failed to be recognized: ${invalidLicenses.stringify()}. Refer to the documentation for a list of valid licenses.''', ); From e4424334677a2f88d0ca55e2bdfdc347eacda3a6 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Fri, 13 Oct 2023 12:46:45 +0100 Subject: [PATCH 51/69] changed if --- .../commands/packages/commands/check/commands/licenses.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index f9498fc9..e22324e6 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -161,9 +161,10 @@ class PackagesCheckLicensesCommand extends Command { } } - final allowedLicenseSet = allowedLicenses.toSet(); final bannedDependencies = >{}; - if (allowedLicenseSet.isNotEmpty) { + + if (allowedLicenses.isNotEmpty) { + final allowedLicenseSet = allowedLicenses.toSet(); for (final dependency in licenses.entries) { final name = dependency.key; final license = dependency.value; From 0e34aa853fe77b4e70b85a29db58cbd7584bb035 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Fri, 13 Oct 2023 12:47:29 +0100 Subject: [PATCH 52/69] move _invalidLicenses --- .../commands/check/commands/licenses.dart | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index e22324e6..3b568835 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -205,6 +205,25 @@ PubspecLock? _tryParsePubspecLock(File pubspecLockFile) { } } +/// Verifies that all [licenses] are valid license inputs. +/// +/// Valid license inputs are: +/// - [SpdxLicense] values. +/// +/// Returns a [List] of invalid licenses, if all licenses are valid the list +/// will be empty. +List _invalidLicenses(List licenses) { + final invalidLicenses = []; + for (final license in licenses) { + final parsedLicense = SpdxLicense.tryParse(license); + if (parsedLicense == null) { + invalidLicenses.add(license); + } + } + + return invalidLicenses; +} + /// Composes a human friendly [String] to report the result of the retrieved /// licenses. String _composeReport({ @@ -270,25 +289,6 @@ String _composeBannedReport(Map> bannedDependencies) { return '''${bannedDependencies.length} $prefix $suffix: ${bannedDependenciesList.stringify()}.'''; } -/// Verifies that all [licenses] are valid license inputs. -/// -/// Valid license inputs are: -/// - [SpdxLicense] values. -/// -/// Returns a [List] of invalid licenses, if all licenses are valid the list -/// will be empty. -List _invalidLicenses(List licenses) { - final invalidLicenses = []; - for (final license in licenses) { - final parsedLicense = SpdxLicense.tryParse(license); - if (parsedLicense == null) { - invalidLicenses.add(license); - } - } - - return invalidLicenses; -} - extension on List { String stringify() { if (isEmpty) return ''; From f05abe1d089798eea8f8d4d807d70c9826c2944f Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Fri, 13 Oct 2023 13:04:02 +0100 Subject: [PATCH 53/69] refactor logic --- .../commands/check/commands/licenses.dart | 50 ++++++++++++------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index 3b568835..367dfbfc 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -161,21 +161,9 @@ class PackagesCheckLicensesCommand extends Command { } } - final bannedDependencies = >{}; - - if (allowedLicenses.isNotEmpty) { - final allowedLicenseSet = allowedLicenses.toSet(); - for (final dependency in licenses.entries) { - final name = dependency.key; - final license = dependency.value; - if (license == null) continue; - - final bannedLicenses = license.difference(allowedLicenseSet); - if (bannedLicenses.isNotEmpty) { - bannedDependencies[name] = bannedLicenses; - } - } - } + final bannedDependencies = allowedLicenses.isNotEmpty + ? _notAllowedLicenses(allowedLicenses, licenses) + : null; progress.complete( _composeReport( @@ -184,7 +172,7 @@ class PackagesCheckLicensesCommand extends Command { ), ); - if (bannedDependencies.isNotEmpty) { + if (bannedDependencies != null) { _logger.err(_composeBannedReport(bannedDependencies)); return ExitCode.config.code; } @@ -224,14 +212,38 @@ List _invalidLicenses(List licenses) { return invalidLicenses; } +/// Returns a [Map] of banned dependencies and their banned licenses. +/// +/// A dependency is considered banned if it has a license that is not in the +/// [allowed] set. +Map> _notAllowedLicenses( + Iterable allowed, + Map?> licenses, +) { + final allowedSet = allowed.toSet(); + final bannedDependencies = >{}; + for (final dependency in licenses.entries) { + final name = dependency.key; + final license = dependency.value; + if (license == null) continue; + + final bannedLicenses = license.difference(allowedSet); + if (bannedLicenses.isNotEmpty) { + bannedDependencies[name] = bannedLicenses; + } + } + + return bannedDependencies; +} + /// Composes a human friendly [String] to report the result of the retrieved /// licenses. String _composeReport({ required Map?> licenses, - required Map> bannedDependencies, + required Map>? bannedDependencies, }) { final bannedLicenseTypes = - bannedDependencies.values.fold({}, (previousValue, licenses) { + bannedDependencies?.values.fold({}, (previousValue, licenses) { if (licenses.isEmpty) return previousValue; return previousValue..addAll(licenses); }); @@ -241,7 +253,7 @@ String _composeReport({ return previousValue..addAll(licenses); }); final coloredLicenseTypes = licenseTypes.map((license) { - if (bannedLicenseTypes.contains(license)) { + if (bannedLicenseTypes != null && bannedLicenseTypes.contains(license)) { return red.wrap(license)!; } return green.wrap(license)!; From 450eb196bd36ac954929b9489e059aed19cfe9df Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Fri, 13 Oct 2023 13:05:02 +0100 Subject: [PATCH 54/69] docs --- .../commands/packages/commands/check/commands/licenses.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index 367dfbfc..5ff71382 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -238,6 +238,9 @@ Map> _notAllowedLicenses( /// Composes a human friendly [String] to report the result of the retrieved /// licenses. +/// +/// If [bannedDependencies] is provided those banned licenses will be +/// highlighted in red. String _composeReport({ required Map?> licenses, required Map>? bannedDependencies, From 7003dd1dcca5e70a446ded3bf219d52a35ed121c Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Fri, 13 Oct 2023 13:13:58 +0100 Subject: [PATCH 55/69] refactor _bannedDependencies --- .../commands/check/commands/licenses.dart | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index 5ff71382..8de29896 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -162,7 +162,7 @@ class PackagesCheckLicensesCommand extends Command { } final bannedDependencies = allowedLicenses.isNotEmpty - ? _notAllowedLicenses(allowedLicenses, licenses) + ? _bannedDependencies(licenses, allowedLicenses.contains) : null; progress.complete( @@ -213,23 +213,21 @@ List _invalidLicenses(List licenses) { } /// Returns a [Map] of banned dependencies and their banned licenses. -/// -/// A dependency is considered banned if it has a license that is not in the -/// [allowed] set. -Map> _notAllowedLicenses( - Iterable allowed, +Map>? _bannedDependencies( Map?> licenses, + bool Function(String license) isAllowed, ) { - final allowedSet = allowed.toSet(); final bannedDependencies = >{}; for (final dependency in licenses.entries) { final name = dependency.key; final license = dependency.value; if (license == null) continue; - final bannedLicenses = license.difference(allowedSet); - if (bannedLicenses.isNotEmpty) { - bannedDependencies[name] = bannedLicenses; + for (final licenseType in license) { + if (isAllowed(licenseType)) continue; + + bannedDependencies.putIfAbsent(name, () => {}); + bannedDependencies[name]!.add(licenseType); } } From f4caa5e147282b784a7ab16f4b0ce409ed2854f4 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Fri, 13 Oct 2023 13:14:46 +0100 Subject: [PATCH 56/69] update _bannedDependencies signature --- lib/src/commands/packages/commands/check/commands/licenses.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index 8de29896..5a036c92 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -213,7 +213,7 @@ List _invalidLicenses(List licenses) { } /// Returns a [Map] of banned dependencies and their banned licenses. -Map>? _bannedDependencies( +Map> _bannedDependencies( Map?> licenses, bool Function(String license) isAllowed, ) { From 41116792411acb157449930143e58dd5cb95f8f9 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Fri, 13 Oct 2023 13:19:07 +0100 Subject: [PATCH 57/69] refactor _bannedDependencies --- .../packages/commands/check/commands/licenses.dart | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index 5a036c92..aac471da 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -162,7 +162,10 @@ class PackagesCheckLicensesCommand extends Command { } final bannedDependencies = allowedLicenses.isNotEmpty - ? _bannedDependencies(licenses, allowedLicenses.contains) + ? _bannedDependencies( + licenses, + allowedLicenses.contains, + ) : null; progress.complete( @@ -213,11 +216,14 @@ List _invalidLicenses(List licenses) { } /// Returns a [Map] of banned dependencies and their banned licenses. -Map> _bannedDependencies( +/// +/// The [Map] is lazily computed, if no dependencies are banned `null` is +/// returned. +Map>? _bannedDependencies( Map?> licenses, bool Function(String license) isAllowed, ) { - final bannedDependencies = >{}; + Map>? bannedDependencies; for (final dependency in licenses.entries) { final name = dependency.key; final license = dependency.value; @@ -226,6 +232,7 @@ Map> _bannedDependencies( for (final licenseType in license) { if (isAllowed(licenseType)) continue; + bannedDependencies ??= >{}; bannedDependencies.putIfAbsent(name, () => {}); bannedDependencies[name]!.add(licenseType); } From 868d5a232dfe8b06b25e60ce3431f5edf44264a0 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Fri, 13 Oct 2023 13:21:48 +0100 Subject: [PATCH 58/69] refactor used typedef --- .../packages/commands/check/commands/licenses.dart | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index aac471da..98a79400 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -18,6 +18,10 @@ const pubspecLockBasename = 'pubspec.lock'; Uri pubLicenseUri(String packageName) => Uri.parse('https://pub.dev/packages/$packageName/license'); +/// Defines a [Map] with banned dependencies as keys and their banned licenses +/// as values. +typedef _BannedDependenciesMap = Map>; + /// {@template packages_check_licenses_command} /// `very_good packages check licenses` command for checking packages licenses. /// {@endtemplate} @@ -219,11 +223,11 @@ List _invalidLicenses(List licenses) { /// /// The [Map] is lazily computed, if no dependencies are banned `null` is /// returned. -Map>? _bannedDependencies( +_BannedDependenciesMap? _bannedDependencies( Map?> licenses, bool Function(String license) isAllowed, ) { - Map>? bannedDependencies; + _BannedDependenciesMap? bannedDependencies; for (final dependency in licenses.entries) { final name = dependency.key; final license = dependency.value; @@ -248,7 +252,7 @@ Map>? _bannedDependencies( /// highlighted in red. String _composeReport({ required Map?> licenses, - required Map>? bannedDependencies, + required _BannedDependenciesMap? bannedDependencies, }) { final bannedLicenseTypes = bannedDependencies?.values.fold({}, (previousValue, licenses) { @@ -281,7 +285,7 @@ String _composeReport({ return '''Retrieved $licenseCount $licenseWord from ${licenses.length} $packageWord$suffix.'''; } -String _composeBannedReport(Map> bannedDependencies) { +String _composeBannedReport(_BannedDependenciesMap bannedDependencies) { final bannedDependenciesList = bannedDependencies.entries.fold( [], (previousValue, element) { From cd7fc597bb751bd7954a12d1f087f1a542b692a8 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Fri, 13 Oct 2023 13:24:44 +0100 Subject: [PATCH 59/69] refactor used typedef --- .../commands/check/commands/licenses.dart | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index 98a79400..be6af86a 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -18,9 +18,12 @@ const pubspecLockBasename = 'pubspec.lock'; Uri pubLicenseUri(String packageName) => Uri.parse('https://pub.dev/packages/$packageName/license'); +/// Defines a [Map] with dependencies as keys and their licenses as values. +typedef _DependencyLicenseMap = Map?>; + /// Defines a [Map] with banned dependencies as keys and their banned licenses /// as values. -typedef _BannedDependenciesMap = Map>; +typedef _BannedDependencyLicenseMap = Map>; /// {@template packages_check_licenses_command} /// `very_good packages check licenses` command for checking packages licenses. @@ -223,11 +226,11 @@ List _invalidLicenses(List licenses) { /// /// The [Map] is lazily computed, if no dependencies are banned `null` is /// returned. -_BannedDependenciesMap? _bannedDependencies( - Map?> licenses, +_BannedDependencyLicenseMap? _bannedDependencies( + _DependencyLicenseMap licenses, bool Function(String license) isAllowed, ) { - _BannedDependenciesMap? bannedDependencies; + _BannedDependencyLicenseMap? bannedDependencies; for (final dependency in licenses.entries) { final name = dependency.key; final license = dependency.value; @@ -251,8 +254,8 @@ _BannedDependenciesMap? _bannedDependencies( /// If [bannedDependencies] is provided those banned licenses will be /// highlighted in red. String _composeReport({ - required Map?> licenses, - required _BannedDependenciesMap? bannedDependencies, + required _DependencyLicenseMap licenses, + required _BannedDependencyLicenseMap? bannedDependencies, }) { final bannedLicenseTypes = bannedDependencies?.values.fold({}, (previousValue, licenses) { @@ -285,7 +288,7 @@ String _composeReport({ return '''Retrieved $licenseCount $licenseWord from ${licenses.length} $packageWord$suffix.'''; } -String _composeBannedReport(_BannedDependenciesMap bannedDependencies) { +String _composeBannedReport(_BannedDependencyLicenseMap bannedDependencies) { final bannedDependenciesList = bannedDependencies.entries.fold( [], (previousValue, element) { From 355dcc7313edff3961d3c0abf889a864d4906991 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Fri, 13 Oct 2023 13:26:42 +0100 Subject: [PATCH 60/69] docs --- lib/src/commands/packages/commands/check/commands/licenses.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index be6af86a..f4f5f5c3 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -19,6 +19,8 @@ Uri pubLicenseUri(String packageName) => Uri.parse('https://pub.dev/packages/$packageName/license'); /// Defines a [Map] with dependencies as keys and their licenses as values. +/// +/// If a dependency failed to be retrieved its license will be `null`. typedef _DependencyLicenseMap = Map?>; /// Defines a [Map] with banned dependencies as keys and their banned licenses From dc7af03bc2d7f550d4cdedc597c365e95f481128 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Fri, 13 Oct 2023 13:27:04 +0100 Subject: [PATCH 61/69] docs --- lib/src/commands/packages/commands/check/commands/licenses.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index f4f5f5c3..f0a946e7 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -20,7 +20,7 @@ Uri pubLicenseUri(String packageName) => /// Defines a [Map] with dependencies as keys and their licenses as values. /// -/// If a dependency failed to be retrieved its license will be `null`. +/// If a dependency's license failed to be retrieved its license will be `null`. typedef _DependencyLicenseMap = Map?>; /// Defines a [Map] with banned dependencies as keys and their banned licenses From 61dfad30d5058829c324b5bd5ee3783e7a5d5977 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Fri, 13 Oct 2023 13:27:29 +0100 Subject: [PATCH 62/69] trailing comma --- .../commands/packages/commands/check/commands/licenses.dart | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index f0a946e7..929e7ee0 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -171,10 +171,7 @@ class PackagesCheckLicensesCommand extends Command { } final bannedDependencies = allowedLicenses.isNotEmpty - ? _bannedDependencies( - licenses, - allowedLicenses.contains, - ) + ? _bannedDependencies(licenses, allowedLicenses.contains) : null; progress.complete( From 230d885ec64bb460eda17e366f5b29a83d630f1f Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Mon, 16 Oct 2023 10:27:00 +0100 Subject: [PATCH 63/69] docs used initialized --- lib/src/commands/packages/commands/check/commands/licenses.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/commands/packages/commands/check/commands/licenses.dart b/lib/src/commands/packages/commands/check/commands/licenses.dart index aab04725..5c4bdf18 100644 --- a/lib/src/commands/packages/commands/check/commands/licenses.dart +++ b/lib/src/commands/packages/commands/check/commands/licenses.dart @@ -225,7 +225,7 @@ List _invalidLicenses(List licenses) { /// Returns a [Map] of banned dependencies and their banned licenses. /// -/// The [Map] is lazily computed, if no dependencies are banned `null` is +/// The [Map] is lazily initialized, if no dependencies are banned `null` is /// returned. _BannedDependencyLicenseMap? _bannedDependencies( _DependencyLicenseMap licenses, From 879f83167e91b69c5f5b175f1ea9057d105664e6 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Mon, 16 Oct 2023 10:29:22 +0100 Subject: [PATCH 64/69] test name --- .../packages/commands/check/commands/licenses_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/src/commands/packages/commands/check/commands/licenses_test.dart b/test/src/commands/packages/commands/check/commands/licenses_test.dart index c14ae189..1794ed1d 100644 --- a/test/src/commands/packages/commands/check/commands/licenses_test.dart +++ b/test/src/commands/packages/commands/check/commands/licenses_test.dart @@ -682,7 +682,7 @@ void main() { ); test( - 'when more than a single license is not allowed', + 'when multiple licenses are not allowed', withRunner( (commandRunner, logger, pubUpdater, pubLicense, printLogs) async { final tempDirectory = Directory.systemTemp.createTempSync(); From 6722c748e365e4171189f86eb98dca23731ed0f4 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Mon, 16 Oct 2023 10:30:58 +0100 Subject: [PATCH 65/69] mason make spdx_license --- lib/src/pub_license/spdx_license.gen.dart | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/lib/src/pub_license/spdx_license.gen.dart b/lib/src/pub_license/spdx_license.gen.dart index 33ce5550..eaa4e6e0 100644 --- a/lib/src/pub_license/spdx_license.gen.dart +++ b/lib/src/pub_license/spdx_license.gen.dart @@ -1,6 +1,6 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -// -// If you need to make changes, please refer to the SPDX License brick +// +// If you need to make changes, please refer to the SPDX License brick // CONTRIBUTING file. // ignore_for_file: type=lint @@ -73,8 +73,7 @@ enum SpdxLicense { $BSD_3_Clause_Modification._('BSD-3-Clause-Modification'), $BSD_3_Clause_No_Military_License._('BSD-3-Clause-No-Military-License'), $BSD_3_Clause_No_Nuclear_License._('BSD-3-Clause-No-Nuclear-License'), - $BSD_3_Clause_No_Nuclear_License_2014._( - 'BSD-3-Clause-No-Nuclear-License-2014'), + $BSD_3_Clause_No_Nuclear_License_2014._('BSD-3-Clause-No-Nuclear-License-2014'), $BSD_3_Clause_No_Nuclear_Warranty._('BSD-3-Clause-No-Nuclear-Warranty'), $BSD_3_Clause_Open_MPI._('BSD-3-Clause-Open-MPI'), $BSD_3_Clause_Sun._('BSD-3-Clause-Sun'), @@ -555,8 +554,7 @@ enum SpdxLicense { $Widget_Workshop._('Widget-Workshop'), $Wsuipa._('Wsuipa'), $X11._('X11'), - $X11_distribute_modifications_variant._( - 'X11-distribute-modifications-variant'), + $X11_distribute_modifications_variant._('X11-distribute-modifications-variant'), $XFree86_1_1._('XFree86-1.1'), $XSkat._('XSkat'), $Xdebug_1_03._('Xdebug-1.03'), @@ -640,8 +638,8 @@ enum SpdxLicense { static SpdxLicense? tryParse(String source) => _valueMap[source]; static final Map _valueMap = SpdxLicense.values - .asNameMap() - .map((key, value) => MapEntry(value.value, value)); + .asNameMap() + .map((key, value) => MapEntry(value.value, value)); final String value; } From d4091e205c4de6e96e94fc8de012c9e3300c9a1c Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Mon, 16 Oct 2023 10:35:23 +0100 Subject: [PATCH 66/69] revert spdx_license.gen.dart --- lib/src/pub_license/spdx_license.gen.dart | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/src/pub_license/spdx_license.gen.dart b/lib/src/pub_license/spdx_license.gen.dart index eaa4e6e0..33ce5550 100644 --- a/lib/src/pub_license/spdx_license.gen.dart +++ b/lib/src/pub_license/spdx_license.gen.dart @@ -1,6 +1,6 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -// -// If you need to make changes, please refer to the SPDX License brick +// +// If you need to make changes, please refer to the SPDX License brick // CONTRIBUTING file. // ignore_for_file: type=lint @@ -73,7 +73,8 @@ enum SpdxLicense { $BSD_3_Clause_Modification._('BSD-3-Clause-Modification'), $BSD_3_Clause_No_Military_License._('BSD-3-Clause-No-Military-License'), $BSD_3_Clause_No_Nuclear_License._('BSD-3-Clause-No-Nuclear-License'), - $BSD_3_Clause_No_Nuclear_License_2014._('BSD-3-Clause-No-Nuclear-License-2014'), + $BSD_3_Clause_No_Nuclear_License_2014._( + 'BSD-3-Clause-No-Nuclear-License-2014'), $BSD_3_Clause_No_Nuclear_Warranty._('BSD-3-Clause-No-Nuclear-Warranty'), $BSD_3_Clause_Open_MPI._('BSD-3-Clause-Open-MPI'), $BSD_3_Clause_Sun._('BSD-3-Clause-Sun'), @@ -554,7 +555,8 @@ enum SpdxLicense { $Widget_Workshop._('Widget-Workshop'), $Wsuipa._('Wsuipa'), $X11._('X11'), - $X11_distribute_modifications_variant._('X11-distribute-modifications-variant'), + $X11_distribute_modifications_variant._( + 'X11-distribute-modifications-variant'), $XFree86_1_1._('XFree86-1.1'), $XSkat._('XSkat'), $Xdebug_1_03._('Xdebug-1.03'), @@ -638,8 +640,8 @@ enum SpdxLicense { static SpdxLicense? tryParse(String source) => _valueMap[source]; static final Map _valueMap = SpdxLicense.values - .asNameMap() - .map((key, value) => MapEntry(value.value, value)); + .asNameMap() + .map((key, value) => MapEntry(value.value, value)); final String value; } From bd44f7de5f33a52d78c06d3bd6102b1583ef4e5c Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Mon, 16 Oct 2023 10:38:48 +0100 Subject: [PATCH 67/69] remove sdk --- .github/workflows/spdx_license.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/spdx_license.yaml b/.github/workflows/spdx_license.yaml index 1321193c..3da230f1 100644 --- a/.github/workflows/spdx_license.yaml +++ b/.github/workflows/spdx_license.yaml @@ -70,8 +70,6 @@ jobs: - name: 🎯 Setup Dart uses: dart-lang/setup-dart@v1 - with: - sdk: 3.1.0 - name: 📦 Install Dependencies run: dart pub get From c41ad0ecf15ef03a3f1383d72b628ca1197bbe9d Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Mon, 16 Oct 2023 10:40:27 +0100 Subject: [PATCH 68/69] mason make spdx_license --- tool/spdx_license/test/spdx_license.gen.dart | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/tool/spdx_license/test/spdx_license.gen.dart b/tool/spdx_license/test/spdx_license.gen.dart index 33ce5550..eaa4e6e0 100644 --- a/tool/spdx_license/test/spdx_license.gen.dart +++ b/tool/spdx_license/test/spdx_license.gen.dart @@ -1,6 +1,6 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -// -// If you need to make changes, please refer to the SPDX License brick +// +// If you need to make changes, please refer to the SPDX License brick // CONTRIBUTING file. // ignore_for_file: type=lint @@ -73,8 +73,7 @@ enum SpdxLicense { $BSD_3_Clause_Modification._('BSD-3-Clause-Modification'), $BSD_3_Clause_No_Military_License._('BSD-3-Clause-No-Military-License'), $BSD_3_Clause_No_Nuclear_License._('BSD-3-Clause-No-Nuclear-License'), - $BSD_3_Clause_No_Nuclear_License_2014._( - 'BSD-3-Clause-No-Nuclear-License-2014'), + $BSD_3_Clause_No_Nuclear_License_2014._('BSD-3-Clause-No-Nuclear-License-2014'), $BSD_3_Clause_No_Nuclear_Warranty._('BSD-3-Clause-No-Nuclear-Warranty'), $BSD_3_Clause_Open_MPI._('BSD-3-Clause-Open-MPI'), $BSD_3_Clause_Sun._('BSD-3-Clause-Sun'), @@ -555,8 +554,7 @@ enum SpdxLicense { $Widget_Workshop._('Widget-Workshop'), $Wsuipa._('Wsuipa'), $X11._('X11'), - $X11_distribute_modifications_variant._( - 'X11-distribute-modifications-variant'), + $X11_distribute_modifications_variant._('X11-distribute-modifications-variant'), $XFree86_1_1._('XFree86-1.1'), $XSkat._('XSkat'), $Xdebug_1_03._('Xdebug-1.03'), @@ -640,8 +638,8 @@ enum SpdxLicense { static SpdxLicense? tryParse(String source) => _valueMap[source]; static final Map _valueMap = SpdxLicense.values - .asNameMap() - .map((key, value) => MapEntry(value.value, value)); + .asNameMap() + .map((key, value) => MapEntry(value.value, value)); final String value; } From 2b4ff5d31e64a86fc2379f8e5bfe08684cf1d5e3 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Mon, 16 Oct 2023 10:43:12 +0100 Subject: [PATCH 69/69] revert change --- .github/workflows/spdx_license.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/spdx_license.yaml b/.github/workflows/spdx_license.yaml index 3da230f1..1321193c 100644 --- a/.github/workflows/spdx_license.yaml +++ b/.github/workflows/spdx_license.yaml @@ -70,6 +70,8 @@ jobs: - name: 🎯 Setup Dart uses: dart-lang/setup-dart@v1 + with: + sdk: 3.1.0 - name: 📦 Install Dependencies run: dart pub get