Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.liferay.jenkins.results.parser.BaseTopLevelBuild Maven / Gradle / Ivy
/**
* SPDX-FileCopyrightText: (c) 2023 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.CIFailureMessageGenerator;
import com.liferay.jenkins.results.parser.failure.message.generator.CITestSuiteValidationFailureMessageGenerator;
import com.liferay.jenkins.results.parser.failure.message.generator.CompileFailureMessageGenerator;
import com.liferay.jenkins.results.parser.failure.message.generator.DownstreamFailureMessageGenerator;
import com.liferay.jenkins.results.parser.failure.message.generator.FailureMessageGenerator;
import com.liferay.jenkins.results.parser.failure.message.generator.FormatFailureMessageGenerator;
import com.liferay.jenkins.results.parser.failure.message.generator.GenericFailureMessageGenerator;
import com.liferay.jenkins.results.parser.failure.message.generator.GitLPushFailureMessageGenerator;
import com.liferay.jenkins.results.parser.failure.message.generator.GradleTaskFailureMessageGenerator;
import com.liferay.jenkins.results.parser.failure.message.generator.InvalidGitCommitSHAFailureMessageGenerator;
import com.liferay.jenkins.results.parser.failure.message.generator.InvalidSenderSHAFailureMessageGenerator;
import com.liferay.jenkins.results.parser.failure.message.generator.JenkinsRegenFailureMessageGenerator;
import com.liferay.jenkins.results.parser.failure.message.generator.JenkinsSourceFormatFailureMessageGenerator;
import com.liferay.jenkins.results.parser.failure.message.generator.PoshiTestFailureMessageGenerator;
import com.liferay.jenkins.results.parser.failure.message.generator.PoshiValidationFailureMessageGenerator;
import com.liferay.jenkins.results.parser.failure.message.generator.RebaseFailureMessageGenerator;
import com.liferay.jenkins.results.parser.testray.TestrayBuild;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.json.JSONException;
import org.json.JSONObject;
/**
* @author Kevin Yen
*/
public abstract class BaseTopLevelBuild
extends BaseParentBuild implements TopLevelBuild {
@Override
public void addTimelineData(TimelineData timelineData) {
timelineData.addTimelineData(this);
if (getTopLevelBuild() == this) {
addDownstreamBuildsTimelineData(timelineData);
}
}
@Override
public String getAcceptanceUpstreamJobName() {
String jobName = getJobName();
if (jobName.contains("pullrequest")) {
String branchName = getBranchName();
if (branchName.startsWith("ee-")) {
return jobName.replace("pullrequest", "upstream");
}
return jobName.replace("pullrequest", "upstream-dxp");
}
return "";
}
@Override
public String getAcceptanceUpstreamJobURL() {
String upstreamAcceptanceJenkinsMaster = null;
try {
upstreamAcceptanceJenkinsMaster =
JenkinsResultsParserUtil.getBuildProperty(
"upstream.acceptance.jenkins.master");
}
catch (IOException ioException) {
throw new RuntimeException(
"Unable to get upstream acceptance Jenkins master property");
}
String jobName = getJobName();
if (jobName.contains("pullrequest")) {
String acceptanceUpstreamJobURL = JenkinsResultsParserUtil.combine(
"https://", upstreamAcceptanceJenkinsMaster,
".liferay.com/job/", getAcceptanceUpstreamJobName());
try {
JenkinsResultsParserUtil.toString(
JenkinsResultsParserUtil.getLocalURL(
acceptanceUpstreamJobURL),
false, 0, 0, 0);
}
catch (IOException ioException) {
return null;
}
return acceptanceUpstreamJobURL;
}
return null;
}
@Override
public URL getArtifactsBaseURL() {
StringBuilder sb = new StringBuilder();
try {
URL buildBaseArtifactURL = new URL(
JenkinsResultsParserUtil.getBuildProperty(
"build.base.artifact.url"));
sb.append(buildBaseArtifactURL);
}
catch (IOException ioException) {
return null;
}
TopLevelBuild topLevelBuild = getTopLevelBuild();
sb.append("/");
sb.append(
JenkinsResultsParserUtil.toDateString(
new Date(topLevelBuild.getStartTime()), "yyyy-MM",
"America/Los_Angeles"));
JenkinsMaster jenkinsMaster = topLevelBuild.getJenkinsMaster();
sb.append("/");
sb.append(jenkinsMaster.getName());
sb.append("/");
sb.append(topLevelBuild.getJobName());
sb.append("/");
sb.append(topLevelBuild.getBuildNumber());
try {
return new URL(sb.toString());
}
catch (MalformedURLException malformedURLException) {
}
return null;
}
@Override
public long getAverageDelayTime() {
if (getDownstreamBuildCount(null) == 0) {
return 0;
}
List allDownstreamBuilds = JenkinsResultsParserUtil.flatten(
getDownstreamBuilds(null));
if (allDownstreamBuilds.isEmpty()) {
return 0;
}
long totalDelayTime = 0;
for (Build downstreamBuild : allDownstreamBuilds) {
totalDelayTime += downstreamBuild.getDelayTime();
}
return totalDelayTime / allDownstreamBuilds.size();
}
@Override
public Map getBaseGitRepositoryDetailsTempMap() {
String gitRepositoryType = getBaseGitRepositoryType();
String tempMapName = "git." + gitRepositoryType + ".properties";
return getTempMap(tempMapName);
}
@Override
public String getBuildName() {
String jenkinsJobVariant = getParameterValue("JENKINS_JOB_VARIANT");
if (!JenkinsResultsParserUtil.isNullOrEmpty(jenkinsJobVariant)) {
return getJobName() + "/" + jenkinsJobVariant;
}
return "top-level";
}
@Override
public Build getControllerBuild() {
if (_controllerBuild != null) {
return _controllerBuild;
}
String controllerBuildURL = getParameterValue("CONTROLLER_BUILD_URL");
if ((controllerBuildURL == null) ||
!controllerBuildURL.matches("https?://.*")) {
return null;
}
_controllerBuild = BuildFactory.newBuild(controllerBuildURL, null);
return _controllerBuild;
}
@Override
public String getDisplayName() {
StringBuilder sb = new StringBuilder(super.getDisplayName());
String jenkinsJobVariant = getParameterValue("JENKINS_JOB_VARIANT");
if ((getParentBuild() != null) && (jenkinsJobVariant != null) &&
!jenkinsJobVariant.isEmpty()) {
sb.append("/");
sb.append(jenkinsJobVariant);
}
return sb.toString();
}
@Override
public AxisBuild getDownstreamAxisBuild(String axisName) {
AxisBuild targetAxisBuild = _downstreamAxisBuilds.get(axisName);
if (targetAxisBuild != null) {
return targetAxisBuild;
}
for (AxisBuild axisBuild : getDownstreamAxisBuilds()) {
if (axisName.equals(axisBuild.getAxisName())) {
return axisBuild;
}
}
return null;
}
@Override
public List getDownstreamAxisBuilds() {
if (_downstreamAxisBuildsPopulated &&
!_downstreamAxisBuilds.isEmpty()) {
List downstreamAxisBuilds = new ArrayList<>(
_downstreamAxisBuilds.values());
Collections.sort(
downstreamAxisBuilds,
new BaseBuild.BuildDisplayNameComparator());
return downstreamAxisBuilds;
}
List downstreamAxisBuilds = new ArrayList<>();
for (BatchBuild downstreamBatchBuild : getDownstreamBatchBuilds()) {
downstreamAxisBuilds.addAll(
downstreamBatchBuild.getDownstreamAxisBuilds());
}
synchronized (_downstreamAxisBuilds) {
if (isCompleted() && !_downstreamAxisBuildsPopulated) {
for (AxisBuild downstreamAxisBuild : downstreamAxisBuilds) {
_downstreamAxisBuilds.put(
downstreamAxisBuild.getAxisName(), downstreamAxisBuild);
}
_downstreamAxisBuildsPopulated = true;
}
}
Collections.sort(
downstreamAxisBuilds, new BaseBuild.BuildDisplayNameComparator());
return downstreamAxisBuilds;
}
@Override
public BatchBuild getDownstreamBatchBuild(String jobVariant) {
BatchBuild targetBatchBuild = _downstreamBatchBuilds.get(jobVariant);
if (targetBatchBuild != null) {
return targetBatchBuild;
}
for (BatchBuild batchBuild : getDownstreamBatchBuilds()) {
if (jobVariant.equals(batchBuild.getJobVariant())) {
return batchBuild;
}
}
return null;
}
@Override
public List getDownstreamBatchBuilds() {
if (_downstreamBatchBuildsPopulated &&
!_downstreamBatchBuilds.isEmpty()) {
List downstreamBatchBuilds = new ArrayList<>(
_downstreamBatchBuilds.values());
Collections.sort(
downstreamBatchBuilds,
new BaseBuild.BuildDisplayNameComparator());
return downstreamBatchBuilds;
}
List downstreamBatchBuilds = new ArrayList<>();
List downstreamBuilds = getDownstreamBuilds(null);
for (Build downstreamBuild : downstreamBuilds) {
if (!(downstreamBuild instanceof BatchBuild)) {
continue;
}
downstreamBatchBuilds.add((BatchBuild)downstreamBuild);
}
synchronized (_downstreamBatchBuilds) {
if (isCompleted() && !_downstreamBatchBuildsPopulated) {
for (BatchBuild downstreamBatchBuild : downstreamBatchBuilds) {
String jobVariant = downstreamBatchBuild.getJobVariant();
if (JenkinsResultsParserUtil.isNullOrEmpty(jobVariant)) {
continue;
}
_downstreamBatchBuilds.put(
jobVariant, downstreamBatchBuild);
}
_downstreamBatchBuildsPopulated = true;
}
}
Collections.sort(
downstreamBatchBuilds, new BaseBuild.BuildDisplayNameComparator());
return downstreamBatchBuilds;
}
@Override
public DownstreamBuild getDownstreamBuild(String axisName) {
for (Build downstreamBuild : getDownstreamBuilds(null)) {
String downstreamAxisName = downstreamBuild.getParameterValue(
"JOB_VARIANT");
if (JenkinsResultsParserUtil.isNullOrEmpty(downstreamAxisName)) {
continue;
}
String downstreamAxisVariable = downstreamBuild.getParameterValue(
"AXIS_VARIABLE");
if (JenkinsResultsParserUtil.isNullOrEmpty(
downstreamAxisVariable)) {
continue;
}
downstreamAxisName += "/" + downstreamAxisVariable;
if (!axisName.equals(downstreamAxisName) ||
!(downstreamBuild instanceof DownstreamBuild)) {
continue;
}
return (DownstreamBuild)downstreamBuild;
}
return null;
}
@Override
public Element getGitHubMessageElement() {
sortDownstreamBuilds();
if (getParentBuild() == null) {
return getTopGitHubMessageElement();
}
return super.getGitHubMessageElement();
}
@Override
public JenkinsCohort getJenkinsCohort() {
if (_jenkinsCohort != null) {
return _jenkinsCohort;
}
String cohortName = JenkinsResultsParserUtil.getCohortName();
if (!JenkinsResultsParserUtil.isNullOrEmpty(cohortName)) {
_jenkinsCohort = JenkinsCohort.getInstance(cohortName);
return _jenkinsCohort;
}
return null;
}
@Override
public String getJenkinsReport() {
try {
return JenkinsResultsParserUtil.toString(
JenkinsResultsParserUtil.getLocalURL(getJenkinsReportURL()));
}
catch (IOException ioException) {
throw new RuntimeException(
"Unable to get Jenkins report", ioException);
}
}
@Override
public synchronized Element getJenkinsReportElement() {
long start = JenkinsResultsParserUtil.getCurrentTimeMillis();
try {
return Dom4JUtil.getNewElement(
"html", null, getJenkinsReportHeadElement(),
getJenkinsReportBodyElement());
}
finally {
String duration = JenkinsResultsParserUtil.toDurationString(
JenkinsResultsParserUtil.getCurrentTimeMillis() - start);
System.out.println("Jenkins reported generated in " + duration);
}
}
@Override
public String getJenkinsReportURL() {
if (fromArchive) {
return getBuildURL() + "/jenkins-report.html";
}
JenkinsMaster jenkinsMaster = getJenkinsMaster();
return JenkinsResultsParserUtil.combine(
"https://", jenkinsMaster.getName(), ".liferay.com/",
"userContent/jobs/", getJobName(), "/builds/",
String.valueOf(getBuildNumber()), "/jenkins-report.html");
}
@Override
public File getJobSummaryDir() {
File jobSummaryDir = new File(getBuildDirPath(), "job-summary");
if (!jobSummaryDir.exists()) {
try {
CIJobSummaryReportUtil.writeJobSummaryReport(
jobSummaryDir, getJob());
}
catch (IOException ioException) {
throw new RuntimeException(ioException);
}
}
return jobSummaryDir;
}
@Override
public int getJobVariantsDownstreamBuildCount(
List jobVariants, String result, String status) {
List jobVariantsDownstreamBuilds =
getJobVariantsDownstreamBuilds(jobVariants, result, status);
return jobVariantsDownstreamBuilds.size();
}
@Override
public List getJobVariantsDownstreamBuilds(
Iterable jobVariants, String result, String status) {
List jobVariantsDownstreamBuilds = new ArrayList<>();
List downstreamBuilds = getDownstreamBuilds(result, status);
for (Build downstreamBuild : downstreamBuilds) {
String downstreamBuildJobVariant = downstreamBuild.getJobVariant();
for (String jobVariant : jobVariants) {
if (downstreamBuildJobVariant.startsWith(jobVariant)) {
jobVariantsDownstreamBuilds.add(downstreamBuild);
break;
}
}
}
return jobVariantsDownstreamBuilds;
}
@Override
public Map getMetricLabels() {
Map metricLabels = new TreeMap<>();
metricLabels.put("job_type", "top-level");
metricLabels.put("top_level_job_name", getJobName());
return metricLabels;
}
@Override
public List getProjectNames() {
return Collections.emptyList();
}
@Override
public String getStatusSummary() {
long currentTimeMillis =
JenkinsResultsParserUtil.getCurrentTimeMillis();
if ((currentTimeMillis - _MILLIS_DOWNSTREAM_BUILDS_LISTING_INTERVAL) >=
_lastDownstreamBuildsListingTimestamp) {
StringBuilder sb = new StringBuilder(_getStatusSummary());
sb.append("\nRunning Builds: ");
_lastDownstreamBuildsListingTimestamp =
JenkinsResultsParserUtil.getCurrentTimeMillis();
for (Build downstreamBuild : getDownstreamBuilds("running")) {
sb.append("\n");
sb.append(downstreamBuild.getBuildURL());
}
return sb.toString();
}
return _getStatusSummary();
}
@Override
public JSONObject getTestReportJSONObject(boolean cache) {
return null;
}
@Override
public String getTestSuiteName() {
String testSuiteName = getParameterValue("CI_TEST_SUITE");
if (testSuiteName == null) {
testSuiteName = "default";
}
return testSuiteName;
}
public TimelineData getTimelineData() {
return new TimelineData(500, this);
}
public URL getUserContentURL() {
JenkinsMaster jenkinsMaster = getJenkinsMaster();
try {
return new URL(
JenkinsResultsParserUtil.combine(
"https://", jenkinsMaster.getName(),
".liferay.com/userContent/jobs/", getJobName(), "/builds/",
String.valueOf(getBuildNumber())));
}
catch (MalformedURLException malformedURLException) {
throw new RuntimeException(malformedURLException);
}
}
@Override
public Element getValidationGitHubMessageElement() {
ValidationBuild validationBuild = null;
for (Build downstreamBuild : getDownstreamBuilds()) {
if (downstreamBuild instanceof ValidationBuild) {
validationBuild = (ValidationBuild)downstreamBuild;
}
}
if (validationBuild == null) {
throw new RuntimeException("Unable to find a validation build");
}
return validationBuild.getGitHubMessageElement();
}
@Override
public boolean isCompareToUpstream() {
return _compareToUpstream;
}
@Override
public boolean isFromCompletedBuild() {
if (fromCompletedBuild) {
return fromCompletedBuild;
}
Build parentBuild = getParentBuild();
if (parentBuild != null) {
return parentBuild.isFromCompletedBuild();
}
String consoleText = getConsoleText();
if (JenkinsResultsParserUtil.isNullOrEmpty(consoleText)) {
return false;
}
if (consoleText.contains("stop-current-job:") ||
consoleText.contains(
"com.liferay.jenkins.results.parser.BuildLauncher teardown")) {
fromCompletedBuild = true;
return fromCompletedBuild;
}
String buildURL = getBuildURL();
if (!JenkinsResultsParserUtil.isURL(buildURL)) {
return false;
}
try {
JSONObject buildJSONObject = JenkinsResultsParserUtil.toJSONObject(
buildURL + "/api/json?tree=result");
if (!JenkinsResultsParserUtil.isNullOrEmpty(
buildJSONObject.optString("result", null))) {
fromCompletedBuild = true;
return fromCompletedBuild;
}
}
catch (IOException | JSONException exception) {
return false;
}
return false;
}
@Override
public boolean isUniqueFailure() {
return true;
}
@Override
public void setCompareToUpstream(boolean compareToUpstream) {
_compareToUpstream = compareToUpstream;
}
@Override
public void takeSlaveOffline(SlaveOfflineRule slaveOfflineRule) {
}
@Override
public synchronized void update() {
if (skipUpdate()) {
return;
}
super.update();
if (_sendBuildMetrics && !fromArchive && (getParentBuild() == null)) {
if (!fromCompletedBuild) {
sendBuildMetricsOnModifiedBuilds();
}
else {
sendBuildMetrics(
StatsDMetricsUtil.generateGaugeDeltaMetric(
"build_slave_usage_gauge", -1, getMetricLabels()));
}
}
}
public class WorkspaceBranchInformation implements BranchInformation {
@Override
public String getCachedRemoteGitRefName() {
return _workspaceGitRepository.getGitHubDevBranchName();
}
@Override
public String getOriginName() {
return _workspaceGitRepository.getSenderBranchUsername();
}
@Override
public Integer getPullRequestNumber() {
Matcher matcher = _gitHubURLPattern.matcher(
_workspaceGitRepository.getGitHubURL());
if (!matcher.find()) {
return 0;
}
return Integer.parseInt(matcher.group("pullNumber"));
}
@Override
public String getReceiverUsername() {
Matcher matcher = _gitHubURLPattern.matcher(
_workspaceGitRepository.getGitHubURL());
if (!matcher.find()) {
return "liferay";
}
return matcher.group("username");
}
@Override
public String getRepositoryName() {
return _workspaceGitRepository.getName();
}
@Override
public String getSenderBranchName() {
return _workspaceGitRepository.getSenderBranchName();
}
@Override
public String getSenderBranchSHA() {
return _workspaceGitRepository.getSenderBranchSHA();
}
@Override
public String getSenderBranchSHAShort() {
String senderBranchSHA = getSenderBranchSHA();
if (senderBranchSHA == null) {
return null;
}
if (senderBranchSHA.length() >= 7) {
senderBranchSHA = senderBranchSHA.substring(0, 7);
}
return senderBranchSHA;
}
@Override
public RemoteGitRef getSenderRemoteGitRef() {
String remoteURL = null;
if (isReleaseBuild()) {
remoteURL = JenkinsResultsParserUtil.combine(
"[email protected] :", getSenderUsername(), "/",
getReleaseRepositoryName(), ".git");
}
else {
remoteURL = JenkinsResultsParserUtil.combine(
"[email protected] :", getSenderUsername(), "/",
getRepositoryName(), ".git");
}
return GitUtil.getRemoteGitRef(
getSenderBranchName(), new File("."), remoteURL);
}
@Override
public String getSenderUsername() {
return _workspaceGitRepository.getSenderBranchUsername();
}
@Override
public String getUpstreamBranchName() {
return _workspaceGitRepository.getUpstreamBranchName();
}
@Override
public String getUpstreamBranchSHA() {
return _workspaceGitRepository.getBaseBranchSHA();
}
protected WorkspaceBranchInformation(
WorkspaceGitRepository workspaceGitRepository) {
_workspaceGitRepository = workspaceGitRepository;
}
private final WorkspaceGitRepository _workspaceGitRepository;
}
protected BaseTopLevelBuild(String url) {
this(url, null);
}
protected BaseTopLevelBuild(String url, TopLevelBuild topLevelBuild) {
super(url, topLevelBuild);
Properties buildProperties = null;
try {
buildProperties = JenkinsResultsParserUtil.getBuildProperties();
}
catch (IOException ioException) {
throw new RuntimeException(
"Unable to get build.properties", ioException);
}
_sendBuildMetrics = Boolean.valueOf(
buildProperties.getProperty("build.metrics.send"));
if (_sendBuildMetrics) {
_metricsHostName = buildProperties.getProperty(
"build.metrics.host.name");
String metricsHostPortString = buildProperties.getProperty(
"build.metrics.host.port");
if ((_metricsHostName == null) || (metricsHostPortString == null)) {
throw new IllegalArgumentException(
"Properties \"build.metrics.host.name\" and " +
"\"build.metrics.host.port\" must be set to send " +
"build metrics");
}
try {
_metricsHostPort = Integer.parseInt(metricsHostPortString);
}
catch (NumberFormatException numberFormatException) {
throw new IllegalArgumentException(
"Please set \"build.metrics.host.port\" to an integer");
}
if (topLevelBuild == null) {
sendBuildMetrics(
StatsDMetricsUtil.generateGaugeDeltaMetric(
"build_slave_usage_gauge", 1, getMetricLabels()));
}
}
}
@Override
protected void findDownstreamBuilds() {
if (getParentBuild() != null) {
return;
}
BuildDatabase buildDatabase = getBuildDatabase();
Properties properties = buildDatabase.getProperties(
BUILD_URLS_PROPERTIES_KEY);
Map urlAxisNames = new HashMap<>();
List badBuildURLs = getBadBuildURLs();
for (String propertyName : properties.stringPropertyNames()) {
if (Objects.equals(propertyName, getJobVariant())) {
continue;
}
String buildURL = properties.getProperty(propertyName);
if (badBuildURLs.contains(buildURL)) {
continue;
}
urlAxisNames.put(buildURL, propertyName);
}
if (!urlAxisNames.isEmpty()) {
addDownstreamBuilds(urlAxisNames);
return;
}
System.out.println(
"Unable to find downstream builds in build-database.json");
_findDownstreamBuildsInConsoleText();
}
@Override
protected List> getArchiveCallables() {
List> archiveCallables = super.getArchiveCallables();
archiveCallables.add(
new Callable() {
@Override
public Object call() {
_archiveBuildDatabase();
return null;
}
});
archiveCallables.add(
new Callable() {
@Override
public Object call() {
_archiveJenkinsReport();
return null;
}
});
archiveCallables.add(
new Callable() {
@Override
public Object call() {
_archiveProperties();
return null;
}
});
return archiveCallables;
}
protected Element getBaseBranchDetailsElement() {
String baseBranchURL = JenkinsResultsParserUtil.combine(
"https://github.com/liferay/", getBaseGitRepositoryName(), "/tree/",
getBranchName());
String baseGitRepositoryName = getBaseGitRepositoryName();
String baseGitRepositorySHA = null;
if ((this instanceof WorkspaceBuild) && !fromArchive) {
WorkspaceBuild workspaceBuild = (WorkspaceBuild)this;
Workspace workspace = workspaceBuild.getWorkspace();
WorkspaceGitRepository workspaceGitRepository =
workspace.getPrimaryWorkspaceGitRepository();
baseGitRepositorySHA = workspaceGitRepository.getBaseBranchSHA();
}
else if (!baseGitRepositoryName.equals("liferay-jenkins-ee") &&
baseGitRepositoryName.endsWith("-ee")) {
baseGitRepositorySHA = getBaseGitRepositorySHA(
baseGitRepositoryName.substring(
0, baseGitRepositoryName.length() - 3));
}
else {
baseGitRepositorySHA = getBaseGitRepositorySHA(
baseGitRepositoryName);
}
Element baseGitBranchDetailsElement = Dom4JUtil.getNewElement(
"p", null, "Branch Name: ",
Dom4JUtil.getNewAnchorElement(baseBranchURL, getBranchName()));
if (baseGitRepositorySHA != null) {
String baseGitRepositoryCommitURL =
"https://github.com/liferay/" + baseGitRepositoryName +
"/commit/" + baseGitRepositorySHA;
Dom4JUtil.addToElement(
baseGitBranchDetailsElement, Dom4JUtil.getNewElement("br"),
"Branch GIT ID: ",
Dom4JUtil.getNewAnchorElement(
baseGitRepositoryCommitURL, baseGitRepositorySHA));
}
return baseGitBranchDetailsElement;
}
protected Element[] getBuildFailureElements() {
List failedDownstreamBuilds = getFailedDownstreamBuilds();
if (failedDownstreamBuilds != null) {
StringBuilder sb = new StringBuilder();
sb.append("\nUnique Failures:");
for (Build failedDownstreamBuild : failedDownstreamBuilds) {
if (failedDownstreamBuild.isUniqueFailure()) {
sb.append("\n");
sb.append(failedDownstreamBuild.getDisplayName());
for (TestResult testResult :
failedDownstreamBuild.
getUniqueFailureTestResults()) {
sb.append("\n\t");
sb.append(testResult.getDisplayName());
}
}
}
sb.append("\n\nUpstream Failures:");
for (Build failedDownstreamBuild : failedDownstreamBuilds) {
if (!failedDownstreamBuild.isUniqueFailure()) {
sb.append("\n");
sb.append(failedDownstreamBuild.getDisplayName());
for (TestResult testResult :
failedDownstreamBuild.
getUpstreamJobFailureTestResults()) {
sb.append("\n\t");
sb.append(testResult.getDisplayName());
}
}
}
System.out.println(sb.toString());
}
List downstreamBuildMessageElements =
getDownstreamBuildMessageElements(failedDownstreamBuilds);
System.out.println(
"Collected " + downstreamBuildMessageElements.size() +
" downstream failure messages");
List allCurrentBuildFailureElements = new ArrayList<>();
List upstreamBuildFailureElements = new ArrayList<>();
int maxFailureCount = 5;
for (Build failedDownstreamBuild : failedDownstreamBuilds) {
Element gitHubMessageElement =
failedDownstreamBuild.getGitHubMessageElement();
if (gitHubMessageElement != null) {
allCurrentBuildFailureElements.add(gitHubMessageElement);
}
Element gitHubMessageUpstreamJobFailureElement =
failedDownstreamBuild.
getGitHubMessageUpstreamJobFailureElement();
if (gitHubMessageUpstreamJobFailureElement != null) {
upstreamBuildFailureElements.add(
gitHubMessageUpstreamJobFailureElement);
}
}
List buildFailureElements = new ArrayList<>();
buildFailureElements.add(Dom4JUtil.getNewElement("hr"));
if (allCurrentBuildFailureElements.isEmpty() &&
upstreamBuildFailureElements.isEmpty()) {
allCurrentBuildFailureElements.add(
0, super.getGitHubMessageElement());
}
if (allCurrentBuildFailureElements.isEmpty() &&
!upstreamBuildFailureElements.isEmpty()) {
String uniqueFailureMessage =
"This pull contains no unique failures.";
if (this instanceof PullRequestPortalTopLevelBuild) {
PullRequestPortalTopLevelBuild pullRequestPortalTopLevelBuild =
(PullRequestPortalTopLevelBuild)this;
String stableJobResult =
pullRequestPortalTopLevelBuild.getStableJobResult();
if ((stableJobResult != null) &&
!stableJobResult.equals("SUCCESS")) {
uniqueFailureMessage = JenkinsResultsParserUtil.combine(
"This pull contains no unique failures. However, the ",
"stable suite failed.");
}
}
buildFailureElements.add(
Dom4JUtil.getNewElement("h4", null, uniqueFailureMessage));
}
else {
String failureTitle = "Failures unique to this pull:";
if (!UpstreamFailureUtil.isUpstreamComparisonAvailable(this) &&
isCompareToUpstream()) {
failureTitle =
"Failures (upstream comparison is not available):";
}
buildFailureElements.add(
Dom4JUtil.getNewElement("h4", null, failureTitle));
buildFailureElements.add(
Dom4JUtil.getOrderedListElement(
allCurrentBuildFailureElements, maxFailureCount));
}
String acceptanceUpstreamJobURL = getAcceptanceUpstreamJobURL();
if ((allCurrentBuildFailureElements.size() < maxFailureCount) &&
!upstreamBuildFailureElements.isEmpty()) {
Element acceptanceUpstreamJobLinkElement =
Dom4JUtil.getNewAnchorElement(
acceptanceUpstreamJobURL, "acceptance upstream results");
Element upstreamJobFailureElement = Dom4JUtil.getNewElement(
"details", null,
Dom4JUtil.getNewElement(
"summary", null,
Dom4JUtil.getNewElement(
"strong", null, "Failures in common with ",
acceptanceUpstreamJobLinkElement, " at ",
UpstreamFailureUtil.getUpstreamJobFailuresSHA(this),
":")));
int remainingFailureCount =
maxFailureCount - allCurrentBuildFailureElements.size();
Dom4JUtil.getOrderedListElement(
upstreamBuildFailureElements, upstreamJobFailureElement,
remainingFailureCount);
buildFailureElements.add(Dom4JUtil.getNewElement("hr"));
buildFailureElements.add(upstreamJobFailureElement);
}
String jobName = getJobName();
if (jobName.contains("pullrequest") &&
upstreamBuildFailureElements.isEmpty() &&
(acceptanceUpstreamJobURL != null)) {
Element upstreamResultElement = Dom4JUtil.getNewElement("h4");
Dom4JUtil.addToElement(
upstreamResultElement, "For upstream results, click ",
Dom4JUtil.getNewAnchorElement(acceptanceUpstreamJobURL, "here"),
".");
buildFailureElements.add(upstreamResultElement);
Map startPropertiesTempMap =
getStartPropertiesTempMap();
String subrepositoryMergePullMentionUsers =
startPropertiesTempMap.get(
"SUBREPOSITORY_MERGE_PULL_MENTION_USERS");
if (subrepositoryMergePullMentionUsers != null) {
StringBuilder sb = new StringBuilder();
sb.append("cc");
for (String subrepositoryMergePullMentionUser :
subrepositoryMergePullMentionUsers.split(",")) {
sb.append(" @");
sb.append(subrepositoryMergePullMentionUser);
}
buildFailureElements.add(
Dom4JUtil.getNewElement("div", null, sb.toString()));
}
}
return buildFailureElements.toArray(new Element[0]);
}
protected Element getDownstreamGitHubMessageElement() {
String status = getStatus();
if (!status.equals("completed") && (getParentBuild() != null)) {
return null;
}
String result = getResult();
if (Objects.equals(result, "SUCCESS")) {
return null;
}
Element messageElement = Dom4JUtil.getNewElement(
"div", null,
Dom4JUtil.getNewAnchorElement(
getBuildURL(), null, getDisplayName()));
if (Objects.equals(result, "ABORTED")) {
messageElement.add(
Dom4JUtil.toCodeSnippetElement("Build was aborted"));
}
if (Objects.equals(result, "FAILURE")) {
Element failureMessageElement = getFailureMessageElement();
if (failureMessageElement != null) {
messageElement.add(failureMessageElement);
}
}
if (Objects.equals(result, "MISSING")) {
messageElement.add(
Dom4JUtil.toCodeSnippetElement("Build was missing"));
}
return messageElement;
}
@Override
protected ExecutorService getExecutorService() {
return _executorService;
}
protected Element getFailedJobSummaryElement() {
Element jobSummaryListElement = getJobSummaryListElement(false, null);
int failCount =
getDownstreamBuildCount(null) -
getDownstreamBuildCountByResult("SUCCESS") + 1;
return Dom4JUtil.getNewElement(
"div", null,
Dom4JUtil.getNewElement(
"h4", null, String.valueOf(failCount), " Failed Jobs:"),
jobSummaryListElement);
}
@Override
protected FailureMessageGenerator[] getFailureMessageGenerators() {
return _FAILURE_MESSAGE_GENERATORS;
}
@Override
protected Element getGitHubMessageJobResultsElement() {
int successCount = getDownstreamBuildCountByResult("SUCCESS");
int failCount = getDownstreamBuildCount(null) - successCount + 1;
return Dom4JUtil.getNewElement(
"div", null, Dom4JUtil.getNewElement("h6", null, "Job Results:"),
Dom4JUtil.getNewElement(
"p", null, String.valueOf(successCount),
JenkinsResultsParserUtil.getNounForm(
successCount, " Jobs", " Job"),
" Passed.", Dom4JUtil.getNewElement("br"),
String.valueOf(failCount),
JenkinsResultsParserUtil.getNounForm(
failCount, " Jobs", " Job"),
" Failed."));
}
protected String getGitRepositoryDetailsPropertiesTempMapURL(
String gitRepositoryType) {
if (fromArchive) {
return JenkinsResultsParserUtil.combine(
getBuildURL(), "git.", gitRepositoryType, ".properties.json");
}
TopLevelBuild topLevelBuild = getTopLevelBuild();
JenkinsMaster topLevelBuildJenkinsMaster =
topLevelBuild.getJenkinsMaster();
return JenkinsResultsParserUtil.combine(
URL_BASE_TEMP_MAP, topLevelBuildJenkinsMaster.getName(), "/",
topLevelBuild.getJobName(), "/",
String.valueOf(topLevelBuild.getBuildNumber()), "/",
topLevelBuild.getJobName(), "/git.", gitRepositoryType,
".properties");
}
protected Element getJenkinsReportBodyElement() {
Element subheadingElement = null;
JSONObject jobJSONObject = getBuildJSONObject();
String description = jobJSONObject.optString("description");
if (!description.isEmpty()) {
subheadingElement = Dom4JUtil.getNewElement("h2");
try {
Dom4JUtil.addRawXMLToElement(subheadingElement, description);
}
catch (DocumentException documentException) {
throw new RuntimeException(
"Unable to parse description HTML " + description,
documentException);
}
}
String buildURL = getBuildURL();
Element headingElement = Dom4JUtil.getNewElement(
"h1", null, "Jenkins report for ",
Dom4JUtil.getNewAnchorElement(buildURL, buildURL));
return Dom4JUtil.getNewElement(
"body", null, headingElement, subheadingElement,
getJenkinsReportCommitElement(), getJenkinsReportSummaryElement(),
getJenkinsReportTimelineElement(),
getJenkinsReportTopLevelTableElement(),
getJenkinsReportDownstreamElement());
}
@Override
protected String getJenkinsReportBuildInfoCellElementTagName() {
return "th";
}
protected Element getJenkinsReportChartJsScriptElement(
String xData, String y1Data, String y2Data) {
String resourceFileContent = null;
try {
resourceFileContent =
JenkinsResultsParserUtil.getResourceFileContent(
"dependencies/chart_template.js");
}
catch (IOException ioException) {
throw new RuntimeException(
"Unable to load resource chart_template.js", ioException);
}
resourceFileContent = resourceFileContent.replace("'xData'", xData);
resourceFileContent = resourceFileContent.replace("'y1Data'", y1Data);
resourceFileContent = resourceFileContent.replace("'y2Data'", y2Data);
Element scriptElement = Dom4JUtil.getNewElement("script");
scriptElement.addText(resourceFileContent);
return scriptElement;
}
protected Element getJenkinsReportCommitElement() {
if (!(this instanceof WorkspaceBuild)) {
return null;
}
WorkspaceBuild workspaceBuild = (WorkspaceBuild)this;
Workspace workspace = workspaceBuild.getWorkspace();
WorkspaceGitRepository workspaceGitRepository =
workspace.getPrimaryWorkspaceGitRepository();
WorkspaceBranchInformation workspaceBranchInformation =
new WorkspaceBranchInformation(workspaceGitRepository);
String senderBranchSHA =
workspaceBranchInformation.getSenderBranchSHA();
GitHubRemoteGitCommit gitHubRemoteGitCommit = null;
if (isReleaseBuild()) {
gitHubRemoteGitCommit = GitCommitFactory.newGitHubRemoteGitCommit(
workspaceBranchInformation.getSenderUsername(),
getReleaseRepositoryName(), senderBranchSHA);
}
else {
gitHubRemoteGitCommit = GitCommitFactory.newGitHubRemoteGitCommit(
workspaceBranchInformation.getSenderUsername(),
workspaceBranchInformation.getRepositoryName(),
senderBranchSHA);
}
return Dom4JUtil.getNewElement(
"div", null,
Dom4JUtil.getNewElement(
"p", null, "Sender Branch Name: ",
workspaceBranchInformation.getSenderBranchName()),
Dom4JUtil.getNewElement(
"p", null, "Sender Branch SHA: ", senderBranchSHA),
Dom4JUtil.getNewElement(
"p", null, "Commit Message: ",
gitHubRemoteGitCommit.getMessage()),
Dom4JUtil.getNewElement(
"p", null, "Commit Date: ",
toJenkinsReportDateString(
gitHubRemoteGitCommit.getCommitDate(),
getJenkinsReportTimeZoneName())));
}
protected Element getJenkinsReportDownstreamElement() {
return Dom4JUtil.getNewElement(
"div", null,
getJenkinsReportDownstreamTableElement(null, "queued", "Queued: "),
getJenkinsReportDownstreamTableElement(
null, "starting", "Starting: "),
getJenkinsReportDownstreamTableElement(
null, "running", "Running: "),
getJenkinsReportDownstreamTableElement(
null, "missing", "Missing: "),
Dom4JUtil.getNewElement("h2", null, "Completed: "),
getJenkinsReportDownstreamTableElement(
"ABORTED", "completed", "---- Aborted: "),
getJenkinsReportDownstreamTableElement(
"FAILURE", "completed", "---- Failure: "),
getJenkinsReportDownstreamTableElement(
"MISSING", "completed", "---- Missing: "),
getJenkinsReportDownstreamTableElement(
"UNSTABLE", "completed", "---- Unstable: "),
getJenkinsReportDownstreamTableElement(
"SUCCESS", "completed", "---- Success: "));
}
protected Element getJenkinsReportDownstreamTableElement(
String result, String status, String captionText) {
List tableRowElements = getJenkinsReportTableRowElements(
result, status);
if (tableRowElements.isEmpty()) {
return null;
}
return Dom4JUtil.getNewElement(
"table", null,
Dom4JUtil.getNewElement(
"caption", null, captionText,
String.valueOf(getDownstreamBuildCount(result, status))),
getJenkinsReportTableColumnHeadersElement(),
tableRowElements.toArray(new Element[0]));
}
protected Element getJenkinsReportHeadElement() {
Element headElement = Dom4JUtil.getNewElement("head");
getResourceFileContentAsElement(
"style", headElement, "dependencies/jenkins_report.css");
Element scriptElement = getResourceFileContentAsElement(
"script", headElement, "dependencies/jenkins_report.js");
scriptElement.addAttribute("language", "javascript");
return headElement;
}
protected Element getJenkinsReportSummaryElement() {
Element summaryElement = Dom4JUtil.getNewElement(
"div", null,
Dom4JUtil.getNewElement(
"p", null,
Dom4JUtil.getNewAnchorElement(
_URL_CI_SYSTEM_STATUS, "CI System Status")),
Dom4JUtil.getNewElement(
"p", null, "Start Time: ",
toJenkinsReportDateString(
new Date(getStartTime()), getJenkinsReportTimeZoneName())),
Dom4JUtil.getNewElement(
"p", null, "Invocation Delay Time: ",
JenkinsResultsParserUtil.toDurationString(
getQueuingDuration())),
Dom4JUtil.getNewElement(
"p", null, "Build Time: ",
JenkinsResultsParserUtil.toDurationString(getDuration())),
Dom4JUtil.getNewElement(
"p", null, "Total CPU Usage Time: ",
JenkinsResultsParserUtil.toDurationString(getTotalDuration())),
Dom4JUtil.getNewElement(
"p", null, "Total number of Jenkins slaves used: ",
String.valueOf(getTotalSlavesUsedCount())),
Dom4JUtil.getNewElement(
"p", null, "Average delay time for invoked build to start: ",
JenkinsResultsParserUtil.toDurationString(
getAverageDelayTime())));
Build longestDelayedDownstreamBuild =
getLongestDelayedDownstreamBuild();
if (longestDelayedDownstreamBuild != null) {
Dom4JUtil.getNewElement(
"p", summaryElement,
"Longest delay time for invoked build to start: ",
Dom4JUtil.getNewAnchorElement(
longestDelayedDownstreamBuild.getBuildURL(),
longestDelayedDownstreamBuild.getDisplayName()),
" in: ",
JenkinsResultsParserUtil.toDurationString(
longestDelayedDownstreamBuild.getDelayTime()));
}
Build longestRunningDownstreamBuild =
getLongestRunningDownstreamBuild();
if (longestRunningDownstreamBuild != null) {
Dom4JUtil.getNewElement(
"p", summaryElement, "Longest Running Downstream Build: ",
Dom4JUtil.getNewAnchorElement(
longestRunningDownstreamBuild.getBuildURL(),
longestRunningDownstreamBuild.getDisplayName()),
" in: ",
JenkinsResultsParserUtil.toDurationString(
longestRunningDownstreamBuild.getDuration()));
}
try {
Properties buildProperties =
JenkinsResultsParserUtil.getBuildProperties();
String longestRunningTestEnabled = buildProperties.getProperty(
"jenkins.report.longest.running.test.enabled", "false");
if (longestRunningTestEnabled.equals("true")) {
TestResult longestRunningTest = getLongestRunningTest();
if (longestRunningTest != null) {
Dom4JUtil.getNewElement(
"p", summaryElement, "Longest Running Test: ",
Dom4JUtil.getNewAnchorElement(
longestRunningTest.getTestReportURL(),
longestRunningTest.getDisplayName()),
" in: ",
JenkinsResultsParserUtil.toDurationString(
longestRunningTest.getDuration()));
}
}
}
catch (IOException ioException) {
throw new RuntimeException(
"Unable to get build properties", ioException);
}
return summaryElement;
}
protected Element getJenkinsReportTableColumnHeadersElement() {
Element nameElement = Dom4JUtil.getNewElement("th", null, "Name");
Element consoleElement = Dom4JUtil.getNewElement("th", null, "Console");
Element testReportElement = Dom4JUtil.getNewElement(
"th", null, "Test Report");
Element startTimeElement = Dom4JUtil.getNewElement(
"th", null, "Start Time");
Element buildTimeElement = Dom4JUtil.getNewElement(
"th", null, "Build Time");
Element estimatedBuildTimeElement = null;
Element diffBuildTimeElement = null;
if (buildDurationsEnabled()) {
estimatedBuildTimeElement = Dom4JUtil.getNewElement(
"th", null, "Build Time (est)");
diffBuildTimeElement = Dom4JUtil.getNewElement(
"th", null, "Build Time (+/-)");
}
Element statusElement = Dom4JUtil.getNewElement("th", null, "Status");
Element resultElement = Dom4JUtil.getNewElement("th", null, "Result");
Element tableColumnHeaderElement = Dom4JUtil.getNewElement("tr");
Dom4JUtil.addToElement(
tableColumnHeaderElement, nameElement, consoleElement,
testReportElement, startTimeElement, buildTimeElement,
estimatedBuildTimeElement, diffBuildTimeElement, statusElement,
resultElement);
return tableColumnHeaderElement;
}
protected Element getJenkinsReportTimelineElement() {
Element canvasElement = Dom4JUtil.getNewElement("canvas");
canvasElement.addAttribute("height", "300");
canvasElement.addAttribute("id", "timeline");
Element scriptElement = Dom4JUtil.getNewElement("script");
scriptElement.addAttribute("src", _URL_CHART_JS);
scriptElement.addText("");
TimelineData timelineData = getTimelineData();
Element chartJSScriptElement = getJenkinsReportChartJsScriptElement(
Arrays.toString(timelineData.getIndexData()),
Arrays.toString(timelineData.getSlaveUsageData()),
Arrays.toString(timelineData.getInvocationsData()));
return Dom4JUtil.getNewElement(
"div", null, canvasElement, scriptElement, chartJSScriptElement);
}
protected Element getJenkinsReportTopLevelTableElement() {
Element topLevelTableElement = Dom4JUtil.getNewElement("table");
String result = getResult();
if (result != null) {
Dom4JUtil.getNewElement(
"caption", topLevelTableElement, "Top Level Build - ",
Dom4JUtil.getNewElement("strong", null, getResult()));
}
else {
Dom4JUtil.getNewElement(
"caption", topLevelTableElement, "Top Level Build - ",
Dom4JUtil.getNewElement(
"strong", null, StringUtils.upperCase(getStatus())));
}
Dom4JUtil.addToElement(
topLevelTableElement, getJenkinsReportTableColumnHeadersElement(),
getJenkinsReportTableRowElement());
List jenkinsReportStopWatchRecordElements =
getJenkinsReportStopWatchRecordElements();
Dom4JUtil.addToElement(
topLevelTableElement,
jenkinsReportStopWatchRecordElements.toArray());
return topLevelTableElement;
}
protected Element getJobSummaryElement() {
int successCount = getDownstreamBuildCountByResult("SUCCESS");
String result = getResult();
if (Objects.equals(result, "SUCCESS")) {
successCount++;
}
Element detailsElement = Dom4JUtil.getNewElement(
"details", null,
Dom4JUtil.getNewElement(
"summary", null,
Dom4JUtil.getNewElement(
"strong", null, "ci:test:", getTestSuiteName(), " - ",
String.valueOf(successCount), " out of ",
String.valueOf(getDownstreamBuildCount(null) + 1),
" jobs PASSED")));
if ((result != null) && !result.equals("SUCCESS")) {
Dom4JUtil.addToElement(
detailsElement, getFailedJobSummaryElement());
}
if (getDownstreamBuildCountByResult("SUCCESS") > 0) {
Dom4JUtil.addToElement(
detailsElement, getSuccessfulJobSummaryElement());
}
return detailsElement;
}
protected Element getJobSummaryListElement() {
Element jobSummaryListElement = Dom4JUtil.getNewElement("ul");
List builds = new ArrayList<>();
builds.add(this);
builds.addAll(getDownstreamBuilds(null));
for (Build build : builds) {
Element jobSummaryListItemElement = Dom4JUtil.getNewElement(
"li", jobSummaryListElement);
jobSummaryListItemElement.add(
build.getGitHubMessageBuildAnchorElement());
}
return jobSummaryListElement;
}
protected Element getJobSummaryListElement(
boolean success, List jobVariants) {
Element batchListElement = null;
String batchName = null;
List builds = new ArrayList<>();
if (jobVariants != null) {
builds.addAll(
getJobVariantsDownstreamBuilds(jobVariants, null, null));
}
else {
builds.add(this);
builds.addAll(getDownstreamBuilds(null));
}
int count = 0;
Element jobSummaryListElement = Dom4JUtil.getNewElement("ul");
for (Build build : builds) {
if (Objects.equals(getResult(), "SUCCESS") == success) {
count++;
if (count > _MAX_JOB_SUMMARY_LIST_SIZE) {
Element jobSummaryListItemElement = Dom4JUtil.getNewElement(
"li", jobSummaryListElement);
jobSummaryListItemElement.addText("...");
break;
}
if (build instanceof DownstreamBuild) {
DownstreamBuild downstreamBuild = (DownstreamBuild)build;
if (!Objects.equals(
batchName, downstreamBuild.getBatchName())) {
batchName = downstreamBuild.getBatchName();
Element batchListItemElement = Dom4JUtil.getNewElement(
"li", jobSummaryListElement);
batchListItemElement.addText(batchName);
batchListElement = Dom4JUtil.getNewElement(
"ul", batchListItemElement);
}
Element batchListItemElement = Dom4JUtil.getNewElement(
"li", batchListElement);
batchListItemElement.add(
build.getGitHubMessageBuildAnchorElement());
continue;
}
Element jobSummaryListItemElement = Dom4JUtil.getNewElement(
"li", jobSummaryListElement);
jobSummaryListItemElement.add(
build.getGitHubMessageBuildAnchorElement());
}
}
return jobSummaryListElement;
}
protected Element getMoreDetailsElement() {
return Dom4JUtil.getNewElement(
"h5", null, "For more details click ",
Dom4JUtil.getNewAnchorElement(getJenkinsReportURL(), "here"), ".");
}
protected Element getReevaluationDetailsElement(
TopLevelBuildReport upstreamTopLevelBuildReport) {
Element growURLElement = Dom4JUtil.getNewAnchorElement(
"https://grow.liferay.com/share" +
"/CI+liferay-continuous-integration+GitHub+Commands#" +
"General-Commands",
"reevaluation");
String buildID = JenkinsResultsParserUtil.getBuildID(getBuildURL());
Element preElement = Dom4JUtil.getNewElement(
"pre", null, "ci:reevaluate:" + buildID);
return Dom4JUtil.getNewElement(
"p", null, "This pull is eligible for ", growURLElement,
". When this ",
Dom4JUtil.getNewAnchorElement(
String.valueOf(upstreamTopLevelBuildReport.getBuildURL()),
"upstream build"),
" has completed, using the following CI command will compare ",
"this pull request result against a more recent upstream result:",
preElement);
}
protected String getReleaseRepositoryName() {
if (!Objects.equals(getBranchName(), "master")) {
return "liferay-portal-ee";
}
return "liferay-portal";
}
protected Element getResourceFileContentAsElement(
String tagName, Element parentElement, String resourceName) {
String resourceFileContent = null;
try {
resourceFileContent =
JenkinsResultsParserUtil.getResourceFileContent(resourceName);
}
catch (IOException ioException) {
throw new RuntimeException(
"Unable to load resource " + resourceName, ioException);
}
return Dom4JUtil.getNewElement(
tagName, parentElement, resourceFileContent);
}
protected Element getResultElement() {
StringBuilder sb = new StringBuilder();
String result = getResult();
int successCount = getDownstreamBuildCountByResult("SUCCESS");
if ((result != null) && result.matches("(APPROVED|SUCCESS)")) {
successCount++;
sb.append(":heavy_check_mark: ");
}
else {
sb.append(":x: ");
}
sb.append("ci:test:");
sb.append(getTestSuiteName());
sb.append(" - ");
sb.append(String.valueOf(successCount));
sb.append(" out of ");
sb.append(String.valueOf(getDownstreamBuildCountByResult(null) + 1));
sb.append(" jobs passed in ");
sb.append(JenkinsResultsParserUtil.toDurationString(getDuration()));
return Dom4JUtil.getNewElement("h3", null, sb.toString());
}
@Override
protected String getStartPropertiesTempMapURL() {
if (fromArchive) {
return getBuildURL() + "/start.properties.json";
}
JenkinsMaster jenkinsMaster = getJenkinsMaster();
return JenkinsResultsParserUtil.combine(
URL_BASE_TEMP_MAP, jenkinsMaster.getName(), "/", getJobName(), "/",
String.valueOf(getBuildNumber()), "/", getJobName(), "/",
"start.properties");
}
@Override
protected String getStopPropertiesTempMapURL() {
if (fromArchive) {
return getBuildURL() + "/stop.properties.json";
}
JenkinsMaster jenkinsMaster = getJenkinsMaster();
return JenkinsResultsParserUtil.combine(
URL_BASE_TEMP_MAP, jenkinsMaster.getName(), "/", getJobName(), "/",
String.valueOf(getBuildNumber()), "/", getJobName(), "/",
"stop.properties");
}
protected Element getSuccessfulJobSummaryElement() {
Element jobSummaryListElement = getJobSummaryListElement(true, null);
int successCount = getDownstreamBuildCountByResult("SUCCESS");
if (Objects.equals(getResult(), "SUCCESS")) {
successCount++;
}
return Dom4JUtil.getNewElement(
"details", null,
Dom4JUtil.getNewElement(
"summary", null,
Dom4JUtil.getNewElement(
"strong", null, String.valueOf(successCount),
" Successful Jobs:")),
jobSummaryListElement);
}
@Override
protected String getTempMapURL(String tempMapName) {
String tempMapURL = super.getTempMapURL(tempMapName);
if (tempMapURL != null) {
return tempMapURL;
}
Matcher matcher = gitRepositoryTempMapNamePattern.matcher(tempMapName);
if (matcher.find()) {
return getGitRepositoryDetailsPropertiesTempMapURL(
matcher.group("gitRepositoryType"));
}
return null;
}
@Override
protected int getTestCountByStatus(String status) {
int testCount = 0;
for (Build downstreamBuild : getDownstreamBuilds(null)) {
if (!(downstreamBuild instanceof BaseBuild)) {
continue;
}
BaseBuild downstreamBaseBuild = (BaseBuild)downstreamBuild;
testCount += downstreamBaseBuild.getTestCountByStatus(status);
}
return testCount;
}
protected Element getTopGitHubMessageElement() {
update();
Element rootElement = Dom4JUtil.getNewElement("html");
rootElement.add(getResultElement());
Element detailsElement = Dom4JUtil.getNewElement(
"details", rootElement,
Dom4JUtil.getNewElement(
"summary", null, "Click here for more details."));
String result = getResult();
if (isCompareToUpstream() &&
UpstreamFailureUtil.isUpstreamComparisonAvailable(this)) {
String upstreamBranchSHA = getUpstreamBranchSHA();
TopLevelBuildReport upstreamTopLevelBuildReport =
UpstreamFailureUtil.getUpstreamTopLevelBuildReport(
this, upstreamBranchSHA);
if ((upstreamTopLevelBuildReport != null) &&
isEligibleForReevaluation(result, upstreamBranchSHA)) {
Dom4JUtil.addToElement(
detailsElement, Dom4JUtil.getNewElement("br"),
getReevaluationDetailsElement(upstreamTopLevelBuildReport));
}
}
Dom4JUtil.addToElement(
detailsElement, Dom4JUtil.getNewElement("h4", null, "Base Branch:"),
getBaseBranchDetailsElement());
if (isCompareToUpstream() &&
UpstreamFailureUtil.isUpstreamComparisonAvailable(this)) {
Dom4JUtil.addToElement(
detailsElement,
Dom4JUtil.getNewElement("h4", null, "Upstream Comparison:"),
getUpstreamComparisonDetailsElement());
}
Dom4JUtil.addToElement(
detailsElement, getJobSummaryElement(), getMoreDetailsElement());
if ((result != null) && !result.equals("SUCCESS")) {
Dom4JUtil.addToElement(
detailsElement, (Object[])getBuildFailureElements());
}
return rootElement;
}
protected String getUpstreamBranchSHA() {
String upstreamBranchSHA = getParameterValue(
"GITHUB_UPSTREAM_BRANCH_SHA");
if ((upstreamBranchSHA == null) || upstreamBranchSHA.isEmpty()) {
Map startPropertiesTempMap =
getStartPropertiesTempMap();
upstreamBranchSHA = startPropertiesTempMap.get(
"GITHUB_UPSTREAM_BRANCH_SHA");
}
return upstreamBranchSHA;
}
protected Element getUpstreamComparisonDetailsElement() {
String upstreamJobFailuresSHA =
UpstreamFailureUtil.getUpstreamJobFailuresSHA(this);
String upstreamCommitURL =
"https://github.com/liferay/" + getBaseGitRepositoryName() +
"/commit/" + upstreamJobFailuresSHA;
Element upstreamComparisonDetailsElement = Dom4JUtil.getNewElement(
"p", null, "Branch GIT ID: ",
Dom4JUtil.getNewAnchorElement(
upstreamCommitURL, upstreamJobFailuresSHA));
TestrayBuild testrayBuild = UpstreamFailureUtil.getUpstreamTestrayBuild(
this);
Dom4JUtil.addToElement(
upstreamComparisonDetailsElement, Dom4JUtil.getNewElement("br"),
"Jenkins Build URL: ",
Dom4JUtil.getNewAnchorElement(
String.valueOf(testrayBuild.getURL()), testrayBuild.getName()));
return upstreamComparisonDetailsElement;
}
protected boolean isEligibleForReevaluation(
String result, String upstreamBranchSHA) {
if (JenkinsResultsParserUtil.isNullOrEmpty(upstreamBranchSHA)) {
return false;
}
if ((result != null) && !result.matches("(APPROVED|SUCCESS)") &&
hasDownstreamBuilds() &&
!upstreamBranchSHA.equals(
UpstreamFailureUtil.getUpstreamJobFailuresSHA(this))) {
return true;
}
return false;
}
protected boolean isReleaseBuild() {
return false;
}
protected void sendBuildMetrics(String message) {
if (_sendBuildMetrics) {
DatagramRequestUtil.send(
message.trim(), _metricsHostName, _metricsHostPort);
}
}
protected void sendBuildMetricsOnModifiedBuilds() {
StringBuilder sb = new StringBuilder();
Map, Integer> slaveUsages =
_getSlaveUsageByLabels();
for (Map.Entry, Integer> slaveUsageEntry :
slaveUsages.entrySet()) {
Map metricLabels = slaveUsageEntry.getKey();
Integer slaveUsage = slaveUsageEntry.getValue();
String buildMetricMessage =
StatsDMetricsUtil.generateGaugeDeltaMetric(
"build_slave_usage_gauge", slaveUsage, metricLabels);
if (buildMetricMessage != null) {
sb.append(buildMetricMessage);
sb.append("\n");
}
}
if (sb.length() > 0) {
sendBuildMetrics(sb.toString());
}
sendBuildMetricsOnModifiedCompletedBuilds();
}
protected void sendBuildMetricsOnModifiedCompletedBuilds() {
List modifiedCompletedBuilds =
getModifiedDownstreamBuildsByStatus("completed");
for (Build modifiedCompletedBuild : modifiedCompletedBuilds) {
if (modifiedCompletedBuild instanceof BatchBuild) {
continue;
}
sendBuildMetrics(
StatsDMetricsUtil.generateTimerMetric(
"jenkins_job_build_duration",
modifiedCompletedBuild.getDuration(),
modifiedCompletedBuild.getMetricLabels()));
}
}
protected static final Pattern gitRepositoryTempMapNamePattern =
Pattern.compile("git\\.(?.*)\\.properties");
private void _archiveBuildDatabase() {
String status = getStatus();
String urlSuffix = "build-database.json";
File archiveFile = getArchiveFile(urlSuffix);
if (!status.equals("completed")) {
if (archiveFile.exists()) {
JenkinsResultsParserUtil.delete(archiveFile);
}
return;
}
if (archiveFile.exists()) {
return;
}
long start = JenkinsResultsParserUtil.getCurrentTimeMillis();
BuildDatabase buildDatabase = getBuildDatabase();
try {
writeArchiveFile(
String.valueOf(buildDatabase.getJSONObject()),
getArchivePath() + "/" + urlSuffix);
}
catch (IOException ioException) {
throw new RuntimeException(
"Unable to archive " + urlSuffix, ioException);
}
finally {
if (JenkinsResultsParserUtil.debug) {
System.out.println(
JenkinsResultsParserUtil.combine(
"Archived ", String.valueOf(getArchiveFile(urlSuffix)),
" in ",
JenkinsResultsParserUtil.toDurationString(
JenkinsResultsParserUtil.getCurrentTimeMillis() -
start)));
}
}
}
private void _archiveJenkinsReport() {
String status = getStatus();
String urlSuffix = "jenkins-report.html";
File archiveFile = getArchiveFile(urlSuffix);
if (!status.equals("completed")) {
if (archiveFile.exists()) {
JenkinsResultsParserUtil.delete(archiveFile);
}
return;
}
if (archiveFile.exists()) {
return;
}
long start = JenkinsResultsParserUtil.getCurrentTimeMillis();
File jenkinsReportFile = new File(getBuildDirPath(), urlSuffix);
try {
if (jenkinsReportFile.exists()) {
JenkinsResultsParserUtil.copy(jenkinsReportFile, archiveFile);
return;
}
}
catch (IOException ioException) {
throw new RuntimeException(
"Unable to copy the Jenkins report", ioException);
}
finally {
if (JenkinsResultsParserUtil.debug) {
System.out.println(
JenkinsResultsParserUtil.combine(
"Archived ", String.valueOf(archiveFile), " in ",
JenkinsResultsParserUtil.toDurationString(
JenkinsResultsParserUtil.getCurrentTimeMillis() -
start)));
}
}
try {
writeArchiveFile(
getJenkinsReport(), getArchivePath() + "/jenkins-report.html");
}
catch (Exception exception) {
System.out.println("Unable to archive Jenkins report");
}
finally {
if (JenkinsResultsParserUtil.debug) {
System.out.println(
JenkinsResultsParserUtil.combine(
"Archived ", String.valueOf(archiveFile), " in ",
JenkinsResultsParserUtil.toDurationString(
JenkinsResultsParserUtil.getCurrentTimeMillis() -
start)));
}
}
}
private void _archiveProperties() {
String status = getStatus();
File archiveFile = new File(
getArchiveRootDir(), getArchiveName() + "/archive.properties");
if (!status.equals("completed")) {
if (archiveFile.exists()) {
JenkinsResultsParserUtil.delete(archiveFile);
}
return;
}
if (archiveFile.exists()) {
return;
}
long start = JenkinsResultsParserUtil.getCurrentTimeMillis();
Properties archiveProperties = new Properties();
archiveProperties.setProperty(
"top.level.build.url", replaceBuildURL(getBuildURL()));
StringWriter sw = new StringWriter();
try {
archiveProperties.store(sw, null);
JenkinsResultsParserUtil.write(archiveFile, sw.toString());
}
catch (IOException ioException) {
throw new RuntimeException(
"Unable to archive properties", ioException);
}
finally {
if (JenkinsResultsParserUtil.debug) {
System.out.println(
JenkinsResultsParserUtil.combine(
"Archived ", String.valueOf(archiveFile), " in ",
JenkinsResultsParserUtil.toDurationString(
JenkinsResultsParserUtil.getCurrentTimeMillis() -
start)));
}
}
}
private void _findDownstreamBuildsInConsoleText() {
if ((getBuildURL() == null) || (getParentBuild() != null)) {
return;
}
String consoleText = getConsoleText();
if (JenkinsResultsParserUtil.isNullOrEmpty(consoleText)) {
return;
}
Set downstreamBuildURLs = new HashSet<>();
for (Build downstreamBuild : getDownstreamBuilds(null)) {
String downstreamBuildURL = downstreamBuild.getBuildURL();
if (downstreamBuildURL != null) {
downstreamBuildURLs.add(downstreamBuildURL);
}
List downstreamBadBuildURLs =
downstreamBuild.getBadBuildURLs();
if (downstreamBadBuildURLs != null) {
downstreamBuildURLs.addAll(downstreamBadBuildURLs);
}
}
Map urlAxisNames = new HashMap<>();
int i = consoleText.lastIndexOf("\nstop-current-job:");
if (i != -1) {
consoleText = consoleText.substring(0, i);
}
Matcher downstreamBuildURLMatcher = _downstreamBuildURLPattern.matcher(
consoleText.substring(consoleReadCursor));
consoleReadCursor = consoleText.length();
while (downstreamBuildURLMatcher.find()) {
String url = downstreamBuildURLMatcher.group("url");
Pattern reinvocationPattern = Pattern.compile(
Pattern.quote(url) + " restarted at (?[^\\s]*)\\.");
Matcher reinvocationMatcher = reinvocationPattern.matcher(
consoleText);
while (reinvocationMatcher.find()) {
url = reinvocationMatcher.group("url");
}
if (downstreamBuildURLs.contains(url) ||
urlAxisNames.containsKey(url)) {
continue;
}
String jobVariant = downstreamBuildURLMatcher.group("jobVariant");
if (!JenkinsResultsParserUtil.isNullOrEmpty(jobVariant)) {
String jobName = downstreamBuildURLMatcher.group("jobName");
if (!JenkinsResultsParserUtil.isNullOrEmpty(jobName) &&
jobVariant.contains(jobName + "/")) {
jobVariant = jobVariant.replaceAll(jobName + "/", "");
}
}
urlAxisNames.put(url, jobVariant);
}
addDownstreamBuilds(urlAxisNames);
}
private Map, Integer> _getSlaveUsageByLabels() {
Map, Integer> slaveUsages = new HashMap<>();
List modifiedDownstreamBuilds = getModifiedDownstreamBuilds();
for (Build modifiedDownstreamBuild : modifiedDownstreamBuilds) {
Map metricLabels =
modifiedDownstreamBuild.getMetricLabels();
Integer slaveUsage = slaveUsages.get(metricLabels);
if (slaveUsage == null) {
slaveUsage = 0;
}
if (modifiedDownstreamBuild instanceof ParentBuild) {
ParentBuild parentBuild = (ParentBuild)modifiedDownstreamBuild;
slaveUsage += parentBuild.getTotalSlavesUsedCount(
"running", true);
slaveUsage -= parentBuild.getTotalSlavesUsedCount(
"completed", true);
}
slaveUsages.put(metricLabels, slaveUsage);
}
return slaveUsages;
}
private String _getStatusSummary() {
return JenkinsResultsParserUtil.combine(
String.valueOf(getDownstreamBuildCount("starting")), " Starting / ",
String.valueOf(getDownstreamBuildCount("missing")), " Missing / ",
String.valueOf(getDownstreamBuildCount("queued")), " Queued / ",
String.valueOf(getDownstreamBuildCount("running")), " Running / ",
String.valueOf(getDownstreamBuildCount("reporting")),
" Reporting / ",
String.valueOf(getDownstreamBuildCount("completed")),
" Completed / ", String.valueOf(getDownstreamBuildCount(null)),
" Total ");
}
private static final FailureMessageGenerator[] _FAILURE_MESSAGE_GENERATORS =
{
new CITestSuiteValidationFailureMessageGenerator(),
new CompileFailureMessageGenerator(),
new FormatFailureMessageGenerator(),
new GitLPushFailureMessageGenerator(),
new JenkinsRegenFailureMessageGenerator(),
new JenkinsSourceFormatFailureMessageGenerator(),
new InvalidGitCommitSHAFailureMessageGenerator(),
new InvalidSenderSHAFailureMessageGenerator(),
new RebaseFailureMessageGenerator(),
//
new PoshiValidationFailureMessageGenerator(),
new PoshiTestFailureMessageGenerator(),
//
new GradleTaskFailureMessageGenerator(),
//
new DownstreamFailureMessageGenerator(),
//
new CIFailureMessageGenerator(),
//
new GenericFailureMessageGenerator()
};
private static final int _MAX_JOB_SUMMARY_LIST_SIZE = 500;
private static final long _MILLIS_DOWNSTREAM_BUILDS_LISTING_INTERVAL =
1000 * 60 * 5;
private static final String _URL_CHART_JS =
"https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js";
private static final String _URL_CI_SYSTEM_STATUS =
"http://test-1-0.liferay.com/userContent/reports/ci-system-status" +
"/index.html";
private static final Pattern _downstreamBuildURLPattern = Pattern.compile(
"[\\'\\\"](?[^\\'\\\"]+)[\\'\\\"] (completed|started) at " +
"(?.+/job/(?[^/]+)/.+)\\.");
private static final ExecutorService _executorService =
JenkinsResultsParserUtil.getNewThreadPoolExecutor(10, true);
private static final Pattern _gitHubURLPattern = Pattern.compile(
"https://github.com/(?[^/]+)/[^/]/pull/" +
"(?\\d+)");
private boolean _compareToUpstream;
private Build _controllerBuild;
private final Map _downstreamAxisBuilds =
new ConcurrentHashMap<>();
private boolean _downstreamAxisBuildsPopulated;
private final Map _downstreamBatchBuilds =
new ConcurrentHashMap<>();
private boolean _downstreamBatchBuildsPopulated;
private JenkinsCohort _jenkinsCohort;
private long _lastDownstreamBuildsListingTimestamp = -1L;
private String _metricsHostName;
private int _metricsHostPort;
private final boolean _sendBuildMetrics;
}