From 6e44d024bdc5c6e022ae305a4823cdcace290ecd Mon Sep 17 00:00:00 2001 From: Felix Angelov Date: Tue, 8 Aug 2023 16:38:36 -0500 Subject: [PATCH] feat(shorebird_cli): add `shorebird flutter version use` (#1070) --- .../versions/flutter_versions_command.dart | 1 + .../flutter_versions_use_command.dart | 74 +++++++++ .../commands/flutter/versions/versions.dart | 1 + .../flutter_versions_use_command_test.dart | 150 ++++++++++++++++++ 4 files changed, 226 insertions(+) create mode 100644 packages/shorebird_cli/lib/src/commands/flutter/versions/flutter_versions_use_command.dart create mode 100644 packages/shorebird_cli/test/src/commands/flutter/versions/flutter_versions_use_command_test.dart diff --git a/packages/shorebird_cli/lib/src/commands/flutter/versions/flutter_versions_command.dart b/packages/shorebird_cli/lib/src/commands/flutter/versions/flutter_versions_command.dart index f4a3361b..b8cdbb53 100644 --- a/packages/shorebird_cli/lib/src/commands/flutter/versions/flutter_versions_command.dart +++ b/packages/shorebird_cli/lib/src/commands/flutter/versions/flutter_versions_command.dart @@ -9,6 +9,7 @@ class FlutterVersionsCommand extends ShorebirdCommand { /// {@macro flutter_versions_command} FlutterVersionsCommand() { addSubcommand(FlutterVersionsListCommand()); + addSubcommand(FlutterVersionsUseCommand()); } @override diff --git a/packages/shorebird_cli/lib/src/commands/flutter/versions/flutter_versions_use_command.dart b/packages/shorebird_cli/lib/src/commands/flutter/versions/flutter_versions_use_command.dart new file mode 100644 index 00000000..dd143a46 --- /dev/null +++ b/packages/shorebird_cli/lib/src/commands/flutter/versions/flutter_versions_use_command.dart @@ -0,0 +1,74 @@ +import 'package:mason_logger/mason_logger.dart'; +import 'package:shorebird_cli/src/command.dart'; +import 'package:shorebird_cli/src/logger.dart'; +import 'package:shorebird_cli/src/shorebird_flutter.dart'; + +/// {@template flutter_versions_use_command} +/// `shorebird flutter versions use` +/// Use a different Flutter version. +/// {@endtemplate} +class FlutterVersionsUseCommand extends ShorebirdCommand { + /// {@macro flutter_versions_use_command} + FlutterVersionsUseCommand(); + + @override + String get description => 'Use a different Flutter version.'; + + @override + String get name => 'use'; + + @override + Future run() async { + if (results.rest.isEmpty) { + logger.err( + ''' +No version specified. +Usage: shorebird flutter versions use +Use `shorebird flutter versions list` to list available versions.''', + ); + return ExitCode.usage.code; + } + + if (results.rest.length > 1) { + logger.err(''' +Too many arguments. +Usage: shorebird flutter versions use '''); + return ExitCode.usage.code; + } + + final version = results.rest.first; + final fetchFlutterVersionsProgress = logger.progress( + 'Fetching Flutter versions', + ); + final List versions; + try { + versions = await shorebirdFlutter.getVersions(); + fetchFlutterVersionsProgress.complete(); + } catch (error) { + fetchFlutterVersionsProgress.fail('Failed to fetch Flutter versions.'); + logger.err('$error'); + return ExitCode.software.code; + } + + if (!versions.contains(version)) { + logger.err(''' +Version $version not found. +Use `shorebird flutter versions list` to list available versions.'''); + return ExitCode.software.code; + } + + final installRevisionProgress = logger.progress( + 'Installing Flutter $version', + ); + try { + await shorebirdFlutter.useVersion(version: version); + installRevisionProgress.complete(); + } catch (error) { + installRevisionProgress.fail('Failed to install Flutter $version.'); + logger.err('$error'); + return ExitCode.software.code; + } + + return ExitCode.success.code; + } +} diff --git a/packages/shorebird_cli/lib/src/commands/flutter/versions/versions.dart b/packages/shorebird_cli/lib/src/commands/flutter/versions/versions.dart index 962c6c02..e8bf0108 100644 --- a/packages/shorebird_cli/lib/src/commands/flutter/versions/versions.dart +++ b/packages/shorebird_cli/lib/src/commands/flutter/versions/versions.dart @@ -1,2 +1,3 @@ export 'flutter_versions_command.dart'; export 'flutter_versions_list_command.dart'; +export 'flutter_versions_use_command.dart'; diff --git a/packages/shorebird_cli/test/src/commands/flutter/versions/flutter_versions_use_command_test.dart b/packages/shorebird_cli/test/src/commands/flutter/versions/flutter_versions_use_command_test.dart new file mode 100644 index 00000000..3583f7b7 --- /dev/null +++ b/packages/shorebird_cli/test/src/commands/flutter/versions/flutter_versions_use_command_test.dart @@ -0,0 +1,150 @@ +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/commands/commands.dart'; +import 'package:shorebird_cli/src/logger.dart'; +import 'package:shorebird_cli/src/shorebird_flutter.dart'; +import 'package:test/test.dart'; + +class _MockArgResults extends Mock implements ArgResults {} + +class _MockLogger extends Mock implements Logger {} + +class _MockProgress extends Mock implements Progress {} + +class _MockShorebirdFlutter extends Mock implements ShorebirdFlutter {} + +void main() { + group(FlutterVersionsUseCommand, () { + const version = '1.2.3'; + + late ArgResults argResults; + late Progress progress; + late Logger logger; + late ShorebirdFlutter shorebirdFlutter; + late FlutterVersionsUseCommand command; + + R runWithOverrides(R Function() body) { + return runScoped( + body, + values: { + loggerRef.overrideWith(() => logger), + shorebirdFlutterRef.overrideWith(() => shorebirdFlutter), + }, + ); + } + + setUp(() { + argResults = _MockArgResults(); + when(() => argResults.rest).thenReturn([version]); + progress = _MockProgress(); + logger = _MockLogger(); + shorebirdFlutter = _MockShorebirdFlutter(); + command = runWithOverrides(FlutterVersionsUseCommand.new) + ..testArgResults = argResults; + + when(() => logger.progress(any())).thenReturn(progress); + when( + () => shorebirdFlutter.getVersions(), + ).thenAnswer((_) async => [version]); + when( + () => shorebirdFlutter.useVersion(version: any(named: 'version')), + ).thenAnswer((_) async {}); + }); + + test('has correct name and description', () { + expect(command.name, equals('use')); + expect(command.description, equals('Use a different Flutter version.')); + }); + + test('exits with code 64 when no version is specified', () async { + when(() => argResults.rest).thenReturn([]); + await expectLater( + runWithOverrides(command.run), + completion(equals(ExitCode.usage.code)), + ); + verify( + () => logger.err(''' +No version specified. +Usage: shorebird flutter versions use +Use `shorebird flutter versions list` to list available versions.'''), + ).called(1); + }); + + test('exits with code 64 when too many args are provided', () async { + when(() => argResults.rest).thenReturn([version, 'foo']); + await expectLater( + runWithOverrides(command.run), + completion(equals(ExitCode.usage.code)), + ); + verify( + () => logger.err(''' +Too many arguments. +Usage: shorebird flutter versions use '''), + ).called(1); + }); + + test('exits with code 70 when unable to fetch versions', () async { + when(() => shorebirdFlutter.getVersions()).thenThrow('error'); + await expectLater( + runWithOverrides(command.run), + completion(equals(ExitCode.software.code)), + ); + verifyInOrder([ + () => logger.progress('Fetching Flutter versions'), + () => progress.fail('Failed to fetch Flutter versions.'), + () => logger.err('error'), + ]); + }); + + test('exits with code 70 when version is not found', () async { + when(() => shorebirdFlutter.getVersions()).thenAnswer( + (_) async => ['other-version'], + ); + await expectLater( + runWithOverrides(command.run), + completion(equals(ExitCode.software.code)), + ); + verifyInOrder([ + () => logger.progress('Fetching Flutter versions'), + () => progress.complete(), + () => logger.err(''' +Version $version not found. +Use `shorebird flutter versions list` to list available versions.'''), + ]); + }); + + test('exits with code 70 when unable to install version', () async { + when( + () => shorebirdFlutter.useVersion(version: any(named: 'version')), + ).thenThrow('error'); + await expectLater( + runWithOverrides(command.run), + completion(equals(ExitCode.software.code)), + ); + verifyInOrder([ + () => logger.progress('Fetching Flutter versions'), + () => progress.complete(), + () => logger.progress('Installing Flutter $version'), + () => progress.fail('Failed to install Flutter $version.'), + () => logger.err('error'), + ]); + }); + + test('exits with code 0 when install succeeds', () async { + await expectLater( + runWithOverrides(command.run), + completion(equals(ExitCode.success.code)), + ); + verifyInOrder([ + () => logger.progress('Fetching Flutter versions'), + () => shorebirdFlutter.getVersions(), + () => progress.complete(), + () => logger.progress('Installing Flutter $version'), + () => shorebirdFlutter.useVersion(version: version), + () => progress.complete(), + ]); + }); + }); +}