feat: better handle archiving failures (#2880)
This commit is contained in:
@@ -54,14 +54,22 @@ class ArtifactBuildException implements Exception {
|
||||
late final String? fixRecommendation;
|
||||
|
||||
List<String> _errorMessageFromOutput(List<String> output) {
|
||||
final failureHeader =
|
||||
RegExp(r'.*FAILURE: Build failed with an exception\..*');
|
||||
// This precedes a stack trace
|
||||
final stackTraceHeader = RegExp(r'.*\* Exception is:.*');
|
||||
final failureHeaders = [
|
||||
RegExp(r'.*FAILURE: Build failed with an exception\..*'),
|
||||
RegExp(r'.*Error \(Xcode\).*'),
|
||||
];
|
||||
|
||||
// This precedes recommendations that are not applicable to us (e.g., "Get
|
||||
// more help at https://help.gradle.org.")
|
||||
final suggestionsHeader = RegExp(r'.*\* Try:.*');
|
||||
final failureFooters = [
|
||||
// This precedes a stack trace
|
||||
RegExp(r'.*\* Exception is:.*'),
|
||||
|
||||
// This precedes recommendations that are not applicable to us (e.g., "Get
|
||||
// more help at https://help.gradle.org.")
|
||||
RegExp(r'.*\* Try:.*'),
|
||||
|
||||
// This precedes a stacktrace in the case of an Xcode error
|
||||
RegExp('Encountered error while archiving for device'),
|
||||
];
|
||||
|
||||
String trimLine(String line) {
|
||||
return line.trim().replaceAll(RegExp(r'^\[.*\]'), '');
|
||||
@@ -70,10 +78,9 @@ class ArtifactBuildException implements Exception {
|
||||
var inErrorOutput = false;
|
||||
final ret = <String>[];
|
||||
for (final line in output) {
|
||||
if (failureHeader.hasMatch(line)) {
|
||||
if (failureHeaders.any((r) => r.hasMatch(line))) {
|
||||
inErrorOutput = true;
|
||||
} else if (stackTraceHeader.hasMatch(line) ||
|
||||
suggestionsHeader.hasMatch(line)) {
|
||||
} else if (failureFooters.any((r) => r.hasMatch(line))) {
|
||||
inErrorOutput = false;
|
||||
}
|
||||
|
||||
@@ -93,6 +100,8 @@ class ArtifactBuildException implements Exception {
|
||||
[RegExp("Execution failed for task ':app:signReleaseBundle'")],
|
||||
_missingKeystoreFixSuggestion,
|
||||
),
|
||||
// Note: Xcode archive failures include suggestions from the flutter tool,
|
||||
// so we don't need to duplicate them here.
|
||||
};
|
||||
|
||||
String? _recommendationFromOutput(List<String> output) {
|
||||
|
||||
+103
-67
@@ -34,83 +34,119 @@ void main() {
|
||||
});
|
||||
});
|
||||
|
||||
group('when an error is recognized but no fix recommendation is found', () {
|
||||
test('has a Flutter error and no fix recommendation', () {
|
||||
final exception = ArtifactBuildException(
|
||||
'message',
|
||||
stderr: [
|
||||
'some stderr output',
|
||||
'FAILURE: Build failed with an exception.',
|
||||
'* Exception is:',
|
||||
'some stack trace',
|
||||
'* Try:',
|
||||
'some recommendation',
|
||||
],
|
||||
stdout: ['some stdout output'],
|
||||
);
|
||||
expect(
|
||||
exception.flutterError,
|
||||
equals('FAILURE: Build failed with an exception.'),
|
||||
);
|
||||
expect(exception.fixRecommendation, isNull);
|
||||
group('gradle', () {
|
||||
group('when an error is recognized but no fix recommendation is found',
|
||||
() {
|
||||
test('has a Flutter error and no fix recommendation', () {
|
||||
final exception = ArtifactBuildException(
|
||||
'message',
|
||||
stderr: [
|
||||
'some stderr output',
|
||||
'FAILURE: Build failed with an exception.',
|
||||
'* Exception is:',
|
||||
'some stack trace',
|
||||
'* Try:',
|
||||
'some recommendation',
|
||||
],
|
||||
stdout: ['some stdout output'],
|
||||
);
|
||||
expect(
|
||||
exception.flutterError,
|
||||
equals('FAILURE: Build failed with an exception.'),
|
||||
);
|
||||
expect(exception.fixRecommendation, isNull);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
group('when a known error is recognized and a fix recommendation is found',
|
||||
() {
|
||||
test('has a Flutter error and a fix recommendation', () {
|
||||
final exception = ArtifactBuildException(
|
||||
'message',
|
||||
stderr: [
|
||||
'some stderr output',
|
||||
'FAILURE: Build failed with an exception.',
|
||||
'* What went wrong:',
|
||||
"Execution failed for task ':app:signReleaseBundle'.",
|
||||
r'''> A failure occurred while executing com.android.build.gradle.internal.tasks.FinalizeBundleTask$BundleToolRunnable''',
|
||||
'> java.lang.NullPointerException (no error message)',
|
||||
'* Exception is:',
|
||||
'some stack trace',
|
||||
'* Try:',
|
||||
'some recommendation',
|
||||
],
|
||||
stdout: ['some stdout output'],
|
||||
);
|
||||
expect(
|
||||
exception.flutterError,
|
||||
equals(r'''
|
||||
group(
|
||||
'when a known error is recognized and a fix recommendation is found',
|
||||
() {
|
||||
test('has a Flutter error and a fix recommendation', () {
|
||||
final exception = ArtifactBuildException(
|
||||
'message',
|
||||
stderr: [
|
||||
'some stderr output',
|
||||
'FAILURE: Build failed with an exception.',
|
||||
'* What went wrong:',
|
||||
"Execution failed for task ':app:signReleaseBundle'.",
|
||||
r'''> A failure occurred while executing com.android.build.gradle.internal.tasks.FinalizeBundleTask$BundleToolRunnable''',
|
||||
'> java.lang.NullPointerException (no error message)',
|
||||
'* Exception is:',
|
||||
'some stack trace',
|
||||
'* Try:',
|
||||
'some recommendation',
|
||||
],
|
||||
stdout: ['some stdout output'],
|
||||
);
|
||||
expect(
|
||||
exception.flutterError,
|
||||
equals(r'''
|
||||
FAILURE: Build failed with an exception.
|
||||
* What went wrong:
|
||||
Execution failed for task ':app:signReleaseBundle'.
|
||||
> A failure occurred while executing com.android.build.gradle.internal.tasks.FinalizeBundleTask$BundleToolRunnable
|
||||
> java.lang.NullPointerException (no error message)'''),
|
||||
);
|
||||
expect(
|
||||
exception.fixRecommendation,
|
||||
contains('This error is likely due to a missing keystore file'),
|
||||
);
|
||||
);
|
||||
expect(
|
||||
exception.fixRecommendation,
|
||||
contains('This error is likely due to a missing keystore file'),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
group('when a fix recommendation is provided', () {
|
||||
test('does not read output to find fix recommendation', () {
|
||||
final exception = ArtifactBuildException(
|
||||
'message',
|
||||
fixRecommendation: 'some recommendation',
|
||||
stderr: [
|
||||
'some stderr output',
|
||||
'FAILURE: Build failed with an exception.',
|
||||
'* Exception is:',
|
||||
'some stack trace',
|
||||
'* Try:',
|
||||
'some recommendation',
|
||||
],
|
||||
stdout: ['some stdout output'],
|
||||
);
|
||||
expect(
|
||||
exception.flutterError,
|
||||
'FAILURE: Build failed with an exception.',
|
||||
);
|
||||
expect(exception.fixRecommendation, equals('some recommendation'));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
group('when a fix recommendation is provided', () {
|
||||
test('does not read output to find fix recommendation', () {
|
||||
final exception = ArtifactBuildException(
|
||||
'message',
|
||||
fixRecommendation: 'some recommendation',
|
||||
stderr: [
|
||||
'some stderr output',
|
||||
'FAILURE: Build failed with an exception.',
|
||||
'* Exception is:',
|
||||
'some stack trace',
|
||||
'* Try:',
|
||||
'some recommendation',
|
||||
],
|
||||
stdout: ['some stdout output'],
|
||||
);
|
||||
expect(
|
||||
exception.flutterError,
|
||||
'FAILURE: Build failed with an exception.',
|
||||
);
|
||||
expect(exception.fixRecommendation, equals('some recommendation'));
|
||||
group('xcode archiving', () {
|
||||
group(
|
||||
'when a known error is recognized and a fix recommendation is found',
|
||||
() {
|
||||
test('has a Flutter error and a fix recommendation', () {
|
||||
final exception = ArtifactBuildException(
|
||||
'message',
|
||||
stderr: [
|
||||
'some stderr output',
|
||||
'Error (Xcode):',
|
||||
'some error message',
|
||||
'some stack trace',
|
||||
'some recommendation',
|
||||
'Encountered error while archiving for device',
|
||||
'not part of the reported error',
|
||||
],
|
||||
stdout: ['some stdout output'],
|
||||
);
|
||||
expect(
|
||||
exception.flutterError,
|
||||
equals(
|
||||
'''
|
||||
Error (Xcode):
|
||||
some error message
|
||||
some stack trace
|
||||
some recommendation''',
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user