All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.liferay.jenkins.results.parser.CISystemHistoryReportUtil Maven / Gradle / Ivy

There is a newer version: 1.0.1492
Show newest version
/**
 * 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 java.io.File;
import java.io.IOException;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Properties;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeoutException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.io.FileUtils;

import org.json.JSONArray;
import org.json.JSONObject;

/**
 * @author Michael Hashimoto
 */
public class CISystemHistoryReportUtil {

	public static void generateCISystemHistoryReport(
			String filePath, String jobName, String testSuiteName)
		throws IOException {

		writeAllDurationsJavaScriptFile();

		writeBackupDurationsJavaScriptFile();

		writeDateDurationsJavaScriptFiles(jobName, testSuiteName);

		writeIndexHtmlFile();

		FileUtils.copyDirectory(
			_CI_SYSTEM_HISTORY_REPORT_DIR, new File(filePath));
	}

	protected static void writeAllDurationsJavaScriptFile() throws IOException {
		File allDurationsFile = new File(
			_CI_SYSTEM_HISTORY_REPORT_DIR, "js/all-durations.js");

		if (allDurationsFile.exists()) {
			JenkinsResultsParserUtil.delete(allDurationsFile);
		}

		for (DurationReport durationReport : _getDurationReports()) {
			JenkinsResultsParserUtil.append(
				allDurationsFile,
				durationReport.getAllDurationsJavaScriptContent());
		}
	}

	protected static void writeBackupDurationsJavaScriptFile()
		throws IOException {

		File backupDurationsFile = new File(
			_CI_SYSTEM_HISTORY_REPORT_DIR, "js/backup-durations.js");

		if (backupDurationsFile.exists()) {
			JenkinsResultsParserUtil.delete(backupDurationsFile);
		}

		for (DurationReport durationReport : _getDurationReports()) {
			JenkinsResultsParserUtil.append(
				backupDurationsFile,
				durationReport.getBackupDurationsJavaScriptContent());
		}
	}

	protected static void writeDateDurationsJavaScriptFile(
			String jobName, final String testSuiteName, String dateString)
		throws IOException {

		final List durationReports = _getDurationReports();

		List jenkinsConsoleGzFiles = _getJenkinsConsoleGzFiles(
			jobName, dateString);

		List> callables = new ArrayList<>();

		System.out.println(
			"Processing " + jenkinsConsoleGzFiles.size() + " files");

		for (final File jenkinsConsoleGzFile : jenkinsConsoleGzFiles) {
			callables.add(
				new Callable() {

					@Override
					public File call() throws Exception {
						long start =
							JenkinsResultsParserUtil.getCurrentTimeMillis();

						try {
							TopLevelBuildReport topLevelBuildReport =
								BuildReportFactory.newTopLevelBuildReport(
									jenkinsConsoleGzFile);

							if ((topLevelBuildReport == null) ||
								!Objects.equals(
									testSuiteName,
									topLevelBuildReport.getTestSuiteName())) {

								return null;
							}

							for (DurationReport durationReport :
									durationReports) {

								durationReport.addDurations(
									topLevelBuildReport);
							}

							return jenkinsConsoleGzFile;
						}
						catch (Exception exception) {
							RuntimeException runtimeException =
								new RuntimeException(
									JenkinsResultsParserUtil.getCanonicalPath(
										jenkinsConsoleGzFile),
									exception);

							runtimeException.printStackTrace();

							return null;
						}
						finally {
							long end =
								JenkinsResultsParserUtil.getCurrentTimeMillis();

							System.out.println(
								JenkinsResultsParserUtil.combine(
									JenkinsResultsParserUtil.getCanonicalPath(
										jenkinsConsoleGzFile),
									" processed in ",
									JenkinsResultsParserUtil.toDurationString(
										end - start)));
						}
					}

				});
		}

		ParallelExecutor parallelExecutor = new ParallelExecutor<>(
			callables, _executorService, "WriteDateDurationsJavaScript");

		try {
			List completedJenkinsConsoleGzFiles =
				parallelExecutor.execute();

			completedJenkinsConsoleGzFiles.removeAll(
				Collections.singleton(null));

			System.out.println(
				"Processed " + completedJenkinsConsoleGzFiles.size() +
					" files");
		}
		catch (TimeoutException timeoutException) {
			throw new RuntimeException(timeoutException);
		}

		File durationsFile = new File(
			_CI_SYSTEM_HISTORY_REPORT_DIR,
			"js/durations-" + dateString + ".js");

		if (durationsFile.exists()) {
			JenkinsResultsParserUtil.delete(durationsFile);
		}

		for (DurationReport durationReport : durationReports) {
			JenkinsResultsParserUtil.append(
				durationsFile,
				durationReport.getDateDurationsJavaScriptContent(dateString));
		}
	}

