Add more information to MergeableInfo to indicate a merged commit
Add two fields contentMerged and commitMerged into MergeableInfo. contentMerged is true if the content of the commit is merged, commitMerged is true if the commit itself is merged. Also add more tests for CheckMergeability class. Change-Id: Ia756644411f217b8d8bae06f44f14a24597544bd
This commit is contained in:
@@ -4915,6 +4915,10 @@ The strategy of the merge, can be `recursive`, `resolve`,
|
|||||||
`simple-two-way-in-core`, `ours` or `theirs`.
|
`simple-two-way-in-core`, `ours` or `theirs`.
|
||||||
|`mergeable` ||
|
|`mergeable` ||
|
||||||
`true` if this change is cleanly mergeable, `false` otherwise
|
`true` if this change is cleanly mergeable, `false` otherwise
|
||||||
|
|`commit_merged` |optional|
|
||||||
|
`true` if this change is already merged, `false` otherwise
|
||||||
|
|`content_merged` |optional|
|
||||||
|
`true` if the content of this change is already merged, `false` otherwise
|
||||||
|`conflicts`|optional|
|
|`conflicts`|optional|
|
||||||
A list of paths with conflicts
|
A list of paths with conflicts
|
||||||
|`mergeable_into`|optional|
|
|`mergeable_into`|optional|
|
||||||
|
@@ -1363,8 +1363,9 @@ The content is returned as base64 encoded string.
|
|||||||
|
|
||||||
Gets whether the source is mergeable with the target branch.
|
Gets whether the source is mergeable with the target branch.
|
||||||
|
|
||||||
The `source` query parameter is required, which can be anything that could be resolved
|
The `source` query parameter is required, which can be anything that could be
|
||||||
to a commit, see examples in link:rest-api-changes.html#merge-input[MergeInput].
|
resolved to a commit, see examples of the `source` attribute in
|
||||||
|
link:rest-api-changes.html#merge-input[MergeInput].
|
||||||
|
|
||||||
Also takes an optional parameter `strategy`, which can be `recursive`, `resolve`,
|
Also takes an optional parameter `strategy`, which can be `recursive`, `resolve`,
|
||||||
`simple-two-way-in-core`, `ours` or `theirs`, default will use project settings.
|
`simple-two-way-in-core`, `ours` or `theirs`, default will use project settings.
|
||||||
@@ -1374,7 +1375,7 @@ Also takes an optional parameter `strategy`, which can be `recursive`, `resolve`
|
|||||||
GET /projects/test/branches/master/mergeable?source=testbranch&strategy=recursive HTTP/1.0
|
GET /projects/test/branches/master/mergeable?source=testbranch&strategy=recursive HTTP/1.0
|
||||||
----
|
----
|
||||||
|
|
||||||
As response a link:#mergeable-info[MergeableInfo] entity is returned.
|
As response a link:rest-api-changes.html#mergeable-info[MergeableInfo] entity is returned.
|
||||||
|
|
||||||
.Response
|
.Response
|
||||||
----
|
----
|
||||||
@@ -1384,9 +1385,67 @@ As response a link:#mergeable-info[MergeableInfo] entity is returned.
|
|||||||
|
|
||||||
)]}'
|
)]}'
|
||||||
{
|
{
|
||||||
submit_type: "MERGE_IF_NECESSARY",
|
"submit_type": "MERGE_IF_NECESSARY",
|
||||||
strategy: "recursive",
|
"strategy": "recursive",
|
||||||
mergeable: true
|
"mergeable": true,
|
||||||
|
"commit_merged": false,
|
||||||
|
"content_merged": false
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
or when there were conflicts.
|
||||||
|
|
||||||
|
.Response
|
||||||
|
----
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
Content-Disposition: attachment
|
||||||
|
Content-Type: application/json; charset=UTF-8
|
||||||
|
|
||||||
|
)]}'
|
||||||
|
{
|
||||||
|
"submit_type": "MERGE_IF_NECESSARY",
|
||||||
|
"strategy": "recursive",
|
||||||
|
"mergeable": false,
|
||||||
|
"conflicts": [
|
||||||
|
"common.txt",
|
||||||
|
"shared.txt"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
or when the 'testbranch' has been already merged.
|
||||||
|
|
||||||
|
.Response
|
||||||
|
----
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
Content-Disposition: attachment
|
||||||
|
Content-Type: application/json; charset=UTF-8
|
||||||
|
|
||||||
|
)]}'
|
||||||
|
{
|
||||||
|
"submit_type": "MERGE_IF_NECESSARY",
|
||||||
|
"strategy": "recursive",
|
||||||
|
"mergeable": true,
|
||||||
|
"commit_merged": true,
|
||||||
|
"content_merged": true
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
or when only the content of 'testbranch' has been merged.
|
||||||
|
|
||||||
|
.Response
|
||||||
|
----
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
Content-Disposition: attachment
|
||||||
|
Content-Type: application/json; charset=UTF-8
|
||||||
|
|
||||||
|
)]}'
|
||||||
|
{
|
||||||
|
"submit_type": "MERGE_IF_NECESSARY",
|
||||||
|
"strategy": "recursive",
|
||||||
|
"mergeable": true,
|
||||||
|
"commit_merged": false,
|
||||||
|
"content_merged": true
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
@@ -20,31 +20,37 @@ import static com.google.gerrit.reviewdb.client.RefNames.changeMetaRef;
|
|||||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||||
import static org.eclipse.jgit.lib.Constants.SIGNED_OFF_BY_TAG;
|
import static org.eclipse.jgit.lib.Constants.SIGNED_OFF_BY_TAG;
|
||||||
|
|
||||||
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.gerrit.acceptance.AbstractDaemonTest;
|
import com.google.gerrit.acceptance.AbstractDaemonTest;
|
||||||
import com.google.gerrit.acceptance.PushOneCommit;
|
import com.google.gerrit.acceptance.PushOneCommit;
|
||||||
import com.google.gerrit.acceptance.PushOneCommit.Result;
|
import com.google.gerrit.acceptance.PushOneCommit.Result;
|
||||||
import com.google.gerrit.acceptance.RestResponse;
|
import com.google.gerrit.acceptance.RestResponse;
|
||||||
|
import com.google.gerrit.extensions.api.changes.ChangeApi;
|
||||||
|
import com.google.gerrit.extensions.api.changes.CherryPickInput;
|
||||||
|
import com.google.gerrit.extensions.api.changes.ReviewInput;
|
||||||
import com.google.gerrit.extensions.client.ChangeStatus;
|
import com.google.gerrit.extensions.client.ChangeStatus;
|
||||||
import com.google.gerrit.extensions.client.GeneralPreferencesInfo;
|
import com.google.gerrit.extensions.client.GeneralPreferencesInfo;
|
||||||
import com.google.gerrit.extensions.common.ChangeInfo;
|
import com.google.gerrit.extensions.common.ChangeInfo;
|
||||||
import com.google.gerrit.extensions.common.ChangeInput;
|
import com.google.gerrit.extensions.common.ChangeInput;
|
||||||
import com.google.gerrit.extensions.common.MergeInput;
|
import com.google.gerrit.extensions.common.MergeInput;
|
||||||
import com.google.gerrit.extensions.common.MergeableInfo;
|
|
||||||
import com.google.gerrit.extensions.restapi.BadRequestException;
|
import com.google.gerrit.extensions.restapi.BadRequestException;
|
||||||
import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
|
import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
|
||||||
import com.google.gerrit.extensions.restapi.RestApiException;
|
import com.google.gerrit.extensions.restapi.RestApiException;
|
||||||
import com.google.gerrit.reviewdb.client.Branch;
|
import com.google.gerrit.reviewdb.client.Branch;
|
||||||
import com.google.gerrit.reviewdb.client.Change;
|
import com.google.gerrit.reviewdb.client.Change;
|
||||||
import com.google.gerrit.server.config.AnonymousCowardNameProvider;
|
import com.google.gerrit.server.config.AnonymousCowardNameProvider;
|
||||||
|
import com.google.gerrit.server.git.ChangeAlreadyMergedException;
|
||||||
import com.google.gerrit.testutil.ConfigSuite;
|
import com.google.gerrit.testutil.ConfigSuite;
|
||||||
import com.google.gerrit.testutil.TestTimeUtil;
|
import com.google.gerrit.testutil.TestTimeUtil;
|
||||||
|
|
||||||
import org.eclipse.jgit.lib.Config;
|
import org.eclipse.jgit.lib.Config;
|
||||||
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
import org.eclipse.jgit.lib.PersonIdent;
|
import org.eclipse.jgit.lib.PersonIdent;
|
||||||
import org.eclipse.jgit.lib.Repository;
|
import org.eclipse.jgit.lib.Repository;
|
||||||
import org.eclipse.jgit.revwalk.RevCommit;
|
import org.eclipse.jgit.revwalk.RevCommit;
|
||||||
import org.eclipse.jgit.revwalk.RevWalk;
|
import org.eclipse.jgit.revwalk.RevWalk;
|
||||||
|
import org.eclipse.jgit.transport.RefSpec;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -142,6 +148,99 @@ public class CreateChangeIT extends AbstractDaemonTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createMergeChange() throws Exception {
|
||||||
|
changeInTwoBranches("branchA", "a.txt", "branchB", "b.txt");
|
||||||
|
ChangeInput in =
|
||||||
|
newMergeChangeInput("branchA", "branchB", "");
|
||||||
|
assertCreateSucceeds(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createMergeChange_Conflicts() throws Exception {
|
||||||
|
changeInTwoBranches("branchA", "shared.txt", "branchB", "shared.txt");
|
||||||
|
ChangeInput in =
|
||||||
|
newMergeChangeInput("branchA", "branchB", "");
|
||||||
|
assertCreateFails(in, RestApiException.class, "merge conflict");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createMergeChange_Conflicts_Ours() throws Exception {
|
||||||
|
changeInTwoBranches("branchA", "shared.txt", "branchB", "shared.txt");
|
||||||
|
ChangeInput in =
|
||||||
|
newMergeChangeInput("branchA", "branchB", "ours");
|
||||||
|
assertCreateSucceeds(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void invalidSource() throws Exception {
|
||||||
|
changeInTwoBranches("branchA", "a.txt", "branchB", "b.txt");
|
||||||
|
ChangeInput in =
|
||||||
|
newMergeChangeInput("branchA", "invalid", "");
|
||||||
|
assertCreateFails(in, BadRequestException.class,
|
||||||
|
"Cannot resolve 'invalid' to a commit");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void invalidStrategy() throws Exception {
|
||||||
|
changeInTwoBranches("branchA", "a.txt", "branchB", "b.txt");
|
||||||
|
ChangeInput in =
|
||||||
|
newMergeChangeInput("branchA", "branchB", "octopus");
|
||||||
|
assertCreateFails(in, BadRequestException.class,
|
||||||
|
"invalid merge strategy: octopus");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void alreadyMerged() throws Exception {
|
||||||
|
ObjectId c0 = testRepo.branch("HEAD").commit().insertChangeId()
|
||||||
|
.message("first commit")
|
||||||
|
.add("a.txt", "a contents ")
|
||||||
|
.create();
|
||||||
|
testRepo.git().push().setRemote("origin").setRefSpecs(
|
||||||
|
new RefSpec("HEAD:refs/heads/master")).call();
|
||||||
|
|
||||||
|
testRepo.branch("HEAD").commit().insertChangeId()
|
||||||
|
.message("second commit")
|
||||||
|
.add("b.txt", "b contents ")
|
||||||
|
.create();
|
||||||
|
testRepo.git().push().setRemote("origin").setRefSpecs(
|
||||||
|
new RefSpec("HEAD:refs/heads/master")).call();
|
||||||
|
|
||||||
|
ChangeInput in =
|
||||||
|
newMergeChangeInput("master", c0.getName(), "");
|
||||||
|
assertCreateFails(in, ChangeAlreadyMergedException.class,
|
||||||
|
"'" + c0.getName() + "' has already been merged");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onlyContentMerged() throws Exception {
|
||||||
|
testRepo.branch("HEAD").commit().insertChangeId()
|
||||||
|
.message("first commit")
|
||||||
|
.add("a.txt", "a contents ")
|
||||||
|
.create();
|
||||||
|
testRepo.git().push().setRemote("origin").setRefSpecs(
|
||||||
|
new RefSpec("HEAD:refs/heads/master")).call();
|
||||||
|
|
||||||
|
// create a change, and cherrypick into master
|
||||||
|
PushOneCommit.Result cId = createChange();
|
||||||
|
RevCommit commitId = cId.getCommit();
|
||||||
|
CherryPickInput cpi = new CherryPickInput();
|
||||||
|
cpi.destination = "master";
|
||||||
|
cpi.message = "cherry pick the commit";
|
||||||
|
ChangeApi orig = gApi.changes()
|
||||||
|
.id(cId.getChangeId());
|
||||||
|
ChangeApi cherry = orig.current().cherryPick(cpi);
|
||||||
|
cherry.current().review(ReviewInput.approve());
|
||||||
|
cherry.current().submit();
|
||||||
|
|
||||||
|
ObjectId remoteId = getRemoteHead();
|
||||||
|
assertThat(remoteId).isNotEqualTo(commitId);
|
||||||
|
|
||||||
|
ChangeInput in =
|
||||||
|
newMergeChangeInput("master", commitId.getName(), "");
|
||||||
|
assertCreateSucceeds(in);
|
||||||
|
}
|
||||||
|
|
||||||
private ChangeInput newChangeInput(ChangeStatus status) {
|
private ChangeInput newChangeInput(ChangeStatus status) {
|
||||||
ChangeInput in = new ChangeInput();
|
ChangeInput in = new ChangeInput();
|
||||||
in.project = project.get();
|
in.project = project.get();
|
||||||
@@ -197,58 +296,25 @@ public class CreateChangeIT extends AbstractDaemonTest {
|
|||||||
assertThat(o.signedOffBy).isTrue();
|
assertThat(o.signedOffBy).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ChangeInput newMergeChangeInput(String targetBranch, String sourceRef,
|
||||||
@Test
|
String strategy) {
|
||||||
public void createMergeChange() throws Exception {
|
|
||||||
changeInTwoBranches("a.txt", "b.txt");
|
|
||||||
ChangeInput in =
|
|
||||||
newMergeChangeInput("master", "branchA", ChangeStatus.NEW);
|
|
||||||
assertCreateSucceeds(in);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void createMergeChange_Conflicts() throws Exception {
|
|
||||||
changeInTwoBranches("shared.txt", "shared.txt");
|
|
||||||
ChangeInput in =
|
|
||||||
newMergeChangeInput("master", "branchA", ChangeStatus.NEW);
|
|
||||||
assertCreateFails(in, RestApiException.class, "merge conflict");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void dryRunMerge() throws Exception {
|
|
||||||
changeInTwoBranches("a.txt", "b.txt");
|
|
||||||
RestResponse r = adminRestSession.get("/projects/" + project.get()
|
|
||||||
+ "/branches/master/mergeable?source=branchA");
|
|
||||||
MergeableInfo m = newGson().fromJson(r.getReader(), MergeableInfo.class);
|
|
||||||
assertThat(m.mergeable).isTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void dryRunMerge_Conflicts() throws Exception {
|
|
||||||
changeInTwoBranches("a.txt", "a.txt");
|
|
||||||
RestResponse r = adminRestSession.get("/projects/" + project.get()
|
|
||||||
+ "/branches/master/mergeable?source=branchA");
|
|
||||||
MergeableInfo m = newGson().fromJson(r.getReader(), MergeableInfo.class);
|
|
||||||
assertThat(m.mergeable).isFalse();
|
|
||||||
assertThat(m.conflicts).containsExactly("a.txt");
|
|
||||||
}
|
|
||||||
|
|
||||||
private ChangeInput newMergeChangeInput(String targetBranch,
|
|
||||||
String sourceRef, ChangeStatus status) {
|
|
||||||
// create a merge change from branchA to master in gerrit
|
// create a merge change from branchA to master in gerrit
|
||||||
ChangeInput in = new ChangeInput();
|
ChangeInput in = new ChangeInput();
|
||||||
in.project = project.get();
|
in.project = project.get();
|
||||||
in.branch = targetBranch;
|
in.branch = targetBranch;
|
||||||
in.subject = "merge " + sourceRef + " to " + targetBranch;
|
in.subject = "merge " + sourceRef + " to " + targetBranch;
|
||||||
in.status = status;
|
in.status = ChangeStatus.NEW;
|
||||||
MergeInput mergeInput = new MergeInput();
|
MergeInput mergeInput = new MergeInput();
|
||||||
mergeInput.source = sourceRef;
|
mergeInput.source = sourceRef;
|
||||||
in.merge = mergeInput;
|
in.merge = mergeInput;
|
||||||
|
if (!Strings.isNullOrEmpty(strategy)) {
|
||||||
|
in.merge.strategy = strategy;
|
||||||
|
}
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void changeInTwoBranches(String fileInMaster, String fileInBranchA)
|
private void changeInTwoBranches(String branchA, String fileA, String branchB,
|
||||||
throws Exception {
|
String fileB) throws Exception {
|
||||||
// create a initial commit in master
|
// create a initial commit in master
|
||||||
Result initialCommit = pushFactory
|
Result initialCommit = pushFactory
|
||||||
.create(db, user.getIdent(), testRepo, "initial commit", "readme.txt",
|
.create(db, user.getIdent(), testRepo, "initial commit", "readme.txt",
|
||||||
@@ -256,21 +322,21 @@ public class CreateChangeIT extends AbstractDaemonTest {
|
|||||||
.to("refs/heads/master");
|
.to("refs/heads/master");
|
||||||
initialCommit.assertOkStatus();
|
initialCommit.assertOkStatus();
|
||||||
|
|
||||||
// create a new branch branchA
|
// create two new branches
|
||||||
createBranch(new Branch.NameKey(project, "branchA"));
|
createBranch(new Branch.NameKey(project, branchA));
|
||||||
|
createBranch(new Branch.NameKey(project, branchB));
|
||||||
// create another commit in master
|
|
||||||
Result changeToMaster = pushFactory
|
|
||||||
.create(db, user.getIdent(), testRepo, "change to master", fileInMaster,
|
|
||||||
"master content")
|
|
||||||
.to("refs/heads/master");
|
|
||||||
changeToMaster.assertOkStatus();
|
|
||||||
|
|
||||||
// create a commit in branchA
|
// create a commit in branchA
|
||||||
PushOneCommit commit = pushFactory
|
Result changeA = pushFactory
|
||||||
.create(db, user.getIdent(), testRepo, "change to branchA",
|
.create(db, user.getIdent(), testRepo, "change A", fileA, "A content")
|
||||||
fileInBranchA, "branchA content");
|
.to("refs/heads/" + branchA);
|
||||||
commit.setParent(initialCommit.getCommit());
|
changeA.assertOkStatus();
|
||||||
commit.to("refs/heads/branchA");
|
|
||||||
|
// create a commit in branchB
|
||||||
|
PushOneCommit commitB = pushFactory
|
||||||
|
.create(db, user.getIdent(), testRepo, "change B", fileB, "B content");
|
||||||
|
commitB.setParent(initialCommit.getCommit());
|
||||||
|
Result changeB = commitB.to("refs/heads/" + branchB);
|
||||||
|
changeB.assertOkStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,248 @@
|
|||||||
|
// 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.acceptance.rest.project;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import com.google.common.base.Strings;
|
||||||
|
import com.google.gerrit.acceptance.AbstractDaemonTest;
|
||||||
|
import com.google.gerrit.acceptance.PushOneCommit;
|
||||||
|
import com.google.gerrit.acceptance.RestResponse;
|
||||||
|
import com.google.gerrit.extensions.api.changes.ChangeApi;
|
||||||
|
import com.google.gerrit.extensions.api.changes.CherryPickInput;
|
||||||
|
import com.google.gerrit.extensions.api.changes.ReviewInput;
|
||||||
|
import com.google.gerrit.extensions.api.projects.BranchInput;
|
||||||
|
import com.google.gerrit.extensions.common.MergeableInfo;
|
||||||
|
import com.google.gerrit.reviewdb.client.Branch;
|
||||||
|
|
||||||
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
|
import org.eclipse.jgit.revwalk.RevCommit;
|
||||||
|
import org.eclipse.jgit.transport.RefSpec;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class CheckMergeabilityIT extends AbstractDaemonTest {
|
||||||
|
|
||||||
|
private Branch.NameKey branch;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
branch = new Branch.NameKey(project, "test");
|
||||||
|
gApi.projects()
|
||||||
|
.name(branch.getParentKey().get())
|
||||||
|
.branch(branch.get()).create(new BranchInput());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkMergeableCommit() throws Exception {
|
||||||
|
RevCommit initialHead = getRemoteHead();
|
||||||
|
testRepo.branch("HEAD").commit().insertChangeId()
|
||||||
|
.message("some change in a")
|
||||||
|
.add("a.txt", "a contents ")
|
||||||
|
.create();
|
||||||
|
testRepo.git().push().setRemote("origin").setRefSpecs(
|
||||||
|
new RefSpec("HEAD:refs/heads/master")).call();
|
||||||
|
|
||||||
|
testRepo.reset(initialHead);
|
||||||
|
testRepo.branch("HEAD").commit().insertChangeId()
|
||||||
|
.message("some change in b")
|
||||||
|
.add("b.txt", "b contents ")
|
||||||
|
.create();
|
||||||
|
testRepo.git().push().setRemote("origin").setRefSpecs(
|
||||||
|
new RefSpec("HEAD:refs/heads/test")).call();
|
||||||
|
|
||||||
|
assertMergeable("master", "test", "recursive");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkUnMergeableCommit() throws Exception {
|
||||||
|
RevCommit initialHead = getRemoteHead();
|
||||||
|
testRepo.branch("HEAD").commit().insertChangeId()
|
||||||
|
.message("some change in a")
|
||||||
|
.add("a.txt", "a contents ")
|
||||||
|
.create();
|
||||||
|
testRepo.git().push().setRemote("origin").setRefSpecs(
|
||||||
|
new RefSpec("HEAD:refs/heads/master")).call();
|
||||||
|
|
||||||
|
testRepo.reset(initialHead);
|
||||||
|
testRepo.branch("HEAD").commit().insertChangeId()
|
||||||
|
.message("some change in a too")
|
||||||
|
.add("a.txt", "a contents too")
|
||||||
|
.create();
|
||||||
|
testRepo.git().push().setRemote("origin").setRefSpecs(
|
||||||
|
new RefSpec("HEAD:refs/heads/test")).call();
|
||||||
|
|
||||||
|
assertUnMergeable("master", "test", "recursive", "a.txt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkOursMergeStrategy() throws Exception {
|
||||||
|
RevCommit initialHead = getRemoteHead();
|
||||||
|
testRepo.branch("HEAD").commit().insertChangeId()
|
||||||
|
.message("some change in a")
|
||||||
|
.add("a.txt", "a contents ")
|
||||||
|
.create();
|
||||||
|
testRepo.git().push().setRemote("origin").setRefSpecs(
|
||||||
|
new RefSpec("HEAD:refs/heads/master")).call();
|
||||||
|
|
||||||
|
testRepo.reset(initialHead);
|
||||||
|
testRepo.branch("HEAD").commit().insertChangeId()
|
||||||
|
.message("some change in a too")
|
||||||
|
.add("a.txt", "a contents too")
|
||||||
|
.create();
|
||||||
|
testRepo.git().push().setRemote("origin").setRefSpecs(
|
||||||
|
new RefSpec("HEAD:refs/heads/test")).call();
|
||||||
|
|
||||||
|
assertMergeable("master", "test", "ours");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkAlreadyMergedCommit() throws Exception {
|
||||||
|
ObjectId c0 = testRepo.branch("HEAD").commit().insertChangeId()
|
||||||
|
.message("first commit")
|
||||||
|
.add("a.txt", "a contents ")
|
||||||
|
.create();
|
||||||
|
testRepo.git().push().setRemote("origin").setRefSpecs(
|
||||||
|
new RefSpec("HEAD:refs/heads/master")).call();
|
||||||
|
|
||||||
|
testRepo.branch("HEAD").commit().insertChangeId()
|
||||||
|
.message("second commit")
|
||||||
|
.add("b.txt", "b contents ")
|
||||||
|
.create();
|
||||||
|
testRepo.git().push().setRemote("origin").setRefSpecs(
|
||||||
|
new RefSpec("HEAD:refs/heads/master")).call();
|
||||||
|
|
||||||
|
assertCommitMerged("master", c0.getName(), "");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkContentMergedCommit() throws Exception {
|
||||||
|
testRepo.branch("HEAD").commit().insertChangeId()
|
||||||
|
.message("first commit")
|
||||||
|
.add("a.txt", "a contents ")
|
||||||
|
.create();
|
||||||
|
testRepo.git().push().setRemote("origin").setRefSpecs(
|
||||||
|
new RefSpec("HEAD:refs/heads/master")).call();
|
||||||
|
|
||||||
|
// create a change, and cherrypick into master
|
||||||
|
PushOneCommit.Result cId = createChange();
|
||||||
|
RevCommit commitId = cId.getCommit();
|
||||||
|
CherryPickInput cpi = new CherryPickInput();
|
||||||
|
cpi.destination = "master";
|
||||||
|
cpi.message = "cherry pick the commit";
|
||||||
|
ChangeApi orig = gApi.changes()
|
||||||
|
.id(cId.getChangeId());
|
||||||
|
ChangeApi cherry = orig.current().cherryPick(cpi);
|
||||||
|
cherry.current().review(ReviewInput.approve());
|
||||||
|
cherry.current().submit();
|
||||||
|
|
||||||
|
ObjectId remoteId = getRemoteHead();
|
||||||
|
assertThat(remoteId).isNotEqualTo(commitId);
|
||||||
|
assertContentMerged("master", commitId.getName(), "recursive");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkInvalidSource() throws Exception {
|
||||||
|
testRepo.branch("HEAD").commit().insertChangeId()
|
||||||
|
.message("first commit")
|
||||||
|
.add("a.txt", "a contents ")
|
||||||
|
.create();
|
||||||
|
testRepo.git().push().setRemote("origin").setRefSpecs(
|
||||||
|
new RefSpec("HEAD:refs/heads/master")).call();
|
||||||
|
|
||||||
|
assertBadRequest("master", "fdsafsdf", "recursive",
|
||||||
|
"Cannot resolve 'fdsafsdf' to a commit");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkInvalidStrategy() throws Exception {
|
||||||
|
RevCommit initialHead = getRemoteHead();
|
||||||
|
testRepo.branch("HEAD").commit().insertChangeId()
|
||||||
|
.message("first commit")
|
||||||
|
.add("a.txt", "a contents ")
|
||||||
|
.create();
|
||||||
|
testRepo.git().push().setRemote("origin").setRefSpecs(
|
||||||
|
new RefSpec("HEAD:refs/heads/master")).call();
|
||||||
|
|
||||||
|
testRepo.reset(initialHead);
|
||||||
|
testRepo.branch("HEAD").commit().insertChangeId()
|
||||||
|
.message("some change in a too")
|
||||||
|
.add("a.txt", "a contents too")
|
||||||
|
.create();
|
||||||
|
testRepo.git().push().setRemote("origin").setRefSpecs(
|
||||||
|
new RefSpec("HEAD:refs/heads/test")).call();
|
||||||
|
|
||||||
|
assertBadRequest("master", "test", "octopus",
|
||||||
|
"invalid merge strategy: octopus");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertMergeable(String targetBranch, String source,
|
||||||
|
String strategy) throws Exception {
|
||||||
|
MergeableInfo
|
||||||
|
mergeableInfo = getMergeableInfo(targetBranch, source, strategy);
|
||||||
|
assertThat(mergeableInfo.mergeable).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertUnMergeable(String targetBranch, String source,
|
||||||
|
String strategy, String... conflicts) throws Exception {
|
||||||
|
MergeableInfo mergeableInfo = getMergeableInfo(targetBranch, source, strategy);
|
||||||
|
assertThat(mergeableInfo.mergeable).isFalse();
|
||||||
|
assertThat(mergeableInfo.conflicts).containsExactly((Object[]) conflicts);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertCommitMerged(String targetBranch, String source,
|
||||||
|
String strategy) throws Exception {
|
||||||
|
MergeableInfo
|
||||||
|
mergeableInfo = getMergeableInfo(targetBranch, source, strategy);
|
||||||
|
assertThat(mergeableInfo.mergeable).isTrue();
|
||||||
|
assertThat(mergeableInfo.commitMerged).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertContentMerged(String targetBranch, String source,
|
||||||
|
String strategy) throws Exception {
|
||||||
|
MergeableInfo
|
||||||
|
mergeableInfo = getMergeableInfo(targetBranch, source, strategy);
|
||||||
|
assertThat(mergeableInfo.mergeable).isTrue();
|
||||||
|
assertThat(mergeableInfo.contentMerged).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertBadRequest(String targetBranch, String source,
|
||||||
|
String strategy, String errMsg) throws Exception {
|
||||||
|
String url = "/projects/" + project.get() + "/branches/" + targetBranch;
|
||||||
|
url += "/mergeable?source=" + source;
|
||||||
|
if (!Strings.isNullOrEmpty(strategy)) {
|
||||||
|
url += "&strategy=" + strategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
RestResponse r = userRestSession.get(url);
|
||||||
|
r.assertBadRequest();
|
||||||
|
assertThat(r.getEntityContent()).isEqualTo(errMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
private MergeableInfo getMergeableInfo(String targetBranch, String source,
|
||||||
|
String strategy) throws Exception {
|
||||||
|
String url = "/projects/" + project.get() + "/branches/" + targetBranch;
|
||||||
|
url += "/mergeable?source=" + source;
|
||||||
|
if (!Strings.isNullOrEmpty(strategy)) {
|
||||||
|
url += "&strategy=" + strategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
RestResponse r = userRestSession.get(url);
|
||||||
|
r.assertOK();
|
||||||
|
MergeableInfo result = newGson().fromJson(r.getReader(), MergeableInfo.class);
|
||||||
|
r.consume();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@@ -22,6 +22,8 @@ public class MergeableInfo {
|
|||||||
public SubmitType submitType;
|
public SubmitType submitType;
|
||||||
public String strategy;
|
public String strategy;
|
||||||
public boolean mergeable;
|
public boolean mergeable;
|
||||||
|
public boolean commitMerged;
|
||||||
|
public boolean contentMerged;
|
||||||
public List<String> conflicts;
|
public List<String> conflicts;
|
||||||
public List<String> mergeableInto;
|
public List<String> mergeableInto;
|
||||||
}
|
}
|
||||||
|
@@ -23,6 +23,7 @@ import com.google.gerrit.common.TimeUtil;
|
|||||||
import com.google.gerrit.common.data.Capable;
|
import com.google.gerrit.common.data.Capable;
|
||||||
import com.google.gerrit.extensions.client.ChangeStatus;
|
import com.google.gerrit.extensions.client.ChangeStatus;
|
||||||
import com.google.gerrit.extensions.client.GeneralPreferencesInfo;
|
import com.google.gerrit.extensions.client.GeneralPreferencesInfo;
|
||||||
|
import com.google.gerrit.extensions.client.SubmitType;
|
||||||
import com.google.gerrit.extensions.common.ChangeInfo;
|
import com.google.gerrit.extensions.common.ChangeInfo;
|
||||||
import com.google.gerrit.extensions.common.ChangeInput;
|
import com.google.gerrit.extensions.common.ChangeInput;
|
||||||
import com.google.gerrit.extensions.common.MergeInput;
|
import com.google.gerrit.extensions.common.MergeInput;
|
||||||
@@ -104,6 +105,7 @@ public class CreateChange implements
|
|||||||
private final PatchSetUtil psUtil;
|
private final PatchSetUtil psUtil;
|
||||||
private final boolean allowDrafts;
|
private final boolean allowDrafts;
|
||||||
private final MergeUtil.Factory mergeUtilFactory;
|
private final MergeUtil.Factory mergeUtilFactory;
|
||||||
|
private final SubmitType submitType;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
CreateChange(@AnonymousCowardName String anonymousCowardName,
|
CreateChange(@AnonymousCowardName String anonymousCowardName,
|
||||||
@@ -135,6 +137,8 @@ public class CreateChange implements
|
|||||||
this.updateFactory = updateFactory;
|
this.updateFactory = updateFactory;
|
||||||
this.psUtil = psUtil;
|
this.psUtil = psUtil;
|
||||||
this.allowDrafts = config.getBoolean("change", "allowDrafts", true);
|
this.allowDrafts = config.getBoolean("change", "allowDrafts", true);
|
||||||
|
this.submitType = config
|
||||||
|
.getEnum("project", null, "submitType", SubmitType.MERGE_IF_NECESSARY);
|
||||||
this.mergeUtilFactory = mergeUtilFactory;
|
this.mergeUtilFactory = mergeUtilFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,6 +245,11 @@ public class CreateChange implements
|
|||||||
RevCommit c;
|
RevCommit c;
|
||||||
if (input.merge != null) {
|
if (input.merge != null) {
|
||||||
// create a merge commit
|
// create a merge commit
|
||||||
|
if (!(submitType.equals(SubmitType.MERGE_ALWAYS) ||
|
||||||
|
submitType.equals(SubmitType.MERGE_IF_NECESSARY))) {
|
||||||
|
throw new BadRequestException(
|
||||||
|
"Submit type: " + submitType + " is not supported");
|
||||||
|
}
|
||||||
c = newMergeCommit(git, oi, rw, rsrc.getControl(), mergeTip, input.merge,
|
c = newMergeCommit(git, oi, rw, rsrc.getControl(), mergeTip, input.merge,
|
||||||
author, commitMessage);
|
author, commitMessage);
|
||||||
} else {
|
} else {
|
||||||
@@ -268,6 +277,8 @@ public class CreateChange implements
|
|||||||
}
|
}
|
||||||
ChangeJson json = jsonFactory.create(ChangeJson.NO_OPTIONS);
|
ChangeJson json = jsonFactory.create(ChangeJson.NO_OPTIONS);
|
||||||
return Response.created(json.format(ins.getChange()));
|
return Response.created(json.format(ins.getChange()));
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
throw new BadRequestException(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -308,9 +319,8 @@ public class CreateChange implements
|
|||||||
Strings.emptyToNull(merge.strategy),
|
Strings.emptyToNull(merge.strategy),
|
||||||
mergeUtil.mergeStrategyName());
|
mergeUtil.mergeStrategyName());
|
||||||
|
|
||||||
return rw.parseCommit(MergeUtil
|
return MergeUtil.createMergeCommit(repo, oi, mergeTip, sourceCommit,
|
||||||
.createMergeCommit(repo, oi, mergeTip, sourceCommit, mergeStrategy,
|
mergeStrategy, authorIdent, commitMessage, rw);
|
||||||
authorIdent, commitMessage, rw));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ObjectId insert(ObjectInserter inserter,
|
private static ObjectId insert(ObjectInserter inserter,
|
||||||
|
@@ -0,0 +1,27 @@
|
|||||||
|
// 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.git;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that the change or commit is already in the source tree.
|
||||||
|
*/
|
||||||
|
public class ChangeAlreadyMergedException extends MergeIdenticalTreeException {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/** @param msg message to return to the client describing the error. */
|
||||||
|
public ChangeAlreadyMergedException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
}
|
@@ -18,13 +18,13 @@ import com.google.gerrit.extensions.restapi.RestApiException;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates that the commit is already contained in destination branch.
|
* Indicates that the commit is already contained in destination branch.
|
||||||
*
|
* Either the commit itself is in the source tree, or the content is merged
|
||||||
*/
|
*/
|
||||||
public class MergeIdenticalTreeException extends RestApiException {
|
public class MergeIdenticalTreeException extends RestApiException {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
/** @param msg message to return to the client describing the error. */
|
/** @param msg message to return to the client describing the error. */
|
||||||
public MergeIdenticalTreeException(String msg) {
|
public MergeIdenticalTreeException(String msg) {
|
||||||
super(msg, null);
|
super(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -208,14 +208,14 @@ public class MergeUtil {
|
|||||||
throw new MergeConflictException("merge conflict");
|
throw new MergeConflictException("merge conflict");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ObjectId createMergeCommit(Repository repo, ObjectInserter inserter,
|
public static RevCommit createMergeCommit(Repository repo, ObjectInserter inserter,
|
||||||
RevCommit mergeTip, RevCommit originalCommit, String mergeStrategy,
|
RevCommit mergeTip, RevCommit originalCommit, String mergeStrategy,
|
||||||
PersonIdent committerIndent, String commitMsg, RevWalk rw)
|
PersonIdent committerIndent, String commitMsg, RevWalk rw)
|
||||||
throws IOException, MergeIdenticalTreeException, MergeConflictException {
|
throws IOException, MergeIdenticalTreeException, MergeConflictException {
|
||||||
|
|
||||||
if (rw.isMergedInto(originalCommit, mergeTip)) {
|
if (rw.isMergedInto(originalCommit, mergeTip)) {
|
||||||
throw new MergeIdenticalTreeException(
|
throw new ChangeAlreadyMergedException(
|
||||||
"merge identical tree: change(s) has been already merged!");
|
"'" + originalCommit.getName() + "' has already been merged");
|
||||||
}
|
}
|
||||||
|
|
||||||
Merger m = newMerger(repo, inserter, mergeStrategy);
|
Merger m = newMerger(repo, inserter, mergeStrategy);
|
||||||
@@ -228,7 +228,7 @@ public class MergeUtil {
|
|||||||
mergeCommit.setAuthor(committerIndent);
|
mergeCommit.setAuthor(committerIndent);
|
||||||
mergeCommit.setCommitter(committerIndent);
|
mergeCommit.setCommitter(committerIndent);
|
||||||
mergeCommit.setMessage(commitMsg);
|
mergeCommit.setMessage(commitMsg);
|
||||||
return inserter.insert(mergeCommit);
|
return rw.parseCommit(inserter.insert(mergeCommit));
|
||||||
}
|
}
|
||||||
List<String> conflicts = ImmutableList.of();
|
List<String> conflicts = ImmutableList.of();
|
||||||
if (m instanceof ResolveMerger) {
|
if (m instanceof ResolveMerger) {
|
||||||
@@ -746,7 +746,12 @@ public class MergeUtil {
|
|||||||
public static RevCommit resolveCommit(Repository repo, RevWalk rw, String str)
|
public static RevCommit resolveCommit(Repository repo, RevWalk rw, String str)
|
||||||
throws BadRequestException, ResourceNotFoundException, IOException {
|
throws BadRequestException, ResourceNotFoundException, IOException {
|
||||||
try {
|
try {
|
||||||
return rw.parseCommit(repo.resolve(str));
|
ObjectId commitId = repo.resolve(str);
|
||||||
|
if (commitId == null) {
|
||||||
|
throw new BadRequestException(
|
||||||
|
"Cannot resolve '" + str + "' to a commit");
|
||||||
|
}
|
||||||
|
return rw.parseCommit(commitId);
|
||||||
} catch (AmbiguousObjectException | IncorrectObjectTypeException |
|
} catch (AmbiguousObjectException | IncorrectObjectTypeException |
|
||||||
RevisionSyntaxException e) {
|
RevisionSyntaxException e) {
|
||||||
throw new BadRequestException(e.getMessage());
|
throw new BadRequestException(e.getMessage());
|
||||||
|
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
package com.google.gerrit.server.project;
|
package com.google.gerrit.server.project;
|
||||||
|
|
||||||
|
import com.google.gerrit.extensions.client.SubmitType;
|
||||||
import com.google.gerrit.extensions.common.MergeableInfo;
|
import com.google.gerrit.extensions.common.MergeableInfo;
|
||||||
import com.google.gerrit.extensions.restapi.BadRequestException;
|
import com.google.gerrit.extensions.restapi.BadRequestException;
|
||||||
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
|
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
|
||||||
@@ -45,6 +46,7 @@ public class CheckMergeability implements RestReadView<BranchResource> {
|
|||||||
|
|
||||||
private String source;
|
private String source;
|
||||||
private String strategy;
|
private String strategy;
|
||||||
|
private SubmitType submitType;
|
||||||
private final Provider<ReviewDb> db;
|
private final Provider<ReviewDb> db;
|
||||||
|
|
||||||
@Option(name = "--source", metaVar = "COMMIT",
|
@Option(name = "--source", metaVar = "COMMIT",
|
||||||
@@ -71,13 +73,22 @@ public class CheckMergeability implements RestReadView<BranchResource> {
|
|||||||
Provider<ReviewDb> db) {
|
Provider<ReviewDb> db) {
|
||||||
this.gitManager = gitManager;
|
this.gitManager = gitManager;
|
||||||
this.strategy = MergeUtil.getMergeStrategy(cfg).getName();
|
this.strategy = MergeUtil.getMergeStrategy(cfg).getName();
|
||||||
|
this.submitType = cfg.getEnum("project", null, "submitType",
|
||||||
|
SubmitType.MERGE_IF_NECESSARY);
|
||||||
this.db = db;
|
this.db = db;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MergeableInfo apply(BranchResource resource)
|
public MergeableInfo apply(BranchResource resource)
|
||||||
throws IOException, BadRequestException, ResourceNotFoundException {
|
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();
|
MergeableInfo result = new MergeableInfo();
|
||||||
|
result.submitType = submitType;
|
||||||
result.strategy = strategy;
|
result.strategy = strategy;
|
||||||
try (Repository git = gitManager.openRepository(resource.getNameKey());
|
try (Repository git = gitManager.openRepository(resource.getNameKey());
|
||||||
RevWalk rw = new RevWalk(git);
|
RevWalk rw = new RevWalk(git);
|
||||||
@@ -97,11 +108,26 @@ public class CheckMergeability implements RestReadView<BranchResource> {
|
|||||||
"do not have read permission for: " + source);
|
"do not have read permission for: " + source);
|
||||||
}
|
}
|
||||||
|
|
||||||
result.mergeable = m.merge(targetCommit, sourceCommit);
|
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) {
|
if (m instanceof ResolveMerger) {
|
||||||
result.conflicts = ((ResolveMerger) m).getUnmergedPaths();
|
result.conflicts = ((ResolveMerger) m).getUnmergedPaths();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
throw new BadRequestException(e.getMessage());
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user