From 3cf119837130105f9186bcf7b8c8fee8eb2d16f3 Mon Sep 17 00:00:00 2001 From: Felix Angelov Date: Fri, 12 May 2023 11:40:43 -0700 Subject: [PATCH] feat(shorebird_cli): `shorebird release` includes `flutter_revision` (#478) --- .../lib/src/commands/release_command.dart | 13 +++++ .../src/commands/release_command_test.dart | 58 ++++++++++++++++++- .../example/main.dart | 2 + .../lib/src/code_push_client.dart | 2 + .../test/src/code_push_client_test.dart | 8 +++ .../create_release_request.dart | 5 ++ .../create_release_request.g.dart | 9 ++- 7 files changed, 95 insertions(+), 2 deletions(-) diff --git a/packages/shorebird_cli/lib/src/commands/release_command.dart b/packages/shorebird_cli/lib/src/commands/release_command.dart index 19326ee2..d8863a67 100644 --- a/packages/shorebird_cli/lib/src/commands/release_command.dart +++ b/packages/shorebird_cli/lib/src/commands/release_command.dart @@ -191,11 +191,24 @@ ${summary.join('\n')} var release = releases.firstWhereOrNull((r) => r.version == releaseVersion); if (release == null) { + final flutterRevisionProgress = logger.progress( + 'Fetching Flutter revision', + ); + final String shorebirdFlutterRevision; + try { + shorebirdFlutterRevision = await getShorebirdFlutterRevision(); + flutterRevisionProgress.complete(); + } catch (error) { + flutterRevisionProgress.fail('$error'); + return ExitCode.software.code; + } + final createReleaseProgress = logger.progress('Creating release'); try { release = await codePushClient.createRelease( appId: app.id, version: releaseVersion, + flutterRevision: shorebirdFlutterRevision, ); createReleaseProgress.complete(); } catch (error) { 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 eee6eb12..a42e57f1 100644 --- a/packages/shorebird_cli/test/src/commands/release_command_test.dart +++ b/packages/shorebird_cli/test/src/commands/release_command_test.dart @@ -10,6 +10,7 @@ import 'package:shorebird_cli/src/auth/auth.dart'; import 'package:shorebird_cli/src/cache.dart'; import 'package:shorebird_cli/src/commands/commands.dart'; import 'package:shorebird_cli/src/shorebird_build_mixin.dart'; +import 'package:shorebird_cli/src/shorebird_environment.dart'; import 'package:shorebird_cli/src/shorebird_process.dart'; import 'package:shorebird_cli/src/validators/validators.dart'; import 'package:shorebird_code_push_client/shorebird_code_push_client.dart'; @@ -41,6 +42,7 @@ class _MockShorebirdProcess extends Mock implements ShorebirdProcess {} void main() { group(ReleaseCommand, () { const appId = 'test-app-id'; + const flutterRevision = '83305b5088e6fe327fb3334a73ff190828d85713'; const versionName = '1.2.3'; const versionCode = '1'; const version = '$versionName+$versionCode'; @@ -52,7 +54,7 @@ void main() { id: 0, appId: appId, version: version, - flutterRevision: '83305b5088e6fe327fb3334a73ff190828d85713', + flutterRevision: flutterRevision, displayName: '1.2.3+1', ); const releaseArtifact = ReleaseArtifact( @@ -77,11 +79,14 @@ flutter: late ArgResults argResults; late http.Client httpClient; + late Directory shorebirdRoot; + late Platform environmentPlatform; late Auth auth; late Cache cache; late Progress progress; late Logger logger; late ProcessResult flutterBuildProcessResult; + late ProcessResult flutterRevisionProcessResult; late ProcessResult releaseVersionNameProcessResult; late ProcessResult releaseVersionCodeProcessResult; late CodePushClient codePushClient; @@ -123,11 +128,14 @@ flutter: setUp(() { argResults = _MockArgResults(); httpClient = _MockHttpClient(); + environmentPlatform = _MockPlatform(); + shorebirdRoot = Directory.systemTemp.createTempSync(); auth = _MockAuth(); cache = _MockCache(); progress = _MockProgress(); logger = _MockLogger(); flutterBuildProcessResult = _MockProcessResult(); + flutterRevisionProcessResult = _MockProcessResult(); releaseVersionNameProcessResult = _MockProcessResult(); releaseVersionCodeProcessResult = _MockProcessResult(); codePushClient = _MockCodePushClient(); @@ -152,6 +160,17 @@ flutter: registerFallbackValue(shorebirdProcess); + ShorebirdEnvironment.platform = environmentPlatform; + when(() => environmentPlatform.script).thenReturn( + Uri.file( + p.join( + shorebirdRoot.path, + 'bin', + 'cache', + 'shorebird.snapshot', + ), + ), + ); when( () => shorebirdProcess.run( 'flutter', @@ -159,6 +178,14 @@ flutter: runInShell: any(named: 'runInShell'), ), ).thenAnswer((_) async => flutterBuildProcessResult); + when( + () => shorebirdProcess.run( + 'git', + any(), + runInShell: any(named: 'runInShell'), + workingDirectory: any(named: 'workingDirectory'), + ), + ).thenAnswer((_) async => flutterRevisionProcessResult); when( () => shorebirdProcess.run( 'java', @@ -189,12 +216,18 @@ flutter: when( () => flutterBuildProcessResult.exitCode, ).thenReturn(ExitCode.success.code); + when( + () => flutterRevisionProcessResult.exitCode, + ).thenReturn(ExitCode.success.code); when( () => releaseVersionNameProcessResult.exitCode, ).thenReturn(ExitCode.success.code); when( () => releaseVersionCodeProcessResult.exitCode, ).thenReturn(ExitCode.success.code); + when( + () => flutterRevisionProcessResult.stdout, + ).thenReturn(flutterRevision); when( () => releaseVersionNameProcessResult.stdout, ).thenReturn(versionName); @@ -211,6 +244,7 @@ flutter: () => codePushClient.createRelease( appId: any(named: 'appId'), version: any(named: 'version'), + flutterRevision: any(named: 'flutterRevision'), ), ).thenAnswer((_) async => release); when( @@ -385,6 +419,27 @@ Did you forget to run "shorebird init"?''', expect(exitCode, ExitCode.software.code); }); + test('throws error when unable to detect flutter revision', () async { + const error = 'oops'; + when(() => flutterRevisionProcessResult.exitCode).thenReturn(1); + when(() => flutterRevisionProcessResult.stderr).thenReturn(error); + when( + () => codePushClient.getReleases(appId: any(named: 'appId')), + ).thenAnswer((_) async => []); + final tempDir = setUpTempDir(); + setUpTempArtifacts(tempDir); + final exitCode = await IOOverrides.runZoned( + command.run, + getCurrentDirectory: () => tempDir, + ); + expect(exitCode, ExitCode.software.code); + verify( + () => progress.fail( + 'Exception: Unable to determine flutter revision: $error', + ), + ).called(1); + }); + test('throws error when creating release fails.', () async { const error = 'something went wrong'; when( @@ -394,6 +449,7 @@ Did you forget to run "shorebird init"?''', () => codePushClient.createRelease( appId: any(named: 'appId'), version: any(named: 'version'), + flutterRevision: any(named: 'flutterRevision'), displayName: any(named: 'displayName'), ), ).thenThrow(error); diff --git a/packages/shorebird_code_push_client/example/main.dart b/packages/shorebird_code_push_client/example/main.dart index df4ba411..31a6d768 100644 --- a/packages/shorebird_code_push_client/example/main.dart +++ b/packages/shorebird_code_push_client/example/main.dart @@ -23,6 +23,8 @@ Future main() async { final release = await client.createRelease( appId: app.id, version: '', // e.g. '1.0.0' + flutterRevision: + '', // e.g. 83305b5088e6fe327fb3334a73ff190828d85713, displayName: '', // e.g. 'v1.0.0' ); diff --git a/packages/shorebird_code_push_client/lib/src/code_push_client.dart b/packages/shorebird_code_push_client/lib/src/code_push_client.dart index 83386118..fecf2cde 100644 --- a/packages/shorebird_code_push_client/lib/src/code_push_client.dart +++ b/packages/shorebird_code_push_client/lib/src/code_push_client.dart @@ -177,6 +177,7 @@ class CodePushClient { Future createRelease({ required String appId, required String version, + required String flutterRevision, String? displayName, }) async { final response = await _httpClient.post( @@ -184,6 +185,7 @@ class CodePushClient { body: json.encode({ 'app_id': appId, 'version': version, + 'flutter_revision': flutterRevision, if (displayName != null) 'display_name': displayName, }), ); diff --git a/packages/shorebird_code_push_client/test/src/code_push_client_test.dart b/packages/shorebird_code_push_client/test/src/code_push_client_test.dart index 1b1e2b37..40aa4ca9 100644 --- a/packages/shorebird_code_push_client/test/src/code_push_client_test.dart +++ b/packages/shorebird_code_push_client/test/src/code_push_client_test.dart @@ -682,6 +682,7 @@ void main() { codePushClient.createRelease( appId: appId, version: version, + flutterRevision: flutterRevision, displayName: displayName, ), throwsA( @@ -712,6 +713,7 @@ void main() { codePushClient.createRelease( appId: appId, version: version, + flutterRevision: flutterRevision, displayName: displayName, ), throwsA( @@ -751,6 +753,7 @@ void main() { codePushClient.createRelease( appId: appId, version: version, + flutterRevision: flutterRevision, displayName: displayName, ), completion( @@ -759,6 +762,11 @@ void main() { .having((r) => r.id, 'id', releaseId) .having((r) => r.appId, 'appId', appId) .having((r) => r.version, 'version', version) + .having( + (r) => r.flutterRevision, + 'flutterRevision', + flutterRevision, + ) .having((r) => r.displayName, 'displayName', displayName), ), ), diff --git a/packages/shorebird_code_push_protocol/lib/src/messages/create_release/create_release_request.dart b/packages/shorebird_code_push_protocol/lib/src/messages/create_release/create_release_request.dart index fc2bdce6..be648d46 100644 --- a/packages/shorebird_code_push_protocol/lib/src/messages/create_release/create_release_request.dart +++ b/packages/shorebird_code_push_protocol/lib/src/messages/create_release/create_release_request.dart @@ -11,6 +11,7 @@ class CreateReleaseRequest { const CreateReleaseRequest({ required this.appId, required this.version, + this.flutterRevision, this.displayName, }); @@ -27,6 +28,10 @@ class CreateReleaseRequest { /// The release version. final String version; + /// The Flutter revision used to create the release. + /// This is nullable for backward compatibility. + final String? flutterRevision; + /// The display name for the release. final String? displayName; } diff --git a/packages/shorebird_code_push_protocol/lib/src/messages/create_release/create_release_request.g.dart b/packages/shorebird_code_push_protocol/lib/src/messages/create_release/create_release_request.g.dart index c338f31e..70002e9c 100644 --- a/packages/shorebird_code_push_protocol/lib/src/messages/create_release/create_release_request.g.dart +++ b/packages/shorebird_code_push_protocol/lib/src/messages/create_release/create_release_request.g.dart @@ -17,11 +17,17 @@ CreateReleaseRequest _$CreateReleaseRequestFromJson( final val = CreateReleaseRequest( appId: $checkedConvert('app_id', (v) => v as String), version: $checkedConvert('version', (v) => v as String), + flutterRevision: + $checkedConvert('flutter_revision', (v) => v as String?), displayName: $checkedConvert('display_name', (v) => v as String?), ); return val; }, - fieldKeyMap: const {'appId': 'app_id', 'displayName': 'display_name'}, + fieldKeyMap: const { + 'appId': 'app_id', + 'flutterRevision': 'flutter_revision', + 'displayName': 'display_name' + }, ); Map _$CreateReleaseRequestToJson( @@ -29,5 +35,6 @@ Map _$CreateReleaseRequestToJson( { 'app_id': instance.appId, 'version': instance.version, + 'flutter_revision': instance.flutterRevision, 'display_name': instance.displayName, };