refactor(shorebird_cli): remove deprecated shorebird apps list/delete commands (#1116)
This commit is contained in:
@@ -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);
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user