diff options
Diffstat (limited to 'java/com/google/gerrit/server/restapi/project/CheckMergeability.java')
-rw-r--r-- | java/com/google/gerrit/server/restapi/project/CheckMergeability.java | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/java/com/google/gerrit/server/restapi/project/CheckMergeability.java b/java/com/google/gerrit/server/restapi/project/CheckMergeability.java new file mode 100644 index 0000000000..de2ac6458d --- /dev/null +++ b/java/com/google/gerrit/server/restapi/project/CheckMergeability.java @@ -0,0 +1,127 @@ +// Copyright (C) 2016 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.restapi.project; + +import com.google.gerrit.extensions.client.SubmitType; +import com.google.gerrit.extensions.common.MergeableInfo; +import com.google.gerrit.extensions.restapi.BadRequestException; +import com.google.gerrit.extensions.restapi.ResourceNotFoundException; +import com.google.gerrit.extensions.restapi.RestReadView; +import com.google.gerrit.server.config.GerritServerConfig; +import com.google.gerrit.server.git.GitRepositoryManager; +import com.google.gerrit.server.git.InMemoryInserter; +import com.google.gerrit.server.git.MergeUtil; +import com.google.gerrit.server.project.BranchResource; +import com.google.inject.Inject; +import java.io.IOException; +import org.eclipse.jgit.lib.Config; +import org.eclipse.jgit.lib.ObjectInserter; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.merge.Merger; +import org.eclipse.jgit.merge.ResolveMerger; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevWalk; +import org.kohsuke.args4j.Option; + +/** Check the mergeability at current branch for a git object references expression. */ +public class CheckMergeability implements RestReadView<BranchResource> { + private String source; + private String strategy; + private SubmitType submitType; + + @Option( + name = "--source", + metaVar = "COMMIT", + usage = + "the source reference to merge, which could be any git object " + + "references expression, refer to " + + "org.eclipse.jgit.lib.Repository#resolve(String)", + required = true) + public void setSource(String source) { + this.source = source; + } + + @Option( + name = "--strategy", + metaVar = "STRATEGY", + usage = "name of the merge strategy, refer to org.eclipse.jgit.merge.MergeStrategy") + public void setStrategy(String strategy) { + this.strategy = strategy; + } + + private final GitRepositoryManager gitManager; + private final CommitsCollection commits; + + @Inject + CheckMergeability( + GitRepositoryManager gitManager, CommitsCollection commits, @GerritServerConfig Config cfg) { + this.gitManager = gitManager; + this.commits = commits; + this.strategy = MergeUtil.getMergeStrategy(cfg).getName(); + this.submitType = cfg.getEnum("project", null, "submitType", SubmitType.MERGE_IF_NECESSARY); + } + + @Override + public MergeableInfo apply(BranchResource resource) + throws IOException, BadRequestException, ResourceNotFoundException { + if (!(submitType.equals(SubmitType.MERGE_ALWAYS) + || submitType.equals(SubmitType.MERGE_IF_NECESSARY))) { + throw new BadRequestException("Submit type: " + submitType + " is not supported"); + } + + MergeableInfo result = new MergeableInfo(); + result.submitType = submitType; + result.strategy = strategy; + try (Repository git = gitManager.openRepository(resource.getNameKey()); + RevWalk rw = new RevWalk(git); + ObjectInserter inserter = new InMemoryInserter(git)) { + Merger m = MergeUtil.newMerger(inserter, git.getConfig(), strategy); + + Ref destRef = git.getRefDatabase().exactRef(resource.getRef()); + if (destRef == null) { + throw new ResourceNotFoundException(resource.getRef()); + } + + RevCommit targetCommit = rw.parseCommit(destRef.getObjectId()); + RevCommit sourceCommit = MergeUtil.resolveCommit(git, rw, source); + + if (!commits.canRead(resource.getProjectState(), git, sourceCommit)) { + throw new BadRequestException("do not have read permission for: " + source); + } + + if (rw.isMergedInto(sourceCommit, targetCommit)) { + result.mergeable = true; + result.commitMerged = true; + result.contentMerged = true; + return result; + } + + if (m.merge(false, targetCommit, sourceCommit)) { + result.mergeable = true; + result.commitMerged = false; + result.contentMerged = m.getResultTreeId().equals(targetCommit.getTree()); + } else { + result.mergeable = false; + if (m instanceof ResolveMerger) { + result.conflicts = ((ResolveMerger) m).getUnmergedPaths(); + } + } + } catch (IllegalArgumentException e) { + throw new BadRequestException(e.getMessage()); + } + return result; + } +} |