feat(shorebird_cli): shorebird patch android supports dynamic Flutter revision (#1023)
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:crypto/crypto.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:mason_logger/mason_logger.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:scoped/scoped.dart';
|
||||
import 'package:shorebird_cli/src/archive_analysis/archive_analysis.dart';
|
||||
import 'package:shorebird_cli/src/archive_analysis/archive_differ.dart';
|
||||
import 'package:shorebird_cli/src/cache.dart';
|
||||
@@ -15,6 +17,7 @@ import 'package:shorebird_cli/src/formatters/formatters.dart';
|
||||
import 'package:shorebird_cli/src/logger.dart';
|
||||
import 'package:shorebird_cli/src/shorebird_build_mixin.dart';
|
||||
import 'package:shorebird_cli/src/shorebird_env.dart';
|
||||
import 'package:shorebird_cli/src/shorebird_flutter_manager.dart';
|
||||
import 'package:shorebird_cli/src/shorebird_release_version_mixin.dart';
|
||||
import 'package:shorebird_cli/src/shorebird_validator.dart';
|
||||
import 'package:shorebird_code_push_client/shorebird_code_push_client.dart';
|
||||
@@ -99,45 +102,22 @@ class PatchAndroidCommand extends ShorebirdCommand
|
||||
const channelName = 'stable';
|
||||
final flavor = results['flavor'] as String?;
|
||||
final target = results['target'] as String?;
|
||||
final buildProgress = logger.progress('Building patch');
|
||||
try {
|
||||
await buildAppBundle(flavor: flavor, target: target);
|
||||
buildProgress.complete();
|
||||
} on ProcessException catch (error) {
|
||||
buildProgress.fail('Failed to build: ${error.message}');
|
||||
return ExitCode.software.code;
|
||||
}
|
||||
|
||||
final shorebirdYaml = shorebirdEnv.getShorebirdYaml()!;
|
||||
final appId = shorebirdYaml.getAppId(flavor: flavor);
|
||||
final app = await codePushClientWrapper.getApp(appId: appId);
|
||||
final releases = await codePushClientWrapper.getReleases(appId: appId);
|
||||
final releaseVersion = results['release-version'] as String? ??
|
||||
await promptForReleaseVersion(releases);
|
||||
|
||||
final bundlePath = flavor != null
|
||||
? './build/app/outputs/bundle/${flavor}Release/app-$flavor-release.aab'
|
||||
: './build/app/outputs/bundle/release/app-release.aab';
|
||||
|
||||
final releaseVersionArg = results['release-version'] as String?;
|
||||
final String releaseVersion;
|
||||
|
||||
final detectReleaseVersionProgress = logger.progress(
|
||||
'Detecting release version',
|
||||
final release = releases.firstWhereOrNull(
|
||||
(r) => r.version == releaseVersion,
|
||||
);
|
||||
try {
|
||||
releaseVersion = releaseVersionArg ??
|
||||
await extractReleaseVersionFromAppBundle(bundlePath);
|
||||
detectReleaseVersionProgress.complete(
|
||||
'Detected release version $releaseVersion',
|
||||
);
|
||||
} catch (error) {
|
||||
detectReleaseVersionProgress.fail('$error');
|
||||
return ExitCode.software.code;
|
||||
|
||||
if (releaseVersion == null || release == null) {
|
||||
logger.info('No releases found');
|
||||
return ExitCode.success.code;
|
||||
}
|
||||
|
||||
final release = await codePushClientWrapper.getRelease(
|
||||
appId: appId,
|
||||
releaseVersion: releaseVersion,
|
||||
);
|
||||
|
||||
if (release.platformStatuses[ReleasePlatform.android] ==
|
||||
ReleaseStatus.draft) {
|
||||
logger.err('''
|
||||
@@ -147,33 +127,6 @@ Please re-run the release command for this version or create a new release.''');
|
||||
return ExitCode.software.code;
|
||||
}
|
||||
|
||||
final shorebirdFlutterRevision = shorebirdEnv.flutterRevision;
|
||||
if (release.flutterRevision != shorebirdFlutterRevision) {
|
||||
logger
|
||||
..err('''
|
||||
Flutter revision mismatch.
|
||||
|
||||
The release you are trying to patch was built with a different version of Flutter.
|
||||
|
||||
Release Flutter Revision: ${release.flutterRevision}
|
||||
Current Flutter Revision: $shorebirdFlutterRevision
|
||||
''')
|
||||
..info(
|
||||
'''
|
||||
Either create a new release using:
|
||||
${lightCyan.wrap('shorebird release')}
|
||||
|
||||
Or downgrade your Flutter version and try again using:
|
||||
${lightCyan.wrap('cd ${shorebirdEnv.flutterDirectory.path}')}
|
||||
${lightCyan.wrap('git checkout ${release.flutterRevision}')}
|
||||
|
||||
Shorebird plans to support this automatically, let us know if it's important to you:
|
||||
https://github.com/shorebirdtech/shorebird/issues/472
|
||||
''',
|
||||
);
|
||||
return ExitCode.software.code;
|
||||
}
|
||||
|
||||
final releaseArtifacts = await codePushClientWrapper.getReleaseArtifacts(
|
||||
appId: app.appId,
|
||||
releaseId: release.id,
|
||||
@@ -211,12 +164,49 @@ https://github.com/shorebirdtech/shorebird/issues/472
|
||||
Uri.parse(releaseAabArtifact.url),
|
||||
httpClient: _httpClient,
|
||||
);
|
||||
downloadReleaseArtifactProgress.complete();
|
||||
} catch (error) {
|
||||
downloadReleaseArtifactProgress.fail('$error');
|
||||
return ExitCode.software.code;
|
||||
}
|
||||
|
||||
downloadReleaseArtifactProgress.complete();
|
||||
final shorebirdFlutterRevision = shorebirdEnv.flutterRevision;
|
||||
if (release.flutterRevision != shorebirdFlutterRevision) {
|
||||
final installFlutterRevisionProgress = logger.progress(
|
||||
'Switching to Flutter revision ${release.flutterRevision}',
|
||||
);
|
||||
try {
|
||||
await shorebirdFlutterManager.installRevision(
|
||||
revision: release.flutterRevision,
|
||||
);
|
||||
installFlutterRevisionProgress.complete();
|
||||
} catch (error) {
|
||||
installFlutterRevisionProgress.fail('$error');
|
||||
return ExitCode.software.code;
|
||||
}
|
||||
}
|
||||
|
||||
final buildProgress = logger.progress('Building patch');
|
||||
try {
|
||||
await runScoped(
|
||||
() => buildAppBundle(flavor: flavor, target: target),
|
||||
values: {
|
||||
shorebirdEnvRef.overrideWith(
|
||||
() => ShorebirdEnv(
|
||||
flutterRevisionOverride: release.flutterRevision,
|
||||
),
|
||||
)
|
||||
},
|
||||
);
|
||||
buildProgress.complete();
|
||||
} on ProcessException catch (error) {
|
||||
buildProgress.fail('Failed to build: ${error.message}');
|
||||
return ExitCode.software.code;
|
||||
}
|
||||
|
||||
final bundlePath = flavor != null
|
||||
? './build/app/outputs/bundle/${flavor}Release/app-$flavor-release.aab'
|
||||
: './build/app/outputs/bundle/release/app-release.aab';
|
||||
|
||||
FileSetDiff contentDiffs;
|
||||
try {
|
||||
@@ -358,6 +348,16 @@ ${summary.join('\n')}
|
||||
return ExitCode.success.code;
|
||||
}
|
||||
|
||||
Future<String?> promptForReleaseVersion(List<Release> releases) async {
|
||||
if (releases.isEmpty) return null;
|
||||
final release = logger.chooseOne(
|
||||
'Which release would you like to patch?',
|
||||
choices: releases,
|
||||
display: (release) => release.version,
|
||||
);
|
||||
return release.version;
|
||||
}
|
||||
|
||||
Future<String> downloadReleaseArtifact(
|
||||
Uri uri, {
|
||||
required http.Client httpClient,
|
||||
|
||||
@@ -22,6 +22,7 @@ import 'package:shorebird_cli/src/platform.dart';
|
||||
import 'package:shorebird_cli/src/process.dart';
|
||||
import 'package:shorebird_cli/src/shorebird_build_mixin.dart';
|
||||
import 'package:shorebird_cli/src/shorebird_env.dart';
|
||||
import 'package:shorebird_cli/src/shorebird_flutter_manager.dart';
|
||||
import 'package:shorebird_cli/src/shorebird_validator.dart';
|
||||
import 'package:shorebird_cli/src/validators/validators.dart';
|
||||
import 'package:shorebird_code_push_client/shorebird_code_push_client.dart';
|
||||
@@ -54,6 +55,8 @@ class _MockProgress extends Mock implements Progress {}
|
||||
|
||||
class _MockProcessResult extends Mock implements ShorebirdProcessResult {}
|
||||
|
||||
class _MockProcessWrapper extends Mock implements ProcessWrapper {}
|
||||
|
||||
class _MockHttpClient extends Mock implements http.Client {}
|
||||
|
||||
class _MockShorebirdEnv extends Mock implements ShorebirdEnv {}
|
||||
@@ -61,6 +64,9 @@ class _MockShorebirdEnv extends Mock implements ShorebirdEnv {}
|
||||
class _MockShorebirdFlutterValidator extends Mock
|
||||
implements ShorebirdFlutterValidator {}
|
||||
|
||||
class _MockShorebirdFlutterManager extends Mock
|
||||
implements ShorebirdFlutterManager {}
|
||||
|
||||
class _MockShorebirdProcess extends Mock implements ShorebirdProcess {}
|
||||
|
||||
class _MockShorebirdValidator extends Mock implements ShorebirdValidator {}
|
||||
@@ -133,6 +139,7 @@ flutter:
|
||||
late ShorebirdProcessResult patchProcessResult;
|
||||
late http.Client httpClient;
|
||||
late Cache cache;
|
||||
late ShorebirdFlutterManager shorebirdFlutterManager;
|
||||
late ShorebirdFlutterValidator flutterValidator;
|
||||
late ShorebirdProcess shorebirdProcess;
|
||||
late ShorebirdValidator shorebirdValidator;
|
||||
@@ -153,6 +160,9 @@ flutter:
|
||||
shorebirdEnvRef.overrideWith(() => shorebirdEnv),
|
||||
platformRef.overrideWith(() => platform),
|
||||
processRef.overrideWith(() => shorebirdProcess),
|
||||
shorebirdFlutterManagerRef.overrideWith(
|
||||
() => shorebirdFlutterManager,
|
||||
),
|
||||
shorebirdValidatorRef.overrideWith(() => shorebirdValidator),
|
||||
},
|
||||
);
|
||||
@@ -217,6 +227,7 @@ flutter:
|
||||
cache = _MockCache();
|
||||
shorebirdEnv = _MockShorebirdEnv();
|
||||
shorebirdProcess = _MockShorebirdProcess();
|
||||
shorebirdFlutterManager = _MockShorebirdFlutterManager();
|
||||
shorebirdValidator = _MockShorebirdValidator();
|
||||
command = runWithOverrides(
|
||||
() => PatchAndroidCommand(
|
||||
@@ -272,6 +283,7 @@ flutter:
|
||||
when(() => argResults['channel']).thenReturn(channelName);
|
||||
when(() => argResults['dry-run']).thenReturn(false);
|
||||
when(() => argResults['force']).thenReturn(false);
|
||||
when(() => argResults['release-version']).thenReturn(release.version);
|
||||
when(() => auth.isAuthenticated).thenReturn(true);
|
||||
when(() => auth.client).thenReturn(httpClient);
|
||||
when(() => logger.progress(any())).thenReturn(progress);
|
||||
@@ -292,11 +304,8 @@ flutter:
|
||||
),
|
||||
).thenAnswer((_) async => app);
|
||||
when(
|
||||
() => codePushClientWrapper.getRelease(
|
||||
appId: any(named: 'appId'),
|
||||
releaseVersion: any(named: 'releaseVersion'),
|
||||
),
|
||||
).thenAnswer((_) async => release);
|
||||
() => codePushClientWrapper.getReleases(appId: any(named: 'appId')),
|
||||
).thenAnswer((_) async => [release]);
|
||||
when(
|
||||
() => codePushClientWrapper.getReleaseArtifacts(
|
||||
appId: any(named: 'appId'),
|
||||
@@ -341,6 +350,11 @@ flutter:
|
||||
when(() => bundletool.getVersionCode(any())).thenAnswer(
|
||||
(_) async => versionCode,
|
||||
);
|
||||
when(
|
||||
() => shorebirdFlutterManager.installRevision(
|
||||
revision: any(named: 'revision'),
|
||||
),
|
||||
).thenAnswer((_) async {});
|
||||
when(
|
||||
() => shorebirdValidator.validatePreconditions(
|
||||
checkUserIsAuthenticated: any(named: 'checkUserIsAuthenticated'),
|
||||
@@ -376,19 +390,6 @@ flutter:
|
||||
).called(1);
|
||||
});
|
||||
|
||||
test('exits with code 70 when building fails', () async {
|
||||
when(() => flutterBuildProcessResult.exitCode).thenReturn(1);
|
||||
when(() => flutterBuildProcessResult.stderr).thenReturn('oops');
|
||||
|
||||
final tempDir = setUpTempDir();
|
||||
final exitCode = await IOOverrides.runZoned(
|
||||
() => runWithOverrides(command.run),
|
||||
getCurrentDirectory: () => tempDir,
|
||||
);
|
||||
|
||||
expect(exitCode, equals(ExitCode.software.code));
|
||||
});
|
||||
|
||||
test(
|
||||
'exits with usage code when '
|
||||
'both --dry-run and --force are specified', () async {
|
||||
@@ -402,6 +403,232 @@ flutter:
|
||||
expect(exitCode, equals(ExitCode.usage.code));
|
||||
});
|
||||
|
||||
test('prompts for release when release-version is not specified', () async {
|
||||
when(() => argResults['release-version']).thenReturn(null);
|
||||
when(
|
||||
() => logger.chooseOne<Release>(
|
||||
any(),
|
||||
choices: any(named: 'choices'),
|
||||
display: any(named: 'display'),
|
||||
),
|
||||
).thenReturn(release);
|
||||
try {
|
||||
await runWithOverrides(command.run);
|
||||
} catch (_) {}
|
||||
await untilCalled(
|
||||
() => logger.chooseOne<Release>(
|
||||
any(),
|
||||
choices: any(named: 'choices'),
|
||||
display: any(named: 'display'),
|
||||
),
|
||||
);
|
||||
final display = verify(
|
||||
() => logger.chooseOne<Release>(
|
||||
any(),
|
||||
choices: any(named: 'choices'),
|
||||
display: captureAny(named: 'display'),
|
||||
),
|
||||
).captured.single as String Function(Release);
|
||||
expect(display(release), equals(release.version));
|
||||
});
|
||||
|
||||
test('exits early when no releases are found', () async {
|
||||
when(() => argResults['release-version']).thenReturn(null);
|
||||
when(
|
||||
() => codePushClientWrapper.getReleases(appId: any(named: 'appId')),
|
||||
).thenAnswer((_) async => []);
|
||||
try {
|
||||
await runWithOverrides(command.run);
|
||||
} catch (_) {}
|
||||
verifyNever(
|
||||
() => logger.chooseOne<Release>(
|
||||
any(),
|
||||
choices: any(named: 'choices'),
|
||||
display: captureAny(named: 'display'),
|
||||
),
|
||||
);
|
||||
verify(() => codePushClientWrapper.getReleases(appId: appId)).called(1);
|
||||
verify(() => logger.info('No releases found')).called(1);
|
||||
});
|
||||
|
||||
test(
|
||||
'''exits with code 70 if release is in draft state for the android platform''',
|
||||
() async {
|
||||
when(
|
||||
() => codePushClientWrapper.getReleases(
|
||||
appId: any(named: 'appId'),
|
||||
),
|
||||
).thenAnswer(
|
||||
(_) async => const [
|
||||
Release(
|
||||
id: 0,
|
||||
appId: appId,
|
||||
version: version,
|
||||
flutterRevision: flutterRevision,
|
||||
displayName: '1.2.3+1',
|
||||
platformStatuses: {releasePlatform: ReleaseStatus.draft},
|
||||
),
|
||||
],
|
||||
);
|
||||
final tempDir = setUpTempDir();
|
||||
setUpTempArtifacts(tempDir);
|
||||
final exitCode = await IOOverrides.runZoned(
|
||||
() => runWithOverrides(command.run),
|
||||
getCurrentDirectory: () => tempDir,
|
||||
);
|
||||
expect(exitCode, ExitCode.software.code);
|
||||
verify(
|
||||
() => logger.err('''
|
||||
Release 1.2.3+1 is in an incomplete state. It's possible that the original release was terminated or failed to complete.
|
||||
|
||||
Please re-run the release command for this version or create a new release.'''),
|
||||
).called(1);
|
||||
});
|
||||
|
||||
test('proceeds if release is in draft state for non-android platform',
|
||||
() async {
|
||||
when(
|
||||
() => codePushClientWrapper.getReleases(
|
||||
appId: any(named: 'appId'),
|
||||
),
|
||||
).thenAnswer(
|
||||
(_) async => const [
|
||||
Release(
|
||||
id: 0,
|
||||
appId: appId,
|
||||
version: version,
|
||||
flutterRevision: flutterRevision,
|
||||
displayName: '1.2.3+1',
|
||||
platformStatuses: {ReleasePlatform.ios: ReleaseStatus.draft},
|
||||
)
|
||||
],
|
||||
);
|
||||
final tempDir = setUpTempDir();
|
||||
setUpTempArtifacts(tempDir);
|
||||
final exitCode = await IOOverrides.runZoned(
|
||||
() => runWithOverrides(command.run),
|
||||
getCurrentDirectory: () => tempDir,
|
||||
);
|
||||
expect(exitCode, ExitCode.success.code);
|
||||
});
|
||||
|
||||
test(
|
||||
'installs correct flutter revision '
|
||||
'when release flutter revision differs', () async {
|
||||
const otherRevision = 'other-revision';
|
||||
when(() => shorebirdEnv.flutterRevision).thenReturn(otherRevision);
|
||||
final tempDir = setUpTempDir();
|
||||
setUpTempArtifacts(tempDir);
|
||||
|
||||
final exitCode = await IOOverrides.runZoned(
|
||||
() => runWithOverrides(command.run),
|
||||
getCurrentDirectory: () => tempDir,
|
||||
);
|
||||
expect(exitCode, equals(ExitCode.success.code));
|
||||
verify(
|
||||
() => logger.progress(
|
||||
'Switching to Flutter revision ${release.flutterRevision}',
|
||||
),
|
||||
).called(1);
|
||||
verify(
|
||||
() => shorebirdFlutterManager.installRevision(
|
||||
revision: release.flutterRevision,
|
||||
),
|
||||
).called(1);
|
||||
});
|
||||
|
||||
test(
|
||||
'builds using correct flutter revision '
|
||||
'when release flutter revision differs', () async {
|
||||
when(
|
||||
() => platform.script,
|
||||
).thenReturn(Uri.parse('file:///bin/cache/shorebird.snapshot'));
|
||||
const otherRevision = 'other-revision';
|
||||
when(() => shorebirdEnv.flutterRevision).thenReturn(otherRevision);
|
||||
final processWrapper = _MockProcessWrapper();
|
||||
when(
|
||||
() => processWrapper.run(
|
||||
any(),
|
||||
any(),
|
||||
runInShell: any(named: 'runInShell'),
|
||||
workingDirectory: any(named: 'workingDirectory'),
|
||||
environment: any(named: 'environment'),
|
||||
),
|
||||
).thenAnswer((_) async => flutterBuildProcessResult);
|
||||
final tempDir = setUpTempDir();
|
||||
setUpTempArtifacts(tempDir);
|
||||
await IOOverrides.runZoned(
|
||||
() => runWithOverrides(
|
||||
() => runScoped(
|
||||
() => command.run(),
|
||||
values: {
|
||||
processRef.overrideWith(
|
||||
() => ShorebirdProcess(
|
||||
logger: logger,
|
||||
processWrapper: processWrapper,
|
||||
),
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
getCurrentDirectory: () => tempDir,
|
||||
);
|
||||
verify(
|
||||
() => processWrapper.run(
|
||||
'/bin/cache/flutter/${release.flutterRevision}/bin/flutter',
|
||||
any(),
|
||||
runInShell: true,
|
||||
workingDirectory: any(named: 'workingDirectory'),
|
||||
environment: any(named: 'environment'),
|
||||
),
|
||||
).called(1);
|
||||
});
|
||||
|
||||
test(
|
||||
'exits with code 70 when '
|
||||
'unable to install correct flutter revision', () async {
|
||||
final exception = Exception('oops');
|
||||
const otherRevision = 'other-revision';
|
||||
when(() => shorebirdEnv.flutterRevision).thenReturn(otherRevision);
|
||||
when(
|
||||
() => shorebirdFlutterManager.installRevision(
|
||||
revision: any(named: 'revision'),
|
||||
),
|
||||
).thenThrow(exception);
|
||||
final tempDir = setUpTempDir();
|
||||
setUpTempArtifacts(tempDir);
|
||||
|
||||
final exitCode = await IOOverrides.runZoned(
|
||||
() => runWithOverrides(command.run),
|
||||
getCurrentDirectory: () => tempDir,
|
||||
);
|
||||
expect(exitCode, equals(ExitCode.software.code));
|
||||
verify(
|
||||
() => logger.progress(
|
||||
'Switching to Flutter revision ${release.flutterRevision}',
|
||||
),
|
||||
).called(1);
|
||||
verify(
|
||||
() => shorebirdFlutterManager.installRevision(
|
||||
revision: release.flutterRevision,
|
||||
),
|
||||
).called(1);
|
||||
verify(() => progress.fail('$exception')).called(1);
|
||||
});
|
||||
|
||||
test('exits with code 70 when building fails', () async {
|
||||
when(() => flutterBuildProcessResult.exitCode).thenReturn(1);
|
||||
when(() => flutterBuildProcessResult.stderr).thenReturn('oops');
|
||||
|
||||
final tempDir = setUpTempDir();
|
||||
final exitCode = await IOOverrides.runZoned(
|
||||
() => runWithOverrides(command.run),
|
||||
getCurrentDirectory: () => tempDir,
|
||||
);
|
||||
|
||||
expect(exitCode, equals(ExitCode.software.code));
|
||||
});
|
||||
|
||||
test('aborts when user opts out', () async {
|
||||
when(() => logger.confirm(any())).thenReturn(false);
|
||||
final tempDir = setUpTempDir();
|
||||
@@ -414,140 +641,6 @@ flutter:
|
||||
verify(() => logger.info('Aborting.')).called(1);
|
||||
});
|
||||
|
||||
test(
|
||||
'''exits with code 70 if release is in draft state for the android platform''',
|
||||
() async {
|
||||
when(
|
||||
() => codePushClientWrapper.getRelease(
|
||||
appId: any(named: 'appId'),
|
||||
releaseVersion: any(named: 'releaseVersion'),
|
||||
),
|
||||
).thenAnswer(
|
||||
(_) async => const Release(
|
||||
id: 0,
|
||||
appId: appId,
|
||||
version: version,
|
||||
flutterRevision: flutterRevision,
|
||||
displayName: '1.2.3+1',
|
||||
platformStatuses: {releasePlatform: ReleaseStatus.draft},
|
||||
),
|
||||
);
|
||||
final tempDir = setUpTempDir();
|
||||
setUpTempArtifacts(tempDir);
|
||||
final exitCode = await IOOverrides.runZoned(
|
||||
() => runWithOverrides(command.run),
|
||||
getCurrentDirectory: () => tempDir,
|
||||
);
|
||||
expect(exitCode, ExitCode.software.code);
|
||||
verify(
|
||||
() => logger.err('''
|
||||
Release 1.2.3+1 is in an incomplete state. It's possible that the original release was terminated or failed to complete.
|
||||
|
||||
Please re-run the release command for this version or create a new release.'''),
|
||||
).called(1);
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
'proceeds if release is in draft state for non-android platform',
|
||||
() async {
|
||||
when(
|
||||
() => codePushClientWrapper.getRelease(
|
||||
appId: any(named: 'appId'),
|
||||
releaseVersion: any(named: 'releaseVersion'),
|
||||
),
|
||||
).thenAnswer(
|
||||
(_) async => const Release(
|
||||
id: 0,
|
||||
appId: appId,
|
||||
version: version,
|
||||
flutterRevision: flutterRevision,
|
||||
displayName: '1.2.3+1',
|
||||
platformStatuses: {ReleasePlatform.ios: ReleaseStatus.draft},
|
||||
),
|
||||
);
|
||||
final tempDir = setUpTempDir();
|
||||
setUpTempArtifacts(tempDir);
|
||||
final exitCode = await IOOverrides.runZoned(
|
||||
() => runWithOverrides(command.run),
|
||||
getCurrentDirectory: () => tempDir,
|
||||
);
|
||||
expect(exitCode, ExitCode.success.code);
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
'errors when shorebird flutter revision '
|
||||
'does not match release revision', () async {
|
||||
const otherRevision = 'other-revision';
|
||||
when(() => shorebirdEnv.flutterRevision).thenReturn(otherRevision);
|
||||
final tempDir = setUpTempDir();
|
||||
setUpTempArtifacts(tempDir);
|
||||
|
||||
final exitCode = await IOOverrides.runZoned(
|
||||
() => runWithOverrides(command.run),
|
||||
getCurrentDirectory: () => tempDir,
|
||||
);
|
||||
|
||||
expect(exitCode, ExitCode.software.code);
|
||||
verify(
|
||||
() => logger.err('''
|
||||
Either create a new release using:
|
||||
${lightCyan.wrap('shorebird release aar')}
|
||||
|
||||
Or downgrade your Flutter version and try again using:
|
||||
${lightCyan.wrap('cd ${shorebirdEnv.flutterDirectory.path}')}
|
||||
${lightCyan.wrap('git checkout ${release.flutterRevision}')}
|
||||
|
||||
Shorebird plans to support this automatically, let us know if it's important to you:
|
||||
https://github.com/shorebirdtech/shorebird/issues/472
|
||||
'''),
|
||||
).called(1);
|
||||
});
|
||||
|
||||
test('errors when detecting release version name fails', () async {
|
||||
final exception = Exception(
|
||||
'Failed to extract version name from app bundle: oops',
|
||||
);
|
||||
when(() => bundletool.getVersionName(any())).thenThrow(exception);
|
||||
final tempDir = setUpTempDir();
|
||||
setUpTempArtifacts(tempDir);
|
||||
final exitCode = await IOOverrides.runZoned(
|
||||
() => runWithOverrides(command.run),
|
||||
getCurrentDirectory: () => tempDir,
|
||||
);
|
||||
expect(exitCode, ExitCode.software.code);
|
||||
verify(() => progress.fail('$exception')).called(1);
|
||||
});
|
||||
|
||||
test('errors when detecting release version code fails', () async {
|
||||
final exception = Exception(
|
||||
'Failed to extract version code from app bundle: oops',
|
||||
);
|
||||
when(() => bundletool.getVersionCode(any())).thenThrow(exception);
|
||||
final tempDir = setUpTempDir();
|
||||
setUpTempArtifacts(tempDir);
|
||||
final exitCode = await IOOverrides.runZoned(
|
||||
() => runWithOverrides(command.run),
|
||||
getCurrentDirectory: () => tempDir,
|
||||
);
|
||||
expect(exitCode, ExitCode.software.code);
|
||||
verify(() => progress.fail('$exception')).called(1);
|
||||
});
|
||||
|
||||
test('prints release version when detected', () async {
|
||||
final tempDir = setUpTempDir();
|
||||
setUpTempArtifacts(tempDir);
|
||||
final exitCode = await IOOverrides.runZoned(
|
||||
() => runWithOverrides(command.run),
|
||||
getCurrentDirectory: () => tempDir,
|
||||
);
|
||||
|
||||
expect(exitCode, equals(ExitCode.success.code));
|
||||
verify(() => progress.complete('Detected release version 1.2.3+1'))
|
||||
.called(1);
|
||||
});
|
||||
|
||||
test('throws error when release artifact does not exist.', () async {
|
||||
when(() => httpClient.send(any())).thenAnswer(
|
||||
(_) async => http.StreamedResponse(
|
||||
|
||||
Reference in New Issue
Block a user