blob: 117f7115c6501974d84049f3c8510617dd50fb24 [file] [log] [blame]
// Copyright (C) 2015 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import hudson.model.*
import hudson.AbortException
import hudson.console.HyperlinkNote
import java.util.concurrent.CancellationException
import groovy.json.*
import java.text.*
String.metaClass.encodeURL = {
java.net.URLEncoder.encode(delegate)
}
class Globals {
static String gerrit = "https://gerrit-review.googlesource.com/"
static String jenkins = "https://gerrit-ci.gerritforge.com/"
static String gerritReviewer = "GerritForge CI <gerritforge@gmail.com>"
static long curlTimeout = 10000
static SimpleDateFormat tsFormat = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss.S Z")
static int maxChanges = 100
static int numRetryBuilds = 3
static int myAccountId = 1022687
static int waitForResultTimeout = 10000
static int maxBuilds = 16
static String verifierJobName = "Gerrit-verifier-change"
}
def lastBuild = build.getPreviousSuccessfulBuild()
def lastBuildStartTimeMillis = lastBuild == null ?
(System.currentTimeMillis() - 1800000) : lastBuild.getStartTimeInMillis()
def sinceMillis = lastBuildStartTimeMillis - (24 * 3600 * 1000)
def since = Globals.tsFormat.format(new Date(sinceMillis))
if(lastBuild != null) {
println "Last successful build was " + lastBuild.toString()
}
println ""
println "Querying Gerrit for last modified changes since ${since} ..."
def gerritQuery = "status:open project:gerrit since:\"" + since + "\""
queryUrl = new URL(Globals.gerrit + "changes/?pp=0&o=CURRENT_REVISION&o=DETAILED_ACCOUNTS&o=DETAILED_LABELS&n=" + Globals.maxChanges + "&q=" +
gerritQuery.encodeURL())
def changes = queryUrl.getText().substring(5)
def jsonSlurper = new JsonSlurper()
def changesJson = jsonSlurper.parseText(changes)
def getBuildRunsInProgress() {
def verifierChangeJob = Hudson.instance.getJob(Globals.verifierJobName)
def verifierRuns = verifierChangeJob.builds
def pendingBuilds = verifierRuns.findAll { it.building }
return pendingBuilds
}
def changeOfBuildRun(run) {
def params = run.allActions.findAll { it in hudson.model.ParametersAction }
return params.collect { it.getParameter("CHANGE_ID").value }
}
def changeUrl(change) {
"${Globals.gerrit}${change}"
}
def acceptedChanges = changesJson.findAll {
change ->
sha1 = change.current_revision
if(sha1 == null) {
println "[WARNING] Skipping change ${changeUrl(change._number)} because it does not have any current revision or patch-set"
return false
}
if(change.hashtags.contains("skipci")) {
println "[WARNING] Skipping change ${changeUrl(change._number)} because it is tagged with #skipci"
return false
}
def canBeVerified = change.labels.Verified
if(canBeVerified != null) {
def verified = canBeVerified.all
if(verified == null) {
true
} else {
def myVerifications = verified.findAll {
verification -> verification._account_id == Globals.myAccountId && verification.value != 0
}
return myVerifications.empty
}
}
}
def inProgress = getBuildRunsInProgress()
if(!inProgress.empty) {
println ""
println "Changes currently in progress: "
inProgress.each {
b -> println("Change ${changeUrl(changeOfBuildRun(b)[0])}: ${Globals.jenkins}${b.url}")
}
}
def inProgressChangesNums = inProgress.collect { changeOfBuildRun(it) }.flatten()
def todoChangesNums = acceptedChanges.collect { "${it._number}" }
def filteredChanges = todoChangesNums - inProgressChangesNums
def buildsBandwith = Globals.maxBuilds - inProgressChangesNums.size
println ""
println "Gerrit has " + filteredChanges.size() + " change(s) since " + since + " $filteredChanges"
if(buildsBandwith <= 0) {
println "... but there is NO bandwidth for further builds yet"
}
else {
if(filteredChanges.size() > buildsBandwith) {
println "... but I've got bandwidth for only ${buildsBandwith} of them at the moment"
}
}
println "================================================================================"
if(buildsBandwith > 0) {
def changesTodo = filteredChanges.reverse().take(buildsBandwith)
changesTodo.each {
println "Building change: ${changeUrl(it)} ..."
}
def builds = changesTodo.collect { change -> { -> build(Globals.verifierJobName, CHANGE_ID: change) } }
parallel(builds)
}