diff options
Diffstat (limited to 'java/com/google/gerrit/server/submit/SubmitDryRun.java')
-rw-r--r-- | java/com/google/gerrit/server/submit/SubmitDryRun.java | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/java/com/google/gerrit/server/submit/SubmitDryRun.java b/java/com/google/gerrit/server/submit/SubmitDryRun.java new file mode 100644 index 0000000000..e273652d9d --- /dev/null +++ b/java/com/google/gerrit/server/submit/SubmitDryRun.java @@ -0,0 +1,157 @@ +// Copyright (C) 2015 The Android Open Source Project +// +// 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.google.gerrit.server.submit; + +import static java.util.stream.Collectors.toSet; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Streams; +import com.google.common.flogger.FluentLogger; +import com.google.gerrit.extensions.client.SubmitType; +import com.google.gerrit.reviewdb.client.Branch; +import com.google.gerrit.server.git.CodeReviewCommit; +import com.google.gerrit.server.git.CodeReviewCommit.CodeReviewRevWalk; +import com.google.gerrit.server.git.MergeUtil; +import com.google.gerrit.server.project.NoSuchProjectException; +import com.google.gerrit.server.project.ProjectCache; +import com.google.gerrit.server.project.ProjectState; +import com.google.gerrit.server.query.change.InternalChangeQuery; +import com.google.inject.Inject; +import com.google.inject.Provider; +import java.io.IOException; +import java.util.Collection; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevFlag; +import org.eclipse.jgit.revwalk.RevObject; +import org.eclipse.jgit.revwalk.RevTag; +import org.eclipse.jgit.revwalk.RevWalk; + +/** Dry run of a submit strategy. */ +public class SubmitDryRun { + private static final FluentLogger logger = FluentLogger.forEnclosingClass(); + + static class Arguments { + final Repository repo; + final CodeReviewRevWalk rw; + final MergeUtil mergeUtil; + final MergeSorter mergeSorter; + + Arguments(Repository repo, CodeReviewRevWalk rw, MergeUtil mergeUtil, MergeSorter mergeSorter) { + this.repo = repo; + this.rw = rw; + this.mergeUtil = mergeUtil; + this.mergeSorter = mergeSorter; + } + } + + public static Set<ObjectId> getAlreadyAccepted(Repository repo) throws IOException { + return Streams.concat( + repo.getRefDatabase().getRefsByPrefix(Constants.R_HEADS).stream(), + repo.getRefDatabase().getRefsByPrefix(Constants.R_TAGS).stream()) + .map(Ref::getObjectId) + .filter(Objects::nonNull) + .collect(toSet()); + } + + public static Set<RevCommit> getAlreadyAccepted(Repository repo, RevWalk rw) throws IOException { + Set<RevCommit> accepted = new HashSet<>(); + addCommits(getAlreadyAccepted(repo), rw, accepted); + return accepted; + } + + public static void addCommits(Iterable<ObjectId> ids, RevWalk rw, Collection<RevCommit> out) + throws IOException { + for (ObjectId id : ids) { + RevObject obj = rw.parseAny(id); + if (obj instanceof RevTag) { + obj = rw.peel(obj); + } + if (obj instanceof RevCommit) { + out.add((RevCommit) obj); + } + } + } + + private final ProjectCache projectCache; + private final MergeUtil.Factory mergeUtilFactory; + private final Provider<InternalChangeQuery> queryProvider; + + @Inject + SubmitDryRun( + ProjectCache projectCache, + MergeUtil.Factory mergeUtilFactory, + Provider<InternalChangeQuery> queryProvider) { + this.projectCache = projectCache; + this.mergeUtilFactory = mergeUtilFactory; + this.queryProvider = queryProvider; + } + + public boolean run( + SubmitType submitType, + Repository repo, + CodeReviewRevWalk rw, + Branch.NameKey destBranch, + ObjectId tip, + ObjectId toMerge, + Set<RevCommit> alreadyAccepted) + throws IntegrationException, NoSuchProjectException, IOException { + CodeReviewCommit tipCommit = rw.parseCommit(tip); + CodeReviewCommit toMergeCommit = rw.parseCommit(toMerge); + RevFlag canMerge = rw.newFlag("CAN_MERGE"); + toMergeCommit.add(canMerge); + Arguments args = + new Arguments( + repo, + rw, + mergeUtilFactory.create(getProject(destBranch)), + new MergeSorter( + rw, alreadyAccepted, canMerge, queryProvider, ImmutableSet.of(toMergeCommit))); + + switch (submitType) { + case CHERRY_PICK: + return CherryPick.dryRun(args, tipCommit, toMergeCommit); + case FAST_FORWARD_ONLY: + return FastForwardOnly.dryRun(args, tipCommit, toMergeCommit); + case MERGE_ALWAYS: + return MergeAlways.dryRun(args, tipCommit, toMergeCommit); + case MERGE_IF_NECESSARY: + return MergeIfNecessary.dryRun(args, tipCommit, toMergeCommit); + case REBASE_IF_NECESSARY: + return RebaseIfNecessary.dryRun(args, repo, tipCommit, toMergeCommit); + case REBASE_ALWAYS: + return RebaseAlways.dryRun(args, repo, tipCommit, toMergeCommit); + case INHERIT: + default: + String errorMsg = "No submit strategy for: " + submitType; + logger.atSevere().log(errorMsg); + throw new IntegrationException(errorMsg); + } + } + + private ProjectState getProject(Branch.NameKey branch) throws NoSuchProjectException { + ProjectState p = projectCache.get(branch.getParentKey()); + if (p == null) { + throw new NoSuchProjectException(branch.getParentKey()); + } + return p; + } +} |