Retry flaky builds up to 3 times
Change-Id: Idb6dbfd80a9148c4c919e548dfe04bc77227634f
diff --git a/jenkins/gerrit-verifier-change.groovy b/jenkins/gerrit-verifier-change.groovy
index 32685ab..b769aea 100644
--- a/jenkins/gerrit-verifier-change.groovy
+++ b/jenkins/gerrit-verifier-change.groovy
@@ -129,19 +129,21 @@
filesJson.keySet().findAll { it != "/COMMIT_MSG" }
}
-def buildsForMode(refspec,sha1,changeUrl,mode,tools,targetBranch) {
+def buildsForMode(refspec,sha1,changeUrl,mode,tools,targetBranch,retryTimes) {
def builds = []
for (tool in tools) {
def buildName = "Gerrit-verifier-$tool"
def key = "$tool/$mode"
builds += {
- Globals.buildsList.put(key,
- build(buildName, REFSPEC: refspec, BRANCH: sha1,
- CHANGE_URL: changeUrl, MODE: mode, TARGET_BRANCH: targetBranch))
- println "Builds status:"
- Globals.buildsList.each {
- n, v -> println " $n : ${v.getResult()}\n (${v.getBuildUrl() + "console"})"
- }
+ retry (retryTimes) {
+ Globals.buildsList.put(key,
+ build(buildName, REFSPEC: refspec, BRANCH: sha1,
+ CHANGE_URL: changeUrl, MODE: mode, TARGET_BRANCH: targetBranch))
+ println "Builds status:"
+ Globals.buildsList.each {
+ n, v -> println " $n : ${v.getResult()}\n (${v.getBuildUrl() + "console"})"
+ }
+ }
}
}
return builds
@@ -216,14 +218,27 @@
def builds = []
println "Running validation jobs using $tools builds for $modes ..."
- modes.collect { buildsForMode(refspec,sha1,changeUrl,it,tools,branch) }.each { builds += it }
+ modes.collect { buildsForMode(refspec,sha1,changeUrl,it,tools,branch,1) }.each { builds += it }
- ignore(FAILURE) {
- parallel (builds)
+ def buildsWithResults = parallelBuilds(builds)
+
+ flaky = flakyBuilds(buildsWithResults)
+ if(flaky.size > 0) {
+ println "** FLAKY Builds detected: ${flaky}"
+
+ def retryBuilds = []
+ def toolsAndModes = flaky.collect { it.split("/") }
+
+ toolsAndModes.each {
+ def tool = it[0]
+ def mode = it[1]
+ Globals.buildsList.remove(it)
+ retryBuilds += buildsForMode(refspec,sha1,changeUrl,mode,[tool],branch,3)
+ }
+ buildsWithResults = parallelBuilds(retryBuilds)
}
- def results = Globals.buildsList.values().collect { waitForResult(it) }
- def res = results.inject(1) { acc, buildResult -> getVerified(acc, buildResult) }
+ def res = buildsWithResults.inject(1) { acc, buildResult -> getVerified(acc, buildResult[1]) }
gerritReview(build.startJob.getBuildUrl() + "console", changeNum, sha1, res, "")
@@ -237,6 +252,27 @@
}
}
+def parallelBuilds(builds) {
+ ignore(FAILURE) {
+ parallel (builds)
+ }
+ def results = Globals.buildsList.values().collect { waitForResult(it) }
+ def buildsWithResults = []
+
+ Globals.buildsList.keySet().eachWithIndex {
+ key,index -> buildsWithResults.add(new Tuple(key, results[index]))
+ }
+ return buildsWithResults
+}
+
+def flakyBuilds(buildsWithResults) {
+ def flaky = buildsWithResults.findAll { it[1] == null || it[1] != SUCCESS }
+ if(flaky.size == buildsWithResults.size) {
+ return []
+ }
+
+ return flaky.collect { it[0] }
+}
def lastBuild = build.getPreviousSuccessfulBuild()
def logOut = new ByteArrayOutputStream()