Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
c8266d34
Unverified
Commit
c8266d34
authored
Feb 18, 2022
by
Emmanuel Garcia
Committed by
GitHub
Feb 18, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Improve Gradle retry logic (#96554)
parent
f9921ebc
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
69 additions
and
68 deletions
+69
-68
gradle.dart
packages/flutter_tools/lib/src/android/gradle.dart
+43
-31
gradle_errors.dart
packages/flutter_tools/lib/src/android/gradle_errors.dart
+2
-2
android_gradle_builder_test.dart
...st/general.shard/android/android_gradle_builder_test.dart
+16
-19
gradle_errors_test.dart
..._tools/test/general.shard/android/gradle_errors_test.dart
+8
-16
No files found.
packages/flutter_tools/lib/src/android/gradle.dart
View file @
c8266d34
...
...
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:math'
;
import
'package:crypto/crypto.dart'
;
import
'package:meta/meta.dart'
;
import
'package:process/process.dart'
;
...
...
@@ -106,6 +108,9 @@ Iterable<String> _apkFilesFor(AndroidBuildInfo androidBuildInfo) {
return
<
String
>[
'app
$flavorString
-
$buildType
.apk'
];
}
// The maximum time to wait before the tool retries a Gradle build.
const
Duration
kMaxRetryTime
=
Duration
(
seconds:
10
);
/// An implementation of the [AndroidBuilder] that delegates to gradle.
class
AndroidGradleBuilder
implements
AndroidBuilder
{
AndroidGradleBuilder
({
...
...
@@ -212,7 +217,7 @@ class AndroidGradleBuilder implements AndroidBuilder {
/// * [target] is the target dart entry point. Typically, `lib/main.dart`.
/// * If [isBuildingBundle] is `true`, then the output artifact is an `*.aab`,
/// otherwise the output artifact is an `*.apk`.
/// * [
retries] is the max number of build retries in case one of the [GradleHandledError] handler
/// * [
maxRetries] If not `null`, this is the max number of build retries in case a retry is triggered.
Future
<
void
>
buildGradleApp
({
required
FlutterProject
project
,
required
AndroidBuildInfo
androidBuildInfo
,
...
...
@@ -221,7 +226,8 @@ class AndroidGradleBuilder implements AndroidBuilder {
required
List
<
GradleHandledError
>
localGradleErrors
,
bool
validateDeferredComponents
=
true
,
bool
deferredComponentsEnabled
=
false
,
int
retries
=
1
,
int
retry
=
0
,
@visibleForTesting
int
?
maxRetries
,
})
async
{
assert
(
project
!=
null
);
assert
(
androidBuildInfo
!=
null
);
...
...
@@ -401,38 +407,44 @@ class AndroidGradleBuilder implements AndroidBuilder {
'Gradle task
$assembleTask
failed with exit code
$exitCode
'
,
exitCode:
exitCode
,
);
}
else
{
final
GradleBuildStatus
status
=
await
detectedGradleError
!.
handler
(
line:
detectedGradleErrorLine
!,
project:
project
,
usesAndroidX:
usesAndroidX
,
multidexEnabled:
androidBuildInfo
.
multidexEnabled
,
);
}
final
GradleBuildStatus
status
=
await
detectedGradleError
!.
handler
(
line:
detectedGradleErrorLine
!,
project:
project
,
usesAndroidX:
usesAndroidX
,
multidexEnabled:
androidBuildInfo
.
multidexEnabled
,
);
if
(
retries
>=
1
)
{
final
String
successEventLabel
=
'gradle-
${detectedGradleError!.eventLabel}
-success'
;
switch
(
status
)
{
case
GradleBuildStatus
.
retry
:
await
buildGradleApp
(
project:
project
,
androidBuildInfo:
androidBuildInfo
,
target:
target
,
isBuildingBundle:
isBuildingBundle
,
localGradleErrors:
localGradleErrors
,
retries:
retries
-
1
,
);
BuildEvent
(
successEventLabel
,
type:
'gradle'
,
flutterUsage:
_usage
).
send
();
return
;
case
GradleBuildStatus
.
exit
:
// noop.
}
if
(
maxRetries
==
null
||
retry
<
maxRetries
)
{
switch
(
status
)
{
case
GradleBuildStatus
.
retry
:
// Use binary exponential backoff before retriggering the build.
// The expected wait times are: 100ms, 200ms, 400ms, and so on...
final
int
waitTime
=
min
(
pow
(
2
,
retry
).
toInt
()
*
100
,
kMaxRetryTime
.
inMicroseconds
);
retry
+=
1
;
_logger
.
printStatus
(
'Retrying Gradle Build: #
$retry
, wait time:
${waitTime}
ms'
);
await
Future
<
void
>.
delayed
(
Duration
(
milliseconds:
waitTime
));
await
buildGradleApp
(
project:
project
,
androidBuildInfo:
androidBuildInfo
,
target:
target
,
isBuildingBundle:
isBuildingBundle
,
localGradleErrors:
localGradleErrors
,
retry:
retry
,
maxRetries:
maxRetries
,
);
final
String
successEventLabel
=
'gradle-
${detectedGradleError!.eventLabel}
-success'
;
BuildEvent
(
successEventLabel
,
type:
'gradle'
,
flutterUsage:
_usage
).
send
();
return
;
case
GradleBuildStatus
.
exit
:
// Continue and throw tool exit.
}
BuildEvent
(
'gradle-
${detectedGradleError?.eventLabel}
-failure'
,
type:
'gradle'
,
flutterUsage:
_usage
).
send
();
throwToolExit
(
'Gradle task
$assembleTask
failed with exit code
$exitCode
'
,
exitCode:
exitCode
,
);
}
BuildEvent
(
'gradle-
${detectedGradleError?.eventLabel}
-failure'
,
type:
'gradle'
,
flutterUsage:
_usage
).
send
();
throwToolExit
(
'Gradle task
$assembleTask
failed with exit code
$exitCode
'
,
exitCode:
exitCode
,
);
}
if
(
isBuildingBundle
)
{
...
...
packages/flutter_tools/lib/src/android/gradle_errors.dart
View file @
c8266d34
...
...
@@ -226,8 +226,8 @@ final GradleHandledError networkErrorHandler = GradleHandledError(
required
bool
multidexEnabled
,
})
async
{
globals
.
printError
(
'
${globals.logger.terminal.warningMark}
Gradle threw an error while downloading artifacts from the network.
'
'
Retrying to download..
.'
'
${globals.logger.terminal.warningMark}
'
'
Gradle threw an error while downloading artifacts from the network
.'
);
try
{
final
String
?
homeDir
=
globals
.
platform
.
environment
[
'HOME'
];
...
...
packages/flutter_tools/test/general.shard/android/android_gradle_builder_test.dart
View file @
c8266d34
...
...
@@ -138,22 +138,8 @@ void main() {
gradleUtils:
FakeGradleUtils
(),
platform:
FakePlatform
(),
);
processManager
.
addCommand
(
const
FakeCommand
(
command:
<
String
>[
'gradlew'
,
'-q'
,
'-Ptarget-platform=android-arm,android-arm64,android-x64'
,
'-Ptarget=lib/main.dart'
,
'-Pbase-application-name=io.flutter.app.FlutterApplication'
,
'-Pdart-obfuscation=false'
,
'-Ptrack-widget-creation=false'
,
'-Ptree-shake-icons=false'
,
'assembleRelease'
,
],
exitCode:
1
,
stderr:
'
\n
Some gradle message
\n
'
));
processManager
.
addCommand
(
const
FakeCommand
(
const
FakeCommand
fakeCmd
=
FakeCommand
(
command:
<
String
>[
'gradlew'
,
'-q'
,
...
...
@@ -166,8 +152,15 @@ void main() {
'assembleRelease'
,
],
exitCode:
1
,
stderr:
'
\n
Some gradle message
\n
'
));
stderr:
'
\n
Some gradle message
\n
'
,
);
processManager
.
addCommand
(
fakeCmd
);
const
int
maxRetries
=
2
;
for
(
int
i
=
0
;
i
<
maxRetries
;
i
++)
{
processManager
.
addCommand
(
fakeCmd
);
}
fileSystem
.
directory
(
'android'
)
.
childFile
(
'build.gradle'
)
...
...
@@ -186,6 +179,7 @@ void main() {
int
testFnCalled
=
0
;
await
expectLater
(()
async
{
await
builder
.
buildGradleApp
(
maxRetries:
maxRetries
,
project:
FlutterProject
.
fromDirectoryTest
(
fileSystem
.
currentDirectory
),
androidBuildInfo:
const
AndroidBuildInfo
(
BuildInfo
(
...
...
@@ -221,7 +215,10 @@ void main() {
message:
'Gradle task assembleRelease failed with exit code 1'
));
expect
(
testFnCalled
,
equals
(
2
));
expect
(
logger
.
statusText
,
contains
(
'Retrying Gradle Build: #1, wait time: 100ms'
));
expect
(
logger
.
statusText
,
contains
(
'Retrying Gradle Build: #2, wait time: 200ms'
));
expect
(
testFnCalled
,
equals
(
maxRetries
+
1
));
expect
(
testUsage
.
events
,
contains
(
const
TestUsageEvent
(
'build'
,
...
...
packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart
View file @
c8266d34
...
...
@@ -102,8 +102,7 @@ at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:61)''';
expect
(
testLogger
.
errorText
,
contains
(
'Gradle threw an error while downloading artifacts from the network. '
'Retrying to download...'
'Gradle threw an error while downloading artifacts from the network.'
)
);
},
overrides:
<
Type
,
Generator
>{
...
...
@@ -133,8 +132,7 @@ at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:61)''';
expect
(
testLogger
.
errorText
,
contains
(
'Gradle threw an error while downloading artifacts from the network. '
'Retrying to download...'
'Gradle threw an error while downloading artifacts from the network.'
)
);
},
overrides:
<
Type
,
Generator
>{
...
...
@@ -155,8 +153,7 @@ Exception in thread "main" java.lang.RuntimeException: Timeout of 120000 reached
expect
(
testLogger
.
errorText
,
contains
(
'Gradle threw an error while downloading artifacts from the network. '
'Retrying to download...'
'Gradle threw an error while downloading artifacts from the network.'
)
);
},
overrides:
<
Type
,
Generator
>{
...
...
@@ -193,8 +190,7 @@ Exception in thread "main" javax.net.ssl.SSLHandshakeException: Remote host clos
expect
(
testLogger
.
errorText
,
contains
(
'Gradle threw an error while downloading artifacts from the network. '
'Retrying to download...'
'Gradle threw an error while downloading artifacts from the network.'
)
);
},
overrides:
<
Type
,
Generator
>{
...
...
@@ -223,8 +219,7 @@ Exception in thread "main" java.io.FileNotFoundException: https://downloads.grad
expect
(
testLogger
.
errorText
,
contains
(
'Gradle threw an error while downloading artifacts from the network. '
'Retrying to download...'
'Gradle threw an error while downloading artifacts from the network.'
)
);
},
overrides:
<
Type
,
Generator
>{
...
...
@@ -264,8 +259,7 @@ Exception in thread "main" java.net.SocketException: Connection reset
expect
(
testLogger
.
errorText
,
contains
(
'Gradle threw an error while downloading artifacts from the network. '
'Retrying to download...'
'Gradle threw an error while downloading artifacts from the network.'
)
);
},
overrides:
<
Type
,
Generator
>{
...
...
@@ -292,8 +286,7 @@ A problem occurred configuring root project 'android'.
expect(testLogger.errorText,
contains(
'
Gradle
threw
an
error
while
downloading
artifacts
from
the
network
.
'
'
Retrying
to
download
...
'
'
Gradle
threw
an
error
while
downloading
artifacts
from
the
network
.
'
)
);
}, overrides: <Type, Generator>{
...
...
@@ -324,8 +317,7 @@ A problem occurred configuring root project 'android'.
expect(testLogger.errorText,
contains(
'
Gradle
threw
an
error
while
downloading
artifacts
from
the
network
.
'
'
Retrying
to
download
...
'
'
Gradle
threw
an
error
while
downloading
artifacts
from
the
network
.
'
)
);
}, overrides: <Type, Generator>{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment