Created
October 17, 2019 05:15
-
-
Save angelworm/a658d7972cc361ffd3b4ab6b45c5420f to your computer and use it in GitHub Desktop.
Review Boardに投げられたレビューをJenkinsでビルドする。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash -xu | |
## Required Environment Variables | |
# | |
# REVIEWBOARD_TOKEN: Access tokens for Review Board user. | |
# REVIEW_DIFF_URL: Posted review request URL. (ex. https://example.org/reviews/api/review-requests/99999/diffs/1/) | |
# | |
# upgrade workspace(for unexpectedly subversion binary upgrade) | |
svn upgrade | |
# remove untracked files(clean check out) | |
svn status | grep '^?' | awk '{print $2}' | xargs rm -rfv | |
# fetch specified diff. | |
curl -sL \ | |
-H "Authorization: token ${REVIEWBOARD_TOKEN}" \ | |
-H "Accept: text/x-patch" \ | |
${REVIEW_DIFF_URL} \ | |
> review.patch | |
# fetch diff information | |
curl -sL \ | |
-H "Authorization: token ${REVIEWBOARD_TOKEN}" \ | |
${REVIEW_DIFF_URL} \ | |
> review_info.json | |
BASEDIR=$(python << EOL | |
import sys, json, re | |
with open('review_info.json', 'r') as target: | |
basedir = json.load(target).get('diff', {}).get('basedir', '.') | |
print(basedir) | |
EOL | |
) | |
# patches diff | |
rm -f REJECT.diff | |
grep -E '^Index:' review.patch | sed "s|^Index: /\?|$BASEDIR/|g" | xargs sed -i 's/\r//g' || true | |
patch -p $STRIP_PATH_PREFIX -r REJECT.diff -l --binary -d $BASEDIR -i review.patch | |
# check patching is successful. | |
if [[ -s REJECT.diff ]]; then | |
echo "Patch Failed!" | |
exit 1 | |
fi |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import jenkins.model.* | |
import java.nio.file.* | |
def reviewBoardAPIURL = "https://example.org/reviews/api" | |
def jenkinsJobName = "jenkins_review_ci" | |
def requestId = build.envVars.REVIEW_REQUEST_ID | |
def diffUri = build.envVars.REVIEW_DIFF_URL | |
def token = "${REVIEWBOARD_TOKEN}" | |
def project = Jenkins.instance.projects.find { | |
it.name == jenkinsJobName | |
} | |
def build = project.builds.find { | |
it.id == "${TARGET_JOB_ID}" | |
} | |
def actions = build.actions | |
println "REVIEW_REQUEST_ID: ${requestId}" | |
println "TARGET_JOB_ID: ${TARGET_JOB_ID}" | |
/* *** *** collet new warnings *** *** */ | |
def newWarnings = actions.findAll { | |
it instanceof hudson.plugins.analysis.core.ResultAction | |
}.collect { | |
it.result.newWarnings | |
}.flatten() | |
if (newWarnings.isEmpty()) { | |
println "Review: No Errors Found!" | |
return | |
} | |
def r | |
/* *** *** collect diff lines *** *** */ | |
r = request(token, "GET", "${diffUri}files/", [ | |
"max-results": "200" | |
]) | |
def files = r.files | |
println "Files: ${files.collect {it.dest_file}}" | |
def updatedLines = r.files.collectEntries { | |
def fileUrl = it.links.self.href | |
def targetFileName = it.dest_file | |
def ri = request(token, "GET", fileUrl, new HashMap(), "application/vnd.reviewboard.org.diff.data+json") | |
def lines = ri.diff_data.chunks.findAll { | |
it.change != 'equal' && it.change != 'delete' | |
}.collect { | |
it.lines.collect { it[4] } | |
}.flatten() | |
[targetFileName, lines] | |
} | |
/* *** *** collect RR target annotations *** *** */ | |
def annots = newWarnings.collect { | |
def annot = it | |
def found = files.find { | |
def rfp = Paths.get(it.dest_file) | |
def afp = Paths.get(annot.pathName, annot.shortFileName) | |
rfp.endsWith(afp) | |
} | |
new Tuple(annot, found) | |
}.findAll { | |
def (a, f) = it | |
if (f == null) { | |
println "RR has not updated: reported: ${a.pathName}/${a.shortFileName}" | |
} | |
return f != null | |
}.findAll { | |
def (a, f) = it | |
if (!(a instanceof hudson.plugins.checkstyle.parser.Warning)) { | |
return true | |
} | |
// if (a instanceof hudson.plugins.warnings.parser.Warning) { | |
// return true | |
// } | |
def updated = updatedLines.find { | |
def rfp = Paths.get(f.dest_file) | |
def afp = Paths.get(it.key) | |
rfp.endsWith(afp) | |
} | |
def linums = updated ?. value ?: [] | |
def ret = a.lineRanges.any { al -> | |
linums.any { al.start <= it && it <= al.end } | |
} | |
if (!ret) { | |
println "Filtered: ${a.shortFileName}:${a.primaryLineNumber} ${a.message}" | |
} | |
ret | |
} | |
if (annots.isEmpty()) { | |
println "Review: No files matched." | |
return | |
} | |
/* *** *** DRY RUN MODE *** *** */ | |
if ("true" == "${DRY_RUN_MODE}") { | |
annots.each { | |
def (annot, found) = it | |
println "Review File: ${annot.pathName}/${annot.shortFileName}: (${annot.origin}) [${annot.type}]${annot.message}" | |
} | |
return | |
} | |
/* *** *** Post RR *** *** */ | |
r = request(token, "POST", "review-requests/${requestId}/reviews/", new HashMap()) | |
def reviewId = r.review.id | |
println "Review: #${reviewId}" | |
try { | |
annots.each { | |
def (annot, found) = it | |
println "Review File: ${annot.pathName}/${annot.shortFileName}:${annot.primaryLineNumber} : (${annot.origin}) [${annot.type}]${annot.message}" | |
request(token, "POST", "review-requests/${requestId}/reviews/${reviewId}/diff-comments/", [ | |
filediff_id: "${found.id}", | |
first_line: "${Math.max(0, annot.primaryLineNumber)}", | |
num_lines: "1", | |
issue_opened: "true", | |
text: "(${annot.origin}) [${annot.type}]${annot.message}" | |
]) | |
} | |
request(token, "PUT", "review-requests/${requestId}/reviews/${reviewId}/", [ | |
body_top: """ | |
BUILD ${build.result}: ${build.absoluteUrl} | |
""", | |
public: "true" | |
]) | |
} catch (Exception e) { | |
try { | |
request(token, "DELETE", "review-requests/${requestId}/reviews/${reviewId}/", new HashMap()) | |
} catch (Exception ie) { | |
e.addSuppressed(ie) | |
} | |
throw e | |
} | |
def request(String token, String method, String action, Map<String, String> params = [], String acceptType = "application/json") { | |
def requestUri = action.startsWith("http") ? action : "${reviewBoardAPIURL}/${action}" | |
def paramStr = params.collect { "${it.key}=${java.net.URLEncoder.encode(it.value, 'UTF-8')}" } join '&' | |
if (method.equalsIgnoreCase('GET')) { | |
requestUri = "${requestUri}?${paramStr}" | |
paramStr = "" | |
} | |
println "Request: ${method} ${requestUri}" | |
URL url = new URL(requestUri) | |
HttpURLConnection conn = (HttpURLConnection)url.openConnection() | |
conn.doInput = true | |
conn.setRequestMethod(method) | |
conn.setRequestProperty("Connection", "Keep-Alive") | |
conn.setRequestProperty("Authorization", "token ${token}") | |
conn.setRequestProperty("Accept", acceptType) | |
def bytes = paramStr.getBytes "UTF-8" | |
if (bytes.length != 0) { | |
conn.doOutput = true | |
conn.setRequestProperty "Content-Type", "application/x-www-form-urlencoded; charset=UTF-8" | |
conn.setRequestProperty "Content-Length", "${bytes.length}" | |
} | |
try { | |
if (bytes.length != 0) { | |
conn.outputStream.write(bytes) | |
conn.outputStream.flush() | |
} | |
conn.connect() | |
def r = new BufferedReader(new InputStreamReader(conn.inputStream)) | |
try { | |
def json = new groovy.json.JsonSlurper() | |
return json.parse(r) | |
} catch (NullPointerException e) { | |
return null | |
} finally { | |
r.close() | |
} | |
} finally { | |
conn.disconnect() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment