diff --git a/packages/shorebird_cli/lib/src/command_runner.dart b/packages/shorebird_cli/lib/src/command_runner.dart index 5bd17642..626d6b78 100644 --- a/packages/shorebird_cli/lib/src/command_runner.dart +++ b/packages/shorebird_cli/lib/src/command_runner.dart @@ -51,6 +51,7 @@ class ShorebirdCliCommandRunner extends CompletionCommandRunner { codePushApiClientBuilder ?? ShorebirdCodePushApiClient.new; addCommand(LoginCommand(auth: authentication, logger: _logger)); + addCommand(LogoutCommand(auth: authentication, logger: _logger)); addCommand( PublishCommand( auth: authentication, diff --git a/packages/shorebird_cli/lib/src/commands/commands.dart b/packages/shorebird_cli/lib/src/commands/commands.dart index 61b0b6ee..005b0f03 100644 --- a/packages/shorebird_cli/lib/src/commands/commands.dart +++ b/packages/shorebird_cli/lib/src/commands/commands.dart @@ -1,3 +1,4 @@ export 'login_command.dart'; +export 'logout_command.dart'; export 'publish_command.dart'; export 'update_command.dart'; diff --git a/packages/shorebird_cli/lib/src/commands/logout_command.dart b/packages/shorebird_cli/lib/src/commands/logout_command.dart new file mode 100644 index 00000000..13ede8bd --- /dev/null +++ b/packages/shorebird_cli/lib/src/commands/logout_command.dart @@ -0,0 +1,39 @@ +import 'package:args/command_runner.dart'; +import 'package:mason_logger/mason_logger.dart'; +import 'package:shorebird_cli/src/auth/auth.dart'; + +/// {@template logout_command} +/// +/// `shorebird logout` +/// Logout of the current Shorebird user. +/// {@endtemplate} +class LogoutCommand extends Command { + /// {@macro logout_command} + LogoutCommand({required Auth auth, required Logger logger}) + : _auth = auth, + _logger = logger; + + @override + String get description => 'Logout of the current Shorebird user'; + + @override + String get name => 'logout'; + + final Auth _auth; + final Logger _logger; + + @override + Future run() async { + final session = _auth.currentSession; + if (session == null) { + _logger.info('You are already logged out.'); + return ExitCode.success.code; + } + + final logoutProgress = _logger.progress('Logging out of shorebird.dev'); + _auth.logout(); + logoutProgress.complete(); + + return ExitCode.success.code; + } +} diff --git a/packages/shorebird_cli/test/src/commands/logout_command_test.dart b/packages/shorebird_cli/test/src/commands/logout_command_test.dart new file mode 100644 index 00000000..bd9c58d4 --- /dev/null +++ b/packages/shorebird_cli/test/src/commands/logout_command_test.dart @@ -0,0 +1,52 @@ +import 'package:mason_logger/mason_logger.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:shorebird_cli/src/auth/auth.dart'; +import 'package:shorebird_cli/src/auth/session.dart'; +import 'package:shorebird_cli/src/commands/logout_command.dart'; +import 'package:test/test.dart'; + +class _MockLogger extends Mock implements Logger {} + +class _MockAuth extends Mock implements Auth {} + +class _MockProgress extends Mock implements Progress {} + +void main() { + group('LogoutCommand', () { + late Logger logger; + late Auth auth; + late LogoutCommand logoutCommand; + + setUp(() { + logger = _MockLogger(); + auth = _MockAuth(); + logoutCommand = LogoutCommand(auth: auth, logger: logger); + + when(() => logger.progress(any())).thenReturn(_MockProgress()); + }); + + test('exits with code 0 when already logged out', () async { + final result = await logoutCommand.run(); + expect(result, equals(ExitCode.success.code)); + + verify( + () => logger.info('You are already logged out.'), + ).called(1); + }); + + test('exits with code 0 when logged out successfully', () async { + const session = Session(apiKey: 'test-api-key', projectId: 'example'); + when(() => auth.currentSession).thenReturn(session); + + final progress = _MockProgress(); + when(() => progress.complete(any())).thenAnswer((invocation) {}); + when(() => logger.progress(any())).thenReturn(progress); + + final result = await logoutCommand.run(); + expect(result, equals(ExitCode.success.code)); + + verify(() => logger.progress('Logging out of shorebird.dev')).called(1); + verify(() => auth.logout()).called(1); + }); + }); +}