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

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

There is a newer version: 1.0.1492
Show newest version
/**
 * SPDX-FileCopyrightText: (c) 2024 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.net.URL;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

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

	public static void mergePortalSubrepository(
			URL jenkinsBuildURL, PullRequest portalPullRequest,
			URL subrepositoryGitHubURL, String subrepositoryUpstreamBranchName,
			String targetGitRepoCommitSHA)
		throws IOException {

		_onMergeStarted(jenkinsBuildURL, portalPullRequest);

		_checkPassingTestSuites(jenkinsBuildURL, portalPullRequest);

		GitWorkingDirectory portalGitWorkingDirectory = _getGitWorkingDirectory(
			jenkinsBuildURL, portalPullRequest, portalPullRequest.getBaseURL(),
			portalPullRequest.getUpstreamRemoteGitBranchName());

		String startingPortalCommitSHA =
			portalGitWorkingDirectory.getLatestCommitSHA();

		GitWorkingDirectory subrepositoryGitWorkingDirectory =
			_getGitWorkingDirectory(
				jenkinsBuildURL, portalPullRequest, subrepositoryGitHubURL,
				subrepositoryUpstreamBranchName);

		String currentGitRepoCommitSHA = _getCurrentGitRepoCommitSHA(
			jenkinsBuildURL, portalPullRequest, portalGitWorkingDirectory,
			subrepositoryGitWorkingDirectory, targetGitRepoCommitSHA);

		_fetchSubrepositoryBranchToPortalRepository(
			jenkinsBuildURL, portalPullRequest, portalGitWorkingDirectory,
			subrepositoryGitWorkingDirectory);

		_checkMergeCommitSHA(
			jenkinsBuildURL, portalPullRequest, currentGitRepoCommitSHA,
			targetGitRepoCommitSHA, portalGitWorkingDirectory,
			subrepositoryGitWorkingDirectory);

		_createAndApplyPatch(
			jenkinsBuildURL, portalPullRequest, portalGitWorkingDirectory,
			subrepositoryGitWorkingDirectory, currentGitRepoCommitSHA,
			targetGitRepoCommitSHA);

		_commitGitRepoUpdates(
			jenkinsBuildURL, portalPullRequest, portalGitWorkingDirectory,
			subrepositoryGitWorkingDirectory, startingPortalCommitSHA,
			targetGitRepoCommitSHA);

		_pushUpdatesToRemoteBranch(
			jenkinsBuildURL, portalPullRequest, portalGitWorkingDirectory);

		String endingPortalCommitSHA =
			portalGitWorkingDirectory.getLatestCommitSHA();

		_onMergeCompleted(
			jenkinsBuildURL, portalPullRequest, subrepositoryGitHubURL,
			targetGitRepoCommitSHA, startingPortalCommitSHA,
			endingPortalCommitSHA);
	}

	private static void _checkMergeCommitSHA(
		URL jenkinsBuildURL, PullRequest portalPullRequest,
		String currentGitRepoCommitSHA, String targetGitRepoCommitSHA,
		GitWorkingDirectory portalGitWorkingDirectory,
		GitWorkingDirectory subrepositoryGitWorkingDirectory) {

		if (Objects.equals(
				subrepositoryGitWorkingDirectory.getMergeBaseCommitSHA(
					currentGitRepoCommitSHA, targetGitRepoCommitSHA),
				currentGitRepoCommitSHA)) {

			return;
		}

		StringBuilder sb = new StringBuilder();

		sb.append(
			_getGitHubURLString(
				portalPullRequest.getBaseURL(), targetGitRepoCommitSHA));
		sb.append(" is incompatible with sha found in '");
		sb.append(
			JenkinsResultsParserUtil.getPathRelativeTo(
				_getGitRepoFile(
					portalGitWorkingDirectory,
					subrepositoryGitWorkingDirectory),
				portalGitWorkingDirectory.getWorkingDirectory()));
		sb.append("'");

		_reportError(sb.toString(), jenkinsBuildURL, portalPullRequest);
	}

	private static void _checkPassingTestSuites(
		URL jenkinsBuildURL, PullRequest portalPullRequest) {

		List requiredPassingTestSuiteNames = new ArrayList<>();

		Collections.addAll(requiredPassingTestSuiteNames, "relevant", "sf");

		requiredPassingTestSuiteNames.removeAll(
			portalPullRequest.getPassingTestSuiteNames());

		if (requiredPassingTestSuiteNames.isEmpty()) {
			return;
		}

		StringBuilder sb = new StringBuilder();

		sb.append("Skip merge subrepo because tests have not passed.\n");
		sb.append("
    \n"); for (String requiredPassingTestSuiteName : requiredPassingTestSuiteNames) { sb.append("
  • ci:test:"); sb.append(requiredPassingTestSuiteName); sb.append("
  • \n"); } sb.append("
\n"); _reportError(sb.toString(), jenkinsBuildURL, portalPullRequest); } private static void _commitGitRepoUpdates( URL jenkinsBuildURL, PullRequest portalPullRequest, GitWorkingDirectory portalGitWorkingDirectory, GitWorkingDirectory subrepositoryGitWorkingDirectory, String startingPortalCommitSHA, String targetGitRepoCommitSHA) { File gitRepoFile = _getGitRepoFile( portalGitWorkingDirectory, subrepositoryGitWorkingDirectory); String gitRepoFilePath = JenkinsResultsParserUtil.getPathRelativeTo( gitRepoFile, portalGitWorkingDirectory.getWorkingDirectory()); try { String gitRepoFileContent = JenkinsResultsParserUtil.read( gitRepoFile); gitRepoFileContent = gitRepoFileContent.replaceAll( "commit = [0-9a-f]{40}", "commit = " + targetGitRepoCommitSHA); gitRepoFileContent = gitRepoFileContent.replaceAll( "parent = [0-9a-f]{40}", "parent = " + startingPortalCommitSHA); JenkinsResultsParserUtil.write(gitRepoFile, gitRepoFileContent); portalGitWorkingDirectory.stageFileInCurrentLocalGitBranch( JenkinsResultsParserUtil.getPathRelativeTo( gitRepoFile, portalGitWorkingDirectory.getWorkingDirectory())); portalGitWorkingDirectory.commitFileToCurrentBranch( gitRepoFilePath, "subrepo:ignore Update '" + gitRepoFilePath + "'."); } catch (IOException ioException) { _reportError( "Unable to update " + gitRepoFilePath, jenkinsBuildURL, portalPullRequest, ioException); } } private static void _createAndApplyPatch( URL jenkinsBuildURL, PullRequest portalPullRequest, GitWorkingDirectory portalGitWorkingDirectory, GitWorkingDirectory subrepositoryGitWorkingDirectory, String gitRepoSHA, String targetGitRepoCommitSHA) { Set modifiedFilesInCommitRange = subrepositoryGitWorkingDirectory.getModifiedFilesInCommitRange( gitRepoSHA, targetGitRepoCommitSHA); StringBuilder sb = new StringBuilder(); sb.append("git format-patch --root \""); sb.append(gitRepoSHA); sb.append(".."); sb.append(targetGitRepoCommitSHA); sb.append("\" -- "); boolean foundModifiedFiles = false; for (File modifiedFile : modifiedFilesInCommitRange) { String modifiedFilePath = JenkinsResultsParserUtil.getCanonicalPath( modifiedFile); if (modifiedFilePath.endsWith("gradle.properties") || modifiedFilePath.endsWith("gradlew") || modifiedFilePath.endsWith("gradlew.bat") || modifiedFilePath.contains("gradle/")) { continue; } sb.append(" "); sb.append( JenkinsResultsParserUtil.getPathRelativeTo( modifiedFile, subrepositoryGitWorkingDirectory.getWorkingDirectory())); foundModifiedFiles = true; } if (!foundModifiedFiles) { _reportError( "No found modified files", jenkinsBuildURL, portalPullRequest); return; } GitUtil.ExecutionResult executionResult = portalGitWorkingDirectory.executeBashCommands( 3, GitUtil.MILLIS_RETRY_DELAY, 1000 * 60 * 10, "rm -f *.patch", sb.toString(), "(git am --abort || true)", JenkinsResultsParserUtil.combine( "git am --directory=\"", _getSubrepositoryModuleDirPath( portalGitWorkingDirectory, subrepositoryGitWorkingDirectory), "\" --keep-cr --whitespace=nowarn *.patch")); if (executionResult.getExitValue() != 0) { throw new RuntimeException( "Unable to create & apply the patch \n" + executionResult.getStandardError()); } System.out.println(executionResult.getStandardOut()); } private static void _fetchSubrepositoryBranchToPortalRepository( URL jenkinsBuildURL, PullRequest portalPullRequest, GitWorkingDirectory portalGitWorkingDirectory, GitWorkingDirectory subrepositoryGitWorkingDirectory) { LocalGitBranch portalCurrentLocalGitBranch = portalGitWorkingDirectory.getCurrentLocalGitBranch(); String portalCurrentBranchSHA = portalCurrentLocalGitBranch.getSHA(); try { portalGitWorkingDirectory.fetch( null, subrepositoryGitWorkingDirectory.getCurrentLocalGitBranch()); } catch (Exception exception) { File subrepositoryWorkingDirectory = subrepositoryGitWorkingDirectory.getWorkingDirectory(); _reportError( "Unable to fetch from " + subrepositoryWorkingDirectory, jenkinsBuildURL, portalPullRequest, exception); } finally { portalGitWorkingDirectory.reset("--hard " + portalCurrentBranchSHA); } } private static String _getCurrentGitRepoCommitSHA( URL jenkinsBuildURL, PullRequest portalPullRequest, GitWorkingDirectory portalGitWorkingDirectory, GitWorkingDirectory subrepositoryGitWorkingDirectory, String targetGitRepoCommitSHA) { File gitRepoFile = _getGitRepoFile( portalGitWorkingDirectory, subrepositoryGitWorkingDirectory); Properties gitRepoProperties = JenkinsResultsParserUtil.getProperties( gitRepoFile); String currentGitRepoCommitSHA = gitRepoProperties.getProperty( "commit"); if (Objects.equals(currentGitRepoCommitSHA, targetGitRepoCommitSHA)) { StringBuilder sb = new StringBuilder(); sb.append( _getGitHubURLString( portalPullRequest.getBaseURL(), targetGitRepoCommitSHA)); sb.append(" already found in '"); sb.append( JenkinsResultsParserUtil.getPathRelativeTo( gitRepoFile, portalGitWorkingDirectory.getWorkingDirectory())); sb.append("'"); _reportError(sb.toString(), jenkinsBuildURL, portalPullRequest); return null; } return currentGitRepoCommitSHA; } private static String _getGitHubURLString( URL gitHubURL, String gitBranchSHA) { StringBuilder sb = new StringBuilder(); Matcher matcher = _gitHubURLPattern.matcher(String.valueOf(gitHubURL)); if (matcher.find()) { sb.append(matcher.group("userName")); sb.append("/"); sb.append(matcher.group("repositoryName")); sb.append("/"); sb.append(matcher.group("branchName")); } else { sb.append(gitHubURL); } if (!JenkinsResultsParserUtil.isNullOrEmpty(gitBranchSHA)) { sb.append(" ("); sb.append(gitBranchSHA.substring(0, 7)); sb.append(")"); } return sb.toString(); } private static File _getGitRepoFile( GitWorkingDirectory portalGitWorkingDirectory, GitWorkingDirectory subrepositoryGitWorkingDirectory) { GitRemote subrepositoryUpstreamGitRemote = subrepositoryGitWorkingDirectory.getUpstreamGitRemote(); Set gitRepoFiles = portalGitWorkingDirectory.findFiles( ".gitrepo", subrepositoryUpstreamGitRemote.getRemoteURL()); for (File gitRepoFile : gitRepoFiles) { return gitRepoFile; } return null; } private static GitWorkingDirectory _getGitWorkingDirectory( URL jenkinsBuildURL, PullRequest portalPullRequest, URL gitHubURL, String upstreamBranchName) throws IOException { Matcher gitHubURLMatcher = _gitHubURLPattern.matcher( String.valueOf(gitHubURL)); if (!gitHubURLMatcher.find()) { _reportError( "Invalid GitHub URL " + gitHubURL, jenkinsBuildURL, portalPullRequest); return null; } String baseRepositoryDirPath = JenkinsResultsParserUtil.getBuildProperty("base.repository.dir"); String repositoryName = gitHubURLMatcher.group("repositoryName"); String repositoryDirPath = JenkinsResultsParserUtil.combine( baseRepositoryDirPath, "/", repositoryName); if (repositoryName.equals("liferay-portal-ee") && upstreamBranchName.matches("\\d+\\.\\d+\\.x")) { repositoryDirPath = JenkinsResultsParserUtil.combine( baseRepositoryDirPath, "/liferay-portal-", upstreamBranchName); } return GitWorkingDirectoryFactory.newGitWorkingDirectory( upstreamBranchName, repositoryDirPath, repositoryName); } private static String _getPullRequestLink(PullRequest portalPullRequest) { StringBuilder sb = new StringBuilder(); sb.append(""); sb.append(portalPullRequest.getReceiverUsername()); sb.append("#"); sb.append(portalPullRequest.getNumber()); sb.append(""); return sb.toString(); } private static String _getSubrepositoryModuleDirPath( GitWorkingDirectory portalGitWorkingDirectory, GitWorkingDirectory subrepositoryGitWorkingDirectory) { String relativeFilePath = JenkinsResultsParserUtil.getPathRelativeTo( _getGitRepoFile( portalGitWorkingDirectory, subrepositoryGitWorkingDirectory), portalGitWorkingDirectory.getWorkingDirectory()); return relativeFilePath.replaceAll("/\\.gitrepo", ""); } private static void _onMergeCompleted( URL jenkinsBuildURL, PullRequest portalPullRequest, URL subrepositoryGitHubURL, String targetGitRepoCommitSHA, String startingPortalCommitSHA, String endingPortalCommitSHA) { Matcher matcher = _gitHubURLPattern.matcher( String.valueOf(subrepositoryGitHubURL)); if (!matcher.find()) { _reportError( "Invalid subrepository github url " + subrepositoryGitHubURL, jenkinsBuildURL, portalPullRequest); return; } String message = JenkinsResultsParserUtil.combine( "Completed subrepo merge process at ", JenkinsResultsParserUtil.toDateString(new Date()), ".\n", "All commits have been successfully pulled.\n", "Diff URL: ", startingPortalCommitSHA.substring(0, 7), "...", endingPortalCommitSHA.substring(0, 7), ""); JenkinsResultsParserUtil.updateBuildDescription( message, jenkinsBuildURL); PullRequest.Comment pullRequestComment = portalPullRequest.addComment( JenkinsResultsParserUtil.combine( message, "\n\nFor more details click here.")); GitHubRemoteGitCommit gitHubRemoteGitCommit = GitCommitFactory.newGitHubRemoteGitCommit( matcher.group("userName"), matcher.group("repositoryName"), targetGitRepoCommitSHA); gitHubRemoteGitCommit.setStatus( GitHubRemoteGitCommit.Status.SUCCESS, "liferay/merged-into-central", JenkinsResultsParserUtil.combine( "Merged into ", portalPullRequest.getReceiverUsername(), "/", portalPullRequest.getGitRepositoryName()), String.valueOf(pullRequestComment.getURL())); portalPullRequest.close(); } private static void _onMergeStarted( URL jenkinsBuildURL, PullRequest portalPullRequest) { portalPullRequest.addComment( JenkinsResultsParserUtil.combine( "Started subrepo merge process here at ", JenkinsResultsParserUtil.toDateString(new Date()), ".")); JenkinsResultsParserUtil.updateBuildDescription( _getPullRequestLink(portalPullRequest), jenkinsBuildURL); } private static void _pushUpdatesToRemoteBranch( URL jenkinsBuildURL, PullRequest portalPullRequest, GitWorkingDirectory portalGitWorkingDirectory) { URL portalBaseURL = portalPullRequest.getBaseURL(); Matcher gitHubURLMatcher = _gitHubURLPattern.matcher( String.valueOf(portalBaseURL)); if (!gitHubURLMatcher.find()) { _reportError( "Invalid GitHub URL " + portalBaseURL, jenkinsBuildURL, portalPullRequest); return; } String remoteURL = JenkinsResultsParserUtil.combine( "[email protected]:", gitHubURLMatcher.group("userName"), "/", gitHubURLMatcher.group("repositoryName"), ".git"); RemoteGitBranch remoteGitBranch = portalGitWorkingDirectory.pushToRemoteGitRepository( false, portalGitWorkingDirectory.getCurrentLocalGitBranch(), gitHubURLMatcher.group("branchName"), remoteURL); if (remoteGitBranch == null) { _reportError( "Unable to push updates to " + remoteURL, jenkinsBuildURL, portalPullRequest); } } private static void _reportError( String errorMessage, URL jenkinsBuildURL, PullRequest portalPullRequest) { _reportError(errorMessage, jenkinsBuildURL, portalPullRequest, null); } private static void _reportError( String errorMessage, URL jenkinsBuildURL, PullRequest portalPullRequest, Exception exception) { System.out.println(errorMessage); JenkinsResultsParserUtil.updateBuildDescription( errorMessage, jenkinsBuildURL); portalPullRequest.addComment( JenkinsResultsParserUtil.combine( errorMessage, "\n\nFor more details click here.")); if (exception != null) { throw new RuntimeException(errorMessage, exception); } throw new RuntimeException(errorMessage); } private static final Pattern _gitHubURLPattern = Pattern.compile( "https://github.com/(?[^/]+)/(?[^/]+)/tree/" + "(?[^/]+)"); }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy