Repository: VeryGoodOpenSource/very_good_cli (dart)

Issue:
feat: add completion to VeryGoodCommandRunner
As a developer, I want to have completion on very_good_cli commands so that I have a better developer experience when working with the CLI

Pull request description:
<!--
  Thanks for contributing!

  Provide a description of your changes below and a general summary in the title

  Please look at the following checklist to ensure that your PR can be accepted quickly:
-->

## Description

Adds the completion package to add bash completion

Closes #590

## Type of Change

<!--- Put an `x` in all the boxes that apply: -->

- [x] ✨ New feature (non-breaking change which adds functionality)
- [ ] 🛠️ Bug fix (non-breaking change which fixes an issue)
- [ ] ❌ Breaking change (fix or feature that would cause existing functionality to change)
- [ ] 🧹 Code refactor
- [ ] ✅ Build configuration change
- [ ] 📝 Documentation
- [ ] 🗑️ Chore

Patch:
diff --git a/lib/src/command_runner.dart b/lib/src/command_runner.dart
index e302a48de..c1b012cd5 100644
--- a/lib/src/command_runner.dart
+++ b/lib/src/command_runner.dart
@@ -1,5 +1,6 @@
 import 'package:args/args.dart';
 import 'package:args/command_runner.dart';
+import 'package:cli_completion/cli_completion.dart';
 import 'package:mason/mason.dart' hide packageVersion;
 import 'package:pub_updater/pub_updater.dart';
 import 'package:usage/usage_io.dart';
@@ -18,7 +19,7 @@ const packageName = 'very_good_cli';
 /// {@template very_good_command_runner}
 /// A [CommandRunner] for the Very Good CLI.
 /// {@endtemplate}
-class VeryGoodCommandRunner extends CommandRunner<int> {
+class VeryGoodCommandRunner extends CompletionCommandRunner<int> {
   /// {@macro very_good_command_runner}
   VeryGoodCommandRunner({
     Analytics? analytics,
@@ -85,6 +86,7 @@ class VeryGoodCommandRunner extends CommandRunner<int> {
             normalizedResponse == 'y' || normalizedResponse == 'yes';
       }
       final _argResults = parse(args);
+
       if (_argResults['verbose'] == true) {
         _logger.level = Level.verbose;
       }
@@ -107,6 +109,11 @@ class VeryGoodCommandRunner extends CommandRunner<int> {
 
   @override
   Future<int?> runCommand(ArgResults topLevelResults) async {
+    if (topLevelResults.command?.name == 'completion') {
+      await super.runCommand(topLevelResults);
+      return ExitCode.success.code;
+    }
+
     _logger
       ..detail('Argument information:')
       ..detail('  Top level options:');
diff --git a/pubspec.yaml b/pubspec.yaml
index 6ce128693..5ca5d7125 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -8,6 +8,7 @@ environment:
 
 dependencies:
   args: ^2.1.0
+  cli_completion: 0.1.0
   glob: ^2.0.2
   lcov_parser: ^0.1.2
   mason: ">=0.1.0-dev.39 <0.1.0-dev.40"


Test patch:
diff --git a/test/src/command_runner_test.dart b/test/src/command_runner_test.dart
index 5f169b0b8..c4766f62f 100644
--- a/test/src/command_runner_test.dart
+++ b/test/src/command_runner_test.dart
@@ -191,6 +191,18 @@ void main() {
         expect(result, equals(ExitCode.success.code));
       });
 
+      test('handles completion command', () async {
+        final result = await commandRunner.run(['completion']);
+        verifyNever(() => logger.info(any()));
+        verifyNever(() => logger.err(any()));
+        verifyNever(() => logger.warn(any()));
+        verifyNever(() => logger.write(any()));
+        verifyNever(() => logger.success(any()));
+        verifyNever(() => logger.detail(any()));
+
+        expect(result, equals(ExitCode.success.code));
+      });
+
       group('--help', () {
         test('outputs usage', () async {
           final result = await commandRunner.run(['--help']);