Merge "Merge branch 'stable-3.1'"

This commit is contained in:
Luca Milanesio
2019-10-22 20:51:20 +00:00
committed by Gerrit Code Review
6 changed files with 557 additions and 233 deletions

View File

@@ -9,7 +9,7 @@ config file that controls many host specific settings for Gerrit.
The contents of the `etc/gerrit.config` file are cached at startup
by Gerrit. For most properties, if they are modified in this file, Gerrit
needs to be restarted before it will use the new values. Some properties
support being link:#reloadConfig[`reloaded`]' without restart.
support being link:#reloadConfig[`reloaded`] without restart.
Sample `etc/gerrit.config`:
----

310
Jenkinsfile vendored Normal file
View File

@@ -0,0 +1,310 @@
#!/usr/bin/env groovy
// Copyright (C) 2019 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 groovy.json.JsonSlurper
import groovy.json.JsonOutput
class Globals {
static final String gerritUrl = "https://gerrit-review.googlesource.com/"
static final String gerritCredentialsId = "gerrit-review.googlesource.com"
static final long curlTimeout = 10000
static final int waitForResultTimeout = 10000
static final String gerritRepositoryNameSha1Suffix = "-a6a0e4682515f3521897c5f950d1394f4619d928"
static final resTicks = [ 'ABORTED':'\u26aa', 'SUCCESS':'\u2705', 'FAILURE':'\u274c' ]
}
class Change {
static String sha1 = ""
static String number = ""
static String branch = ""
static String ref = ""
static String patchNum = ""
static String url = ""
}
class Build {
String url
String result
Build(url, result) {
this.url = url
this.result = result
}
}
class Builds {
static Set<String> modes = []
static Build codeStyle = null
static Map verification = [:]
}
class GerritCheck {
String uuid
String changeNum
String sha1
Build build
GerritCheck(name, changeNum, sha1, build) {
this.uuid = "gerritforge:" + name.replaceAll("(bazel/)", "") +
Globals.gerritRepositoryNameSha1Suffix
this.changeNum = changeNum
this.sha1 = sha1
this.build = build
}
def getCheckResultFromBuild() {
switch(build.result) {
case 'SUCCESS':
return "SUCCESSFUL"
case 'NOT_BUILT':
case 'ABORTED':
return "NOT_STARTED"
case 'FAILURE':
case 'UNSTABLE':
default:
return "FAILED"
}
}
def createCheckPayload() {
return JsonOutput.toJson([
checker_uuid: uuid,
state: getCheckResultFromBuild(),
url: "${build.url}consoleText"
])
}
}
def postCheck(check) {
def gerritPostUrl = Globals.gerritUrl +
"a/changes/${check.changeNum}/revisions/${check.sha1}/checks"
try {
def json = check.createCheckPayload()
httpRequest(httpMode: 'POST', authentication: Globals.gerritCredentialsId,
contentType: 'APPLICATION_JSON', requestBody: json,
validResponseCodes: '200', url: gerritPostUrl)
echo "----------------------------------------------------------------------------"
echo "Gerrit Check: ${check.uuid}=" + check.build.result + " to change " +
check.changeNum + "/" + check.sha1
echo "----------------------------------------------------------------------------"
} catch(Exception e) {
echo "ERROR> Failed to post check results to Gerrit: ${e}"
}
}
def queryChangedFiles(url, changeNum, sha1) {
def queryUrl = "${url}changes/${Change.number}/revisions/${Change.sha1}/files/"
def response = httpRequest queryUrl
def files = response.getContent().substring(5)
def filesJson = new JsonSlurper().parseText(files)
return filesJson.keySet().findAll { it != "/COMMIT_MSG" }
}
def queryChange(){
def requestedChangeId = env.BRANCH_NAME.split('/')[1]
def queryUrl = "${Globals.gerritUrl}changes/${requestedChangeId}/?pp=0&O=3"
def response = httpRequest queryUrl
def jsonSlurper = new JsonSlurper()
return jsonSlurper.parseText(response.getContent().substring(5))
}
def getChangeMetaData(){
def changeJson = queryChange()
Change.sha1 = changeJson.current_revision
Change.number = changeJson._number
Change.branch = changeJson.branch
def revision = changeJson.revisions.get(Change.sha1)
Change.ref = revision.ref
Change.patchNum = revision._number
Change.url = Globals.gerritUrl + "#/c/" + Change.number + "/" + Change.patchNum
}
def collectBuildModes() {
Builds.modes = ["notedb"]
def changedFiles = queryChangedFiles(Globals.gerritUrl, Change.number, Change.sha1)
def polygerritFiles = changedFiles.findAll { it.startsWith("polygerrit-ui") ||
it.startsWith("lib/js") }
if(polygerritFiles.size() > 0 || changedFiles.contains("WORKSPACE")) {
if(changedFiles.size() == polygerritFiles.size()) {
println "Only PolyGerrit UI changes detected, skipping other test modes..."
Builds.modes = ["polygerrit"]
} else {
println "PolyGerrit UI changes detected, adding 'polygerrit' validation..."
Builds.modes += "polygerrit"
}
}
}
def prepareBuildsForMode(buildName, mode="notedb", retryTimes = 1) {
def propagate = retryTimes == 1 ? false : true
return {
stage("${buildName}/${mode}") {
catchError{
retry(retryTimes){
def slaveBuild = build job: "${buildName}", parameters: [
string(name: 'REFSPEC', value: Change.ref),
string(name: 'BRANCH', value: Change.sha1),
string(name: 'CHANGE_URL', value: Change.url),
string(name: 'MODE', value: mode),
string(name: 'TARGET_BRANCH', value: Change.branch)
], propagate: propagate
if (buildName == "Gerrit-codestyle"){
Builds.codeStyle = new Build(
slaveBuild.getAbsoluteUrl(), slaveBuild.getResult())
} else {
Builds.verification[mode] = new Build(
slaveBuild.getAbsoluteUrl(), slaveBuild.getResult())
}
}
}
}
}
}
def collectBuilds() {
def builds = [:]
builds["Gerrit-codestyle"] = prepareBuildsForMode("Gerrit-codestyle")
Builds.modes.each {
builds["Gerrit-verification(${it})"] = prepareBuildsForMode("Gerrit-verifier-bazel", it)
}
return builds
}
def findFlakyBuilds() {
def flaky = Builds.verification.findAll { it.value.result == null ||
it.value.result != 'SUCCESS' }
if(flaky.size() == Builds.verification.size()) {
return []
}
def retryBuilds = []
flaky.each {
def mode = it.key
Builds.verification.remove(mode)
retryBuilds += mode
}
return retryBuilds
}
def getLabelValue(acc, res) {
if(res == null || res == 'ABORTED') {
return 0
}
switch(acc) {
case 0: return 0
case 1:
if(res == null) {
return 0;
}
switch(res) {
case 'SUCCESS': return +1;
case 'FAILURE': return -1;
default: return 0;
}
case -1: return -1
}
}
def setResult(resultVerify, resultCodeStyle) {
if (resultVerify == 0 || resultCodeStyle == 0) {
currentBuild.result = 'ABORTED'
} else if (resultVerify == -1 || resultCodeStyle == -1) {
currentBuild.result = 'FAILURE'
} else {
currentBuild.result = 'SUCCESS'
}
}
def findCodestyleFilesInLog(build) {
def codeStyleFiles = []
def needsFormatting = false
def response = httpRequest "${build.url}consoleText"
response.content.eachLine {
needsFormatting = needsFormatting || (it ==~ /.*Need Formatting.*/)
if(needsFormatting && it ==~ /\[.*\]/) {
codeStyleFiles += it.substring(1,it.length()-1)
}
}
return codeStyleFiles
}
def createCodeStyleMsgBody(build, label) {
def codeStyleFiles = findCodestyleFilesInLog(build)
def formattingMsg = label < 0 ? ('The following files need formatting:\n ' +
codeStyleFiles.join('\n ')) : 'All files are correctly formatted'
def url = build.url + "consoleText"
return "${Globals.resTicks[build.result]} $formattingMsg\n (${url})"
}
def createVerifyMsgBody(builds) {
def msgList = builds.collect { type, build -> [
'type': type, 'res': build.result, 'url': build.url + "consoleText" ]
}
return msgList.collect {
"${Globals.resTicks[it.res]} ${it.type} : ${it.res}\n (${it.url})"
} .join('\n')
}
node ('master') {
stage('Preparing'){
gerritReview labels: ['Verified': 0, 'Code-Style': 0]
getChangeMetaData()
collectBuildModes()
}
parallel(collectBuilds())
stage('Retry Flaky Builds'){
def flakyBuildsModes = findFlakyBuilds()
if (flakyBuildsModes.size() > 0){
parallel flakyBuildsModes.collectEntries {
["Gerrit-verification(${it})" :
prepareBuildsForMode("Gerrit-verifier-bazel", it, 3)]
}
}
}
stage('Report to Gerrit'){
resCodeStyle = getLabelValue(1, Builds.codeStyle.result)
gerritReview(
labels: ['Code-Style': resCodeStyle],
message: createCodeStyleMsgBody(Builds.codeStyle, resCodeStyle))
postCheck(new GerritCheck("codestyle", Change.number, Change.sha1, Builds.codeStyle))
def verificationResults = Builds.verification.collect { k, v -> v }
def resVerify = verificationResults.inject(1) {
acc, build -> getLabelValue(acc, build.result)
}
gerritReview(
labels: ['Verified': resVerify],
message: createVerifyMsgBody(Builds.verification))
Builds.verification.each { type, build -> postCheck(
new GerritCheck(type, Change.number, Change.sha1, build)
)}
setResult(resVerify, resCodeStyle)
}
}

