feat(shorebird_cli): add channel support to patch and preview commands (#1340)
This commit is contained in:
@@ -49,6 +49,11 @@ class PatchAndroidCommand extends ShorebirdCommand
|
||||
'flavor',
|
||||
help: 'The product flavor to use when building the app.',
|
||||
)
|
||||
..addOption(
|
||||
'channel',
|
||||
help: 'The channel to publish the patch to.',
|
||||
defaultsTo: 'stable',
|
||||
)
|
||||
..addFlag(
|
||||
'force',
|
||||
abbr: 'f',
|
||||
@@ -97,7 +102,7 @@ class PatchAndroidCommand extends ShorebirdCommand
|
||||
await cache.updateAll();
|
||||
|
||||
const platform = ReleasePlatform.android;
|
||||
const channelName = 'stable';
|
||||
final channelName = results['channel'] as String;
|
||||
final flavor = results['flavor'] as String?;
|
||||
final target = results['target'] as String?;
|
||||
|
||||
|
||||
@@ -42,6 +42,11 @@ class PatchIosCommand extends ShorebirdCommand
|
||||
'flavor',
|
||||
help: 'The product flavor to use when building the app.',
|
||||
)
|
||||
..addOption(
|
||||
'channel',
|
||||
help: 'The channel to publish the patch to.',
|
||||
defaultsTo: 'stable',
|
||||
)
|
||||
..addFlag(
|
||||
'codesign',
|
||||
help: 'Codesign the application bundle.',
|
||||
@@ -95,7 +100,7 @@ class PatchIosCommand extends ShorebirdCommand
|
||||
}
|
||||
|
||||
const arch = 'aarch64';
|
||||
const channelName = 'stable';
|
||||
final channelName = results['channel'] as String;
|
||||
const releasePlatform = ReleasePlatform.ios;
|
||||
final flavor = results['flavor'] as String?;
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:isolate';
|
||||
|
||||
import 'package:archive/archive_io.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:mason_logger/mason_logger.dart';
|
||||
@@ -17,6 +19,7 @@ import 'package:shorebird_cli/src/logger.dart';
|
||||
import 'package:shorebird_cli/src/shorebird_validator.dart';
|
||||
import 'package:shorebird_cli/src/third_party/flutter_tools/lib/flutter_tools.dart';
|
||||
import 'package:shorebird_code_push_client/shorebird_code_push_client.dart';
|
||||
import 'package:yaml_edit/yaml_edit.dart';
|
||||
|
||||
/// {@template preview_command}
|
||||
/// `shorebird preview` command.
|
||||
@@ -49,6 +52,11 @@ class PreviewCommand extends ShorebirdCommand {
|
||||
ReleasePlatform.ios.name: 'iOS',
|
||||
},
|
||||
help: 'The platform of the release.',
|
||||
)
|
||||
..addOption(
|
||||
'channel',
|
||||
defaultsTo: 'stable',
|
||||
help: 'The channel to preview the release for.',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -103,17 +111,20 @@ class PreviewCommand extends ShorebirdCommand {
|
||||
);
|
||||
|
||||
final deviceId = results['device-id'] as String?;
|
||||
final channel = results['channel'] as String;
|
||||
|
||||
return switch (platform) {
|
||||
ReleasePlatform.android => installAndLaunchAndroid(
|
||||
appId: appId,
|
||||
release: release,
|
||||
deviceId: deviceId,
|
||||
channel: channel,
|
||||
),
|
||||
ReleasePlatform.ios => installAndLaunchIos(
|
||||
appId: appId,
|
||||
release: release,
|
||||
deviceId: deviceId,
|
||||
channel: channel,
|
||||
),
|
||||
};
|
||||
}
|
||||
@@ -151,6 +162,7 @@ class PreviewCommand extends ShorebirdCommand {
|
||||
Future<int> installAndLaunchAndroid({
|
||||
required String appId,
|
||||
required Release release,
|
||||
required String channel,
|
||||
String? deviceId,
|
||||
}) async {
|
||||
const platform = ReleasePlatform.android;
|
||||
@@ -187,6 +199,23 @@ class PreviewCommand extends ShorebirdCommand {
|
||||
}
|
||||
}
|
||||
|
||||
final apksPath = getArtifactPath(
|
||||
appId: appId,
|
||||
release: release,
|
||||
platform: platform,
|
||||
extension: 'apks',
|
||||
);
|
||||
|
||||
if (File(apksPath).existsSync()) File(apksPath).deleteSync();
|
||||
final progress = logger.progress('Using channel $channel');
|
||||
try {
|
||||
await setChannelOnAab(aabFile: aabFile, channel: channel);
|
||||
progress.complete();
|
||||
} catch (error) {
|
||||
progress.fail('$error');
|
||||
return ExitCode.software.code;
|
||||
}
|
||||
|
||||
final extractMetadataProgress = logger.progress('Extracting metadata');
|
||||
late String package;
|
||||
try {
|
||||
@@ -197,22 +226,13 @@ class PreviewCommand extends ShorebirdCommand {
|
||||
return ExitCode.software.code;
|
||||
}
|
||||
|
||||
final apksPath = getArtifactPath(
|
||||
appId: appId,
|
||||
release: release,
|
||||
platform: platform,
|
||||
extension: 'apks',
|
||||
);
|
||||
|
||||
if (!File(apksPath).existsSync()) {
|
||||
final buildApksProgress = logger.progress('Building apks');
|
||||
try {
|
||||
await bundletool.buildApks(bundle: aabFile.path, output: apksPath);
|
||||
buildApksProgress.complete();
|
||||
} catch (error) {
|
||||
buildApksProgress.fail('$error');
|
||||
return ExitCode.software.code;
|
||||
}
|
||||
final buildApksProgress = logger.progress('Building apks');
|
||||
try {
|
||||
await bundletool.buildApks(bundle: aabFile.path, output: apksPath);
|
||||
buildApksProgress.complete();
|
||||
} catch (error) {
|
||||
buildApksProgress.fail('$error');
|
||||
return ExitCode.software.code;
|
||||
}
|
||||
|
||||
final installApksProgress = logger.progress('Installing apks');
|
||||
@@ -247,6 +267,7 @@ class PreviewCommand extends ShorebirdCommand {
|
||||
Future<int> installAndLaunchIos({
|
||||
required String appId,
|
||||
required Release release,
|
||||
required String channel,
|
||||
String? deviceId,
|
||||
}) async {
|
||||
const platform = ReleasePlatform.ios;
|
||||
@@ -285,6 +306,18 @@ class PreviewCommand extends ShorebirdCommand {
|
||||
}
|
||||
}
|
||||
|
||||
final progress = logger.progress('Using channel $channel');
|
||||
try {
|
||||
await setChannelOnRunner(
|
||||
runnerDirectory: runnerDirectory,
|
||||
channel: channel,
|
||||
);
|
||||
progress.complete();
|
||||
} catch (error) {
|
||||
progress.fail('$error');
|
||||
return ExitCode.software.code;
|
||||
}
|
||||
|
||||
try {
|
||||
final exitCode = await iosDeploy.installAndLaunchApp(
|
||||
bundlePath: runnerDirectory.path,
|
||||
@@ -308,4 +341,87 @@ class PreviewCommand extends ShorebirdCommand {
|
||||
'${platform.name}_${release.version}.$extension',
|
||||
);
|
||||
}
|
||||
|
||||
/// Sets the channel property in the shorebird.yaml file inside the Runner.app
|
||||
Future<void> setChannelOnRunner({
|
||||
required Directory runnerDirectory,
|
||||
required String channel,
|
||||
}) async {
|
||||
await Isolate.run(() async {
|
||||
final shorebirdYaml = File(
|
||||
p.join(
|
||||
runnerDirectory.path,
|
||||
'Frameworks',
|
||||
'App.framework',
|
||||
'flutter_assets',
|
||||
'shorebird.yaml',
|
||||
),
|
||||
);
|
||||
|
||||
if (!shorebirdYaml.existsSync()) {
|
||||
throw Exception('Unable to find shorebird.yaml');
|
||||
}
|
||||
|
||||
final yaml = YamlEditor(shorebirdYaml.readAsStringSync())
|
||||
..update(['channel'], channel);
|
||||
|
||||
shorebirdYaml.writeAsStringSync(yaml.toString(), flush: true);
|
||||
});
|
||||
}
|
||||
|
||||
/// Unzips the `.aab` and sets the channel property in the shorebird.yaml
|
||||
/// file inside the base module and then re-zips the `.aab`.
|
||||
Future<void> setChannelOnAab({
|
||||
required File aabFile,
|
||||
required String channel,
|
||||
}) async {
|
||||
// Getting the reference here since we cannot inside the isolate.
|
||||
final extractZip = artifactManager.extractZip;
|
||||
|
||||
await Isolate.run(() async {
|
||||
final tempDir = Directory.systemTemp.createTempSync();
|
||||
final basename = p.basenameWithoutExtension(aabFile.path);
|
||||
final outputPath = p.join(tempDir.path, basename);
|
||||
|
||||
await extractZip(
|
||||
zipFile: aabFile,
|
||||
outputDirectory: Directory(outputPath),
|
||||
);
|
||||
|
||||
final shorebirdYaml = File(
|
||||
p.join(
|
||||
outputPath,
|
||||
'base',
|
||||
'assets',
|
||||
'flutter_assets',
|
||||
'shorebird.yaml',
|
||||
),
|
||||
);
|
||||
|
||||
if (!shorebirdYaml.existsSync()) {
|
||||
throw Exception('Unable to find shorebird.yaml');
|
||||
}
|
||||
|
||||
final yaml = YamlEditor(shorebirdYaml.readAsStringSync())
|
||||
..update(['channel'], channel);
|
||||
|
||||
shorebirdYaml.writeAsStringSync(yaml.toString(), flush: true);
|
||||
|
||||
// This is equivalent to `zip --no-dir-entries`
|
||||
// Which does NOT create entries in the zip archive for directories.
|
||||
// It's important to do this because bundletool expects the
|
||||
// .aab not to contain any directories.
|
||||
final encoder = ZipFileEncoder()..create(aabFile.path);
|
||||
for (final file in Directory(outputPath).listSync(recursive: true)) {
|
||||
if (file is File) {
|
||||
await encoder.addFile(
|
||||
file,
|
||||
file.path.replaceFirst('$outputPath/', ''),
|
||||
);
|
||||
}
|
||||
}
|
||||
encoder.close();
|
||||
tempDir.deleteSync(recursive: true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ void main() {
|
||||
const version = '$versionName+$versionCode';
|
||||
const arch = 'aarch64';
|
||||
const releasePlatform = ReleasePlatform.android;
|
||||
const channelName = 'stable';
|
||||
const channelName = 'test-channel';
|
||||
const appDisplayName = 'Test App';
|
||||
final appMetadata = AppMetadata(
|
||||
appId: appId,
|
||||
@@ -786,10 +786,10 @@ Please re-run the release command for this version or create a new release.'''),
|
||||
verifyNever(() => logger.confirm(any()));
|
||||
verify(
|
||||
() => codePushClientWrapper.publishPatch(
|
||||
appId: any(named: 'appId'),
|
||||
releaseId: any(named: 'releaseId'),
|
||||
platform: any(named: 'platform'),
|
||||
channelName: any(named: 'channelName'),
|
||||
appId: appId,
|
||||
releaseId: release.id,
|
||||
platform: releasePlatform,
|
||||
channelName: channelName,
|
||||
patchArtifactBundles: any(named: 'patchArtifactBundles'),
|
||||
),
|
||||
).called(1);
|
||||
@@ -813,10 +813,10 @@ Please re-run the release command for this version or create a new release.'''),
|
||||
).called(1);
|
||||
verify(
|
||||
() => codePushClientWrapper.publishPatch(
|
||||
appId: any(named: 'appId'),
|
||||
releaseId: any(named: 'releaseId'),
|
||||
platform: any(named: 'platform'),
|
||||
channelName: any(named: 'channelName'),
|
||||
appId: appId,
|
||||
releaseId: release.id,
|
||||
platform: releasePlatform,
|
||||
channelName: channelName,
|
||||
patchArtifactBundles: any(named: 'patchArtifactBundles'),
|
||||
),
|
||||
).called(1);
|
||||
@@ -863,10 +863,10 @@ flavors:
|
||||
);
|
||||
verify(
|
||||
() => codePushClientWrapper.publishPatch(
|
||||
appId: any(named: 'appId'),
|
||||
releaseId: any(named: 'releaseId'),
|
||||
platform: any(named: 'platform'),
|
||||
channelName: any(named: 'channelName'),
|
||||
appId: appId,
|
||||
releaseId: release.id,
|
||||
platform: releasePlatform,
|
||||
channelName: channelName,
|
||||
patchArtifactBundles: any(named: 'patchArtifactBundles'),
|
||||
),
|
||||
).called(1);
|
||||
|
||||
@@ -38,7 +38,9 @@ void main() {
|
||||
const versionCode = '1';
|
||||
const version = '$versionName+$versionCode';
|
||||
const arch = 'aarch64';
|
||||
const channelName = 'test-channel';
|
||||
const appDisplayName = 'Test App';
|
||||
const releasePlatform = ReleasePlatform.ios;
|
||||
const platformName = 'ios';
|
||||
const elfAotSnapshotFileName = 'out.aot';
|
||||
const ipaPath = 'build/ios/ipa/Runner.ipa';
|
||||
@@ -252,6 +254,7 @@ flutter:
|
||||
when(() => argResults['force']).thenReturn(false);
|
||||
when(() => argResults['release-version']).thenReturn(release.version);
|
||||
when(() => argResults['codesign']).thenReturn(true);
|
||||
when(() => argResults['channel']).thenReturn(channelName);
|
||||
when(() => argResults.rest).thenReturn([]);
|
||||
when(() => auth.isAuthenticated).thenReturn(true);
|
||||
when(() => auth.client).thenReturn(httpClient);
|
||||
@@ -845,10 +848,10 @@ Please re-run the release command for this version or create a new release.'''),
|
||||
verifyNever(() => logger.confirm(any()));
|
||||
verify(
|
||||
() => codePushClientWrapper.publishPatch(
|
||||
appId: any(named: 'appId'),
|
||||
releaseId: any(named: 'releaseId'),
|
||||
platform: any(named: 'platform'),
|
||||
channelName: any(named: 'channelName'),
|
||||
appId: appId,
|
||||
releaseId: release.id,
|
||||
platform: releasePlatform,
|
||||
channelName: channelName,
|
||||
patchArtifactBundles: any(named: 'patchArtifactBundles'),
|
||||
),
|
||||
).called(1);
|
||||
@@ -872,10 +875,10 @@ Please re-run the release command for this version or create a new release.'''),
|
||||
).called(1);
|
||||
verify(
|
||||
() => codePushClientWrapper.publishPatch(
|
||||
appId: any(named: 'appId'),
|
||||
releaseId: any(named: 'releaseId'),
|
||||
platform: any(named: 'platform'),
|
||||
channelName: any(named: 'channelName'),
|
||||
appId: appId,
|
||||
releaseId: release.id,
|
||||
platform: releasePlatform,
|
||||
channelName: channelName,
|
||||
patchArtifactBundles: any(named: 'patchArtifactBundles'),
|
||||
),
|
||||
).called(1);
|
||||
@@ -976,10 +979,10 @@ flavors:
|
||||
expect(exitCode, ExitCode.success.code);
|
||||
verify(
|
||||
() => codePushClientWrapper.publishPatch(
|
||||
appId: any(named: 'appId'),
|
||||
releaseId: any(named: 'releaseId'),
|
||||
platform: any(named: 'platform'),
|
||||
channelName: any(named: 'channelName'),
|
||||
appId: appId,
|
||||
releaseId: release.id,
|
||||
platform: releasePlatform,
|
||||
channelName: channelName,
|
||||
patchArtifactBundles: any(named: 'patchArtifactBundles'),
|
||||
),
|
||||
).called(1);
|
||||
|
||||
@@ -27,6 +27,7 @@ void main() {
|
||||
const appId = 'test-app-id';
|
||||
const appDisplayName = 'Test App';
|
||||
const releaseVersion = '1.2.3';
|
||||
const channel = 'stable';
|
||||
const releaseId = 42;
|
||||
|
||||
late AppMetadata app;
|
||||
@@ -85,6 +86,7 @@ void main() {
|
||||
|
||||
when(() => argResults['app-id']).thenReturn(appId);
|
||||
when(() => argResults['release-version']).thenReturn(releaseVersion);
|
||||
when(() => argResults['channel']).thenReturn(channel);
|
||||
when(() => auth.isAuthenticated).thenReturn(true);
|
||||
when(() => cache.getPreviewDirectory(any())).thenReturn(previewDirectory);
|
||||
when(
|
||||
@@ -188,8 +190,9 @@ void main() {
|
||||
authRef.overrideWith(() => auth),
|
||||
bundletoolRef.overrideWith(() => bundletool),
|
||||
cacheRef.overrideWith(() => cache),
|
||||
codePushClientWrapperRef
|
||||
.overrideWith(() => codePushClientWrapper),
|
||||
codePushClientWrapperRef.overrideWith(
|
||||
() => codePushClientWrapper,
|
||||
),
|
||||
loggerRef.overrideWith(() => logger),
|
||||
shorebirdValidatorRef.overrideWith(() => shorebirdValidator),
|
||||
},
|
||||
@@ -197,6 +200,20 @@ void main() {
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> createShorebirdYaml(Invocation invocation) async {
|
||||
File(
|
||||
p.join(
|
||||
(invocation.namedArguments[#outputDirectory] as Directory).path,
|
||||
'base',
|
||||
'assets',
|
||||
'flutter_assets',
|
||||
'shorebird.yaml',
|
||||
),
|
||||
)
|
||||
..createSync(recursive: true)
|
||||
..writeAsStringSync('app_id: $appId', flush: true);
|
||||
}
|
||||
|
||||
setUp(() {
|
||||
adb = MockAdb();
|
||||
bundletool = MockBundleTool();
|
||||
@@ -289,7 +306,22 @@ void main() {
|
||||
verify(() => progress.fail('$exception')).called(1);
|
||||
});
|
||||
|
||||
test('exits with code 70 when unable to find shorebird.yaml', () async {
|
||||
final result = await runWithOverrides(command.run);
|
||||
expect(result, equals(ExitCode.software.code));
|
||||
verify(
|
||||
() => progress.fail('Exception: Unable to find shorebird.yaml'),
|
||||
).called(1);
|
||||
});
|
||||
|
||||
test('exits with code 70 when extracting metadata fails', () async {
|
||||
when(
|
||||
() => artifactManager.extractZip(
|
||||
zipFile: any(named: 'zipFile'),
|
||||
outputDirectory: any(named: 'outputDirectory'),
|
||||
),
|
||||
).thenAnswer(createShorebirdYaml);
|
||||
|
||||
final exception = Exception('oops');
|
||||
when(() => bundletool.getPackageName(any())).thenThrow(exception);
|
||||
final result = await runWithOverrides(command.run);
|
||||
@@ -298,6 +330,13 @@ void main() {
|
||||
});
|
||||
|
||||
test('exits with code 70 when building apks fails', () async {
|
||||
when(
|
||||
() => artifactManager.extractZip(
|
||||
zipFile: any(named: 'zipFile'),
|
||||
outputDirectory: any(named: 'outputDirectory'),
|
||||
),
|
||||
).thenAnswer(createShorebirdYaml);
|
||||
|
||||
final exception = Exception('oops');
|
||||
when(
|
||||
() => bundletool.buildApks(
|
||||
@@ -313,6 +352,13 @@ void main() {
|
||||
});
|
||||
|
||||
test('exits with code 70 when installing apks fails', () async {
|
||||
when(
|
||||
() => artifactManager.extractZip(
|
||||
zipFile: any(named: 'zipFile'),
|
||||
outputDirectory: any(named: 'outputDirectory'),
|
||||
),
|
||||
).thenAnswer(createShorebirdYaml);
|
||||
|
||||
final exception = Exception('oops');
|
||||
when(
|
||||
() => bundletool.installApks(apks: any(named: 'apks')),
|
||||
@@ -323,6 +369,13 @@ void main() {
|
||||
});
|
||||
|
||||
test('exits with code 70 when starting app fails', () async {
|
||||
when(
|
||||
() => artifactManager.extractZip(
|
||||
zipFile: any(named: 'zipFile'),
|
||||
outputDirectory: any(named: 'outputDirectory'),
|
||||
),
|
||||
).thenAnswer(createShorebirdYaml);
|
||||
|
||||
final exception = Exception('oops');
|
||||
when(() => adb.startApp(package: any(named: 'package')))
|
||||
.thenThrow(exception);
|
||||
@@ -332,6 +385,13 @@ void main() {
|
||||
});
|
||||
|
||||
test('exits with non-zero exit code when logcat process fails', () async {
|
||||
when(
|
||||
() => artifactManager.extractZip(
|
||||
zipFile: any(named: 'zipFile'),
|
||||
outputDirectory: any(named: 'outputDirectory'),
|
||||
),
|
||||
).thenAnswer(createShorebirdYaml);
|
||||
|
||||
when(() => process.exitCode).thenAnswer((_) async => 1);
|
||||
final result = await runWithOverrides(command.run);
|
||||
expect(result, equals(1));
|
||||
@@ -339,6 +399,13 @@ void main() {
|
||||
});
|
||||
|
||||
test('pipes stdout output to logger', () async {
|
||||
when(
|
||||
() => artifactManager.extractZip(
|
||||
zipFile: any(named: 'zipFile'),
|
||||
outputDirectory: any(named: 'outputDirectory'),
|
||||
),
|
||||
).thenAnswer(createShorebirdYaml);
|
||||
|
||||
final completer = Completer<int>();
|
||||
when(() => process.exitCode).thenAnswer((_) => completer.future);
|
||||
const output = 'hello world';
|
||||
@@ -352,6 +419,13 @@ void main() {
|
||||
});
|
||||
|
||||
test('pipes stderr output to logger', () async {
|
||||
when(
|
||||
() => artifactManager.extractZip(
|
||||
zipFile: any(named: 'zipFile'),
|
||||
outputDirectory: any(named: 'outputDirectory'),
|
||||
),
|
||||
).thenAnswer(createShorebirdYaml);
|
||||
|
||||
final completer = Completer<int>();
|
||||
when(() => process.exitCode).thenAnswer((_) => completer.future);
|
||||
const output = 'hello world';
|
||||
@@ -365,6 +439,13 @@ void main() {
|
||||
});
|
||||
|
||||
test('queries for apps when app-id is not specified', () async {
|
||||
when(
|
||||
() => artifactManager.extractZip(
|
||||
zipFile: any(named: 'zipFile'),
|
||||
outputDirectory: any(named: 'outputDirectory'),
|
||||
),
|
||||
).thenAnswer(createShorebirdYaml);
|
||||
|
||||
when(() => argResults['app-id']).thenReturn(null);
|
||||
when(
|
||||
() => logger.chooseOne<AppMetadata>(
|
||||
@@ -387,6 +468,13 @@ void main() {
|
||||
});
|
||||
|
||||
test('prompts for platforms when platform is not specified', () async {
|
||||
when(
|
||||
() => artifactManager.extractZip(
|
||||
zipFile: any(named: 'zipFile'),
|
||||
outputDirectory: any(named: 'outputDirectory'),
|
||||
),
|
||||
).thenAnswer(createShorebirdYaml);
|
||||
|
||||
when(() => argResults['platform']).thenReturn(null);
|
||||
when(
|
||||
() => logger.chooseOne<String>(
|
||||
@@ -458,6 +546,13 @@ void main() {
|
||||
test(
|
||||
'queries for releases when '
|
||||
'release-version is not specified', () async {
|
||||
when(
|
||||
() => artifactManager.extractZip(
|
||||
zipFile: any(named: 'zipFile'),
|
||||
outputDirectory: any(named: 'outputDirectory'),
|
||||
),
|
||||
).thenAnswer(createShorebirdYaml);
|
||||
|
||||
when(() => argResults['release-version']).thenReturn(null);
|
||||
when(
|
||||
() => logger.chooseOne<Release>(
|
||||
@@ -485,6 +580,13 @@ void main() {
|
||||
});
|
||||
|
||||
test('forwards deviceId to adb and bundletool', () async {
|
||||
when(
|
||||
() => artifactManager.extractZip(
|
||||
zipFile: any(named: 'zipFile'),
|
||||
outputDirectory: any(named: 'outputDirectory'),
|
||||
),
|
||||
).thenAnswer(createShorebirdYaml);
|
||||
|
||||
const deviceId = '1234';
|
||||
when(() => argResults['device-id']).thenReturn(deviceId);
|
||||
await runWithOverrides(command.run);
|
||||
@@ -613,7 +715,29 @@ void main() {
|
||||
verify(() => progress.fail('$exception')).called(1);
|
||||
});
|
||||
|
||||
test('exits with code 70 when unable to find shorebird.yaml', () async {
|
||||
final result = await runWithOverrides(command.run);
|
||||
expect(result, equals(ExitCode.software.code));
|
||||
verify(
|
||||
() => progress.fail('Exception: Unable to find shorebird.yaml'),
|
||||
).called(1);
|
||||
verifyNever(
|
||||
() => iosDeploy.installAndLaunchApp(bundlePath: runnerPath()),
|
||||
);
|
||||
});
|
||||
|
||||
test('exits with code 70 when install/launch throws', () async {
|
||||
File(
|
||||
p.join(
|
||||
runnerPath(),
|
||||
'Frameworks',
|
||||
'App.framework',
|
||||
'flutter_assets',
|
||||
'shorebird.yaml',
|
||||
),
|
||||
)
|
||||
..createSync(recursive: true)
|
||||
..writeAsStringSync('app_id: $appId', flush: true);
|
||||
final exception = Exception('oops');
|
||||
when(
|
||||
() => iosDeploy.installAndLaunchApp(
|
||||
@@ -629,6 +753,17 @@ void main() {
|
||||
});
|
||||
|
||||
test('exits with code 0 when install/launch succeeds', () async {
|
||||
final shorebirdYaml = File(
|
||||
p.join(
|
||||
runnerPath(),
|
||||
'Frameworks',
|
||||
'App.framework',
|
||||
'flutter_assets',
|
||||
'shorebird.yaml',
|
||||
),
|
||||
)
|
||||
..createSync(recursive: true)
|
||||
..writeAsStringSync('app_id: $appId', flush: true);
|
||||
when(
|
||||
() => iosDeploy.installAndLaunchApp(
|
||||
bundlePath: any(named: 'bundlePath'),
|
||||
@@ -640,6 +775,13 @@ void main() {
|
||||
verify(
|
||||
() => iosDeploy.installAndLaunchApp(bundlePath: runnerPath()),
|
||||
).called(1);
|
||||
expect(
|
||||
shorebirdYaml.readAsStringSync(),
|
||||
equals('''
|
||||
app_id: $appId
|
||||
channel: $channel
|
||||
'''),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ void main() {
|
||||
displayName: 'display-name',
|
||||
createdAt: DateTime(2022),
|
||||
updatedAt: DateTime(2023),
|
||||
)
|
||||
),
|
||||
],
|
||||
);
|
||||
expect(
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ void main() {
|
||||
},
|
||||
createdAt: DateTime(2022),
|
||||
updatedAt: DateTime(2023),
|
||||
)
|
||||
),
|
||||
],
|
||||
);
|
||||
expect(
|
||||
|
||||
Reference in New Issue
Block a user