From c363c83bc151b6c57b6a66cb62200e2ada9da26d Mon Sep 17 00:00:00 2001 From: Felix Angelov Date: Wed, 19 Jul 2023 10:29:53 -0500 Subject: [PATCH] chore(shorebird_cli): remove deprecated `shorebird run` command (#873) --- .../shorebird_cli/lib/src/command_runner.dart | 1 - .../lib/src/commands/commands.dart | 1 - .../lib/src/commands/run_command.dart | 103 ------ .../test/src/commands/run_command_test.dart | 324 ------------------ 4 files changed, 429 deletions(-) delete mode 100644 packages/shorebird_cli/lib/src/commands/run_command.dart delete mode 100644 packages/shorebird_cli/test/src/commands/run_command_test.dart diff --git a/packages/shorebird_cli/lib/src/command_runner.dart b/packages/shorebird_cli/lib/src/command_runner.dart index 8e0388ac..cba31d82 100644 --- a/packages/shorebird_cli/lib/src/command_runner.dart +++ b/packages/shorebird_cli/lib/src/command_runner.dart @@ -68,7 +68,6 @@ class ShorebirdCliCommandRunner extends CompletionCommandRunner { addCommand(PreviewCommand()); addCommand(ReleaseCommand()); addCommand(ReleasesCommand()); - addCommand(RunCommand()); addCommand(UpgradeCommand()); } diff --git a/packages/shorebird_cli/lib/src/commands/commands.dart b/packages/shorebird_cli/lib/src/commands/commands.dart index 3b18800f..af8d9eec 100644 --- a/packages/shorebird_cli/lib/src/commands/commands.dart +++ b/packages/shorebird_cli/lib/src/commands/commands.dart @@ -12,5 +12,4 @@ export 'patch/patch.dart'; export 'preview_command.dart'; export 'release/release.dart'; export 'releases/releases.dart'; -export 'run_command.dart'; export 'upgrade_command.dart'; diff --git a/packages/shorebird_cli/lib/src/commands/run_command.dart b/packages/shorebird_cli/lib/src/commands/run_command.dart deleted file mode 100644 index 912e089a..00000000 --- a/packages/shorebird_cli/lib/src/commands/run_command.dart +++ /dev/null @@ -1,103 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; - -import 'package:shorebird_cli/src/command.dart'; -import 'package:shorebird_cli/src/logger.dart'; -import 'package:shorebird_cli/src/process.dart'; -import 'package:shorebird_cli/src/shorebird_config_mixin.dart'; -import 'package:shorebird_cli/src/shorebird_validation_mixin.dart'; - -/// {@template run_command} -/// `shorebird run` -/// Run the Flutter application. -/// {@endtemplate} -class RunCommand extends ShorebirdCommand - with ShorebirdConfigMixin, ShorebirdValidationMixin { - /// {@macro run_command} - RunCommand({super.buildCodePushClient, super.validators}) { - argParser - ..addOption( - 'device-id', - abbr: 'd', - help: 'Target device id or name.', - ) - ..addOption( - 'target', - abbr: 't', - help: 'The main entrypoint file of the application.', - ) - ..addMultiOption( - 'dart-define', - help: 'Additional key-value pairs that will be available as constants ' - '''from the String.fromEnvironment, bool.fromEnvironment, and int.fromEnvironment ''' - 'constructors.\n' - '''Multiple defines can be passed by repeating "--dart-define" multiple times.''', - splitCommas: false, - valueHelp: 'foo=bar', - ) - ..addOption( - 'flavor', - help: 'The product flavor to use when building the app.', - ); - } - - @override - String get description => 'Run the Flutter application.'; - - @override - String get name => 'run'; - - @override - bool get hidden => true; - - @override - Future run() async { - logger.warn( - ''' -This command is deprecated and will be removed in a future release. -Please use "shorebird preview" instead.''', - ); - - try { - await validatePreconditions( - checkUserIsAuthenticated: true, - checkValidators: true, - ); - } on PreconditionFailedException catch (e) { - return e.exitCode.code; - } - - logger.info('Running app...'); - - final deviceId = results['device-id'] as String?; - final flavor = results['flavor'] as String?; - final target = results['target'] as String?; - final dartDefines = results['dart-define'] as List?; - final flutter = await process.start( - 'flutter', - [ - 'run', - // Eventually we should support running in both debug and release mode. - '--release', - if (deviceId != null) '--device-id=$deviceId', - if (flavor != null) '--flavor=$flavor', - if (target != null) '--target=$target', - if (dartDefines != null) ...dartDefines.map((e) => '--dart-define=$e'), - ...results.rest - ], - runInShell: true, - ); - - flutter.stdout.listen((event) { - logger.info(utf8.decode(event)); - }); - flutter.stderr.listen((event) { - logger.err(utf8.decode(event)); - }); - - unawaited(flutter.stdin.addStream(stdin)); - - return flutter.exitCode; - } -} diff --git a/packages/shorebird_cli/test/src/commands/run_command_test.dart b/packages/shorebird_cli/test/src/commands/run_command_test.dart deleted file mode 100644 index bd0aa7e3..00000000 --- a/packages/shorebird_cli/test/src/commands/run_command_test.dart +++ /dev/null @@ -1,324 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; - -import 'package:args/args.dart'; -import 'package:http/http.dart' as http; -import 'package:mason_logger/mason_logger.dart'; -import 'package:mocktail/mocktail.dart'; -import 'package:scoped/scoped.dart'; -import 'package:shorebird_cli/src/auth/auth.dart'; -import 'package:shorebird_cli/src/commands/run_command.dart'; -import 'package:shorebird_cli/src/logger.dart'; -import 'package:shorebird_cli/src/process.dart'; -import 'package:shorebird_cli/src/validators/validators.dart'; -import 'package:shorebird_code_push_client/shorebird_code_push_client.dart'; -import 'package:test/test.dart'; - -class _MockArgResults extends Mock implements ArgResults {} - -class _MockHttpClient extends Mock implements http.Client {} - -class _MockAuth extends Mock implements Auth {} - -class _MockLogger extends Mock implements Logger {} - -class _MockProgress extends Mock implements Progress {} - -class _MockProcess extends Mock implements Process {} - -class _MockCodePushClient extends Mock implements CodePushClient {} - -class _MockAndroidInternetPermissionValidator extends Mock - implements AndroidInternetPermissionValidator {} - -class _MockShorebirdFlutterValidator extends Mock - implements ShorebirdFlutterValidator {} - -class _MockShorebirdProcess extends Mock implements ShorebirdProcess {} - -class _MockIOSink extends Mock implements IOSink {} - -void main() { - group(RunCommand, () { - late ArgResults argResults; - late http.Client httpClient; - late Auth auth; - late Logger logger; - late Process process; - late CodePushClient codePushClient; - late AndroidInternetPermissionValidator androidInternetPermissionValidator; - late ShorebirdFlutterValidator flutterValidator; - late ShorebirdProcess shorebirdProcess; - late RunCommand command; - late IOSink ioSink; - - R runWithOverrides(R Function() body) { - return runScoped( - body, - values: { - authRef.overrideWith(() => auth), - loggerRef.overrideWith(() => logger), - processRef.overrideWith(() => shorebirdProcess), - }, - ); - } - - setUpAll(() { - registerFallbackValue(const Stream>.empty()); - }); - - setUp(() { - argResults = _MockArgResults(); - httpClient = _MockHttpClient(); - auth = _MockAuth(); - logger = _MockLogger(); - process = _MockProcess(); - shorebirdProcess = _MockShorebirdProcess(); - codePushClient = _MockCodePushClient(); - androidInternetPermissionValidator = - _MockAndroidInternetPermissionValidator(); - flutterValidator = _MockShorebirdFlutterValidator(); - ioSink = _MockIOSink(); - - registerFallbackValue(shorebirdProcess); - - when( - () => shorebirdProcess.start( - any(), - any(), - runInShell: any(named: 'runInShell'), - ), - ).thenAnswer((_) async => process); - when(() => argResults.rest).thenReturn([]); - when(() => auth.isAuthenticated).thenReturn(true); - when(() => auth.client).thenReturn(httpClient); - when(() => logger.progress(any())).thenReturn(_MockProgress()); - when( - () => androidInternetPermissionValidator.validate(any()), - ).thenAnswer((_) async => []); - when(() => flutterValidator.validate(any())).thenAnswer((_) async => []); - when(() => ioSink.addStream(any())).thenAnswer((_) async {}); - - command = runWithOverrides( - () => RunCommand( - buildCodePushClient: ({ - required http.Client httpClient, - Uri? hostedUri, - }) { - return codePushClient; - }, - validators: [ - androidInternetPermissionValidator, - flutterValidator, - ], - ), - )..testArgResults = argResults; - }); - - test('command is hidden', () { - expect(command.hidden, isTrue); - }); - - test('has a description', () { - expect(command.description, isNotEmpty); - }); - - test('logs deprecation warning', () async { - runWithOverrides(command.run).ignore(); - - verify( - () => logger.warn(''' -This command is deprecated and will be removed in a future release. -Please use "shorebird preview" instead.'''), - ).called(1); - }); - - test('exits with no user when not logged in', () async { - when(() => auth.isAuthenticated).thenReturn(false); - - final result = await runWithOverrides(command.run); - expect(result, equals(ExitCode.noUser.code)); - - verify( - () => logger.err(any(that: contains('You must be logged in to run'))), - ).called(1); - }); - - test('exits with code when running the app fails', () async { - final tempDir = Directory.systemTemp.createTempSync(); - - final progress = _MockProgress(); - when(() => logger.progress(any())).thenReturn(progress); - - const error = 'oops something went wrong'; - const exitCode = 1; - when( - () => process.stdout, - ).thenAnswer((_) => const Stream.empty()); - when(() => process.stdin).thenAnswer((_) => ioSink); - when(() => process.stderr).thenAnswer( - (_) => Stream.value(utf8.encode(error)), - ); - when(() => process.exitCode).thenAnswer((_) async => exitCode); - - final result = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); - - await expectLater(result, equals(exitCode)); - verify(() => logger.err(error)).called(1); - }); - - test('exits with code 0 when running the app succeeds', () async { - final tempDir = Directory.systemTemp.createTempSync(); - - final progress = _MockProgress(); - when(() => logger.progress(any())).thenReturn(progress); - - const output = 'some output'; - when( - () => process.stdout, - ).thenAnswer((_) => Stream.value(utf8.encode(output))); - when(() => process.stdin).thenAnswer((_) => ioSink); - when(() => process.stderr).thenAnswer((_) => const Stream.empty()); - when( - () => process.exitCode, - ).thenAnswer((_) async => ExitCode.success.code); - - final result = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); - - await expectLater(result, equals(ExitCode.success.code)); - verify(() => logger.info(output)).called(1); - verify(() => ioSink.addStream(any())).called(1); - }); - - test('passes additional args when specified', () async { - final tempDir = Directory.systemTemp.createTempSync(); - - final progress = _MockProgress(); - when(() => logger.progress(any())).thenReturn(progress); - - const deviceId = 'test-device-id'; - const flavor = 'development'; - const target = './lib/main_development.dart'; - const dartDefines = ['FOO=BAR', 'BAZ=QUX']; - when(() => argResults['device-id']).thenReturn(deviceId); - when(() => argResults['flavor']).thenReturn(flavor); - when(() => argResults['target']).thenReturn(target); - when(() => argResults['dart-define']).thenReturn(dartDefines); - - when(() => process.stdout).thenAnswer((_) => const Stream.empty()); - when(() => process.stdin).thenAnswer((_) => ioSink); - when(() => process.stderr).thenAnswer((_) => const Stream.empty()); - when( - () => process.exitCode, - ).thenAnswer((_) async => ExitCode.success.code); - - final result = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); - - final args = verify( - () => shorebirdProcess.start( - any(), - captureAny(), - runInShell: any(named: 'runInShell'), - ), - ).captured.first as List; - expect( - args, - equals([ - 'run', - '--release', - '--device-id=$deviceId', - '--flavor=$flavor', - '--target=$target', - '--dart-define=${dartDefines[0]}', - '--dart-define=${dartDefines[1]}', - ]), - ); - - await expectLater(result, equals(ExitCode.success.code)); - }); - - test('prints validation warnings', () async { - when(() => flutterValidator.validate(any())).thenAnswer( - (_) async => [ - const ValidationIssue( - severity: ValidationIssueSeverity.warning, - message: 'Flutter issue', - ), - ], - ); - when(() => androidInternetPermissionValidator.validate(any())).thenAnswer( - (_) async => [ - const ValidationIssue( - severity: ValidationIssueSeverity.warning, - message: 'Android issue', - ), - ], - ); - final tempDir = Directory.systemTemp.createTempSync(); - - final progress = _MockProgress(); - when(() => logger.progress(any())).thenReturn(progress); - - const output = 'some output'; - final ioSink = IOSink(StreamController()); - when( - () => process.stdout, - ).thenAnswer((_) => Stream.value(utf8.encode(output))); - when(() => process.stdin).thenAnswer((_) => ioSink); - when(() => process.stderr).thenAnswer((_) => const Stream.empty()); - when( - () => process.exitCode, - ).thenAnswer((_) async => ExitCode.success.code); - - final result = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); - - await expectLater(result, equals(ExitCode.success.code)); - verify(() => logger.info(output)).called(1); - verify( - () => logger.info(any(that: contains('Flutter issue'))), - ).called(1); - verify( - () => logger.info(any(that: contains('Android issue'))), - ).called(1); - }); - - test('aborts on validation errors', () async { - when(() => androidInternetPermissionValidator.validate(any())).thenAnswer( - (_) async => [ - const ValidationIssue( - severity: ValidationIssueSeverity.error, - message: 'Android issue', - ), - ], - ); - final tempDir = Directory.systemTemp.createTempSync(); - - final progress = _MockProgress(); - when(() => logger.progress(any())).thenReturn(progress); - - final result = await IOOverrides.runZoned( - () => runWithOverrides(command.run), - getCurrentDirectory: () => tempDir, - ); - - await expectLater(result, equals(ExitCode.config.code)); - verify( - () => logger.info(any(that: contains('Android issue'))), - ).called(1); - verify(() => logger.err('Aborting due to validation errors.')).called(1); - }); - }); -}