	protected static void writeDateDurationsJavaScriptFiles(
			String jobName, String testSuiteName)
		throws IOException {

		int size = _dateStrings.size();

		for (int i = size - _MONTH_RECORD_COUNT; i < size; i++) {
			writeDateDurationsJavaScriptFile(
				jobName, testSuiteName, _dateStrings.get(i));
		}
	}

	protected static void writeIndexHtmlFile() throws IOException {
		File indexHtmlFile = new File(
			_CI_SYSTEM_HISTORY_REPORT_DIR, "index.html");

		if (!indexHtmlFile.exists()) {
			return;
		}

		String content = JenkinsResultsParserUtil.read(indexHtmlFile);

		StringBuilder sb = new StringBuilder();

		sb.append("\t\t\n\n");

		for (String dateString : _dateStrings) {
			sb.append("\t\t\n");
		}

		sb.append("\n\t\t\n");

		JenkinsResultsParserUtil.write(
			indexHtmlFile,
			content.replaceAll("\\t\\t\\n", sb.toString()));
	}

	private static int _getBuildPropertyInt(
		String propertyName, int defaultValue) {

		try {
			return Integer.parseInt(
				JenkinsResultsParserUtil.getProperty(
					_buildProperties, propertyName));
		}
		catch (Exception exception) {
			return defaultValue;
		}
	}

	private static List _getDurationReports() {
		List durationReports = new ArrayList<>();

		for (String propertyName : _buildProperties.stringPropertyNames()) {
			Matcher matcher = _durationPropertyPattern.matcher(propertyName);

			if (!matcher.find()) {
				continue;
			}

			durationReports.add(
				new DurationReport(
					matcher.group("buildType"),
					matcher.group("durationReportType")));
		}

		Collections.sort(durationReports);

		return durationReports;
	}

	private static List _getJenkinsConsoleGzFiles(
		String jobName, String dateString) {

		List jenkinsConsoleGzFiles = new ArrayList<>();

		File testrayLogsDateDir = new File(_TESTRAY_LOGS_DIR, dateString);

		if (!testrayLogsDateDir.exists()) {
			return jenkinsConsoleGzFiles;
		}

		Process process;

		try {
			process = JenkinsResultsParserUtil.executeBashCommands(
				true, _TESTRAY_LOGS_DIR, 1000 * 60 * 60,
				JenkinsResultsParserUtil.combine(
					"find ", dateString, "/*/",
					JenkinsResultsParserUtil.escapeForBash(jobName),
					"/*/jenkins-console.txt.gz"));
		}
		catch (IOException | TimeoutException exception) {
			return jenkinsConsoleGzFiles;
		}

		int exitValue = process.exitValue();

		if (exitValue != 0) {
			return jenkinsConsoleGzFiles;
		}

		String output = null;

		try {
			output = JenkinsResultsParserUtil.readInputStream(
				process.getInputStream());

			output = output.replace("Finished executing Bash commands.\n", "");

			output = output.trim();
		}
		catch (IOException ioException) {
			return jenkinsConsoleGzFiles;
		}

		if (JenkinsResultsParserUtil.isNullOrEmpty(output)) {
			return jenkinsConsoleGzFiles;
		}

		for (String jenkinsConsoleGzFilePath : output.split("\n")) {
			jenkinsConsoleGzFiles.add(
				new File(_TESTRAY_LOGS_DIR, jenkinsConsoleGzFilePath));
		}

		return jenkinsConsoleGzFiles;
	}

	private static final File _CI_SYSTEM_HISTORY_REPORT_DIR;

	private static final int _MONTH_COUNT;

	private static final int _MONTH_RECORD_COUNT;

