diff --git a/packages/shorebird_cli/lib/src/commands/apps/apps.dart b/packages/shorebird_cli/lib/src/commands/apps/apps.dart index be07b901..ee0075bd 100644 --- a/packages/shorebird_cli/lib/src/commands/apps/apps.dart +++ b/packages/shorebird_cli/lib/src/commands/apps/apps.dart @@ -1,4 +1,2 @@ export 'apps_command.dart'; export 'create_apps_command.dart'; -export 'delete_apps_command.dart'; -export 'list_apps_command.dart'; diff --git a/packages/shorebird_cli/lib/src/commands/apps/apps_command.dart b/packages/shorebird_cli/lib/src/commands/apps/apps_command.dart index 7345a759..d38e59a3 100644 --- a/packages/shorebird_cli/lib/src/commands/apps/apps_command.dart +++ b/packages/shorebird_cli/lib/src/commands/apps/apps_command.dart @@ -10,8 +10,6 @@ class AppsCommand extends ShorebirdCommand { /// {@macro apps_command} AppsCommand() { addSubcommand(CreateAppCommand()); - addSubcommand(DeleteAppCommand()); - addSubcommand(ListAppsCommand()); } @override diff --git a/packages/shorebird_cli/lib/src/commands/apps/delete_apps_command.dart b/packages/shorebird_cli/lib/src/commands/apps/delete_apps_command.dart deleted file mode 100644 index 0780c75e..00000000 --- a/packages/shorebird_cli/lib/src/commands/apps/delete_apps_command.dart +++ /dev/null @@ -1,94 +0,0 @@ -import 'dart:async'; - -import 'package:mason_logger/mason_logger.dart'; -import 'package:shorebird_cli/src/code_push_client_wrapper.dart'; -import 'package:shorebird_cli/src/command.dart'; -import 'package:shorebird_cli/src/logger.dart'; -import 'package:shorebird_cli/src/shorebird_env.dart'; -import 'package:shorebird_cli/src/shorebird_validator.dart'; - -/// {@template delete_app_command} -/// -/// `shorebird apps delete` -/// Delete an existing app on Shorebird. -/// {@endtemplate} -class DeleteAppCommand extends ShorebirdCommand { - /// {@macro delete_app_command} - DeleteAppCommand() { - argParser - ..addOption( - 'app-id', - help: ''' -The unique application identifier. -Defaults to the app_id in "shorebird.yaml".''', - ) - ..addFlag( - 'force', - abbr: 'f', - help: 'Release without confirmation if there are no errors.', - negatable: false, - ); - } - - @override - String get description => 'Delete an existing app on Shorebird.'; - - @override - String get name => 'delete'; - - @override - Future? run() async { - final consoleLink = link(uri: Uri.parse('https://console.shorebird.dev')); - logger.warn( - ''' -This command is deprecated and will be removed in a future release. -Please use $consoleLink instead.''', - ); - - try { - await shorebirdValidator.validatePreconditions( - checkUserIsAuthenticated: true, - ); - } on PreconditionFailedException catch (e) { - return e.exitCode.code; - } - - final appIdArg = results['app-id'] as String?; - final force = results['force'] == true; - late final String appId; - - if (appIdArg == null) { - String? defaultAppId; - try { - defaultAppId = shorebirdEnv.getShorebirdYaml()?.appId; - } catch (_) {} - - appId = logger.prompt( - '${lightGreen.wrap('?')} Enter the App ID', - defaultValue: defaultAppId, - ); - } else { - appId = appIdArg; - } - - final shouldProceed = - force || logger.confirm('Deleting an app is permanent. Continue?'); - if (!shouldProceed) { - logger.info('Aborted.'); - return ExitCode.success.code; - } - - try { - await codePushClientWrapper.codePushClient.deleteApp(appId: appId); - } catch (error) { - logger.err('$error'); - return ExitCode.software.code; - } - - logger.info( - '${lightGreen.wrap('Deleted app: ${cyan.wrap(appId)}')}', - ); - - return ExitCode.success.code; - } -} diff --git a/packages/shorebird_cli/lib/src/commands/apps/list_apps_command.dart b/packages/shorebird_cli/lib/src/commands/apps/list_apps_command.dart deleted file mode 100644 index 60d787af..00000000 --- a/packages/shorebird_cli/lib/src/commands/apps/list_apps_command.dart +++ /dev/null @@ -1,97 +0,0 @@ -import 'dart:async'; - -import 'package:barbecue/barbecue.dart'; -import 'package:mason_logger/mason_logger.dart'; -import 'package:shorebird_cli/src/code_push_client_wrapper.dart'; -import 'package:shorebird_cli/src/command.dart'; -import 'package:shorebird_cli/src/logger.dart'; -import 'package:shorebird_cli/src/shorebird_validator.dart'; -import 'package:shorebird_code_push_client/shorebird_code_push_client.dart'; - -/// {@template list_apps_command} -/// -/// `shorebird apps list` -/// List all apps using Shorebird. -/// {@endtemplate} -class ListAppsCommand extends ShorebirdCommand { - @override - String get description => 'List all apps using Shorebird.'; - - @override - String get name => 'list'; - - @override - List get aliases => ['ls']; - - @override - Future? run() async { - final consoleLink = link(uri: Uri.parse('https://console.shorebird.dev')); - logger.warn( - ''' -This command is deprecated and will be removed in a future release. -Please use $consoleLink instead.''', - ); - - try { - await shorebirdValidator.validatePreconditions( - checkUserIsAuthenticated: true, - ); - } on PreconditionFailedException catch (e) { - return e.exitCode.code; - } - - final apps = await codePushClientWrapper.getApps(); - - logger.info('📱 Apps'); - - if (apps.isEmpty) { - logger.info('(empty)'); - return ExitCode.success.code; - } - - logger.info(apps.prettyPrint()); - - return ExitCode.success.code; - } -} - -extension on List { - String prettyPrint() { - const cellStyle = CellStyle( - paddingLeft: 1, - paddingRight: 1, - borderBottom: true, - borderTop: true, - borderLeft: true, - borderRight: true, - ); - return Table( - cellStyle: cellStyle, - header: const TableSection( - rows: [ - Row( - cells: [ - Cell('Name'), - Cell('ID'), - Cell('Release'), - Cell('Patch'), - ], - ) - ], - ), - body: TableSection( - rows: [ - for (final app in this) - Row( - cells: [ - Cell(app.displayName), - Cell(app.appId), - Cell(app.latestReleaseVersion ?? '--'), - Cell(app.latestPatchNumber?.toString() ?? '--'), - ], - ), - ], - ), - ).render(); - } -} diff --git a/packages/shorebird_cli/test/src/commands/apps/delete_apps_command_test.dart b/packages/shorebird_cli/test/src/commands/apps/delete_apps_command_test.dart deleted file mode 100644 index dd5e92a4..00000000 --- a/packages/shorebird_cli/test/src/commands/apps/delete_apps_command_test.dart +++ /dev/null @@ -1,152 +0,0 @@ -import 'package:args/args.dart'; -import 'package:mason_logger/mason_logger.dart'; -import 'package:mocktail/mocktail.dart'; -import 'package:scoped/scoped.dart'; -import 'package:shorebird_cli/src/code_push_client_wrapper.dart'; -import 'package:shorebird_cli/src/commands/commands.dart'; -import 'package:shorebird_cli/src/logger.dart'; -import 'package:shorebird_cli/src/shorebird_env.dart'; -import 'package:shorebird_cli/src/shorebird_validator.dart'; -import 'package:shorebird_code_push_client/shorebird_code_push_client.dart'; -import 'package:test/test.dart'; - -class _MockArgResults extends Mock implements ArgResults {} - -class _MockCodePushClientWrapper extends Mock - implements CodePushClientWrapper {} - -class _MockCodePushClient extends Mock implements CodePushClient {} - -class _MockLogger extends Mock implements Logger {} - -class _MockShorebirdValidator extends Mock implements ShorebirdValidator {} - -class _MockShorebirdEnv extends Mock implements ShorebirdEnv {} - -void main() { - group(DeleteAppCommand, () { - const appId = 'example'; - - late ArgResults argResults; - late Logger logger; - late CodePushClientWrapper codePushClientWrapper; - late CodePushClient codePushClient; - late ShorebirdEnv shorebirdEnv; - late ShorebirdValidator shorebirdValidator; - late DeleteAppCommand command; - - R runWithOverrides(R Function() body) { - return runScoped( - body, - values: { - codePushClientWrapperRef.overrideWith(() => codePushClientWrapper), - loggerRef.overrideWith(() => logger), - shorebirdEnvRef.overrideWith(() => shorebirdEnv), - shorebirdValidatorRef.overrideWith(() => shorebirdValidator), - }, - ); - } - - setUp(() { - argResults = _MockArgResults(); - logger = _MockLogger(); - codePushClientWrapper = _MockCodePushClientWrapper(); - codePushClient = _MockCodePushClient(); - shorebirdEnv = _MockShorebirdEnv(); - shorebirdValidator = _MockShorebirdValidator(); - - when( - () => shorebirdValidator.validatePreconditions( - checkUserIsAuthenticated: any(named: 'checkUserIsAuthenticated'), - ), - ).thenAnswer((_) async {}); - when( - () => codePushClientWrapper.codePushClient, - ).thenReturn(codePushClient); - - command = runWithOverrides(DeleteAppCommand.new) - ..testArgResults = argResults; - }); - - test('has a description', () { - expect( - command.description, - equals('Delete an existing app on Shorebird.'), - ); - }); - - test('exits when validation fails', () async { - final exception = ValidationFailedException(); - when( - () => shorebirdValidator.validatePreconditions( - checkUserIsAuthenticated: any(named: 'checkUserIsAuthenticated'), - ), - ).thenThrow(exception); - await expectLater( - runWithOverrides(command.run), - completion(equals(exception.exitCode.code)), - ); - verify( - () => shorebirdValidator.validatePreconditions( - checkUserIsAuthenticated: true, - ), - ).called(1); - }); - - test('prompts for app-id when not provided', () async { - when(() => logger.confirm(any())).thenReturn(false); - when(() => logger.prompt(any())).thenReturn(appId); - await runWithOverrides(command.run); - verify(() => logger.prompt(any())).called(1); - }); - - test('uses provided app-id when provided', () async { - when(() => logger.confirm(any())).thenReturn(false); - when(() => argResults['app-id']).thenReturn(appId); - await runWithOverrides(command.run); - verifyNever(() => logger.prompt(any())); - }); - - test('aborts when user does not confirm', () async { - when(() => logger.confirm(any())).thenReturn(false); - when(() => argResults['app-id']).thenReturn(appId); - final result = await runWithOverrides(command.run); - expect(result, ExitCode.success.code); - verifyNever(() => codePushClient.deleteApp(appId: appId)); - verify(() => logger.info('Aborted.')).called(1); - }); - - test('does not prompt for confirmation when force flag is provided', - () async { - when(() => argResults['app-id']).thenReturn(appId); - when(() => argResults['force']).thenReturn(true); - when( - () => codePushClient.deleteApp(appId: appId), - ).thenAnswer((_) async {}); - final result = await runWithOverrides(command.run); - expect(result, ExitCode.success.code); - verify(() => codePushClient.deleteApp(appId: appId)); - verifyNever(() => logger.confirm(any())); - }); - - test('returns success when app is deleted', () async { - when(() => logger.confirm(any())).thenReturn(true); - when(() => argResults['app-id']).thenReturn(appId); - when( - () => codePushClient.deleteApp(appId: appId), - ).thenAnswer((_) async {}); - final result = await runWithOverrides(command.run); - expect(result, ExitCode.success.code); - }); - - test('returns software error when app deletion fails', () async { - final error = Exception('oops'); - when(() => logger.confirm(any())).thenReturn(true); - when(() => argResults['app-id']).thenReturn(appId); - when(() => codePushClient.deleteApp(appId: appId)).thenThrow(error); - final result = await runWithOverrides(command.run); - expect(result, ExitCode.software.code); - verify(() => logger.err('$error')).called(1); - }); - }); -} diff --git a/packages/shorebird_cli/test/src/commands/apps/list_apps_command_test.dart b/packages/shorebird_cli/test/src/commands/apps/list_apps_command_test.dart deleted file mode 100644 index 961d2076..00000000 --- a/packages/shorebird_cli/test/src/commands/apps/list_apps_command_test.dart +++ /dev/null @@ -1,113 +0,0 @@ -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/code_push_client_wrapper.dart'; -import 'package:shorebird_cli/src/commands/commands.dart'; -import 'package:shorebird_cli/src/logger.dart'; -import 'package:shorebird_cli/src/shorebird_validator.dart'; -import 'package:shorebird_code_push_client/shorebird_code_push_client.dart'; -import 'package:test/test.dart'; - -class _MockAuth extends Mock implements Auth {} - -class _MockCodePushClientWrapper extends Mock - implements CodePushClientWrapper {} - -class _MockLogger extends Mock implements Logger {} - -class _MockShorebirdValidator extends Mock implements ShorebirdValidator {} - -void main() { - group(ListAppsCommand, () { - late Auth auth; - late CodePushClientWrapper codePushClientWrapper; - late Logger logger; - late ShorebirdValidator shorebirdValidator; - late ListAppsCommand command; - - R runWithOverrides(R Function() body) { - return runScoped( - body, - values: { - authRef.overrideWith(() => auth), - codePushClientWrapperRef.overrideWith(() => codePushClientWrapper), - loggerRef.overrideWith(() => logger), - shorebirdValidatorRef.overrideWith(() => shorebirdValidator), - }, - ); - } - - setUp(() { - auth = _MockAuth(); - codePushClientWrapper = _MockCodePushClientWrapper(); - logger = _MockLogger(); - shorebirdValidator = _MockShorebirdValidator(); - command = ListAppsCommand(); - - when(() => auth.isAuthenticated).thenReturn(true); - when( - () => shorebirdValidator.validatePreconditions( - checkUserIsAuthenticated: any(named: 'checkUserIsAuthenticated'), - ), - ).thenAnswer((_) async {}); - }); - - test('has a description', () { - expect(command.description, equals('List all apps using Shorebird.')); - }); - - test('exits when validation fails', () async { - final exception = ValidationFailedException(); - when( - () => shorebirdValidator.validatePreconditions( - checkUserIsAuthenticated: any(named: 'checkUserIsAuthenticated'), - ), - ).thenThrow(exception); - await expectLater( - runWithOverrides(command.run), - completion(equals(exception.exitCode.code)), - ); - verify( - () => shorebirdValidator.validatePreconditions( - checkUserIsAuthenticated: true, - ), - ).called(1); - }); - - test('returns ExitCode.success when apps are empty', () async { - when(codePushClientWrapper.getApps).thenAnswer((_) async => []); - expect(await runWithOverrides(command.run), ExitCode.success.code); - verify(() => logger.info('(empty)')).called(1); - }); - - test('returns ExitCode.success when apps are not empty', () async { - final apps = [ - const AppMetadata( - appId: '30370f27-dbf1-4673-8b20-fb096e38dffa', - displayName: 'Shorebird Counter', - latestReleaseVersion: '1.0.0', - latestPatchNumber: 1, - ), - const AppMetadata( - appId: '05b45471-a5f3-48cd-b26a-da29d95914a7', - displayName: 'Shorebird Clock', - ), - ]; - when(codePushClientWrapper.getApps).thenAnswer((_) async => apps); - expect(await runWithOverrides(command.run), ExitCode.success.code); - verify( - () => logger.info( - ''' -┌───────────────────┬──────────────────────────────────────┬─────────┬───────┐ -│ Name │ ID │ Release │ Patch │ -├───────────────────┼──────────────────────────────────────┼─────────┼───────┤ -│ Shorebird Counter │ 30370f27-dbf1-4673-8b20-fb096e38dffa │ 1.0.0 │ 1 │ -├───────────────────┼──────────────────────────────────────┼─────────┼───────┤ -│ Shorebird Clock │ 05b45471-a5f3-48cd-b26a-da29d95914a7 │ -- │ -- │ -└───────────────────┴──────────────────────────────────────┴─────────┴───────┘''', - ), - ).called(1); - }); - }); -}