View File

@@ -22,6 +22,9 @@ languages included. Build it with the following:
$> # start in some temp directory
$> git clone https://github.com/highlightjs/highlight.js
$> cd highlight.js
$> git clone https://github.com/highlightjs/highlightjs-closure-templates
$> ln -s ../../highlightjs-closure-templates/soy.js src/languages/soy.js
$> mkdir test/detect/soy && ln -s ../../../highlightjs-closure-templates/test/detect/soy/default.txt test/detect/soy/default.txt
$> npm install
$> node tools/build.js -n

File diff suppressed because one or more lines are too long

View File

@@ -78,6 +78,7 @@
'text/x-scss': 'scss',
'text/x-scheme': 'scheme',
'text/x-shell': 'shell',
'text/x-soy': 'soy',
'text/x-spreadsheet': 'excel',
'text/x-sh': 'bash',
'text/x-sql': 'sql',

View File

@@ -100,8 +100,12 @@ HISTORY.md = text/x-gfm
in = text/x-properties
ini = text/x-properties
intr = text/x-dylan
j2 = text/x-jinja2
jade = text/x-pug
java = text/x-java
Jenkinsfile = text/x-groovy
jinja = text/x-jinja2
jinja2 = text/x-jinja2
jl = text/x-julia
jruby = text/x-ruby
js = text/javascript