/* * Copyright 2014 ArcBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.arcbees.pullrequest; import java.io.IOException; import java.util.List; import java.util.Map; import org.jetbrains.annotations.NotNull; import com.arcbees.vcs.VcsApi; import com.arcbees.vcs.VcsApiFactories; import com.arcbees.vcs.VcsConstants; import com.arcbees.vcs.VcsPropertiesHelper; import com.arcbees.vcs.model.Comment; import com.arcbees.vcs.model.Commit; import com.arcbees.vcs.model.PullRequest; import com.arcbees.vcs.model.PullRequestTarget; import com.arcbees.vcs.model.PullRequests; import com.arcbees.vcs.util.JsonCustomDataStorage; import com.google.common.base.Strings; import com.google.common.collect.Lists; import jetbrains.buildServer.buildTriggers.BuildTriggerDescriptor; import jetbrains.buildServer.buildTriggers.BuildTriggerException; import jetbrains.buildServer.buildTriggers.PolledBuildTrigger; import jetbrains.buildServer.buildTriggers.PolledTriggerContext; import jetbrains.buildServer.messages.Status; import jetbrains.buildServer.serverSide.BatchTrigger; import jetbrains.buildServer.serverSide.BranchEx; import jetbrains.buildServer.serverSide.BuildCustomizer; import jetbrains.buildServer.serverSide.BuildCustomizerFactory; import jetbrains.buildServer.serverSide.BuildTypeEx; import jetbrains.buildServer.serverSide.TriggerTask; import jetbrains.buildServer.vcs.SVcsModification; import jetbrains.buildServer.vcs.SelectPrevBuildPolicy; public class PullRequestsTrigger extends PolledBuildTrigger { private final VcsApiFactories vcsApiFactories; private final BatchTrigger batchTrigger; private final VcsConstants vcsConstants; private final BuildCustomizerFactory buildCustomizerFactory; private final PullRequestChainParser pullRequestChainParser; public PullRequestsTrigger( VcsApiFactories vcsApiFactories, BatchTrigger batchTrigger, VcsConstants vcsConstants, BuildCustomizerFactory buildCustomizerFactory, PullRequestChainParser pullRequestChainParser) { this.vcsApiFactories = vcsApiFactories; this.batchTrigger = batchTrigger; this.vcsConstants = vcsConstants; this.buildCustomizerFactory = buildCustomizerFactory; this.pullRequestChainParser = pullRequestChainParser; } @Override public void triggerBuild(@NotNull PolledTriggerContext context) throws BuildTriggerException { BuildTriggerDescriptor triggerDescriptor = context.getTriggerDescriptor(); Map<String, String> properties = triggerDescriptor.getProperties(); VcsPropertiesHelper vcsPropertiesHelper = new VcsPropertiesHelper(properties, vcsConstants); String repositoryOwner = vcsPropertiesHelper.getRepositoryOwner(); String repositoryName = vcsPropertiesHelper.getRepositoryName(); VcsApi vcsApi = vcsApiFactories.create(vcsPropertiesHelper); try { PullRequests<? extends PullRequest> pullRequests = vcsApi.getOpenedPullRequests(); pullRequestChainParser.parsePullRequestChains(pullRequests); JsonCustomDataStorage<PullRequestBuild> dataStorage = JsonCustomDataStorage.create(context.getCustomDataStorage(), PullRequestBuild.class); List<TriggerTask> triggerTasks = Lists.newArrayList(); for (PullRequest pullRequest : pullRequests.getPullRequests()) { if (shouldBuildPullRequest(vcsPropertiesHelper, pullRequest)) { String pullRequestKey = getPullRequestKey(repositoryOwner, repositoryName, pullRequest); PullRequestBuild pullRequestBuild = dataStorage.getValue(pullRequestKey); String lastTriggeredCommitHash = ""; Status lastStatus = Status.UNKNOWN; Comment lastComment = null; if (pullRequestBuild != null) { lastTriggeredCommitHash = pullRequestBuild.getLastCommitHash(); lastComment = pullRequestBuild.getLastComment(); lastStatus = pullRequestBuild.getLastStatus(); } boolean buildAdded = addBuildTask(context, triggerTasks, pullRequest, lastTriggeredCommitHash); if (buildAdded) { pullRequestBuild = new PullRequestBuild(pullRequest, lastStatus, lastComment); dataStorage.putValue(pullRequestKey, pullRequestBuild); } } } batchTrigger.processTasks(triggerTasks, triggerDescriptor.getTriggerName()); } catch (IOException e) { e.printStackTrace(); } } private boolean shouldBuildPullRequest(VcsPropertiesHelper vcsPropertiesHelper, PullRequest pullRequest) { String baseBranch = vcsPropertiesHelper.getBaseBranch(); return Strings.isNullOrEmpty(baseBranch) || pullRequest.getBranchChain().contains(baseBranch); } private boolean addBuildTask(PolledTriggerContext context, List<TriggerTask> triggerTasks, PullRequest pullRequest, String lastTriggeredCommitHash) { PullRequestTarget source = pullRequest.getSource(); Commit lastCommit = source.getCommit(); boolean added = false; if (!lastCommit.getHash().equals(lastTriggeredCommitHash)) { addBuildTask(context, triggerTasks, source); added = true; } return added; } private void addBuildTask(PolledTriggerContext context, List<TriggerTask> triggerTasks, PullRequestTarget source) { BuildTypeEx buildType = (BuildTypeEx) context.getBuildType(); BuildCustomizer buildCustomizer = buildCustomizerFactory.createBuildCustomizer(buildType, null); buildCustomizer.setCleanSources(true); BranchEx branch = buildType.getBranchByDisplayName(source.getBranch().getName()); SVcsModification lastModification = checkChanges(source.getCommit().getHash(), branch.getDummyBuild().getChanges(SelectPrevBuildPolicy.SINCE_NULL_BUILD, true)); buildCustomizer.setDesiredBranchName(branch.getName()); if (lastModification != null) { buildCustomizer.setChangesUpTo(lastModification); } TriggerTask task = batchTrigger.newTriggerTask(buildCustomizer.createPromotion()); triggerTasks.add(task); } private SVcsModification checkChanges(String commitHash, List<SVcsModification> changes) { for (SVcsModification sVcsModification : changes) { if (sVcsModification.getVersion().startsWith(commitHash)) { return sVcsModification; } } return null; } private String getPullRequestKey(String repositoryOwner, String repositoryName, PullRequest pullRequest) { return vcsConstants.getPullRequestKey() + repositoryOwner + "_" + repositoryName + "_" + pullRequest.getId(); } }