diff --git a/packages/shorebird_cli/lib/src/commands/release_command.dart b/packages/shorebird_cli/lib/src/commands/release_command.dart index fa81057e..0eeb9896 100644 --- a/packages/shorebird_cli/lib/src/commands/release_command.dart +++ b/packages/shorebird_cli/lib/src/commands/release_command.dart @@ -11,6 +11,7 @@ import 'package:shorebird_cli/src/shorebird_config_mixin.dart'; import 'package:shorebird_cli/src/shorebird_create_app_mixin.dart'; import 'package:shorebird_cli/src/shorebird_validation_mixin.dart'; import 'package:shorebird_code_push_client/shorebird_code_push_client.dart'; +import 'package:version/version.dart'; /// {@template release_command} /// `shorebird release` @@ -117,11 +118,27 @@ Did you forget to run "shorebird init"?''', if (releaseVersionArg == null) logger.info(''); - final releaseVersion = releaseVersionArg ?? - logger.prompt( - 'What is the version of this release?', - defaultValue: versionString, + String? releaseVersion; + var releaseVersionInput = releaseVersionArg; + while (releaseVersion == null) { + releaseVersionInput = releaseVersionInput ?? + logger.prompt( + 'What is the version of this release?', + defaultValue: versionString, + ); + try { + releaseVersion = Version.parse(releaseVersionInput).toString(); + } catch (error) { + final shouldContinue = logger.confirm( + '''"$releaseVersionInput" does not look like a version number. Proceed anyways?''', ); + if (shouldContinue) { + releaseVersion = releaseVersionInput; + } else { + releaseVersionInput = null; + } + } + } final platform = results['platform'] as String; final archNames = architectures.keys.map( @@ -154,7 +171,8 @@ ${styleBold.wrap(lightGreen.wrap('šŸš€ Ready to create a new release!'))} return ExitCode.software.code; } - var release = releases.firstWhereOrNull((r) => r.version == releaseVersion); + var release = releases + .firstWhereOrNull((r) => r.version == releaseVersion.toString()); if (release == null) { final createReleaseProgress = logger.progress('Creating release'); try { diff --git a/packages/shorebird_cli/test/src/commands/init_command_test.dart b/packages/shorebird_cli/test/src/commands/init_command_test.dart index 2a408339..dfc70763 100644 --- a/packages/shorebird_cli/test/src/commands/init_command_test.dart +++ b/packages/shorebird_cli/test/src/commands/init_command_test.dart @@ -292,7 +292,7 @@ flutter: File(p.join(tempDir.path, 'pubspec.yaml')).writeAsStringSync(''' $pubspecYamlContent flutter: - assets: + assets: - some/asset.txt '''); await IOOverrides.runZoned( @@ -304,7 +304,7 @@ flutter: equals(''' $pubspecYamlContent flutter: - assets: + assets: - some/asset.txt - shorebird.yaml '''), diff --git a/packages/shorebird_cli/test/src/commands/release_command_test.dart b/packages/shorebird_cli/test/src/commands/release_command_test.dart index 063d778b..9fd1ce9c 100644 --- a/packages/shorebird_cli/test/src/commands/release_command_test.dart +++ b/packages/shorebird_cli/test/src/commands/release_command_test.dart @@ -253,8 +253,11 @@ Did you forget to run "shorebird init"?''', test('aborts when user opts out', () async { when(() => logger.confirm(any())).thenReturn(false); when( - () => logger.prompt(any(), defaultValue: any(named: 'defaultValue')), - ).thenReturn(appDisplayName); + () => logger.prompt( + 'What is the version of this release?', + defaultValue: any(named: 'defaultValue'), + ), + ).thenAnswer((_) => '1.0.0'); final tempDir = setUpTempDir(); setUpTempArtifacts(tempDir); final exitCode = await IOOverrides.runZoned( @@ -265,6 +268,91 @@ Did you forget to run "shorebird init"?''', verify(() => logger.info('Aborting.')).called(1); }); + test( + 'prompts user for version until a valid version is provided', + () async { + final versionNumberResponses = [ + 'asdf', + 'y', + '1.2.3', + ]; + when( + () => logger.prompt( + 'What is the version of this release?', + defaultValue: any(named: 'defaultValue'), + ), + ).thenAnswer((_) => versionNumberResponses.removeAt(0)); + when( + () => logger.confirm( + any(that: contains('does not look like a version')), + ), + ).thenReturn(false); + + final tempDir = setUpTempDir(); + setUpTempArtifacts(tempDir); + final exitCode = await IOOverrides.runZoned( + command.run, + getCurrentDirectory: () => tempDir, + ); + + expect(exitCode, ExitCode.success.code); + verify( + () => logger.confirm( + any( + that: contains( + '"asdf" does not look like a version number', + ), + ), + ), + ).called(1); + verify( + () => logger.confirm( + any( + that: contains( + '"y" does not look like a version number', + ), + ), + ), + ).called(1); + }, + ); + + test( + 'prompts user for version until they choose to proceed anyways', + () async { + when( + () => logger.prompt( + 'What is the version of this release?', + defaultValue: any(named: 'defaultValue'), + ), + ).thenReturn('asdf'); + when( + () => logger.confirm( + any(that: contains('does not look like a version number')), + ), + ).thenReturn(true); + + final tempDir = setUpTempDir(); + setUpTempArtifacts(tempDir); + final exitCode = await IOOverrides.runZoned( + command.run, + getCurrentDirectory: () => tempDir, + ); + + expect(exitCode, ExitCode.success.code); + verify( + () => logger.confirm( + any( + that: contains( + '"asdf" does not look like a version number', + ), + ), + ), + ).called(1); + verify(() => logger.success('\nāœ… Published Release!')).called(1); + }, + ); + test('throws error when fetching releases fails.', () async { const error = 'something went wrong'; when(