diff --git a/packages/shorebird_cli/lib/src/shorebird_validator.dart b/packages/shorebird_cli/lib/src/shorebird_validator.dart index 8cd7c4a5..bab7a389 100644 --- a/packages/shorebird_cli/lib/src/shorebird_validator.dart +++ b/packages/shorebird_cli/lib/src/shorebird_validator.dart @@ -26,6 +26,13 @@ class ValidationFailedException implements PreconditionFailedException { ExitCode get exitCode => ExitCode.config; } +class UnsupportedContextException implements PreconditionFailedException { + // coverage:ignore-start + @override + ExitCode get exitCode => ExitCode.unavailable; + // coverage:ignore-end +} + class UnsupportedOperatingSystemException implements PreconditionFailedException { @override @@ -80,6 +87,13 @@ class ShorebirdValidator { throw ShorebirdNotInitializedException(); } + for (final validator in validators) { + if (!validator.canRunInCurrentContext()) { + logger.err(validator.incorrectContextMessage); + throw UnsupportedContextException(); + } + } + final validationIssues = await runValidators(validators); if (validationIssuesContainsError(validationIssues)) { logValidationFailure(issues: validationIssues); diff --git a/packages/shorebird_cli/lib/src/validators/android_internet_permission_validator.dart b/packages/shorebird_cli/lib/src/validators/android_internet_permission_validator.dart index b9bb80ef..3d909136 100644 --- a/packages/shorebird_cli/lib/src/validators/android_internet_permission_validator.dart +++ b/packages/shorebird_cli/lib/src/validators/android_internet_permission_validator.dart @@ -24,6 +24,14 @@ class AndroidInternetPermissionValidator extends Validator { @override bool canRunInCurrentContext() => _androidSrcDirectory.existsSync(); + // coverage:ignore-start + @override + String get incorrectContextMessage => ''' +The ${_androidSrcDirectory.path} directory does not exist. + +The command you are running must be run at the root of a Flutter app project that supports the Android platform. If you are releasing a Flutter module, use 'aar' in place of 'android' in your shorebird command.'''; + // coverage:ignore-end + @override Future> validate() async { const manifestFileName = 'AndroidManifest.xml'; diff --git a/packages/shorebird_cli/lib/src/validators/shorebird_flutter_validator.dart b/packages/shorebird_cli/lib/src/validators/shorebird_flutter_validator.dart index faaa0a10..af6b7f82 100644 --- a/packages/shorebird_cli/lib/src/validators/shorebird_flutter_validator.dart +++ b/packages/shorebird_cli/lib/src/validators/shorebird_flutter_validator.dart @@ -21,9 +21,6 @@ class ShorebirdFlutterValidator extends Validator { @override String get description => 'Flutter install is correct'; - @override - bool canRunInCurrentContext() => true; - @override Future> validate() async { final issues = []; diff --git a/packages/shorebird_cli/lib/src/validators/shorebird_version_validator.dart b/packages/shorebird_cli/lib/src/validators/shorebird_version_validator.dart index e9c6bceb..c405df6a 100644 --- a/packages/shorebird_cli/lib/src/validators/shorebird_version_validator.dart +++ b/packages/shorebird_cli/lib/src/validators/shorebird_version_validator.dart @@ -10,9 +10,6 @@ class ShorebirdVersionValidator extends Validator { @override String get description => 'Shorebird is up-to-date'; - @override - bool canRunInCurrentContext() => true; - @override Future> validate() async { final bool isShorebirdUpToDate; diff --git a/packages/shorebird_cli/lib/src/validators/validators.dart b/packages/shorebird_cli/lib/src/validators/validators.dart index bcb8bf52..48dabdd9 100644 --- a/packages/shorebird_cli/lib/src/validators/validators.dart +++ b/packages/shorebird_cli/lib/src/validators/validators.dart @@ -85,5 +85,10 @@ abstract class Validator { /// Not all validators use [process]. Future> validate(); - bool canRunInCurrentContext(); + /// Whether it makes sense to run the validator in the current working + /// directory. + bool canRunInCurrentContext() => true; + + /// User-facing message explaining why [canRunInCurrentContext] is false. + String? get incorrectContextMessage => null; } diff --git a/packages/shorebird_cli/test/src/shorebird_validator_test.dart b/packages/shorebird_cli/test/src/shorebird_validator_test.dart index 028659dd..3fc69898 100644 --- a/packages/shorebird_cli/test/src/shorebird_validator_test.dart +++ b/packages/shorebird_cli/test/src/shorebird_validator_test.dart @@ -153,6 +153,23 @@ void main() { ), ).called(1); }); + + test( + '''throws UnsupportedContextException if validator cannot be run in current context''', + () async { + const errorMessage = 'Cannot run in this context'; + when(() => validator.canRunInCurrentContext()).thenReturn(false); + when(() => validator.incorrectContextMessage).thenReturn(errorMessage); + await expectLater( + runWithOverrides( + () => shorebirdValidator.validatePreconditions( + validators: [validator], + ), + ), + throwsA(isA()), + ); + verify(() => logger.err(errorMessage)).called(1); + }); }); }); } diff --git a/packages/shorebird_cli/test/src/validators/validator_test.dart b/packages/shorebird_cli/test/src/validators/validator_test.dart new file mode 100644 index 00000000..ff49b126 --- /dev/null +++ b/packages/shorebird_cli/test/src/validators/validator_test.dart @@ -0,0 +1,24 @@ +import 'package:shorebird_cli/src/validators/validators.dart'; +import 'package:test/test.dart'; + +void main() { + group(Validator, () { + test('canRunInContext is true by default', () { + expect(FakeValidator().canRunInCurrentContext(), equals(true)); + }); + + test('incorrectContextMessage is null by default', () { + expect(FakeValidator().incorrectContextMessage, isNull); + }); + }); +} + +class FakeValidator extends Validator { + @override + String get description => 'A fake validator for testing'; + + @override + Future> validate() async { + return []; + } +}