	private static final long _START_TIME =
		JenkinsResultsParserUtil.getCurrentTimeMillis();

	private static final File _TESTRAY_LOGS_DIR;

	private static final Properties _buildProperties;
	private static final List _dateStrings;
	private static final Pattern _durationPropertyPattern = Pattern.compile(
		"ci.system.history.title\\[(?[^\\]]+)\\]" +
			"\\[(?[^\\]]+)\\]");
	private static final ExecutorService _executorService =
		JenkinsResultsParserUtil.getNewThreadPoolExecutor(20, true);

	static {
		_buildProperties = new Properties() {
			{
				try {
					putAll(JenkinsResultsParserUtil.getBuildProperties());
				}
				catch (IOException ioException) {
					throw new RuntimeException(ioException);
				}
			}
		};

		_CI_SYSTEM_HISTORY_REPORT_DIR = new File(
			_buildProperties.getProperty("ci.system.history.report.dir"));

		_MONTH_COUNT = _getBuildPropertyInt(
			"ci.system.history.report.month.count", 12);

		_MONTH_RECORD_COUNT = _getBuildPropertyInt(
			"ci.system.history.report.month.record.count", 2);

		_dateStrings = new ArrayList() {
			{
				LocalDate currentLocalDate = LocalDate.now();

				for (int i = _MONTH_COUNT - 1; i >= 0; i--) {
					LocalDate localDate = currentLocalDate.minusMonths(i);

					add(
						localDate.format(
							DateTimeFormatter.ofPattern("yyyy-MM")));
				}
			}
		};

		_TESTRAY_LOGS_DIR = new File(
			_buildProperties.getProperty("jenkins.testray.results.dir"),
			"production/logs");
	}

	private static class DurationReport implements Comparable {

		public void addDurations(TopLevelBuildReport topLevelBuildReport) {
			if (topLevelBuildReport == null) {
				return;
			}

			if (_buildType.equals("top.level")) {
				if (_durationReportType.equals("active.duration")) {
					_durations.add(
						topLevelBuildReport.getTopLevelActiveDuration());

					return;
				}

				if (_durationReportType.equals("passive.duration")) {
					_durations.add(
						topLevelBuildReport.getTopLevelPassiveDuration());

					return;
				}

				_durations.add(
					_getDuration(
						topLevelBuildReport.getStopWatchRecordsGroup(),
						_durationReportType));

				return;
			}

			List downstreamBuildReports =
				topLevelBuildReport.getDownstreamBuildReports();

			if (!_buildType.equals("downstream") ||
				downstreamBuildReports.isEmpty()) {

				return;
			}

			for (DownstreamBuildReport downstreamBuildReport :
					downstreamBuildReports) {

				_durations.add(
					_getDuration(
						downstreamBuildReport.getStopWatchRecordsGroup(),
						_durationReportType));
			}
		}

		@Override
		public int compareTo(DurationReport durationReport) {
			String id = durationReport._getID();

			return id.compareTo(_getID());
		}

		public String getAllDurationsJavaScriptContent() {
			StringBuilder sb = new StringBuilder();

			sb.append("var ");
			sb.append(getAllDurationsJavaScriptVarName());
			sb.append(" = ");
			sb.append(getAllDurationsJavaScriptVarValue());
			sb.append(";\n");

			sb.append("createContainer(");
			sb.append(getAllDurationsJavaScriptVarName());
			sb.append(");\n\n");

			return sb.toString();
		}

		public String getAllDurationsJavaScriptVarName() {
			return JenkinsResultsParserUtil.combine(
				_getJavaScriptID(), "_all_durations");
		}

		public String getAllDurationsJavaScriptVarValue() {
			JSONObject jsonObject = new JSONObject();

			jsonObject.put(
				"description", _description
			).put(
				"durations", getDurationsJavaScriptVarNames()
			).put(
				"durations_dates", getDateJavaScriptVarNames()
			).put(
				"id", _getID()
			).put(
				"modification_date", _START_TIME
			).put(
				"title", _title
			);

			String javascriptVarValue = jsonObject.toString();

			return javascriptVarValue.replaceAll(
				"\\\"([^\\\"]+_\\d{4}_\\d{2})\\\"", "$1");
		}

