diff --git a/src/main/java/org/jboss/set/assist/CommitHomeService.java b/src/main/java/org/jboss/set/assist/CommitHomeService.java new file mode 100644 index 0000000..7c49b51 --- /dev/null +++ b/src/main/java/org/jboss/set/assist/CommitHomeService.java @@ -0,0 +1,135 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2020, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.jboss.set.assist; + +import org.jboss.set.aphrodite.Aphrodite; +import org.jboss.set.aphrodite.domain.Commit; +import org.jboss.set.aphrodite.domain.PullRequest; +import org.jboss.set.aphrodite.simplecontainer.SimpleContainer; +import org.jboss.set.aphrodite.spi.NotFoundException; + +import javax.naming.NameNotFoundException; +import java.time.Duration; +import java.time.Instant; +import java.time.LocalTime; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class CommitHomeService { + private static final Logger logger = Logger.getLogger(CommitHomeService.class.getCanonicalName()); + private static Aphrodite aphrodite; + private static Store store; + + private static final String FUTURE = "-future"; + private static final String EAP_REPO = "jbossas/jboss-eap7"; + + private static final long MONTH_MILLI = 2629800000L; // milliseconds in a month + + static { + try { + aphrodite = SimpleContainer.instance().lookup(Aphrodite.class.getSimpleName(), Aphrodite.class); + } catch (NameNotFoundException e) { + logger.log(Level.SEVERE, "Can not get aphrodite service due to : ", e); + } + } + + private static Store store() { + if (store == null) { + store = new Store(); + } + return store; + } + + private static List getLastCommits(PullRequest pullRequest) { + if (!isEAP7PR(pullRequest)) { + return null; + } + + String branch = pullRequest.getCodebase().getName() + FUTURE; + if (store().getCommits(branch) == null || store().isStale()) { + try { + long since = Instant.now().toEpochMilli() - 5 * MONTH_MILLI; // 5 months in the past + List list = aphrodite.getCommitsSince(pullRequest.getRepository().getURL(), branch, since); + store().putCommits(branch, list); + store().update(); + } catch (NotFoundException nfe) { + logger.warning("Could not retrieve commits from " + pullRequest.getRepository().getURL()); + } + } + + return store().getCommits(branch); + } + + + private static boolean isEAP7PR(PullRequest pr) { + return pr.getURL().toString().contains(EAP_REPO) && pr.getCodebase().getName().startsWith("7."); + } + + /** + * Checks all commits (SHA or message) of the given PR against last commits from a future branch + * (only considers PRs submitted to a 7..x branch) + * + * @param pullRequest + * @return false if PR is not submitted to 7.x or if one or more commits are missing in the future branch, true otherwise + */ + public static boolean isMergedInFutureBranch(PullRequest pullRequest) { + if (!isEAP7PR(pullRequest)) { + return false; + } + + List lastCommits = getLastCommits(pullRequest); + for (Commit prCommit : pullRequest.getCommits()) { + boolean found = lastCommits.stream() + .anyMatch(commit -> prCommit.getSha().equals(commit.getSha()) || pullRequest.getTitle().equals(commit.getMessage())); + if (!found) { + return false; + } + } + + return true; + } + + private static class Store { + private Map> commitMap = new HashMap<>(); + private LocalTime lastUpdate = LocalTime.now(); + + public List getCommits(String branch) { + return commitMap.get(branch); + } + + public void putCommits(String branch, List commits) { + commitMap.put(branch, commits); + } + + public void update() { + lastUpdate = isStale() ? LocalTime.now() : lastUpdate; + } + + public boolean isStale() { + return Duration.between(lastUpdate, LocalTime.now()).toHours() >= 2; + } + } +} diff --git a/src/main/java/org/jboss/set/assist/data/payload/AssociatedPullRequest.java b/src/main/java/org/jboss/set/assist/data/payload/AssociatedPullRequest.java index b6ec0d2..b3cfec2 100644 --- a/src/main/java/org/jboss/set/assist/data/payload/AssociatedPullRequest.java +++ b/src/main/java/org/jboss/set/assist/data/payload/AssociatedPullRequest.java @@ -40,10 +40,11 @@ public class AssociatedPullRequest { private URL upstreamIssueFromPRDesc; private URL upstreamPullRequestFromPRDesc; private String upstreamPatchState; + private boolean mergedInFuture; public AssociatedPullRequest(String label, URL link, String codebase, String patchState, String commitStatus, String mergeStatus, boolean noUpstreamRequired, URL upstreamIssueFromPRDesc, - URL upstreamPullRequestFromPRDesc, String upstreamPatchState) { + URL upstreamPullRequestFromPRDesc, String upstreamPatchState, boolean mergedInFuture) { this.label = label; this.link = link; this.codebase = codebase; @@ -54,11 +55,12 @@ public AssociatedPullRequest(String label, URL link, String codebase, String pat this.upstreamIssueFromPRDesc = upstreamIssueFromPRDesc; this.upstreamPullRequestFromPRDesc = upstreamPullRequestFromPRDesc; this.upstreamPatchState = upstreamPatchState; + this.mergedInFuture = mergedInFuture; } public AssociatedPullRequest(String label, URL link, String codebase, String patchState, String commitStatus, String mergeStatus, boolean noUpstreamRequired) { - this(label, link, codebase, patchState, commitStatus, mergeStatus, noUpstreamRequired, null, null, null); + this(label, link, codebase, patchState, commitStatus, mergeStatus, noUpstreamRequired, null, null, null, false); } public String getLabel() { @@ -100,4 +102,8 @@ public String getMergeStatus() { public String getUpstreamPatchState() { return upstreamPatchState; } + + public boolean isMergedInFuture() { + return mergedInFuture; + } } diff --git a/src/main/java/org/jboss/set/assist/evaluator/impl/payload/AssociatedPullRequestEvaluator.java b/src/main/java/org/jboss/set/assist/evaluator/impl/payload/AssociatedPullRequestEvaluator.java index 2a35679..eda2eea 100644 --- a/src/main/java/org/jboss/set/assist/evaluator/impl/payload/AssociatedPullRequestEvaluator.java +++ b/src/main/java/org/jboss/set/assist/evaluator/impl/payload/AssociatedPullRequestEvaluator.java @@ -29,6 +29,7 @@ import org.jboss.set.aphrodite.domain.PatchType; import org.jboss.set.aphrodite.domain.PullRequest; import org.jboss.set.aphrodite.domain.Stream; +import org.jboss.set.assist.CommitHomeService; import org.jboss.set.assist.GitUtil; import org.jboss.set.assist.PatchHomeService; import org.jboss.set.assist.data.payload.AssociatedPullRequest; @@ -90,6 +91,7 @@ public void eval(PayloadEvaluatorContext context, Map data) { for (PullRequest pullRequest : relatedPullRequests) { CommitStatus commitStatus = PatchHomeService.retrieveCommitStatus(pullRequest); + boolean mergedInFuture = CommitHomeService.isMergedInFutureBranch(pullRequest); URL upstreamIssueFromPRDesc = null; URL upstreamPRFromPRDesc = null; String upstreamPatchState = null; @@ -110,7 +112,7 @@ public void eval(PayloadEvaluatorContext context, Map data) { pullRequest.getCodebase().getName(), pullRequest.getState().toString(), commitStatus.toString(), pullRequest.getMergableState() == null?null:pullRequest.getMergableState().name(), - !pullRequest.isUpstreamRequired(), upstreamIssueFromPRDesc, upstreamPRFromPRDesc, upstreamPatchState)); + !pullRequest.isUpstreamRequired(), upstreamIssueFromPRDesc, upstreamPRFromPRDesc, upstreamPatchState, mergedInFuture)); } data.put(KEY, relatedDataList);