From 1e1038707a545deac9a8d4d9a7f68c19f8670cd9 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Wed, 22 Nov 2023 12:45:50 +0000 Subject: [PATCH] fix: sort directive ordering on post generation (#122) --- .../workflows/very_good_dart_cli_hooks.yaml | 21 +++++ brick/hooks/.gitignore | 4 + brick/hooks/analysis_options.yaml | 1 + brick/hooks/post_gen.dart | 30 ++++++ brick/hooks/pubspec.yaml | 13 +++ brick/hooks/test/post_gen_test.dart | 93 +++++++++++++++++++ 6 files changed, 162 insertions(+) create mode 100644 .github/workflows/very_good_dart_cli_hooks.yaml create mode 100644 brick/hooks/.gitignore create mode 100644 brick/hooks/analysis_options.yaml create mode 100644 brick/hooks/post_gen.dart create mode 100644 brick/hooks/pubspec.yaml create mode 100644 brick/hooks/test/post_gen_test.dart diff --git a/.github/workflows/very_good_dart_cli_hooks.yaml b/.github/workflows/very_good_dart_cli_hooks.yaml new file mode 100644 index 0000000..1eb9f42 --- /dev/null +++ b/.github/workflows/very_good_dart_cli_hooks.yaml @@ -0,0 +1,21 @@ +name: very_good_dart_cli_hooks + +on: + pull_request: + paths: + - ".github/workflows/very_good_dart_cli_hooks.yaml" + - "brick/hooks/**" + push: + branches: + - main + paths: + - ".github/workflows/very_good_dart_cli_hooks.yaml" + - "brick/hooks/**" + +jobs: + build: + uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/dart_package.yml@v1 + with: + working_directory: "brick/hooks" + analyze_directories: "test" + report_on: "post_gen.dart" diff --git a/brick/hooks/.gitignore b/brick/hooks/.gitignore new file mode 100644 index 0000000..7b37acf --- /dev/null +++ b/brick/hooks/.gitignore @@ -0,0 +1,4 @@ +.dart_tool +.packages +pubspec.lock +build diff --git a/brick/hooks/analysis_options.yaml b/brick/hooks/analysis_options.yaml new file mode 100644 index 0000000..799268d --- /dev/null +++ b/brick/hooks/analysis_options.yaml @@ -0,0 +1 @@ +include: package:very_good_analysis/analysis_options.5.1.0.yaml diff --git a/brick/hooks/post_gen.dart b/brick/hooks/post_gen.dart new file mode 100644 index 0000000..b9f038b --- /dev/null +++ b/brick/hooks/post_gen.dart @@ -0,0 +1,30 @@ +import 'dart:io'; + +import 'package:mason/mason.dart'; +import 'package:meta/meta.dart'; + +/// Type definition for [Process.run]. +typedef RunProcess = Future Function( + String executable, + List arguments, { + String? workingDirectory, + bool runInShell, +}); + +Future run( + HookContext context, { + @visibleForTesting RunProcess runProcess = Process.run, +}) async { + // Some imports are relative to the user specified package name, hence + // we try to fix the import directive ordering after the template has + // been generated. + // + // We only fix for the [directives_ordering](https://dart.dev/tools/linter-rules/directives_ordering) + // linter rules, as the other rule should be tackled by the template itself. + await runProcess('dart', [ + 'fix', + Directory.current.path, + '--apply', + '--code=directives_ordering', + ]); +} diff --git a/brick/hooks/pubspec.yaml b/brick/hooks/pubspec.yaml new file mode 100644 index 0000000..7f7f614 --- /dev/null +++ b/brick/hooks/pubspec.yaml @@ -0,0 +1,13 @@ +name: very_good_dart_cli_hooks + +environment: + sdk: ">=2.12.0 <3.0.0" + +dependencies: + mason: ">=0.1.0-dev.51 <0.1.0" + meta: ^1.11.0 + +dev_dependencies: + mocktail: ^1.0.0 + test: ^1.19.2 + very_good_analysis: ^5.1.0 diff --git a/brick/hooks/test/post_gen_test.dart b/brick/hooks/test/post_gen_test.dart new file mode 100644 index 0000000..5da6c12 --- /dev/null +++ b/brick/hooks/test/post_gen_test.dart @@ -0,0 +1,93 @@ +import 'dart:io'; + +import 'package:mason/mason.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:test/test.dart'; + +import '../post_gen.dart' as post_gen; + +class _MockHookContext extends Mock implements HookContext {} + +class _MockProcessResult extends Mock implements ProcessResult {} + +void main() { + group('post_gen', () { + late HookContext context; + late ProcessResult processResult; + late List invocations; + + setUp(() { + context = _MockHookContext(); + processResult = _MockProcessResult(); + invocations = []; + }); + + Future runProcess( + String executable, + List arguments, { + String? workingDirectory, + bool runInShell = false, + }) async { + final positionalArguments = [executable, arguments]; + final namedArguments = { + const Symbol('workingDirectory'): workingDirectory, + const Symbol('runInShell'): runInShell, + }; + final invocation = Invocation.method( + const Symbol('runProcess'), + positionalArguments, + namedArguments, + ); + invocations.add(invocation); + + return processResult; + } + + test('fixes `directives_ordering` Dart linter rule', () async { + await post_gen.run(context, runProcess: runProcess); + + expect(invocations, contains(_IsDartDirectiveOrderingFix())); + }); + }); +} + +Matcher isDartDirectiveOrderingFix() { + return _IsDartDirectiveOrderingFix(); +} + +class _IsDartDirectiveOrderingFix extends Matcher { + @override + bool matches(dynamic item, Map matchState) { + if (item is! Invocation) { + return false; + } + + final invocation = item; + final executableName = invocation.positionalArguments[0] as String; + final arguments = invocation.positionalArguments[1] as List; + final workingDirectory = + invocation.namedArguments[const Symbol('workingDirectory')] as String?; + + return executableName == 'dart' && + arguments.contains('fix') && + arguments.contains(Directory.current.path) && + arguments.contains('--apply') && + arguments.contains('--code=directives_ordering') && + workingDirectory == null; + } + + @override + Description describe(Description description) { + return description.add('is a Dart fix for directives_ordering'); + } + + @override + Description describeMismatch( + dynamic item, + Description mismatchDescription, + Map matchState, + bool verbose, + ) { + return mismatchDescription.add('is not a Dart fix for directives_ordering'); + } +}