		public String getBackupDurationsJavaScriptContent() {
			StringBuilder sb = new StringBuilder();

			for (String durationsJavaScriptVarName :
					getDurationsJavaScriptVarNames()) {

				sb.append(durationsJavaScriptVarName);
				sb.append(" = []\n");
			}

			for (String dateJavaScriptVarName : getDateJavaScriptVarNames()) {
				sb.append(dateJavaScriptVarName);
				sb.append(" = [\"");

				sb.append(
					dateJavaScriptVarName.replaceAll(
						".+(\\d{4}_\\d{2})", "$1"));

				sb.append("\"]\n");
			}

			return sb.toString();
		}

		public String getDateDurationsJavaScriptContent(String dateString) {
			StringBuilder sb = new StringBuilder();

			_durations.removeAll(Arrays.asList(null, 0L));

			sb.append("var ");
			sb.append(getDateJavaScriptVarName(dateString));
			sb.append(" = ");
			sb.append(getDateJavaScriptVarValue(dateString, _durations));

			sb.append("\nvar ");
			sb.append(getDurationsJavaScriptVarName(dateString));
			sb.append(" = ");
			sb.append(_durations);
			sb.append("\n\n");

			return sb.toString();
		}

		public String getDateJavaScriptVarName(String dateString) {
			return JenkinsResultsParserUtil.combine(
				_getJavaScriptID(), "_date_", dateString.replaceAll("-", "_"));
		}

		public List getDateJavaScriptVarNames() {
			List dateDurationJavaScriptVars = new ArrayList<>();

			for (String dateString : _dateStrings) {
				dateDurationJavaScriptVars.add(
					getDateJavaScriptVarName(dateString));
			}

			return dateDurationJavaScriptVars;
		}

		public String getDateJavaScriptVarValue(
			String dateString, List durations) {

			JSONArray jsonArray = new JSONArray();

			jsonArray.put(dateString);

			if ((durations == null) || durations.isEmpty()) {
				return jsonArray.toString();
			}

			String meanString = JenkinsResultsParserUtil.toDurationString(
				JenkinsResultsParserUtil.getAverage(durations));

			jsonArray.put("mean: " + meanString);

			jsonArray.put("total: " + String.format("%,d", durations.size()));

			return jsonArray.toString();
		}

		public String getDurationsJavaScriptVarName(String dateString) {
			return JenkinsResultsParserUtil.combine(
				_getJavaScriptID(), "_durations_",
				dateString.replaceAll("-", "_"));
		}

		public List getDurationsJavaScriptVarNames() {
			List durationsJavaScriptVarNames = new ArrayList<>();

			for (String dateString : _dateStrings) {
				durationsJavaScriptVarNames.add(
					getDurationsJavaScriptVarName(dateString));
			}

			return durationsJavaScriptVarNames;
		}

		private DurationReport(String buildType, String durationReportType) {
			_buildType = buildType;

			_description = JenkinsResultsParserUtil.getProperty(
				_buildProperties, "ci.system.history.description", buildType,
				durationReportType);

			_title = JenkinsResultsParserUtil.getProperty(
				_buildProperties, "ci.system.history.title", buildType,
				durationReportType);

			_durationReportType = durationReportType;
		}

		private long _getDuration(
			StopWatchRecordsGroup stopWatchRecordsGroup,
			String durationReportType) {

			if (stopWatchRecordsGroup == null) {
				return 0L;
			}

			StopWatchRecord stopWatchRecord = stopWatchRecordsGroup.get(
				durationReportType);

			if (stopWatchRecord == null) {
				return 0L;
			}

			long duration = stopWatchRecord.getDuration();

			if (duration < 0) {
				return 0L;
			}

			return duration;
		}

		private String _getID() {
			String id = _buildType + "-" + _durationReportType;

			id = id.replaceAll("_", "-");
			id = id.replaceAll("\\.", "-");

			return id;
		}

		private String _getJavaScriptID() {
			String javascriptID = _buildType + "_" + _durationReportType;

			javascriptID = javascriptID.replaceAll("-", "_");
			javascriptID = javascriptID.replaceAll("\\.", "_");

			return javascriptID;
		}

		private final String _buildType;
		private final String _description;
		private final String _durationReportType;
		private final List _durations = new ArrayList<>();
		private final String _title;

	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy