in src/main/java/org/apache/jenkins/gitpubsub/ASFGitSCMFileSystem.java [186:300]
public boolean changesSince(SCMRevision revision, @NonNull OutputStream changeLogStream)
throws UnsupportedOperationException, IOException, InterruptedException {
if (revision == null ? getRevision() == null : revision.equals(getRevision())) {
// special case where somebody is asking one of two stupid questions:
// 1. what has changed between the latest and the latest
// 2. what has changed between the current revision and the current revision
return false;
}
int count = 0;
SimpleDateFormat rfc = new SimpleDateFormat(RFC_2822);
FastDateFormat iso = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ssZ");
StringBuilder log = new StringBuilder(1024);
StringBuilder para = new StringBuilder(1024);
String endHash;
if (revision instanceof AbstractGitSCMSource.SCMRevisionImpl) {
endHash = ((AbstractGitSCMSource.SCMRevisionImpl) revision).getHash().toLowerCase(Locale.ENGLISH);
} else {
endHash = null;
}
// this is the format expected by GitSCM, so we need to format each GHCommit with the same format
// commit %H%ntree %T%nparent %P%nauthor %aN <%aE> %ai%ncommitter %cN <%cE> %ci%n%n%w(76,4,4)%s%n%n%b
UriTemplate shortLogTemplate = buildTemplateWithRemote("{+server}{?p}{;a,h,pg}", remote)
.set("a", "shortlog")
.set("h", refOrHash);
UriTemplate commitTemplate = buildTemplateWithRemote("{+server}{?p}{;a,h}", remote)
.set("a", "commit");
int pg = 0;
while (count < GitSCM.MAX_CHANGELOG) {
if (pg > 0) {
shortLogTemplate.set("pg", pg);
}
pg++;
Document doc = fetchDocument(shortLogTemplate.expand());
for (Element element : doc.select("table.shortlog tr td a.subject")) {
Matcher href = URL_EXTRACT_H.matcher(element.attr("href"));
if (!href.matches()) {
continue;
}
if (href.group(1).toLowerCase(Locale.ENGLISH).equals(endHash)) {
return count > 0;
}
commitTemplate.set("h", href.group(1));
Document commit = fetchDocument(commitTemplate.expand());
log.setLength(0);
Elements sha1s = commit.select("table.object_header tr td.sha1");
log.append("commit ").append(sha1s.get(0).text().trim()).append('\n');
log.append("tree ").append(sha1s.get(1).text().trim()).append('\n');
log.append("parent");
for (int i = 2; i < sha1s.size(); i++) {
log.append(' ').append(sha1s.get(i).text().trim());
}
log.append('\n');
Elements persons = commit.select("table.object_header tr");
try {
log.append("author ")
.append(persons.get(0).child(1).text().trim())
.append(' ')
.append(iso.format(rfc.parse(persons.get(1).child(1).text())))
.append('\n');
log.append("committer ")
.append(persons.get(2).child(1).text().trim())
.append(' ')
.append(iso.format(rfc.parse(persons.get(3).child(1).text())))
.append('\n');
} catch (ParseException e) {
throw new IOException(e);
}
log.append('\n');
Element messageDiv = commit.select("div.page_body").get(0);
para.setLength(0);
boolean inPara = false;
for (Node node : messageDiv.childNodes()) {
if (node instanceof TextNode) {
String s = ((TextNode) node).text().trim();
if (!s.isEmpty()) {
if (para.length() > 0) {
para.append(' ');
}
para.append(s.replace('\u00a0', '\u0020'));
inPara = true;
}
} else if (node instanceof Element) {
if (((Element) node).tagName().equalsIgnoreCase("br")) {
if (inPara) {
inPara = false;
} else {
if (para.length() > 0) {
log.append(" ")
.append(WordUtils.wrap(para.toString(), 72, "\n ", false));
para.setLength(0);
}
log.append("\n\n");
}
}
}
}
if (para.length() > 0) {
log.append(" ")
.append(WordUtils.wrap(para.toString(), 72, "\n ", false));
log.append('\n');
}
if (inPara) {
log.append('\n');
}
log.append('\n');
changeLogStream.write(log.toString().getBytes(StandardCharsets.UTF_8));
changeLogStream.flush();
count++;
if (count >= GitSCM.MAX_CHANGELOG) {
break;
}
}
}
return count > 0;
}