fix(shorebird_cli): handle case where IPA generation failed with exit code 0 (#618)
This commit is contained in:
@@ -64,10 +64,10 @@ runs:
|
||||
dart pub global activate coverage
|
||||
dart test -j ${{inputs.concurrency}} --coverage=coverage --platform=${{inputs.platform}} && dart pub global run coverage:format_coverage --lcov --in=coverage --out=coverage/lcov.info --packages=.dart_tool/package_config.json --report-on=${{inputs.report_on}} --check-ignore
|
||||
|
||||
- name: Upload Coverage
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
# - name: Upload Coverage
|
||||
# uses: codecov/codecov-action@v3
|
||||
# with:
|
||||
# token: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
- uses: VeryGoodOpenSource/very_good_coverage@v2
|
||||
with:
|
||||
|
||||
@@ -75,7 +75,11 @@ make smaller updates to your app.
|
||||
try {
|
||||
await buildIpa(flavor: flavor);
|
||||
} on ProcessException catch (error) {
|
||||
buildProgress.fail('Failed to build: ${error.message}');
|
||||
buildProgress.fail('Failed to build IPA: ${error.message}');
|
||||
return ExitCode.software.code;
|
||||
} on BuildException catch (error) {
|
||||
buildProgress.fail('Failed to build IPA');
|
||||
logger.err(error.message);
|
||||
return ExitCode.software.code;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,17 @@ class ArchMetadata {
|
||||
final String enginePath;
|
||||
}
|
||||
|
||||
/// {@template build_exception}
|
||||
/// Thrown when a build fails.
|
||||
/// {@endtemplate}
|
||||
class BuildException implements Exception {
|
||||
/// {@macro build_exception}
|
||||
BuildException(this.message);
|
||||
|
||||
/// Information about the build failure.
|
||||
final String message;
|
||||
}
|
||||
|
||||
mixin ShorebirdBuildMixin on ShorebirdCommand {
|
||||
// This exists only so tests can get the full list.
|
||||
static const allAndroidArchitectures = <Arch, ArchMetadata>{
|
||||
@@ -182,9 +193,42 @@ mixin ShorebirdBuildMixin on ShorebirdCommand {
|
||||
result.stderr.toString(),
|
||||
result.exitCode,
|
||||
);
|
||||
} else if (result.stderr
|
||||
.toString()
|
||||
.contains('Encountered error while creating the IPA')) {
|
||||
final errorMessage = _failedToCreateIpaErrorMessage(
|
||||
stderr: result.stderr.toString(),
|
||||
);
|
||||
|
||||
throw BuildException(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
String _failedToCreateIpaErrorMessage({required String stderr}) {
|
||||
// The full error text consists of many repeated lines of the format:
|
||||
// (newlines added for line length)
|
||||
//
|
||||
// error: exportArchive: No signing certificate "iOS Distribution" found
|
||||
// error: exportArchive: Communication with Apple failed
|
||||
// error: exportArchive: No signing certificate "iOS Distribution" found
|
||||
// error: exportArchive: Team "My Team" does not have permission to
|
||||
// create "iOS App Store" provisioning profiles.
|
||||
// error: exportArchive: No profiles for 'com.example.demo' were found
|
||||
// error: exportArchive: Communication with Apple failed
|
||||
// error: exportArchive: No signing certificate "iOS Distribution" found
|
||||
// error: exportArchive: Communication with Apple failed
|
||||
final exportArchiveRegex = RegExp(r'^error: exportArchive: (.+)$');
|
||||
|
||||
return stderr
|
||||
.split('\n')
|
||||
.map((l) => l.trim())
|
||||
.toSet()
|
||||
.map(exportArchiveRegex.firstMatch)
|
||||
.whereType<Match>()
|
||||
.map((m) => ' ${m.group(1)!}')
|
||||
.join('\n');
|
||||
}
|
||||
|
||||
Future<String> createDiff({
|
||||
required String releaseArtifactPath,
|
||||
required String patchArtifactPath,
|
||||
|
||||
@@ -227,7 +227,8 @@ flutter:
|
||||
expect(exitCode, equals(ExitCode.noUser.code));
|
||||
});
|
||||
|
||||
test('exits with code 70 when building fails', () async {
|
||||
test('exits with code 70 when build fails with non-zero exit code',
|
||||
() async {
|
||||
when(() => flutterBuildProcessResult.exitCode).thenReturn(1);
|
||||
when(() => flutterBuildProcessResult.stderr).thenReturn('oops');
|
||||
|
||||
@@ -243,6 +244,43 @@ flutter:
|
||||
).called(1);
|
||||
});
|
||||
|
||||
test('exits with code 70 when building fails with 0 exit code', () async {
|
||||
when(() => flutterBuildProcessResult.exitCode).thenReturn(0);
|
||||
when(() => flutterBuildProcessResult.stderr).thenReturn('''
|
||||
Encountered error while creating the IPA:
|
||||
error: exportArchive: Communication with Apple failed
|
||||
error: exportArchive: No signing certificate "iOS Distribution" found
|
||||
error: exportArchive: Communication with Apple failed
|
||||
error: exportArchive: No signing certificate "iOS Distribution" found
|
||||
error: exportArchive: Team "My Team" does not have permission to create "iOS App Store" provisioning profiles.
|
||||
error: exportArchive: No profiles for 'com.example.co' were found
|
||||
error: exportArchive: Communication with Apple failed
|
||||
error: exportArchive: No signing certificate "iOS Distribution" found
|
||||
error: exportArchive: Communication with Apple failed
|
||||
error: exportArchive: No signing certificate "iOS Distribution" found
|
||||
error: exportArchive: Communication with Apple failed
|
||||
error: exportArchive: No signing certificate "iOS Distribution" found
|
||||
''');
|
||||
|
||||
final tempDir = setUpTempDir();
|
||||
final exitCode = await IOOverrides.runZoned(
|
||||
() => runWithOverrides(command.run),
|
||||
getCurrentDirectory: () => tempDir,
|
||||
);
|
||||
|
||||
expect(exitCode, equals(ExitCode.software.code));
|
||||
verify(
|
||||
() => progress.fail(any(that: contains('Failed to build'))),
|
||||
).called(1);
|
||||
verify(
|
||||
() => logger.err('''
|
||||
Communication with Apple failed
|
||||
No signing certificate "iOS Distribution" found
|
||||
Team "My Team" does not have permission to create "iOS App Store" provisioning profiles.
|
||||
No profiles for 'com.example.co' were found'''),
|
||||
).called(1);
|
||||
});
|
||||
|
||||
test('exits with code 70 when release version cannot be determiend',
|
||||
() async {
|
||||
when(() => ipa.versionNumber).thenThrow(Exception('oops'));
|
||||
|
||||
Reference in New Issue
Block a user