Repository: VeryGoodOpenSource/very_good_cli (dart)

Issue:
fix: `very_good packages get -r` silently quits if there is no `flutter` executable available
**Description**
Hello!

When using `very_good packages get -r` on CI without Flutter being installed, the command silently quits without installing the dependencies. This behaviour is kinda misleading and a warning of some sort would be great to have.

For example,
```yaml
jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Install Beta Dart
        uses: dart-lang/setup-dart@v1
        with:
          sdk: beta

      - name: Install Very Good CLI
        run: |
          dart pub global activate very_good_cli
          dart pub global run very_good_cli:very_good --analytics=false

      - name: Install dependencies
        run: dart pub global run very_good_cli:very_good packages get -r
```

The output looks like:
<img width="760" alt="Screenshot 2023-07-10 at 14 36 48" src="https://github.com/VeryGoodOpenSource/very_good_cli/assets/21116742/a4565f6a-0a28-44f1-b312-e00f003c00b5">

**Steps To Reproduce**

1. Create a github workflow with the steps above
2. Run it

Pull request description:
## Status

**READY**

## Description

Hey very_good_ventures team,

This PR resolves #760 by ensuring the Flutter SDK is checked before executing pub get, which improves error handling for missing SDK scenarios. I also noticed that the "Flutter not installed" issue isn't handled in many scenarios. Maybe we can use this PR as a foundation to handle Flutter installation checks in other commands as well.

Let me know what you think!

## Type of Change

- [ ] ✨ New feature (non-breaking change which adds functionality)
- [x] 🛠️ 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/commands/packages/commands/get.dart b/lib/src/commands/packages/commands/get.dart
index e0855ac35..4c79f4b79 100644
--- a/lib/src/commands/packages/commands/get.dart
+++ b/lib/src/commands/packages/commands/get.dart
@@ -50,21 +50,27 @@ class PackagesGetCommand extends Command<int> {
     final target = _argResults.rest.length == 1 ? _argResults.rest[0] : '.';
     final targetPath = path.normalize(Directory(target).absolute.path);
     final isFlutterInstalled = await Flutter.installed(logger: _logger);
-    if (isFlutterInstalled) {
-      try {
-        await Flutter.pubGet(
-          cwd: targetPath,
-          recursive: recursive,
-          ignore: ignore,
-          logger: _logger,
-        );
-      } on PubspecNotFound catch (_) {
-        _logger.err('Could not find a pubspec.yaml in $targetPath');
-        return ExitCode.noInput.code;
-      } on Exception catch (error) {
-        _logger.err('$error');
-        return ExitCode.unavailable.code;
-      }
+    if (!isFlutterInstalled) {
+      _logger.err(
+        'Could not find Flutter SDK. '
+        'Please ensure it is installed and added to your PATH. '
+        'For troubleshooting, see https://docs.flutter.dev/install/troubleshoot',
+      );
+      return ExitCode.unavailable.code;
+    }
+    try {
+      await Flutter.pubGet(
+        cwd: targetPath,
+        recursive: recursive,
+        ignore: ignore,
+        logger: _logger,
+      );
+    } on PubspecNotFound catch (_) {
+      _logger.err('Could not find a pubspec.yaml in $targetPath');
+      return ExitCode.noInput.code;
+    } on Exception catch (error) {
+      _logger.err('$error');
+      return ExitCode.unavailable.code;
     }
     return ExitCode.success.code;
   }


Test patch:
diff --git a/test/src/commands/packages/commands/get_test.dart b/test/src/commands/packages/commands/get_test.dart
index 7dcb52aff..873e4b2ee 100644
--- a/test/src/commands/packages/commands/get_test.dart
+++ b/test/src/commands/packages/commands/get_test.dart
@@ -7,6 +7,7 @@ import 'package:mocktail/mocktail.dart';
 import 'package:path/path.dart' as path;
 import 'package:test/test.dart';
 import 'package:universal_io/io.dart';
+import 'package:very_good_cli/src/cli/cli.dart';
 
 import '../../../../helpers/helpers.dart';
 
@@ -99,6 +100,58 @@ void main() {
       }),
     );
 
+    test(
+      'returns exit code unavailable when Flutter is not installed',
+      withRunner((commandRunner, logger, pubUpdater, printLogs) async {
+        final tempDirectory = Directory.systemTemp.createTempSync();
+        addTearDown(() => tempDirectory.deleteSync(recursive: true));
+
+        File(path.join(tempDirectory.path, 'pubspec.yaml')).writeAsStringSync(
+          '''
+name: example
+version: 0.1.0
+
+environment:
+sdk: ^3.8.0
+''',
+        );
+
+        // Mock flutter process to simulate flutter not being installed
+        Future<ProcessResult> mockProcess(
+          String executable,
+          List<String> arguments, {
+          String? workingDirectory,
+          bool runInShell = false,
+        }) async {
+          if (executable == 'flutter') {
+            throw Exception('flutter not installed');
+          }
+          return ProcessResult(42, 0, '', '');
+        }
+
+        late int result;
+        await ProcessOverrides.runZoned(
+          () async {
+            result = await commandRunner.run([
+              'packages',
+              'get',
+              tempDirectory.path,
+            ]);
+          },
+          runProcess: mockProcess,
+        );
+
+        expect(result, equals(ExitCode.unavailable.code));
+        verify(() {
+          logger.err(
+            'Could not find Flutter SDK. '
+            'Please ensure it is installed and added to your PATH. '
+            'For troubleshooting, see https://docs.flutter.dev/install/troubleshoot',
+          );
+        }).called(1);
+      }),
+    );
+
     test(
       'ignores .fvm directory',
       withRunner((commandRunner, logger, pubUpdater, printLogs) async {