feat(shorebird_cli): shorebird release uploads artifacts for all arches (#265)

This commit is contained in:
Felix Angelov
2023-04-07 11:54:38 -05:00
committed by GitHub
parent 5f435a9f0f
commit 352970fb63
4 changed files with 107 additions and 178 deletions
+14 -16
View File
@@ -202,32 +202,30 @@ shorebird release
**Sample**
```
shorebird release
✓ Building release (17.9s)
✓ Fetching apps (0.1s)
$ shorebird release
✓ Building release (5.1s)
✓ Fetching apps (0.2s)
What is the version of this release? (0.1.0) 0.1.0
What is the version of this release? (1.0.0) 1.0.0
🚀 Ready to create a new release!
📱 App: My App (61fc9c16-3c4a-4825-a155-9765993614aa)
📦 Release Version: 0.1.0
Architecture: aarch64
🕹️ Platform: android
#️⃣ Hash: cfe26dddf8aff17131042f9dfad409c83eb130c5a9f2fd6f77325b2388062265
Your next step is to upload the release artifact to the Play Store.
./build/app/outputs/bundle/release/app-release.aab
See the following link for more information:
https://support.google.com/googleplay/android-developer/answer/9859152?hl=en
📱 App: My App (30370f27-dbf1-4673-8b20-fb096e38dffa)
📦 Release Version: 1.0.0
🕹 Platform: android (arm64, arm32, x86)
Would you like to continue? (y/N) Yes
✓ Fetching releases (55ms)
✓ Creating release (45ms)
✓ Creating artifact (1.8s)
✓ Creating artifacts (4.6s)
✅ Published Release!
Your next step is to upload the app bundle to the Play Store.
./build/app/outputs/bundle/release/app-release.aab
See the following link for more information:
https://support.google.com/googleplay/android-developer/answer/9859152?hl=en
```
### Patch
@@ -41,13 +41,6 @@ class ReleaseCommand extends ShorebirdCommand
allowed: ['android'],
allowedHelp: {'android': 'The Android platform.'},
defaultsTo: 'android',
)
..addOption(
'arch',
help: 'The architecture of the release (e.g. "aarch64").',
allowed: ['aarch64'],
allowedHelp: {'aarch64': 'The 64-bit ARM architecture.'},
defaultsTo: 'aarch64',
);
}
@@ -88,27 +81,6 @@ make smaller updates to your app.
return ExitCode.software.code;
}
final artifactPath = p.join(
Directory.current.path,
'build',
'app',
'intermediates',
'stripped_native_libs',
'release',
'out',
'lib',
'arm64-v8a',
'libapp.so',
);
final artifact = File(artifactPath);
if (!artifact.existsSync()) {
logger.err('Artifact not found: "${artifact.path}"');
return ExitCode.software.code;
}
final hash = _hashFn(await artifact.readAsBytes());
final pubspecYaml = getPubspecYaml()!;
final shorebirdYaml = getShorebirdYaml()!;
final codePushClient = buildCodePushClient(
@@ -152,8 +124,11 @@ Did you forget to run "shorebird init"?''',
'What is the version of this release?',
defaultValue: pubspecVersionString,
);
final arch = results['arch'] as String;
final platform = results['platform'] as String;
final archNames = ShorebirdBuildMixin.architectures.keys.map(
(arch) => arch.name,
);
logger.info('''
@@ -161,9 +136,7 @@ ${styleBold.wrap(lightGreen.wrap('🚀 Ready to create a new release!'))}
📱 App: ${lightCyan.wrap(app.displayName)} ${lightCyan.wrap('(${app.id})')}
📦 Release Version: ${lightCyan.wrap(releaseVersion)}
Architecture: ${lightCyan.wrap(arch)}
🕹️ Platform: ${lightCyan.wrap(platform)}
#️⃣ Hash: ${lightCyan.wrap(hash)}
🕹 Platform: ${lightCyan.wrap(platform)} ${lightCyan.wrap('(${archNames.join(', ')})')}
''');
final confirm = logger.confirm('Would you like to continue?');
@@ -198,26 +171,44 @@ ${styleBold.wrap(lightGreen.wrap('🚀 Ready to create a new release!'))}
}
}
final createArtifactProgress = logger.progress('Creating artifact');
try {
await codePushClient.createReleaseArtifact(
releaseId: release.id,
artifactPath: artifact.path,
arch: arch,
platform: platform,
hash: hash,
final createArtifactProgress = logger.progress('Creating artifacts');
for (final archMetadata in ShorebirdBuildMixin.architectures.values) {
final artifactPath = p.join(
Directory.current.path,
'build',
'app',
'intermediates',
'stripped_native_libs',
'release',
'out',
'lib',
archMetadata.path,
'libapp.so',
);
createArtifactProgress.complete();
} catch (error) {
createArtifactProgress.fail('$error');
return ExitCode.software.code;
final artifact = File(artifactPath);
final hash = _hashFn(await artifact.readAsBytes());
try {
await codePushClient.createReleaseArtifact(
releaseId: release.id,
artifactPath: artifact.path,
arch: archMetadata.arch,
platform: platform,
hash: hash,
);
} catch (error) {
createArtifactProgress.fail('$error');
return ExitCode.software.code;
}
}
createArtifactProgress.complete();
logger
..success('\n✅ Published Release!')
..info('''
Your next step is to upload the release artifact to the Play Store.
Your next step is to upload the app bundle to the Play Store.
${lightCyan.wrap("./build/app/outputs/bundle/release/app-release.aab")}
See the following link for more information:
@@ -3,7 +3,36 @@ import 'dart:io';
import 'package:mason_logger/mason_logger.dart';
import 'package:shorebird_cli/src/command.dart';
enum Arch {
arm64,
arm32,
x86,
}
class ArchMetadata {
const ArchMetadata({required this.path, required this.arch});
final String path;
final String arch;
}
mixin ShorebirdBuildMixin on ShorebirdCommand {
// TODO(felangel): extend to other platforms.
static const architectures = <Arch, ArchMetadata>{
Arch.arm64: ArchMetadata(
path: 'arm64-v8a',
arch: 'aarch64',
),
Arch.arm32: ArchMetadata(
path: 'armeabi-v7a',
arch: 'arm',
),
Arch.x86: ArchMetadata(
path: 'x86_64',
arch: 'x86_64',
),
};
Future<void> buildRelease() async {
const executable = 'flutter';
final arguments = [
@@ -8,6 +8,7 @@ import 'package:path/path.dart' as p;
import 'package:shorebird_cli/src/auth/auth.dart';
import 'package:shorebird_cli/src/commands/commands.dart';
import 'package:shorebird_cli/src/config/config.dart';
import 'package:shorebird_cli/src/shorebird_build_mixin.dart';
import 'package:shorebird_cli/src/validators/validators.dart';
import 'package:shorebird_code_push_client/shorebird_code_push_client.dart';
import 'package:test/test.dart';
@@ -86,6 +87,24 @@ flutter:
return tempDir;
}
void setUpTempArtifacts(Directory dir) {
for (final archMetadata in ShorebirdBuildMixin.architectures.values) {
final artifactPath = p.join(
dir.path,
'build',
'app',
'intermediates',
'stripped_native_libs',
'release',
'out',
'lib',
archMetadata.path,
'libapp.so',
);
File(artifactPath).createSync(recursive: true);
}
}
setUp(() {
argResults = _MockArgResults();
applicationConfigHome = Directory.systemTemp.createTempSync();
@@ -192,36 +211,12 @@ flutter:
expect(exitCode, equals(ExitCode.software.code));
});
test('throws software error when artifact is not found (default).',
() async {
final tempDir = setUpTempDir();
final exitCode = await IOOverrides.runZoned(
command.run,
getCurrentDirectory: () => tempDir,
);
verify(
() => logger.err(any(that: contains('Artifact not found:'))),
).called(1);
expect(exitCode, ExitCode.software.code);
});
test('throws error when fetching apps fails.', () async {
const error = 'something went wrong';
when(() => codePushClient.getApps()).thenThrow(error);
final tempDir = setUpTempDir();
final artifactPath = p.join(
tempDir.path,
'build',
'app',
'intermediates',
'stripped_native_libs',
'release',
'out',
'lib',
'arm64-v8a',
'libapp.so',
);
File(artifactPath).createSync(recursive: true);
setUpTempArtifacts(tempDir);
final exitCode = await IOOverrides.runZoned(
command.run,
getCurrentDirectory: () => tempDir,
@@ -236,19 +231,7 @@ flutter:
).thenReturn(appDisplayName);
when(() => codePushClient.getApps()).thenAnswer((_) async => []);
final tempDir = setUpTempDir();
final artifactPath = p.join(
tempDir.path,
'build',
'app',
'intermediates',
'stripped_native_libs',
'release',
'out',
'lib',
'arm64-v8a',
'libapp.so',
);
File(artifactPath).createSync(recursive: true);
setUpTempArtifacts(tempDir);
final exitCode = await IOOverrides.runZoned(
command.run,
getCurrentDirectory: () => tempDir,
@@ -269,19 +252,7 @@ Did you forget to run "shorebird init"?''',
() => logger.prompt(any(), defaultValue: any(named: 'defaultValue')),
).thenReturn(appDisplayName);
final tempDir = setUpTempDir();
final artifactPath = p.join(
tempDir.path,
'build',
'app',
'intermediates',
'stripped_native_libs',
'release',
'out',
'lib',
'arm64-v8a',
'libapp.so',
);
File(artifactPath).createSync(recursive: true);
setUpTempArtifacts(tempDir);
final exitCode = await IOOverrides.runZoned(
command.run,
getCurrentDirectory: () => tempDir,
@@ -296,19 +267,7 @@ Did you forget to run "shorebird init"?''',
() => codePushClient.getReleases(appId: any(named: 'appId')),
).thenThrow(error);
final tempDir = setUpTempDir();
final artifactPath = p.join(
tempDir.path,
'build',
'app',
'intermediates',
'stripped_native_libs',
'release',
'out',
'lib',
'arm64-v8a',
'libapp.so',
);
File(artifactPath).createSync(recursive: true);
setUpTempArtifacts(tempDir);
final exitCode = await IOOverrides.runZoned(
command.run,
getCurrentDirectory: () => tempDir,
@@ -330,19 +289,7 @@ Did you forget to run "shorebird init"?''',
),
).thenThrow(error);
final tempDir = setUpTempDir();
final artifactPath = p.join(
tempDir.path,
'build',
'app',
'intermediates',
'stripped_native_libs',
'release',
'out',
'lib',
'arm64-v8a',
'libapp.so',
);
File(artifactPath).createSync(recursive: true);
setUpTempArtifacts(tempDir);
final exitCode = await IOOverrides.runZoned(
command.run,
getCurrentDirectory: () => tempDir,
@@ -366,19 +313,7 @@ Did you forget to run "shorebird init"?''',
),
).thenThrow(error);
final tempDir = setUpTempDir();
final artifactPath = p.join(
tempDir.path,
'build',
'app',
'intermediates',
'stripped_native_libs',
'release',
'out',
'lib',
'arm64-v8a',
'libapp.so',
);
File(artifactPath).createSync(recursive: true);
setUpTempArtifacts(tempDir);
final exitCode = await IOOverrides.runZoned(
command.run,
getCurrentDirectory: () => tempDir,
@@ -389,19 +324,7 @@ Did you forget to run "shorebird init"?''',
test('succeeds when release is successful', () async {
final tempDir = setUpTempDir();
final artifactPath = p.join(
tempDir.path,
'build',
'app',
'intermediates',
'stripped_native_libs',
'release',
'out',
'lib',
'arm64-v8a',
'libapp.so',
);
File(artifactPath).createSync(recursive: true);
setUpTempArtifacts(tempDir);
final exitCode = await IOOverrides.runZoned(
command.run,
getCurrentDirectory: () => tempDir,
@@ -425,19 +348,7 @@ Did you forget to run "shorebird init"?''',
],
);
final tempDir = setUpTempDir();
final artifactPath = p.join(
tempDir.path,
'build',
'app',
'intermediates',
'stripped_native_libs',
'release',
'out',
'lib',
'arm64-v8a',
'libapp.so',
);
File(artifactPath).createSync(recursive: true);
setUpTempArtifacts(tempDir);
final exitCode = await IOOverrides.runZoned(
command.run,
getCurrentDirectory: () => tempDir,