com.liferay.jenkins.results.parser.BatchBuild Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of com.liferay.jenkins.results.parser
Show all versions of com.liferay.jenkins.results.parser
Liferay Jenkins Results Parser
/**
* SPDX-FileCopyrightText: (c) 2000 Liferay, Inc. https://liferay.com
* SPDX-License-Identifier: LGPL-2.1-or-later OR LicenseRef-Liferay-DXP-EULA-2.0.0-2023-06
*/
package com.liferay.jenkins.results.parser;
import com.liferay.jenkins.results.parser.failure.message.generator.ClosedChannelExceptionFailureMessageGenerator;
import com.liferay.jenkins.results.parser.failure.message.generator.FailureMessageGenerator;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.dom4j.Element;
import org.json.JSONArray;
import org.json.JSONObject;
/**
* @author Kevin Yen
*/
public class BatchBuild extends BaseParentBuild {
@Override
public void addTimelineData(TimelineData timelineData) {
addDownstreamBuildsTimelineData(timelineData);
}
@Override
public URL getArtifactsBaseURL() {
TopLevelBuild topLevelBuild = getTopLevelBuild();
StringBuilder sb = new StringBuilder();
sb.append(topLevelBuild.getArtifactsBaseURL());
sb.append("/");
sb.append(getParameterValue("JOB_VARIANT"));
try {
return new URL(sb.toString());
}
catch (MalformedURLException malformedURLException) {
return null;
}
}
public String getBatchName() {
return batchName;
}
@Override
public String getBuildName() {
String buildName = getJobVariant();
if (JenkinsResultsParserUtil.isNullOrEmpty(buildName)) {
buildName = getJobName();
}
return buildName;
}
public List getDownstreamAxisBuilds() {
List downstreamAxisBuilds = new ArrayList<>();
List downstreamBuilds = getDownstreamBuilds(null);
for (Build downstreamBuild : downstreamBuilds) {
if (!(downstreamBuild instanceof AxisBuild)) {
continue;
}
downstreamAxisBuilds.add((AxisBuild)downstreamBuild);
}
Collections.sort(
downstreamAxisBuilds, new BaseBuild.BuildDisplayNameComparator());
return downstreamAxisBuilds;
}
@Override
public Element getGitHubMessageElement() {
sortDownstreamBuilds();
Element messageElement = super.getGitHubMessageElement();
if (messageElement == null) {
return null;
}
String result = getResult();
if (result.equals("ABORTED") && (getDownstreamBuildCount(null) == 0)) {
_gitHubMessageElement = messageElement;
return _gitHubMessageElement;
}
List failedDownstreamBuilds = getFailedDownstreamBuilds();
List downstreamBuildMessageElements =
getDownstreamBuildMessageElements(failedDownstreamBuilds);
if (result.equals("FAILURE") &&
downstreamBuildMessageElements.isEmpty()) {
_gitHubMessageElement = messageElement;
return _gitHubMessageElement;
}
List failureElements = new ArrayList<>();
List upstreamJobFailureElements = new ArrayList<>();
for (Build failedDownstreamBuild : failedDownstreamBuilds) {
Element gitHubMessageElement =
failedDownstreamBuild.getGitHubMessageElement();
if (gitHubMessageElement != null) {
failureElements.add(gitHubMessageElement);
}
Element gitHubMessageUpstreamJobFailureElement =
failedDownstreamBuild.
getGitHubMessageUpstreamJobFailureElement();
if (gitHubMessageUpstreamJobFailureElement != null) {
upstreamJobFailureElements.add(
gitHubMessageUpstreamJobFailureElement);
}
}
if (!upstreamJobFailureElements.isEmpty()) {
upstreamJobFailureMessageElement = getGitHubMessageElement(true);
Dom4JUtil.getOrderedListElement(
upstreamJobFailureElements, upstreamJobFailureMessageElement,
4);
}
Dom4JUtil.getOrderedListElement(failureElements, messageElement, 4);
if (failureElements.size() >= 4) {
Dom4JUtil.getNewElement(
"strong", messageElement, "Click ",
Dom4JUtil.getNewAnchorElement(
getBuildURL() + "testReport", "here"),
" for more failures.");
}
if (failureElements.isEmpty()) {
return null;
}
_gitHubMessageElement = messageElement;
return _gitHubMessageElement;
}
@Override
public Long getInvokedTime() {
if (invokedTime != null) {
return invokedTime;
}
StringBuilder sb = new StringBuilder();
sb.append("\\s*\\[echo\\]\\s*");
sb.append(Pattern.quote(getJobName()));
String jobVariant = getJobVariant();
if ((jobVariant != null) && !jobVariant.isEmpty()) {
sb.append("/");
sb.append(Pattern.quote(jobVariant));
}
sb.append("\\s*invoked time: (?[^\\n]*)");
Pattern pattern = Pattern.compile(sb.toString());
Build parentBuild = getParentBuild();
String parentConsoleText = parentBuild.getConsoleText();
for (String line : parentConsoleText.split("\n")) {
Matcher matcher = pattern.matcher(line);
if (!matcher.find()) {
continue;
}
Properties buildProperties = null;
try {
buildProperties = JenkinsResultsParserUtil.getBuildProperties();
}
catch (IOException ioException) {
throw new RuntimeException(
"Unable to get build properties", ioException);
}
SimpleDateFormat sdf = new SimpleDateFormat(
buildProperties.getProperty("jenkins.report.date.format"));
Date date = null;
try {
date = sdf.parse(matcher.group("invokedTime"));
}
catch (ParseException parseException) {
throw new RuntimeException(
"Unable to get invoked time", parseException);
}
invokedTime = date.getTime();
return invokedTime;
}
return getStartTime();
}
@Override
public Map getMetricLabels() {
Map metricLabels = super.getMetricLabels();
metricLabels.put("job_type", batchName);
return metricLabels;
}
@Override
public synchronized List getTestClassResults() {
List testClassResults = new ArrayList<>();
for (AxisBuild axisBuild : getDownstreamAxisBuilds()) {
testClassResults.addAll(axisBuild.getTestClassResults());
}
return testClassResults;
}
@Override
public synchronized List getTestResults() {
List testResults = new ArrayList<>();
for (AxisBuild axisBuild : getDownstreamAxisBuilds()) {
testResults.addAll(axisBuild.getTestResults());
}
return testResults;
}
@Override
public long getTotalDuration() {
long totalDuration = super.getTotalDuration();
return totalDuration - getDuration();
}
@Override
public int getTotalSlavesUsedCount() {
return getTotalSlavesUsedCount(null, false);
}
@Override
public int getTotalSlavesUsedCount(
String status, boolean modifiedBuildsOnly) {
return getTotalSlavesUsedCount(status, modifiedBuildsOnly, true);
}
@Override
public void saveBuildURLInBuildDatabase() {
BuildDatabase buildDatabase = getBuildDatabase();
buildDatabase.putProperty(
BUILD_URLS_PROPERTIES_KEY, getBatchName(), getBuildURL(), false);
}
protected BatchBuild(String url) {
this(url, null);
}
protected BatchBuild(String url, TopLevelBuild topLevelBuild) {
super(url, topLevelBuild);
String jobVariant = getJobVariant();
if ((jobVariant != null) && !jobVariant.isEmpty()) {
Matcher matcher = _jobVariantPattern.matcher(jobVariant);
if (!matcher.matches()) {
throw new RuntimeException(
JenkinsResultsParserUtil.combine(
"Unable to find batch name of batch build from ",
"job variant '", jobVariant,
"'. Job variant must match pattern '",
_jobVariantPattern.pattern(), "'."));
}
batchName = matcher.group("batchName");
}
else {
batchName = null;
}
}
@Override
protected void findDownstreamBuilds() {
List downstreamBuildURLs = new ArrayList<>();
JSONObject buildJSONObject = getBuildJSONObject("runs[number,url]");
if ((buildJSONObject != null) && buildJSONObject.has("runs")) {
JSONArray runsJSONArray = buildJSONObject.getJSONArray("runs");
if (runsJSONArray != null) {
for (int i = 0; i < runsJSONArray.length(); i++) {
JSONObject runJSONObject = runsJSONArray.getJSONObject(i);
if (runJSONObject.getInt("number") != getBuildNumber()) {
continue;
}
String url = runJSONObject.getString("url");
if (hasBuildURL(url) || downstreamBuildURLs.contains(url)) {
continue;
}
downstreamBuildURLs.add(url);
}
}
}
addDownstreamBuilds(downstreamBuildURLs.toArray(new String[0]));
}
protected AxisBuild getAxisBuild(String axisVariable) {
for (AxisBuild downstreamAxisBuild : getDownstreamAxisBuilds()) {
if (axisVariable.equals(downstreamAxisBuild.getAxisVariable())) {
return downstreamAxisBuild;
}
}
return null;
}
@Override
protected ExecutorService getExecutorService() {
return _executorService;
}
@Override
protected Element getFailureMessageElement() {
for (FailureMessageGenerator failureMessageGenerator :
getFailureMessageGenerators()) {
Element failureMessage = failureMessageGenerator.getMessageElement(
this);
if (failureMessage != null) {
return failureMessage;
}
}
return null;
}
@Override
protected FailureMessageGenerator[] getFailureMessageGenerators() {
return _FAILURE_MESSAGE_GENERATORS;
}
@Override
protected Element getGitHubMessageJobResultsElement() {
return getGitHubMessageJobResultsElement(false);
}
@Override
protected Element getGitHubMessageJobResultsElement(
boolean showCommonFailuresCount) {
String result = getResult();
int failCount = getDownstreamBuildCountByResult("FAILURE");
int successCount = getDownstreamBuildCountByResult("SUCCESS");
if (result.equals("UNSTABLE")) {
failCount = getTestCountByStatus("FAILURE");
successCount = getTestCountByStatus("SUCCESS");
if (isCompareToUpstream()) {
List upstreamJobFailureTestResults =
getUpstreamJobFailureTestResults();
int upstreamFailCount = upstreamJobFailureTestResults.size();
if (showCommonFailuresCount) {
failCount = upstreamFailCount;
}
else {
failCount = failCount - upstreamFailCount;
}
}
}
return Dom4JUtil.getNewElement(
"div", null, Dom4JUtil.getNewElement("h6", null, "Job Results:"),
Dom4JUtil.getNewElement(
"p", null, String.valueOf(successCount),
JenkinsResultsParserUtil.getNounForm(
successCount, " Tests", " Test"),
" Passed.", Dom4JUtil.getNewElement("br"),
String.valueOf(failCount),
JenkinsResultsParserUtil.getNounForm(
failCount, " Tests", " Test"),
" Failed."));
}
@Override
protected String getJenkinsReportBuildInfoCellElementTagName() {
return "th";
}
@Override
protected List getJenkinsReportTableRowElements(
String result, String status) {
List tableRowElements = new ArrayList<>();
tableRowElements.add(getJenkinsReportTableRowElement());
for (AxisBuild downstreamAxisBuild : getDownstreamAxisBuilds()) {
tableRowElements.addAll(
downstreamAxisBuild.getJenkinsReportTableRowElements(
downstreamAxisBuild.getResult(),
downstreamAxisBuild.getStatus()));
}
return tableRowElements;
}
@Override
protected int getTestCountByStatus(String status) {
JSONObject testReportJSONObject = getTestReportJSONObject(false);
int failCount = testReportJSONObject.getInt("failCount");
if (status.equals("SUCCESS")) {
int totalCount = testReportJSONObject.getInt("totalCount");
int skipCount = testReportJSONObject.getInt("skipCount");
return totalCount - skipCount - failCount;
}
if (status.equals("FAILURE")) {
return failCount;
}
throw new IllegalArgumentException("Invalid status: " + status);
}
protected final String batchName;
private static final FailureMessageGenerator[] _FAILURE_MESSAGE_GENERATORS =
{new ClosedChannelExceptionFailureMessageGenerator()};
private static final ExecutorService _executorService =
JenkinsResultsParserUtil.getNewThreadPoolExecutor(10, true);
private static final Pattern _jobVariantPattern = Pattern.compile(
"(?[^/]+)(/.*)?");
private Element _gitHubMessageElement;
}