refactor(shorebird_cli): remove deprecated shorebird apps list/delete commands (#1116)

This commit is contained in:
Felix Angelov
2023-08-17 12:51:47 -05:00
committed by GitHub
parent a13c867b07
commit 271df80a13
6 changed files with 0 additions and 460 deletions
@@ -1,4 +1,2 @@
export 'apps_command.dart';
export 'create_apps_command.dart';
export 'delete_apps_command.dart';
export 'list_apps_command.dart';
@@ -10,8 +10,6 @@ class AppsCommand extends ShorebirdCommand {
/// {@macro apps_command}
AppsCommand() {
addSubcommand(CreateAppCommand());
addSubcommand(DeleteAppCommand());
addSubcommand(ListAppsCommand());
}
@override
@@ -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<int>? 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;
}
}
@@ -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<String> get aliases => ['ls'];
@override
Future<int>? 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<AppMetadata> {
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();
}
}
@@ -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>(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);
});
});
}
@@ -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>(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);
});
});
}