Merge changes I66527dd1,Iafcfe3f2,I1f7d77fc,I8a75c32a
* changes: GetMergeList: Also allow caching of responses for non-merges Include a magic /MERGE_LIST file for merge commits Patch: Add static method to check if file is magic Don't compare commit message against auto-merge commit
This commit is contained in:
commit
b7f970bf12
@ -17,6 +17,8 @@ package com.google.gerrit.acceptance;
|
|||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static com.google.gerrit.acceptance.GitUtil.initSsh;
|
import static com.google.gerrit.acceptance.GitUtil.initSsh;
|
||||||
import static com.google.gerrit.extensions.api.changes.SubmittedTogetherOption.NON_VISIBLE_CHANGES;
|
import static com.google.gerrit.extensions.api.changes.SubmittedTogetherOption.NON_VISIBLE_CHANGES;
|
||||||
|
import static com.google.gerrit.reviewdb.client.Patch.COMMIT_MSG;
|
||||||
|
import static com.google.gerrit.reviewdb.client.Patch.MERGE_LIST;
|
||||||
import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
|
import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
|
||||||
import static org.eclipse.jgit.lib.Constants.HEAD;
|
import static org.eclipse.jgit.lib.Constants.HEAD;
|
||||||
|
|
||||||
@ -48,6 +50,8 @@ import com.google.gerrit.extensions.client.ListChangesOption;
|
|||||||
import com.google.gerrit.extensions.client.SubmitType;
|
import com.google.gerrit.extensions.client.SubmitType;
|
||||||
import com.google.gerrit.extensions.common.ActionInfo;
|
import com.google.gerrit.extensions.common.ActionInfo;
|
||||||
import com.google.gerrit.extensions.common.ChangeInfo;
|
import com.google.gerrit.extensions.common.ChangeInfo;
|
||||||
|
import com.google.gerrit.extensions.common.ChangeType;
|
||||||
|
import com.google.gerrit.extensions.common.DiffInfo;
|
||||||
import com.google.gerrit.extensions.common.EditInfo;
|
import com.google.gerrit.extensions.common.EditInfo;
|
||||||
import com.google.gerrit.extensions.restapi.BinaryResult;
|
import com.google.gerrit.extensions.restapi.BinaryResult;
|
||||||
import com.google.gerrit.extensions.restapi.IdString;
|
import com.google.gerrit.extensions.restapi.IdString;
|
||||||
@ -67,6 +71,7 @@ import com.google.gerrit.server.account.AccountCache;
|
|||||||
import com.google.gerrit.server.account.GroupCache;
|
import com.google.gerrit.server.account.GroupCache;
|
||||||
import com.google.gerrit.server.change.Abandon;
|
import com.google.gerrit.server.change.Abandon;
|
||||||
import com.google.gerrit.server.change.ChangeResource;
|
import com.google.gerrit.server.change.ChangeResource;
|
||||||
|
import com.google.gerrit.server.change.FileContentUtil;
|
||||||
import com.google.gerrit.server.change.RevisionResource;
|
import com.google.gerrit.server.change.RevisionResource;
|
||||||
import com.google.gerrit.server.change.Revisions;
|
import com.google.gerrit.server.change.Revisions;
|
||||||
import com.google.gerrit.server.config.AllProjectsName;
|
import com.google.gerrit.server.config.AllProjectsName;
|
||||||
@ -546,21 +551,26 @@ public abstract class AbstractDaemonTest {
|
|||||||
|
|
||||||
protected PushOneCommit.Result createMergeCommitChange(String ref)
|
protected PushOneCommit.Result createMergeCommitChange(String ref)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
return createMergeCommitChange(ref, "foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected PushOneCommit.Result createMergeCommitChange(String ref, String file)
|
||||||
|
throws Exception {
|
||||||
ObjectId initial = repo().exactRef(HEAD).getLeaf().getObjectId();
|
ObjectId initial = repo().exactRef(HEAD).getLeaf().getObjectId();
|
||||||
|
|
||||||
PushOneCommit.Result p1 = pushFactory.create(db, admin.getIdent(),
|
PushOneCommit.Result p1 = pushFactory.create(db, admin.getIdent(),
|
||||||
testRepo, "parent 1", ImmutableMap.of("foo", "foo-1", "bar", "bar-1"))
|
testRepo, "parent 1", ImmutableMap.of(file, "foo-1", "bar", "bar-1"))
|
||||||
.to(ref);
|
.to(ref);
|
||||||
|
|
||||||
// reset HEAD in order to create a sibling of the first change
|
// reset HEAD in order to create a sibling of the first change
|
||||||
testRepo.reset(initial);
|
testRepo.reset(initial);
|
||||||
|
|
||||||
PushOneCommit.Result p2 = pushFactory.create(db, admin.getIdent(),
|
PushOneCommit.Result p2 = pushFactory.create(db, admin.getIdent(),
|
||||||
testRepo, "parent 2", ImmutableMap.of("foo", "foo-2", "bar", "bar-2"))
|
testRepo, "parent 2", ImmutableMap.of(file, "foo-2", "bar", "bar-2"))
|
||||||
.to(ref);
|
.to(ref);
|
||||||
|
|
||||||
PushOneCommit m = pushFactory.create(db, admin.getIdent(), testRepo, "merge",
|
PushOneCommit m = pushFactory.create(db, admin.getIdent(), testRepo, "merge",
|
||||||
ImmutableMap.of("foo", "foo-1", "bar", "bar-2"));
|
ImmutableMap.of(file, "foo-1", "bar", "bar-2"));
|
||||||
m.setParents(ImmutableList.of(p1.getCommit(), p2.getCommit()));
|
m.setParents(ImmutableList.of(p1.getCommit(), p2.getCommit()));
|
||||||
PushOneCommit.Result result = m.to(ref);
|
PushOneCommit.Result result = m.to(ref);
|
||||||
result.assertOkStatus();
|
result.assertOkStatus();
|
||||||
@ -1086,4 +1096,45 @@ public abstract class AbstractDaemonTest {
|
|||||||
}
|
}
|
||||||
assertThat(refValues.keySet()).containsAnyIn(trees.keySet());
|
assertThat(refValues.keySet()).containsAnyIn(trees.keySet());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void assertDiffForNewFile(DiffInfo diff, RevCommit commit,
|
||||||
|
String path, String expectedContentSideB) throws Exception {
|
||||||
|
List<String> expectedLines = new ArrayList<>();
|
||||||
|
for (String line : expectedContentSideB.split("\n")) {
|
||||||
|
expectedLines.add(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
assertThat(diff.binary).isNull();
|
||||||
|
assertThat(diff.changeType).isEqualTo(ChangeType.ADDED);
|
||||||
|
assertThat(diff.diffHeader).isNotNull();
|
||||||
|
assertThat(diff.intralineStatus).isNull();
|
||||||
|
assertThat(diff.webLinks).isNull();
|
||||||
|
|
||||||
|
assertThat(diff.metaA).isNull();
|
||||||
|
assertThat(diff.metaB).isNotNull();
|
||||||
|
assertThat(diff.metaB.commitId).isEqualTo(commit.name());
|
||||||
|
|
||||||
|
String expectedContentType = "text/plain";
|
||||||
|
if (COMMIT_MSG.equals(path)) {
|
||||||
|
expectedContentType = FileContentUtil.TEXT_X_GERRIT_COMMIT_MESSAGE;
|
||||||
|
} else if (MERGE_LIST.equals(path)) {
|
||||||
|
expectedContentType = FileContentUtil.TEXT_X_GERRIT_MERGE_LIST;
|
||||||
|
}
|
||||||
|
assertThat(diff.metaB.contentType).isEqualTo(expectedContentType);
|
||||||
|
|
||||||
|
assertThat(diff.metaB.lines).isEqualTo(expectedLines.size());
|
||||||
|
assertThat(diff.metaB.name).isEqualTo(path);
|
||||||
|
assertThat(diff.metaB.webLinks).isNull();
|
||||||
|
|
||||||
|
assertThat(diff.content).hasSize(1);
|
||||||
|
DiffInfo.ContentEntry contentEntry = diff.content.get(0);
|
||||||
|
assertThat(contentEntry.b).containsExactlyElementsIn(expectedLines)
|
||||||
|
.inOrder();
|
||||||
|
assertThat(contentEntry.a).isNull();
|
||||||
|
assertThat(contentEntry.ab).isNull();
|
||||||
|
assertThat(contentEntry.common).isNull();
|
||||||
|
assertThat(contentEntry.editA).isNull();
|
||||||
|
assertThat(contentEntry.editB).isNull();
|
||||||
|
assertThat(contentEntry.skip).isNull();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,80 +0,0 @@
|
|||||||
// 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.api.change;
|
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
|
||||||
import static org.eclipse.jgit.lib.Constants.HEAD;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
|
||||||
import com.google.gerrit.acceptance.AbstractDaemonTest;
|
|
||||||
import com.google.gerrit.acceptance.NoHttpd;
|
|
||||||
import com.google.gerrit.acceptance.PushOneCommit;
|
|
||||||
import com.google.gerrit.extensions.common.CommitInfo;
|
|
||||||
|
|
||||||
import org.eclipse.jgit.lib.ObjectId;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@NoHttpd
|
|
||||||
public class GetMergeListIT extends AbstractDaemonTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getMergeList() throws Exception {
|
|
||||||
ObjectId initial = repo().exactRef(HEAD).getLeaf().getObjectId();
|
|
||||||
|
|
||||||
PushOneCommit.Result gp1 = pushFactory
|
|
||||||
.create(db, admin.getIdent(), testRepo, "grand parent 1",
|
|
||||||
ImmutableMap.of("foo", "foo-1.1", "bar", "bar-1.1"))
|
|
||||||
.to("refs/for/master");
|
|
||||||
|
|
||||||
PushOneCommit.Result p1 = pushFactory
|
|
||||||
.create(db, admin.getIdent(), testRepo, "parent 1",
|
|
||||||
ImmutableMap.of("foo", "foo-1.2", "bar", "bar-1.2"))
|
|
||||||
.to("refs/for/master");
|
|
||||||
|
|
||||||
// reset HEAD in order to create a sibling of the first change
|
|
||||||
testRepo.reset(initial);
|
|
||||||
|
|
||||||
PushOneCommit.Result gp2 = pushFactory
|
|
||||||
.create(db, admin.getIdent(), testRepo, "grand parent 1",
|
|
||||||
ImmutableMap.of("foo", "foo-2.1", "bar", "bar-2.1"))
|
|
||||||
.to("refs/for/master");
|
|
||||||
|
|
||||||
PushOneCommit.Result p2 = pushFactory
|
|
||||||
.create(db, admin.getIdent(), testRepo, "parent 2",
|
|
||||||
ImmutableMap.of("foo", "foo-2.2", "bar", "bar-2.2"))
|
|
||||||
.to("refs/for/master");
|
|
||||||
|
|
||||||
PushOneCommit m = pushFactory.create(db, admin.getIdent(), testRepo,
|
|
||||||
"merge", ImmutableMap.of("foo", "foo-1", "bar", "bar-2"));
|
|
||||||
m.setParents(ImmutableList.of(p1.getCommit(), p2.getCommit()));
|
|
||||||
PushOneCommit.Result result = m.to("refs/for/master");
|
|
||||||
result.assertOkStatus();
|
|
||||||
|
|
||||||
List<CommitInfo> mergeList =
|
|
||||||
gApi.changes().id(result.getChangeId()).current().getMergeList().get();
|
|
||||||
assertThat(mergeList).hasSize(2);
|
|
||||||
assertThat(mergeList.get(0).commit).isEqualTo(p2.getCommit().name());
|
|
||||||
assertThat(mergeList.get(1).commit).isEqualTo(gp2.getCommit().name());
|
|
||||||
|
|
||||||
mergeList = gApi.changes().id(result.getChangeId()).current().getMergeList()
|
|
||||||
.withUninterestingParent(2).get();
|
|
||||||
assertThat(mergeList).hasSize(2);
|
|
||||||
assertThat(mergeList.get(0).commit).isEqualTo(p1.getCommit().name());
|
|
||||||
assertThat(mergeList.get(1).commit).isEqualTo(gp1.getCommit().name());
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,209 @@
|
|||||||
|
// 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.api.change;
|
||||||
|
|
||||||
|
import static com.google.common.collect.Iterables.getOnlyElement;
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
import static com.google.gerrit.reviewdb.client.Patch.MERGE_LIST;
|
||||||
|
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||||
|
import static org.eclipse.jgit.lib.Constants.HEAD;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.gerrit.acceptance.AbstractDaemonTest;
|
||||||
|
import com.google.gerrit.acceptance.NoHttpd;
|
||||||
|
import com.google.gerrit.acceptance.PushOneCommit;
|
||||||
|
import com.google.gerrit.common.RawInputUtil;
|
||||||
|
import com.google.gerrit.extensions.api.changes.RevisionApi;
|
||||||
|
import com.google.gerrit.extensions.common.CommitInfo;
|
||||||
|
import com.google.gerrit.extensions.common.DiffInfo;
|
||||||
|
import com.google.gerrit.extensions.restapi.BinaryResult;
|
||||||
|
import com.google.gerrit.server.edit.ChangeEditModifier;
|
||||||
|
import com.google.gerrit.server.edit.ChangeEditUtil;
|
||||||
|
import com.google.gerrit.server.project.InvalidChangeOperationException;
|
||||||
|
import com.google.gerrit.server.query.change.ChangeData;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
|
import org.eclipse.jgit.dircache.InvalidPathException;
|
||||||
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
|
import org.eclipse.jgit.revwalk.RevCommit;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@NoHttpd
|
||||||
|
public class MergeListIT extends AbstractDaemonTest {
|
||||||
|
|
||||||
|
private String changeId;
|
||||||
|
private RevCommit merge;
|
||||||
|
private RevCommit parent1;
|
||||||
|
private RevCommit grandParent1;
|
||||||
|
private RevCommit parent2;
|
||||||
|
private RevCommit grandParent2;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private ChangeEditModifier modifier;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private ChangeEditUtil editUtil;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() throws Exception {
|
||||||
|
ObjectId initial = repo().exactRef(HEAD).getLeaf().getObjectId();
|
||||||
|
|
||||||
|
PushOneCommit.Result gp1 = pushFactory
|
||||||
|
.create(db, admin.getIdent(), testRepo, "grand parent 1",
|
||||||
|
ImmutableMap.of("foo", "foo-1.1", "bar", "bar-1.1"))
|
||||||
|
.to("refs/for/master");
|
||||||
|
grandParent1 = gp1.getCommit();
|
||||||
|
|
||||||
|
PushOneCommit.Result p1 = pushFactory
|
||||||
|
.create(db, admin.getIdent(), testRepo, "parent 1",
|
||||||
|
ImmutableMap.of("foo", "foo-1.2", "bar", "bar-1.2"))
|
||||||
|
.to("refs/for/master");
|
||||||
|
parent1 = p1.getCommit();
|
||||||
|
|
||||||
|
// reset HEAD in order to create a sibling of the first change
|
||||||
|
testRepo.reset(initial);
|
||||||
|
|
||||||
|
PushOneCommit.Result gp2 = pushFactory
|
||||||
|
.create(db, admin.getIdent(), testRepo, "grand parent 2",
|
||||||
|
ImmutableMap.of("foo", "foo-2.1", "bar", "bar-2.1"))
|
||||||
|
.to("refs/for/master");
|
||||||
|
grandParent2 = gp2.getCommit();
|
||||||
|
|
||||||
|
PushOneCommit.Result p2 = pushFactory
|
||||||
|
.create(db, admin.getIdent(), testRepo, "parent 2",
|
||||||
|
ImmutableMap.of("foo", "foo-2.2", "bar", "bar-2.2"))
|
||||||
|
.to("refs/for/master");
|
||||||
|
parent2 = p2.getCommit();
|
||||||
|
|
||||||
|
PushOneCommit m = pushFactory.create(db, admin.getIdent(), testRepo,
|
||||||
|
"merge", ImmutableMap.of("foo", "foo-1", "bar", "bar-2"));
|
||||||
|
m.setParents(ImmutableList.of(p1.getCommit(), p2.getCommit()));
|
||||||
|
PushOneCommit.Result result = m.to("refs/for/master");
|
||||||
|
result.assertOkStatus();
|
||||||
|
merge = result.getCommit();
|
||||||
|
changeId = result.getChangeId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getMergeList() throws Exception {
|
||||||
|
List<CommitInfo> mergeList = current(changeId).getMergeList().get();
|
||||||
|
assertThat(mergeList).hasSize(2);
|
||||||
|
assertThat(mergeList.get(0).commit).isEqualTo(parent2.name());
|
||||||
|
assertThat(mergeList.get(1).commit).isEqualTo(grandParent2.name());
|
||||||
|
|
||||||
|
mergeList = current(changeId).getMergeList()
|
||||||
|
.withUninterestingParent(2).get();
|
||||||
|
assertThat(mergeList).hasSize(2);
|
||||||
|
assertThat(mergeList.get(0).commit).isEqualTo(parent1.name());
|
||||||
|
assertThat(mergeList.get(1).commit).isEqualTo(grandParent1.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getMergeListContent() throws Exception {
|
||||||
|
BinaryResult bin = current(changeId).file(MERGE_LIST).content();
|
||||||
|
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||||
|
bin.writeTo(os);
|
||||||
|
String content = new String(os.toByteArray(), UTF_8);
|
||||||
|
assertThat(content).isEqualTo(
|
||||||
|
getMergeListContent(parent2, grandParent2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getFileList() throws Exception {
|
||||||
|
assertThat(getFiles(changeId)).contains(MERGE_LIST);
|
||||||
|
assertThat(getFiles(changeId, 1)).contains(MERGE_LIST);
|
||||||
|
assertThat(getFiles(changeId, 2)).contains(MERGE_LIST);
|
||||||
|
|
||||||
|
assertThat(getFiles(createChange().getChangeId()))
|
||||||
|
.doesNotContain(MERGE_LIST);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getDiffForMergeList() throws Exception {
|
||||||
|
DiffInfo diff = getMergeListDiff(changeId);
|
||||||
|
assertDiffForNewFile(diff, merge, MERGE_LIST,
|
||||||
|
getMergeListContent(parent2, grandParent2));
|
||||||
|
|
||||||
|
diff = getMergeListDiff(changeId, 1);
|
||||||
|
assertDiffForNewFile(diff, merge, MERGE_LIST,
|
||||||
|
getMergeListContent(parent2, grandParent2));
|
||||||
|
|
||||||
|
diff = getMergeListDiff(changeId, 2);
|
||||||
|
assertDiffForNewFile(diff, merge, MERGE_LIST,
|
||||||
|
getMergeListContent(parent1, grandParent1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void editMergeList() throws Exception {
|
||||||
|
ChangeData cd = getOnlyElement(queryProvider.get().byKeyPrefix(changeId));
|
||||||
|
modifier.createEdit(cd.change(), cd.currentPatchSet());
|
||||||
|
|
||||||
|
exception.expect(InvalidPathException.class);
|
||||||
|
exception.expectMessage("Invalid path: " + MERGE_LIST);
|
||||||
|
modifier.modifyFile(editUtil.byChange(cd.change()).get(), MERGE_LIST,
|
||||||
|
RawInputUtil.create("new content"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteMergeList() throws Exception {
|
||||||
|
ChangeData cd = getOnlyElement(queryProvider.get().byKeyPrefix(changeId));
|
||||||
|
modifier.createEdit(cd.change(), cd.currentPatchSet());
|
||||||
|
|
||||||
|
exception.expect(InvalidChangeOperationException.class);
|
||||||
|
exception.expectMessage("no changes were made");
|
||||||
|
modifier.deleteFile(editUtil.byChange(cd.change()).get(), MERGE_LIST);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getMergeListContent(RevCommit... commits) {
|
||||||
|
StringBuilder mergeList = new StringBuilder("Merge List:\n\n");
|
||||||
|
for (RevCommit c : commits) {
|
||||||
|
mergeList.append("* ")
|
||||||
|
.append(c.abbreviate(8).name())
|
||||||
|
.append(" ")
|
||||||
|
.append(c.getShortMessage())
|
||||||
|
.append("\n");
|
||||||
|
}
|
||||||
|
return mergeList.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<String> getFiles(String changeId) throws Exception {
|
||||||
|
return current(changeId).files().keySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<String> getFiles(String changeId, int parent) throws Exception {
|
||||||
|
return current(changeId).files(parent).keySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
private DiffInfo getMergeListDiff(String changeId) throws Exception {
|
||||||
|
return current(changeId).file(MERGE_LIST).diff();
|
||||||
|
}
|
||||||
|
|
||||||
|
private DiffInfo getMergeListDiff(String changeId, int parent)
|
||||||
|
throws Exception {
|
||||||
|
return current(changeId).file(MERGE_LIST).diff(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private RevisionApi current(String changeId) throws Exception {
|
||||||
|
return gApi.changes()
|
||||||
|
.id(changeId)
|
||||||
|
.current();
|
||||||
|
}
|
||||||
|
}
|
@ -20,11 +20,13 @@ import static com.google.gerrit.acceptance.PushOneCommit.FILE_NAME;
|
|||||||
import static com.google.gerrit.acceptance.PushOneCommit.PATCH;
|
import static com.google.gerrit.acceptance.PushOneCommit.PATCH;
|
||||||
import static com.google.gerrit.acceptance.PushOneCommit.SUBJECT;
|
import static com.google.gerrit.acceptance.PushOneCommit.SUBJECT;
|
||||||
import static com.google.gerrit.reviewdb.client.Patch.COMMIT_MSG;
|
import static com.google.gerrit.reviewdb.client.Patch.COMMIT_MSG;
|
||||||
|
import static com.google.gerrit.reviewdb.client.Patch.MERGE_LIST;
|
||||||
import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
|
import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
|
||||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||||
import static org.eclipse.jgit.lib.Constants.HEAD;
|
import static org.eclipse.jgit.lib.Constants.HEAD;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import com.google.common.base.Joiner;
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.gerrit.acceptance.AbstractDaemonTest;
|
import com.google.gerrit.acceptance.AbstractDaemonTest;
|
||||||
@ -45,7 +47,6 @@ import com.google.gerrit.extensions.client.ChangeStatus;
|
|||||||
import com.google.gerrit.extensions.client.SubmitType;
|
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.ChangeMessageInfo;
|
import com.google.gerrit.extensions.common.ChangeMessageInfo;
|
||||||
import com.google.gerrit.extensions.common.ChangeType;
|
|
||||||
import com.google.gerrit.extensions.common.CommentInfo;
|
import com.google.gerrit.extensions.common.CommentInfo;
|
||||||
import com.google.gerrit.extensions.common.DiffInfo;
|
import com.google.gerrit.extensions.common.DiffInfo;
|
||||||
import com.google.gerrit.extensions.common.FileInfo;
|
import com.google.gerrit.extensions.common.FileInfo;
|
||||||
@ -539,7 +540,7 @@ public class RevisionIT extends AbstractDaemonTest {
|
|||||||
.revision(r.getCommit().name())
|
.revision(r.getCommit().name())
|
||||||
.files()
|
.files()
|
||||||
.keySet()
|
.keySet()
|
||||||
).containsExactly(COMMIT_MSG, "foo", "bar");
|
).containsExactly(COMMIT_MSG, MERGE_LIST, "foo", "bar");
|
||||||
|
|
||||||
// list files against parent 1
|
// list files against parent 1
|
||||||
assertThat(gApi.changes()
|
assertThat(gApi.changes()
|
||||||
@ -547,7 +548,7 @@ public class RevisionIT extends AbstractDaemonTest {
|
|||||||
.revision(r.getCommit().name())
|
.revision(r.getCommit().name())
|
||||||
.files(1)
|
.files(1)
|
||||||
.keySet()
|
.keySet()
|
||||||
).containsExactly(COMMIT_MSG, "bar");
|
).containsExactly(COMMIT_MSG, MERGE_LIST, "bar");
|
||||||
|
|
||||||
// list files against parent 2
|
// list files against parent 2
|
||||||
assertThat(gApi.changes()
|
assertThat(gApi.changes()
|
||||||
@ -555,7 +556,7 @@ public class RevisionIT extends AbstractDaemonTest {
|
|||||||
.revision(r.getCommit().name())
|
.revision(r.getCommit().name())
|
||||||
.files(2)
|
.files(2)
|
||||||
.keySet()
|
.keySet()
|
||||||
).containsExactly(COMMIT_MSG, "foo");
|
).containsExactly(COMMIT_MSG, MERGE_LIST, "foo");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -853,66 +854,40 @@ public class RevisionIT extends AbstractDaemonTest {
|
|||||||
.file(path)
|
.file(path)
|
||||||
.diff();
|
.diff();
|
||||||
|
|
||||||
List<String> expectedLines = new ArrayList<>();
|
List<String> headers = new ArrayList<>();
|
||||||
if (path.equals(COMMIT_MSG)) {
|
if (path.equals(COMMIT_MSG)) {
|
||||||
RevCommit c = pushResult.getCommit();
|
RevCommit c = pushResult.getCommit();
|
||||||
|
|
||||||
RevCommit parentCommit = c.getParents()[0];
|
RevCommit parentCommit = c.getParents()[0];
|
||||||
String parentCommitId = testRepo.getRevWalk().getObjectReader()
|
String parentCommitId = testRepo.getRevWalk().getObjectReader()
|
||||||
.abbreviate(parentCommit.getId(), 8).name();
|
.abbreviate(parentCommit.getId(), 8).name();
|
||||||
expectedLines.add("Parent: " + parentCommitId + " ("
|
headers.add("Parent: " + parentCommitId + " ("
|
||||||
+ parentCommit.getShortMessage() + ")");
|
+ parentCommit.getShortMessage() + ")");
|
||||||
|
|
||||||
SimpleDateFormat dtfmt =
|
SimpleDateFormat dtfmt =
|
||||||
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z", Locale.US);
|
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z", Locale.US);
|
||||||
PersonIdent author = c.getAuthorIdent();
|
PersonIdent author = c.getAuthorIdent();
|
||||||
dtfmt.setTimeZone(author.getTimeZone());
|
dtfmt.setTimeZone(author.getTimeZone());
|
||||||
expectedLines.add("Author: " + author.getName() + " <"
|
headers.add("Author: " + author.getName() + " <"
|
||||||
+ author.getEmailAddress() + ">");
|
+ author.getEmailAddress() + ">");
|
||||||
expectedLines.add("AuthorDate: "
|
headers.add("AuthorDate: "
|
||||||
+ dtfmt.format(Long.valueOf(author.getWhen().getTime())));
|
+ dtfmt.format(Long.valueOf(author.getWhen().getTime())));
|
||||||
|
|
||||||
PersonIdent committer = c.getCommitterIdent();
|
PersonIdent committer = c.getCommitterIdent();
|
||||||
dtfmt.setTimeZone(committer.getTimeZone());
|
dtfmt.setTimeZone(committer.getTimeZone());
|
||||||
expectedLines.add("Commit: " + committer.getName() + " <"
|
headers.add("Commit: " + committer.getName() + " <"
|
||||||
+ committer.getEmailAddress() + ">");
|
+ committer.getEmailAddress() + ">");
|
||||||
expectedLines.add("CommitDate: "
|
headers.add("CommitDate: "
|
||||||
+ dtfmt.format(Long.valueOf(committer.getWhen().getTime())));
|
+ dtfmt.format(Long.valueOf(committer.getWhen().getTime())));
|
||||||
expectedLines.add("");
|
headers.add("");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (String line : expectedContentSideB.split("\n")) {
|
if (!headers.isEmpty()) {
|
||||||
expectedLines.add(line);
|
String header = Joiner.on("\n").join(headers);
|
||||||
|
expectedContentSideB = header + "\n" + expectedContentSideB;
|
||||||
}
|
}
|
||||||
|
|
||||||
assertThat(diff.binary).isNull();
|
assertDiffForNewFile(diff, pushResult.getCommit(), path,
|
||||||
assertThat(diff.changeType).isEqualTo(ChangeType.ADDED);
|
expectedContentSideB);
|
||||||
assertThat(diff.diffHeader).isNotNull();
|
|
||||||
assertThat(diff.intralineStatus).isNull();
|
|
||||||
assertThat(diff.webLinks).isNull();
|
|
||||||
|
|
||||||
assertThat(diff.metaA).isNull();
|
|
||||||
assertThat(diff.metaB).isNotNull();
|
|
||||||
assertThat(diff.metaB.commitId).isEqualTo(pushResult.getCommit().name());
|
|
||||||
assertThat(diff.metaB.contentType).isEqualTo(
|
|
||||||
path.equals(COMMIT_MSG)
|
|
||||||
? "text/x-gerrit-commit-message"
|
|
||||||
: "text/plain");
|
|
||||||
assertThat(diff.metaB.lines).isEqualTo(expectedLines.size());
|
|
||||||
assertThat(diff.metaB.name).isEqualTo(path);
|
|
||||||
assertThat(diff.metaB.webLinks).isNull();
|
|
||||||
|
|
||||||
assertThat(diff.content).hasSize(1);
|
|
||||||
DiffInfo.ContentEntry contentEntry = diff.content.get(0);
|
|
||||||
assertThat(contentEntry.b).hasSize(expectedLines.size());
|
|
||||||
for (int i = 0; i < contentEntry.b.size(); i++) {
|
|
||||||
assertThat(contentEntry.b.get(i)).isEqualTo(expectedLines.get(i));
|
|
||||||
}
|
|
||||||
assertThat(contentEntry.a).isNull();
|
|
||||||
assertThat(contentEntry.ab).isNull();
|
|
||||||
assertThat(contentEntry.common).isNull();
|
|
||||||
assertThat(contentEntry.editA).isNull();
|
|
||||||
assertThat(contentEntry.editB).isNull();
|
|
||||||
assertThat(contentEntry.skip).isNull();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,9 +32,11 @@ import com.google.gerrit.extensions.api.changes.ReviewInput.DraftHandling;
|
|||||||
import com.google.gerrit.extensions.client.Comment;
|
import com.google.gerrit.extensions.client.Comment;
|
||||||
import com.google.gerrit.extensions.client.Side;
|
import com.google.gerrit.extensions.client.Side;
|
||||||
import com.google.gerrit.extensions.common.CommentInfo;
|
import com.google.gerrit.extensions.common.CommentInfo;
|
||||||
|
import com.google.gerrit.extensions.restapi.BadRequestException;
|
||||||
import com.google.gerrit.extensions.restapi.IdString;
|
import com.google.gerrit.extensions.restapi.IdString;
|
||||||
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
|
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
|
||||||
import com.google.gerrit.extensions.restapi.TopLevelResource;
|
import com.google.gerrit.extensions.restapi.TopLevelResource;
|
||||||
|
import com.google.gerrit.reviewdb.client.Patch;
|
||||||
import com.google.gerrit.server.change.ChangeResource;
|
import com.google.gerrit.server.change.ChangeResource;
|
||||||
import com.google.gerrit.server.change.ChangesCollection;
|
import com.google.gerrit.server.change.ChangesCollection;
|
||||||
import com.google.gerrit.server.change.PostReview;
|
import com.google.gerrit.server.change.PostReview;
|
||||||
@ -148,8 +150,8 @@ public class CommentsIT extends AbstractDaemonTest {
|
|||||||
@Test
|
@Test
|
||||||
public void postCommentOnMergeCommitChange() throws Exception {
|
public void postCommentOnMergeCommitChange() throws Exception {
|
||||||
for (Integer line : lines) {
|
for (Integer line : lines) {
|
||||||
final String file = "/COMMIT_MSG";
|
String file = "foo";
|
||||||
PushOneCommit.Result r = createMergeCommitChange("refs/for/master");
|
PushOneCommit.Result r = createMergeCommitChange("refs/for/master", file);
|
||||||
String changeId = r.getChangeId();
|
String changeId = r.getChangeId();
|
||||||
String revId = r.getCommit().getName();
|
String revId = r.getCommit().getName();
|
||||||
ReviewInput input = new ReviewInput();
|
ReviewInput input = new ReviewInput();
|
||||||
@ -165,6 +167,39 @@ public class CommentsIT extends AbstractDaemonTest {
|
|||||||
assertThat(Lists.transform(result.get(file), infoToInput(file)))
|
assertThat(Lists.transform(result.get(file), infoToInput(file)))
|
||||||
.containsExactly(c1, c2, c3, c4);
|
.containsExactly(c1, c2, c3, c4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for the commit message comments on the auto-merge are not possible
|
||||||
|
for (Integer line : lines) {
|
||||||
|
String file = Patch.COMMIT_MSG;
|
||||||
|
PushOneCommit.Result r = createMergeCommitChange("refs/for/master");
|
||||||
|
String changeId = r.getChangeId();
|
||||||
|
String revId = r.getCommit().getName();
|
||||||
|
ReviewInput input = new ReviewInput();
|
||||||
|
CommentInput c1 = newComment(file, Side.REVISION, line, "ps-1");
|
||||||
|
CommentInput c2 = newCommentOnParent(file, 1, line, "parent-1 of ps-1");
|
||||||
|
CommentInput c3 = newCommentOnParent(file, 2, line, "parent-2 of ps-1");
|
||||||
|
input.comments = new HashMap<>();
|
||||||
|
input.comments.put(file, ImmutableList.of(c1, c2, c3));
|
||||||
|
revision(r).review(input);
|
||||||
|
Map<String, List<CommentInfo>> result = getPublishedComments(changeId, revId);
|
||||||
|
assertThat(result).isNotEmpty();
|
||||||
|
assertThat(Lists.transform(result.get(file), infoToInput(file)))
|
||||||
|
.containsExactly(c1, c2, c3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void postCommentOnCommitMessageOnAutoMerge() throws Exception {
|
||||||
|
PushOneCommit.Result r = createMergeCommitChange("refs/for/master");
|
||||||
|
ReviewInput input = new ReviewInput();
|
||||||
|
CommentInput c =
|
||||||
|
newComment(Patch.COMMIT_MSG, Side.PARENT, 0, "comment on auto-merge");
|
||||||
|
input.comments = new HashMap<>();
|
||||||
|
input.comments.put(Patch.COMMIT_MSG, ImmutableList.of(c));
|
||||||
|
exception.expect(BadRequestException.class);
|
||||||
|
exception.expectMessage(
|
||||||
|
"cannot comment on " + Patch.COMMIT_MSG + " on auto-merge");
|
||||||
|
revision(r).review(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -56,6 +56,12 @@ public class FileInfo extends JavaScriptObject {
|
|||||||
} else if (Patch.COMMIT_MSG.equals(b.path())) {
|
} else if (Patch.COMMIT_MSG.equals(b.path())) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
if (Patch.MERGE_LIST.equals(a.path())) {
|
||||||
|
return -1;
|
||||||
|
} else if (Patch.MERGE_LIST.equals(b.path())) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Look at file suffixes to check if it makes sense to use a different order
|
// Look at file suffixes to check if it makes sense to use a different order
|
||||||
int s1 = a.path().lastIndexOf('.');
|
int s1 = a.path().lastIndexOf('.');
|
||||||
int s2 = b.path().lastIndexOf('.');
|
int s2 = b.path().lastIndexOf('.');
|
||||||
@ -76,9 +82,15 @@ public class FileInfo extends JavaScriptObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static String getFileName(String path) {
|
public static String getFileName(String path) {
|
||||||
String fileName = Patch.COMMIT_MSG.equals(path)
|
String fileName;
|
||||||
? "Commit Message"
|
if (Patch.COMMIT_MSG.equals(path)) {
|
||||||
: path;
|
fileName = "Commit Message";
|
||||||
|
} else if (Patch.MERGE_LIST.equals(path)) {
|
||||||
|
fileName = "Merge List";
|
||||||
|
} else {
|
||||||
|
fileName = path;
|
||||||
|
}
|
||||||
|
|
||||||
int s = fileName.lastIndexOf('/');
|
int s = fileName.lastIndexOf('/');
|
||||||
return s >= 0 ? fileName.substring(s + 1) : fileName;
|
return s >= 0 ? fileName.substring(s + 1) : fileName;
|
||||||
}
|
}
|
||||||
|
@ -486,7 +486,11 @@ public class Dispatcher {
|
|||||||
} else if ("unified".equals(panel)) {
|
} else if ("unified".equals(panel)) {
|
||||||
unified(token, baseId, id, side, line);
|
unified(token, baseId, id, side, line);
|
||||||
} else if ("edit".equals(panel)) {
|
} else if ("edit".equals(panel)) {
|
||||||
codemirrorForEdit(token, id, line);
|
if (!Patch.isMagic(id.get()) || Patch.COMMIT_MSG.equals(id.get())) {
|
||||||
|
codemirrorForEdit(token, id, line);
|
||||||
|
} else {
|
||||||
|
Gerrit.display(token, new NotFoundScreen());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Gerrit.display(token, new NotFoundScreen());
|
Gerrit.display(token, new NotFoundScreen());
|
||||||
}
|
}
|
||||||
|
@ -267,11 +267,18 @@ public class FileTable extends FlowPanel {
|
|||||||
if (table != null) {
|
if (table != null) {
|
||||||
String self = Gerrit.selfRedirect(null);
|
String self = Gerrit.selfRedirect(null);
|
||||||
for (FileInfo info : Natives.asList(table.list)) {
|
for (FileInfo info : Natives.asList(table.list)) {
|
||||||
Window.open(self + "#" + url(info), "_blank", null);
|
if (canOpen(info.path())) {
|
||||||
|
Window.open(self + "#" + url(info), "_blank", null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean canOpen(String path) {
|
||||||
|
return mode != Mode.EDIT || !Patch.isMagic(path)
|
||||||
|
|| Patch.COMMIT_MSG.equals(path);
|
||||||
|
}
|
||||||
|
|
||||||
private void setTable(MyTable table) {
|
private void setTable(MyTable table) {
|
||||||
clear();
|
clear();
|
||||||
add(table);
|
add(table);
|
||||||
@ -429,7 +436,10 @@ public class FileTable extends FlowPanel {
|
|||||||
@Override
|
@Override
|
||||||
protected void onOpenRow(int row) {
|
protected void onOpenRow(int row) {
|
||||||
if (1 <= row && row <= list.length()) {
|
if (1 <= row && row <= list.length()) {
|
||||||
Gerrit.display(url(list.get(row - 1)));
|
FileInfo info = list.get(row - 1);
|
||||||
|
if (canOpen(info.path())) {
|
||||||
|
Gerrit.display(url(info));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -452,7 +462,10 @@ public class FileTable extends FlowPanel {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onKeyPress(KeyPressEvent event) {
|
public void onKeyPress(KeyPressEvent event) {
|
||||||
Gerrit.display(url(list.get(index)));
|
FileInfo info = list.get(index);
|
||||||
|
if (canOpen(info.path())) {
|
||||||
|
Gerrit.display(url(info));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -538,7 +551,7 @@ public class FileTable extends FlowPanel {
|
|||||||
bytesDeleted = 0;
|
bytesDeleted = 0;
|
||||||
for (int i = 0; i < list.length(); i++) {
|
for (int i = 0; i < list.length(); i++) {
|
||||||
FileInfo info = list.get(i);
|
FileInfo info = list.get(i);
|
||||||
if (!Patch.COMMIT_MSG.equals(info.path())) {
|
if (!Patch.isMagic(info.path())) {
|
||||||
if (!info.binary()) {
|
if (!info.binary()) {
|
||||||
hasNonBinaryFile = true;
|
hasNonBinaryFile = true;
|
||||||
inserted += info.linesInserted();
|
inserted += info.linesInserted();
|
||||||
@ -628,7 +641,7 @@ public class FileTable extends FlowPanel {
|
|||||||
private void columnDeleteRestore(SafeHtmlBuilder sb, FileInfo info) {
|
private void columnDeleteRestore(SafeHtmlBuilder sb, FileInfo info) {
|
||||||
sb.openTd().setStyleName(R.css().restoreDelete());
|
sb.openTd().setStyleName(R.css().restoreDelete());
|
||||||
if (hasUser) {
|
if (hasUser) {
|
||||||
if (!Patch.COMMIT_MSG.equals(info.path())) {
|
if (!Patch.isMagic(info.path())) {
|
||||||
boolean editable = isEditable(info);
|
boolean editable = isEditable(info);
|
||||||
sb.openDiv()
|
sb.openDiv()
|
||||||
.openElement("button")
|
.openElement("button")
|
||||||
@ -659,7 +672,7 @@ public class FileTable extends FlowPanel {
|
|||||||
|
|
||||||
private void columnStatus(SafeHtmlBuilder sb, FileInfo info) {
|
private void columnStatus(SafeHtmlBuilder sb, FileInfo info) {
|
||||||
sb.openTd().setStyleName(R.css().status());
|
sb.openTd().setStyleName(R.css().status());
|
||||||
if (!Patch.COMMIT_MSG.equals(info.path())
|
if (!Patch.isMagic(info.path())
|
||||||
&& info.status() != null
|
&& info.status() != null
|
||||||
&& !ChangeType.MODIFIED.matches(info.status())) {
|
&& !ChangeType.MODIFIED.matches(info.status())) {
|
||||||
sb.append(info.status());
|
sb.append(info.status());
|
||||||
@ -668,20 +681,43 @@ public class FileTable extends FlowPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void columnPath(SafeHtmlBuilder sb, FileInfo info) {
|
private void columnPath(SafeHtmlBuilder sb, FileInfo info) {
|
||||||
sb.openTd()
|
|
||||||
.setStyleName(R.css().pathColumn())
|
|
||||||
.openAnchor();
|
|
||||||
|
|
||||||
String path = info.path();
|
String path = info.path();
|
||||||
|
|
||||||
|
sb.openTd()
|
||||||
|
.setStyleName(R.css().pathColumn());
|
||||||
|
|
||||||
|
if (!canOpen(path)) {
|
||||||
|
sb.openDiv();
|
||||||
|
appendPath(path);
|
||||||
|
sb.closeDiv();
|
||||||
|
sb.closeTd();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.openAnchor();
|
||||||
|
|
||||||
if (mode == Mode.EDIT && !isEditable(info)) {
|
if (mode == Mode.EDIT && !isEditable(info)) {
|
||||||
sb.setAttribute("onclick", RESTORE + "(event," + info._row() + ")");
|
sb.setAttribute("onclick", RESTORE + "(event," + info._row() + ")");
|
||||||
} else {
|
} else {
|
||||||
sb.setAttribute("href", "#" + url(info))
|
sb.setAttribute("href", "#" + url(info))
|
||||||
.setAttribute("onclick", OPEN + "(event," + info._row() + ")");
|
.setAttribute("onclick", OPEN + "(event," + info._row() + ")");
|
||||||
}
|
}
|
||||||
|
appendPath(path);
|
||||||
|
sb.closeAnchor();
|
||||||
|
if (info.oldPath() != null) {
|
||||||
|
sb.br();
|
||||||
|
sb.openSpan().setStyleName(R.css().renameCopySource())
|
||||||
|
.append(info.oldPath())
|
||||||
|
.closeSpan();
|
||||||
|
}
|
||||||
|
sb.closeTd();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void appendPath(String path) {
|
||||||
if (Patch.COMMIT_MSG.equals(path)) {
|
if (Patch.COMMIT_MSG.equals(path)) {
|
||||||
sb.append(Util.C.commitMessage());
|
sb.append(Util.C.commitMessage());
|
||||||
|
} else if (Patch.MERGE_LIST.equals(path)) {
|
||||||
|
sb.append(Util.C.mergeList());
|
||||||
} else if (Gerrit.getUserPreferences().muteCommonPathPrefixes()) {
|
} else if (Gerrit.getUserPreferences().muteCommonPathPrefixes()) {
|
||||||
int commonPrefixLen = commonPrefix(path);
|
int commonPrefixLen = commonPrefix(path);
|
||||||
if (commonPrefixLen > 0) {
|
if (commonPrefixLen > 0) {
|
||||||
@ -694,15 +730,6 @@ public class FileTable extends FlowPanel {
|
|||||||
} else {
|
} else {
|
||||||
sb.append(path);
|
sb.append(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
sb.closeAnchor();
|
|
||||||
if (info.oldPath() != null) {
|
|
||||||
sb.br();
|
|
||||||
sb.openSpan().setStyleName(R.css().renameCopySource())
|
|
||||||
.append(info.oldPath())
|
|
||||||
.closeSpan();
|
|
||||||
}
|
|
||||||
sb.closeTd();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int commonPrefix(String path) {
|
private int commonPrefix(String path) {
|
||||||
@ -784,7 +811,7 @@ public class FileTable extends FlowPanel {
|
|||||||
|
|
||||||
private void columnDelta1(SafeHtmlBuilder sb, FileInfo info) {
|
private void columnDelta1(SafeHtmlBuilder sb, FileInfo info) {
|
||||||
sb.openTd().setStyleName(R.css().deltaColumn1());
|
sb.openTd().setStyleName(R.css().deltaColumn1());
|
||||||
if (!Patch.COMMIT_MSG.equals(info.path()) && !info.binary()) {
|
if (!Patch.isMagic(info.path()) && !info.binary()) {
|
||||||
if (showChangeSizeBars) {
|
if (showChangeSizeBars) {
|
||||||
sb.append(info.linesInserted() + info.linesDeleted());
|
sb.append(info.linesInserted() + info.linesDeleted());
|
||||||
} else if (!ChangeType.DELETED.matches(info.status())) {
|
} else if (!ChangeType.DELETED.matches(info.status())) {
|
||||||
@ -813,7 +840,7 @@ public class FileTable extends FlowPanel {
|
|||||||
private void columnDelta2(SafeHtmlBuilder sb, FileInfo info) {
|
private void columnDelta2(SafeHtmlBuilder sb, FileInfo info) {
|
||||||
sb.openTd().setStyleName(R.css().deltaColumn2());
|
sb.openTd().setStyleName(R.css().deltaColumn2());
|
||||||
if (showChangeSizeBars
|
if (showChangeSizeBars
|
||||||
&& !Patch.COMMIT_MSG.equals(info.path()) && !info.binary()
|
&& !Patch.isMagic(info.path()) && !info.binary()
|
||||||
&& (info.linesInserted() != 0 || info.linesDeleted() != 0)) {
|
&& (info.linesInserted() != 0 || info.linesDeleted() != 0)) {
|
||||||
int w = 80;
|
int w = 80;
|
||||||
int t = inserted + deleted;
|
int t = inserted + deleted;
|
||||||
|
@ -176,6 +176,10 @@ class Message extends Composite {
|
|||||||
if (l != null) {
|
if (l != null) {
|
||||||
comments.add(new FileComments(clp, ps, Util.C.commitMessage(), l));
|
comments.add(new FileComments(clp, ps, Util.C.commitMessage(), l));
|
||||||
}
|
}
|
||||||
|
l = m.remove(Patch.MERGE_LIST);
|
||||||
|
if (l != null) {
|
||||||
|
comments.add(new FileComments(clp, ps, Util.C.mergeList(), l));
|
||||||
|
}
|
||||||
for (Map.Entry<String, List<CommentInfo>> e : m.entrySet()) {
|
for (Map.Entry<String, List<CommentInfo>> e : m.entrySet()) {
|
||||||
comments.add(new FileComments(clp, ps, e.getKey(), e.getValue()));
|
comments.add(new FileComments(clp, ps, e.getKey(), e.getValue()));
|
||||||
}
|
}
|
||||||
|
@ -422,12 +422,17 @@ public class ReplyBox extends Composite {
|
|||||||
comments.add(new FileComments(clp, psId,
|
comments.add(new FileComments(clp, psId,
|
||||||
Util.C.commitMessage(), copyPath(Patch.COMMIT_MSG, l)));
|
Util.C.commitMessage(), copyPath(Patch.COMMIT_MSG, l)));
|
||||||
}
|
}
|
||||||
|
l = m.get(Patch.MERGE_LIST);
|
||||||
|
if (l != null) {
|
||||||
|
comments.add(new FileComments(clp, psId, Util.C.commitMessage(),
|
||||||
|
copyPath(Patch.MERGE_LIST, l)));
|
||||||
|
}
|
||||||
|
|
||||||
List<String> paths = new ArrayList<>(m.keySet());
|
List<String> paths = new ArrayList<>(m.keySet());
|
||||||
Collections.sort(paths);
|
Collections.sort(paths);
|
||||||
|
|
||||||
for (String path : paths) {
|
for (String path : paths) {
|
||||||
if (!path.equals(Patch.COMMIT_MSG)) {
|
if (!Patch.isMagic(path)) {
|
||||||
comments.add(new FileComments(clp, psId,
|
comments.add(new FileComments(clp, psId,
|
||||||
path, copyPath(path, m.get(path))));
|
path, copyPath(path, m.get(path))));
|
||||||
}
|
}
|
||||||
|
@ -63,6 +63,7 @@ public interface ChangeConstants extends Constants {
|
|||||||
String patchTableColumnComments();
|
String patchTableColumnComments();
|
||||||
String patchTableColumnSize();
|
String patchTableColumnSize();
|
||||||
String commitMessage();
|
String commitMessage();
|
||||||
|
String mergeList();
|
||||||
|
|
||||||
String patchTablePrev();
|
String patchTablePrev();
|
||||||
String patchTableNext();
|
String patchTableNext();
|
||||||
|
@ -45,6 +45,7 @@ patchTableColumnName = File Path
|
|||||||
patchTableColumnComments = Comments
|
patchTableColumnComments = Comments
|
||||||
patchTableColumnSize = Size
|
patchTableColumnSize = Size
|
||||||
commitMessage = Commit Message
|
commitMessage = Commit Message
|
||||||
|
mergeList = Merge List
|
||||||
|
|
||||||
patchTablePrev = Previous file
|
patchTablePrev = Previous file
|
||||||
patchTableNext = Next file
|
patchTableNext = Next file
|
||||||
|
@ -122,6 +122,8 @@ public class Header extends Composite {
|
|||||||
SafeHtmlBuilder b = new SafeHtmlBuilder();
|
SafeHtmlBuilder b = new SafeHtmlBuilder();
|
||||||
if (Patch.COMMIT_MSG.equals(path)) {
|
if (Patch.COMMIT_MSG.equals(path)) {
|
||||||
return b.append(Util.C.commitMessage());
|
return b.append(Util.C.commitMessage());
|
||||||
|
} else if (Patch.MERGE_LIST.equals(path)) {
|
||||||
|
return b.append(Util.C.mergeList());
|
||||||
}
|
}
|
||||||
|
|
||||||
int s = path.lastIndexOf('/') + 1;
|
int s = path.lastIndexOf('/') + 1;
|
||||||
|
@ -128,7 +128,7 @@ class PatchSetSelectBox extends Composite {
|
|||||||
if (meta == null) {
|
if (meta == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!Patch.COMMIT_MSG.equals(path)) {
|
if (!Patch.isMagic(path)) {
|
||||||
linkPanel.add(createDownloadLink());
|
linkPanel.add(createDownloadLink());
|
||||||
}
|
}
|
||||||
if (!binary && open && idActive != null && Gerrit.isSignedIn()) {
|
if (!binary && open && idActive != null && Gerrit.isSignedIn()) {
|
||||||
@ -147,7 +147,7 @@ class PatchSetSelectBox extends Composite {
|
|||||||
|
|
||||||
void setUpBlame(final CodeMirror cm, final boolean isBase,
|
void setUpBlame(final CodeMirror cm, final boolean isBase,
|
||||||
final PatchSet.Id rev, final String path) {
|
final PatchSet.Id rev, final String path) {
|
||||||
if (!Patch.COMMIT_MSG.equals(path) && Gerrit.isSignedIn()
|
if (!Patch.isMagic(path) && Gerrit.isSignedIn()
|
||||||
&& Gerrit.info().change().allowBlame()) {
|
&& Gerrit.info().change().allowBlame()) {
|
||||||
Anchor blameIcon = createBlameIcon();
|
Anchor blameIcon = createBlameIcon();
|
||||||
blameIcon.addClickHandler(new ClickHandler() {
|
blameIcon.addClickHandler(new ClickHandler() {
|
||||||
|
@ -22,6 +22,22 @@ public final class Patch {
|
|||||||
/** Magical file name which represents the commit message. */
|
/** Magical file name which represents the commit message. */
|
||||||
public static final String COMMIT_MSG = "/COMMIT_MSG";
|
public static final String COMMIT_MSG = "/COMMIT_MSG";
|
||||||
|
|
||||||
|
/** Magical file name which represents the merge list of a merge commit. */
|
||||||
|
public static final String MERGE_LIST = "/MERGE_LIST";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given path represents a magic file. A magic file is a
|
||||||
|
* generated file that is automatically included into changes. It does not
|
||||||
|
* exist in the commit of the patch set.
|
||||||
|
*
|
||||||
|
* @param path the file path
|
||||||
|
* @return {@code true} if the path represents a magic file, otherwise
|
||||||
|
* {@code false}.
|
||||||
|
*/
|
||||||
|
public static boolean isMagic(String path) {
|
||||||
|
return COMMIT_MSG.equals(path) || MERGE_LIST.equals(path);
|
||||||
|
}
|
||||||
|
|
||||||
public static class Key extends StringKey<PatchSet.Id> {
|
public static class Key extends StringKey<PatchSet.Id> {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
|
|
||||||
package com.google.gerrit.server;
|
package com.google.gerrit.server;
|
||||||
|
|
||||||
|
import static java.util.stream.Collectors.toList;
|
||||||
|
|
||||||
import static com.google.common.base.MoreObjects.firstNonNull;
|
import static com.google.common.base.MoreObjects.firstNonNull;
|
||||||
import static com.google.common.base.Preconditions.checkArgument;
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
import static java.util.stream.Collectors.toList;
|
import static java.util.stream.Collectors.toList;
|
||||||
@ -27,6 +29,7 @@ import com.google.gerrit.extensions.client.Side;
|
|||||||
import com.google.gerrit.extensions.common.CommentInfo;
|
import com.google.gerrit.extensions.common.CommentInfo;
|
||||||
import com.google.gerrit.reviewdb.client.Account;
|
import com.google.gerrit.reviewdb.client.Account;
|
||||||
import com.google.gerrit.reviewdb.client.Change;
|
import com.google.gerrit.reviewdb.client.Change;
|
||||||
|
import com.google.gerrit.reviewdb.client.Patch;
|
||||||
import com.google.gerrit.reviewdb.client.PatchLineComment;
|
import com.google.gerrit.reviewdb.client.PatchLineComment;
|
||||||
import com.google.gerrit.reviewdb.client.PatchLineComment.Status;
|
import com.google.gerrit.reviewdb.client.PatchLineComment.Status;
|
||||||
import com.google.gerrit.reviewdb.client.PatchSet;
|
import com.google.gerrit.reviewdb.client.PatchSet;
|
||||||
@ -210,10 +213,27 @@ public class PatchLineCommentsUtil {
|
|||||||
public List<PatchLineComment> publishedByPatchSet(ReviewDb db,
|
public List<PatchLineComment> publishedByPatchSet(ReviewDb db,
|
||||||
ChangeNotes notes, PatchSet.Id psId) throws OrmException {
|
ChangeNotes notes, PatchSet.Id psId) throws OrmException {
|
||||||
if (!migration.readChanges()) {
|
if (!migration.readChanges()) {
|
||||||
return sort(
|
return removeCommentsOnAncestorOfCommitMessage(sort(
|
||||||
db.patchComments().publishedByPatchSet(psId).toList());
|
db.patchComments().publishedByPatchSet(psId).toList()));
|
||||||
}
|
}
|
||||||
return commentsOnPatchSet(notes.load().getComments().values(), psId);
|
return removeCommentsOnAncestorOfCommitMessage(
|
||||||
|
commentsOnPatchSet(notes.load().getComments().values(), psId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For the commit message the A side in a diff view is always empty when a
|
||||||
|
* comparison against an ancestor is done, so there can't be any comments on
|
||||||
|
* this ancestor. However earlier we showed the auto-merge commit message on
|
||||||
|
* side A when for a merge commit a comparison against the auto-merge was
|
||||||
|
* done. From that time there may still be comments on the auto-merge commit
|
||||||
|
* message and those we want to filter out.
|
||||||
|
*/
|
||||||
|
private List<PatchLineComment> removeCommentsOnAncestorOfCommitMessage(
|
||||||
|
List<PatchLineComment> list) {
|
||||||
|
return list.stream()
|
||||||
|
.filter(c -> c.getSide() != 0
|
||||||
|
|| !Patch.COMMIT_MSG.equals(c.getKey().getParentKey().get()))
|
||||||
|
.collect(toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<PatchLineComment> draftByPatchSetAuthor(ReviewDb db,
|
public List<PatchLineComment> draftByPatchSetAuthor(ReviewDb db,
|
||||||
|
@ -1056,6 +1056,7 @@ public class ChangeJson {
|
|||||||
if (has(ALL_FILES) || (out.isCurrent && has(CURRENT_FILES))) {
|
if (has(ALL_FILES) || (out.isCurrent && has(CURRENT_FILES))) {
|
||||||
out.files = fileInfoJson.toFileInfoMap(c, in);
|
out.files = fileInfoJson.toFileInfoMap(c, in);
|
||||||
out.files.remove(Patch.COMMIT_MSG);
|
out.files.remove(Patch.COMMIT_MSG);
|
||||||
|
out.files.remove(Patch.MERGE_LIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((out.isCurrent || (out.draft != null && out.draft))
|
if ((out.isCurrent || (out.draft != null && out.draft))
|
||||||
|
@ -54,6 +54,7 @@ import java.util.zip.ZipOutputStream;
|
|||||||
@Singleton
|
@Singleton
|
||||||
public class FileContentUtil {
|
public class FileContentUtil {
|
||||||
public static final String TEXT_X_GERRIT_COMMIT_MESSAGE = "text/x-gerrit-commit-message";
|
public static final String TEXT_X_GERRIT_COMMIT_MESSAGE = "text/x-gerrit-commit-message";
|
||||||
|
public static final String TEXT_X_GERRIT_MERGE_LIST = "text/x-gerrit-merge-list";
|
||||||
private static final String X_GIT_SYMLINK = "x-git/symlink";
|
private static final String X_GIT_SYMLINK = "x-git/symlink";
|
||||||
private static final String X_GIT_GITLINK = "x-git/gitlink";
|
private static final String X_GIT_GITLINK = "x-git/gitlink";
|
||||||
private static final int MAX_SIZE = 5 << 20;
|
private static final int MAX_SIZE = 5 << 20;
|
||||||
@ -264,6 +265,9 @@ public class FileContentUtil {
|
|||||||
if (Patch.COMMIT_MSG.equals(path)) {
|
if (Patch.COMMIT_MSG.equals(path)) {
|
||||||
return TEXT_X_GERRIT_COMMIT_MESSAGE;
|
return TEXT_X_GERRIT_COMMIT_MESSAGE;
|
||||||
}
|
}
|
||||||
|
if (Patch.MERGE_LIST.equals(path)) {
|
||||||
|
return TEXT_X_GERRIT_MERGE_LIST;
|
||||||
|
}
|
||||||
if (project != null) {
|
if (project != null) {
|
||||||
for (ProjectState p : project.tree()) {
|
for (ProjectState p : project.tree()) {
|
||||||
String t = p.getConfig().getMimeTypes().getMimeType(path);
|
String t = p.getConfig().getMimeTypes().getMimeType(path);
|
||||||
|
@ -24,6 +24,8 @@ import com.google.gerrit.reviewdb.server.ReviewDb;
|
|||||||
import com.google.gerrit.server.PatchSetUtil;
|
import com.google.gerrit.server.PatchSetUtil;
|
||||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||||
import com.google.gerrit.server.notedb.ChangeNotes;
|
import com.google.gerrit.server.notedb.ChangeNotes;
|
||||||
|
import com.google.gerrit.server.patch.ComparisonType;
|
||||||
|
import com.google.gerrit.server.patch.Text;
|
||||||
import com.google.gerrit.server.project.NoSuchChangeException;
|
import com.google.gerrit.server.project.NoSuchChangeException;
|
||||||
import com.google.gwtorm.server.OrmException;
|
import com.google.gwtorm.server.OrmException;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
@ -68,6 +70,12 @@ public class GetContent implements RestReadView<FileResource> {
|
|||||||
return BinaryResult.create(msg)
|
return BinaryResult.create(msg)
|
||||||
.setContentType(FileContentUtil.TEXT_X_GERRIT_COMMIT_MESSAGE)
|
.setContentType(FileContentUtil.TEXT_X_GERRIT_COMMIT_MESSAGE)
|
||||||
.base64();
|
.base64();
|
||||||
|
} else if (Patch.MERGE_LIST.equals(path)) {
|
||||||
|
byte[] mergeList = getMergeList(
|
||||||
|
rsrc.getRevision().getChangeResource().getNotes());
|
||||||
|
return BinaryResult.create(mergeList)
|
||||||
|
.setContentType(FileContentUtil.TEXT_X_GERRIT_MERGE_LIST)
|
||||||
|
.base64();
|
||||||
}
|
}
|
||||||
return fileContentUtil.getContent(
|
return fileContentUtil.getContent(
|
||||||
rsrc.getRevision().getControl().getProjectControl().getProjectState(),
|
rsrc.getRevision().getControl().getProjectControl().getProjectState(),
|
||||||
@ -92,4 +100,22 @@ public class GetContent implements RestReadView<FileResource> {
|
|||||||
throw new NoSuchChangeException(changeId, e);
|
throw new NoSuchChangeException(changeId, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private byte[] getMergeList(ChangeNotes notes)
|
||||||
|
throws NoSuchChangeException, OrmException, IOException {
|
||||||
|
Change.Id changeId = notes.getChangeId();
|
||||||
|
PatchSet ps = psUtil.current(db.get(), notes);
|
||||||
|
if (ps == null) {
|
||||||
|
throw new NoSuchChangeException(changeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
try (Repository git = gitManager.openRepository(notes.getProjectName());
|
||||||
|
RevWalk revWalk = new RevWalk(git)) {
|
||||||
|
return Text.forMergeList(ComparisonType.againstAutoMerge(),
|
||||||
|
revWalk.getObjectReader(),
|
||||||
|
ObjectId.fromString(ps.getRevision().get())).getContent();
|
||||||
|
} catch (RepositoryNotFoundException e) {
|
||||||
|
throw new NoSuchChangeException(changeId, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ import com.google.gerrit.extensions.restapi.Response;
|
|||||||
import com.google.gerrit.extensions.restapi.RestReadView;
|
import com.google.gerrit.extensions.restapi.RestReadView;
|
||||||
import com.google.gerrit.reviewdb.client.Project;
|
import com.google.gerrit.reviewdb.client.Project;
|
||||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||||
|
import com.google.gerrit.server.patch.MergeListBuilder;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
import org.eclipse.jgit.lib.ObjectId;
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
@ -46,7 +47,8 @@ public class GetMergeList implements RestReadView<RevisionResource> {
|
|||||||
private boolean addLinks;
|
private boolean addLinks;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
GetMergeList(GitRepositoryManager repoManager, ChangeJson.Factory json) {
|
GetMergeList(GitRepositoryManager repoManager,
|
||||||
|
ChangeJson.Factory json) {
|
||||||
this.repoManager = repoManager;
|
this.repoManager = repoManager;
|
||||||
this.json = json;
|
this.json = json;
|
||||||
}
|
}
|
||||||
@ -62,7 +64,6 @@ public class GetMergeList implements RestReadView<RevisionResource> {
|
|||||||
@Override
|
@Override
|
||||||
public Response<List<CommitInfo>> apply(RevisionResource rsrc)
|
public Response<List<CommitInfo>> apply(RevisionResource rsrc)
|
||||||
throws BadRequestException, IOException {
|
throws BadRequestException, IOException {
|
||||||
List<CommitInfo> result = new ArrayList<>();
|
|
||||||
Project.NameKey p = rsrc.getChange().getProject();
|
Project.NameKey p = rsrc.getChange().getProject();
|
||||||
try (Repository repo = repoManager.openRepository(p);
|
try (Repository repo = repoManager.openRepository(p);
|
||||||
RevWalk rw = new RevWalk(repo)) {
|
RevWalk rw = new RevWalk(repo)) {
|
||||||
@ -76,26 +77,22 @@ public class GetMergeList implements RestReadView<RevisionResource> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (commit.getParentCount() < 2) {
|
if (commit.getParentCount() < 2) {
|
||||||
return Response.<List<CommitInfo>> ok(ImmutableList.<CommitInfo> of());
|
return createResponse(rsrc, ImmutableList.<CommitInfo> of());
|
||||||
}
|
|
||||||
|
|
||||||
for (int parent = 0; parent < commit.getParentCount(); parent++) {
|
|
||||||
if (parent == uninterestingParent - 1) {
|
|
||||||
rw.markUninteresting(commit.getParent(parent));
|
|
||||||
} else {
|
|
||||||
rw.markStart(commit.getParent(parent));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<RevCommit> commits =
|
||||||
|
MergeListBuilder.build(rw, commit, uninterestingParent);
|
||||||
|
List<CommitInfo> result = new ArrayList<>(commits.size());
|
||||||
ChangeJson changeJson = json.create(ChangeJson.NO_OPTIONS);
|
ChangeJson changeJson = json.create(ChangeJson.NO_OPTIONS);
|
||||||
RevCommit c;
|
for (RevCommit c : commits) {
|
||||||
while ((c = rw.next()) != null) {
|
result.add(changeJson.toCommit(rsrc.getControl(), rw, c, addLinks, true));
|
||||||
CommitInfo info =
|
|
||||||
changeJson.toCommit(rsrc.getControl(), rw, c, addLinks, true);
|
|
||||||
result.add(info);
|
|
||||||
}
|
}
|
||||||
|
return createResponse(rsrc, result);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Response<List<CommitInfo>> createResponse(
|
||||||
|
RevisionResource rsrc, List<CommitInfo> result) {
|
||||||
Response<List<CommitInfo>> r = Response.ok(result);
|
Response<List<CommitInfo>> r = Response.ok(result);
|
||||||
if (rsrc.isCacheable()) {
|
if (rsrc.isCacheable()) {
|
||||||
r.caching(CacheControl.PRIVATE(7, TimeUnit.DAYS));
|
r.caching(CacheControl.PRIVATE(7, TimeUnit.DAYS));
|
||||||
|
@ -324,11 +324,19 @@ public class PostReview implements RestModifyView<RevisionResource, ReviewInput>
|
|||||||
while (mapItr.hasNext()) {
|
while (mapItr.hasNext()) {
|
||||||
Map.Entry<String, List<CommentInput>> ent = mapItr.next();
|
Map.Entry<String, List<CommentInput>> ent = mapItr.next();
|
||||||
String path = ent.getKey();
|
String path = ent.getKey();
|
||||||
if (!filePaths.contains(path) && !Patch.COMMIT_MSG.equals(path)) {
|
if (!filePaths.contains(path) && !Patch.isMagic(path)) {
|
||||||
throw new BadRequestException(String.format(
|
throw new BadRequestException(String.format(
|
||||||
"file %s not found in revision %s",
|
"file %s not found in revision %s",
|
||||||
path, revision.getChange().currentPatchSetId()));
|
path, revision.getChange().currentPatchSetId()));
|
||||||
}
|
}
|
||||||
|
if (Patch.isMagic(path)) {
|
||||||
|
for (CommentInput comment : ent.getValue()) {
|
||||||
|
if (comment.side == Side.PARENT && comment.parent == null) {
|
||||||
|
throw new BadRequestException(
|
||||||
|
String.format("cannot comment on %s on auto-merge", path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
List<CommentInput> list = ent.getValue();
|
List<CommentInput> list = ent.getValue();
|
||||||
if (list == null) {
|
if (list == null) {
|
||||||
|
@ -496,7 +496,7 @@ public class EventFactory {
|
|||||||
List<Patch> list =
|
List<Patch> list =
|
||||||
patchListCache.get(change, patchSet).toPatchList(pId);
|
patchListCache.get(change, patchSet).toPatchList(pId);
|
||||||
for (Patch pe : list) {
|
for (Patch pe : list) {
|
||||||
if (!Patch.COMMIT_MSG.equals(pe.getFileName())) {
|
if (!Patch.isMagic(pe.getFileName())) {
|
||||||
p.sizeDeletions -= pe.getDeletions();
|
p.sizeDeletions -= pe.getDeletions();
|
||||||
p.sizeInsertions += pe.getInsertions();
|
p.sizeInsertions += pe.getInsertions();
|
||||||
}
|
}
|
||||||
|
@ -259,7 +259,7 @@ public abstract class ChangeEmail extends NotificationEmail {
|
|||||||
detail.append("---\n");
|
detail.append("---\n");
|
||||||
PatchList patchList = getPatchList();
|
PatchList patchList = getPatchList();
|
||||||
for (PatchListEntry p : patchList.getPatches()) {
|
for (PatchListEntry p : patchList.getPatches()) {
|
||||||
if (Patch.COMMIT_MSG.equals(p.getNewName())) {
|
if (Patch.isMagic(p.getNewName())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
detail.append(p.getChangeType().getCode())
|
detail.append(p.getChangeType().getCode())
|
||||||
|
@ -75,7 +75,7 @@ public class CommentSender extends ReplyToChangeSender {
|
|||||||
Set<String> paths = new HashSet<>();
|
Set<String> paths = new HashSet<>();
|
||||||
for (PatchLineComment c : plc) {
|
for (PatchLineComment c : plc) {
|
||||||
Patch.Key p = c.getKey().getParentKey();
|
Patch.Key p = c.getKey().getParentKey();
|
||||||
if (!Patch.COMMIT_MSG.equals(p.getFileName())) {
|
if (!Patch.isMagic(p.getFileName())) {
|
||||||
paths.add(p.getFileName());
|
paths.add(p.getFileName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -137,6 +137,8 @@ public class CommentSender extends ReplyToChangeSender {
|
|||||||
}
|
}
|
||||||
if (Patch.COMMIT_MSG.equals(pk.get())) {
|
if (Patch.COMMIT_MSG.equals(pk.get())) {
|
||||||
cmts.append("Commit Message:\n\n");
|
cmts.append("Commit Message:\n\n");
|
||||||
|
} else if (Patch.MERGE_LIST.equals(pk.get())) {
|
||||||
|
cmts.append("Merge List:\n\n");
|
||||||
} else {
|
} else {
|
||||||
cmts.append("File ").append(pk.get()).append(":\n\n");
|
cmts.append("File ").append(pk.get()).append(":\n\n");
|
||||||
}
|
}
|
||||||
@ -144,8 +146,7 @@ public class CommentSender extends ReplyToChangeSender {
|
|||||||
|
|
||||||
if (patchList != null) {
|
if (patchList != null) {
|
||||||
try {
|
try {
|
||||||
currentFileData =
|
currentFileData = new PatchFile(repo, patchList, pk.get());
|
||||||
new PatchFile(repo, patchList, pk.get());
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.warn(String.format(
|
log.warn(String.format(
|
||||||
"Cannot load %s from %s in %s",
|
"Cannot load %s from %s in %s",
|
||||||
|
@ -0,0 +1,77 @@
|
|||||||
|
// 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.patch;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
import static com.google.gerrit.server.ioutil.BasicSerialization.readVarInt32;
|
||||||
|
import static com.google.gerrit.server.ioutil.BasicSerialization.writeVarInt32;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
public class ComparisonType {
|
||||||
|
|
||||||
|
/** 1-based parent */
|
||||||
|
private final Integer parentNum;
|
||||||
|
|
||||||
|
private final boolean autoMerge;
|
||||||
|
|
||||||
|
public static ComparisonType againstOtherPatchSet() {
|
||||||
|
return new ComparisonType(null, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ComparisonType againstParent(int parentNum) {
|
||||||
|
return new ComparisonType(parentNum, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ComparisonType againstAutoMerge() {
|
||||||
|
return new ComparisonType(null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ComparisonType(Integer parentNum, boolean autoMerge) {
|
||||||
|
this.parentNum = parentNum;
|
||||||
|
this.autoMerge = autoMerge;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAgainstParentOrAutoMerge() {
|
||||||
|
return isAgainstParent() || isAgainstAutoMerge();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAgainstParent() {
|
||||||
|
return parentNum != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAgainstAutoMerge() {
|
||||||
|
return autoMerge;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getParentNum() {
|
||||||
|
checkNotNull(parentNum);
|
||||||
|
return parentNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeTo(OutputStream out) throws IOException {
|
||||||
|
writeVarInt32(out, parentNum != null ? parentNum : 0);
|
||||||
|
writeVarInt32(out, autoMerge ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ComparisonType readFrom(InputStream in) throws IOException {
|
||||||
|
int p = readVarInt32(in);
|
||||||
|
Integer parentNum = p > 0 ? p : null;
|
||||||
|
boolean autoMerge = readVarInt32(in) != 0;
|
||||||
|
return new ComparisonType(parentNum, autoMerge);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
// 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.patch;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
|
||||||
|
import org.eclipse.jgit.revwalk.RevCommit;
|
||||||
|
import org.eclipse.jgit.revwalk.RevWalk;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class MergeListBuilder {
|
||||||
|
public static List<RevCommit> build(RevWalk rw, RevCommit merge,
|
||||||
|
int uninterestingParent) throws IOException {
|
||||||
|
rw.reset();
|
||||||
|
rw.parseBody(merge);
|
||||||
|
if (merge.getParentCount() < 2) {
|
||||||
|
return ImmutableList.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int parent = 0; parent < merge.getParentCount(); parent++) {
|
||||||
|
RevCommit parentCommit = merge.getParent(parent);
|
||||||
|
rw.parseBody(parentCommit);
|
||||||
|
if (parent == uninterestingParent - 1) {
|
||||||
|
rw.markUninteresting(parentCommit);
|
||||||
|
} else {
|
||||||
|
rw.markStart(parentCommit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<RevCommit> result = new ArrayList<>();
|
||||||
|
RevCommit c;
|
||||||
|
while ((c = rw.next()) != null) {
|
||||||
|
result.add(c);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@ -44,9 +44,8 @@ public class PatchFile {
|
|||||||
private Text a;
|
private Text a;
|
||||||
private Text b;
|
private Text b;
|
||||||
|
|
||||||
public PatchFile(final Repository repo, final PatchList patchList,
|
public PatchFile(Repository repo, PatchList patchList, String fileName)
|
||||||
final String fileName) throws MissingObjectException,
|
throws MissingObjectException, IncorrectObjectTypeException, IOException {
|
||||||
IncorrectObjectTypeException, IOException {
|
|
||||||
this.repo = repo;
|
this.repo = repo;
|
||||||
this.entry = patchList.get(fileName);
|
this.entry = patchList.get(fileName);
|
||||||
|
|
||||||
@ -55,7 +54,7 @@ public class PatchFile {
|
|||||||
final RevCommit bCommit = rw.parseCommit(patchList.getNewId());
|
final RevCommit bCommit = rw.parseCommit(patchList.getNewId());
|
||||||
|
|
||||||
if (Patch.COMMIT_MSG.equals(fileName)) {
|
if (Patch.COMMIT_MSG.equals(fileName)) {
|
||||||
if (patchList.isAgainstParent()) {
|
if (patchList.getComparisonType().isAgainstParentOrAutoMerge()) {
|
||||||
a = Text.EMPTY;
|
a = Text.EMPTY;
|
||||||
} else {
|
} else {
|
||||||
// For the initial commit, we have an empty tree on Side A
|
// For the initial commit, we have an empty tree on Side A
|
||||||
@ -68,7 +67,16 @@ public class PatchFile {
|
|||||||
|
|
||||||
aTree = null;
|
aTree = null;
|
||||||
bTree = null;
|
bTree = null;
|
||||||
|
} else if (Patch.MERGE_LIST.equals(fileName)) {
|
||||||
|
// For the initial commit, we have an empty tree on Side A
|
||||||
|
RevObject object = rw.parseAny(patchList.getOldId());
|
||||||
|
a = object instanceof RevCommit
|
||||||
|
? Text.forMergeList(patchList.getComparisonType(), reader, object)
|
||||||
|
: Text.EMPTY;
|
||||||
|
b = Text.forMergeList(patchList.getComparisonType(), reader, bCommit);
|
||||||
|
|
||||||
|
aTree = null;
|
||||||
|
bTree = null;
|
||||||
} else {
|
} else {
|
||||||
if (patchList.getOldId() != null) {
|
if (patchList.getOldId() != null) {
|
||||||
aTree = rw.parseTree(patchList.getOldId());
|
aTree = rw.parseTree(patchList.getOldId());
|
||||||
|
@ -58,16 +58,19 @@ public class PatchList implements Serializable {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private transient ObjectId oldId;
|
private transient ObjectId oldId;
|
||||||
private transient ObjectId newId;
|
private transient ObjectId newId;
|
||||||
private transient boolean againstParent;
|
private transient boolean isMerge;
|
||||||
|
private transient ComparisonType comparisonType;
|
||||||
private transient int insertions;
|
private transient int insertions;
|
||||||
private transient int deletions;
|
private transient int deletions;
|
||||||
private transient PatchListEntry[] patches;
|
private transient PatchListEntry[] patches;
|
||||||
|
|
||||||
public PatchList(@Nullable final AnyObjectId oldId, final AnyObjectId newId,
|
public PatchList(@Nullable AnyObjectId oldId, AnyObjectId newId,
|
||||||
final boolean againstParent, final PatchListEntry[] patches) {
|
boolean isMerge, ComparisonType comparisonType,
|
||||||
|
PatchListEntry[] patches) {
|
||||||
this.oldId = oldId != null ? oldId.copy() : null;
|
this.oldId = oldId != null ? oldId.copy() : null;
|
||||||
this.newId = newId.copy();
|
this.newId = newId.copy();
|
||||||
this.againstParent = againstParent;
|
this.isMerge = isMerge;
|
||||||
|
this.comparisonType = comparisonType;
|
||||||
|
|
||||||
// We assume index 0 contains the magic commit message entry.
|
// We assume index 0 contains the magic commit message entry.
|
||||||
if (patches.length > 1) {
|
if (patches.length > 1) {
|
||||||
@ -97,9 +100,9 @@ public class PatchList implements Serializable {
|
|||||||
return Collections.unmodifiableList(Arrays.asList(patches));
|
return Collections.unmodifiableList(Arrays.asList(patches));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return true if {@link #getOldId} is {@link #getNewId}'s ancestor. */
|
/** @return the comparison type */
|
||||||
public boolean isAgainstParent() {
|
public ComparisonType getComparisonType() {
|
||||||
return againstParent;
|
return comparisonType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return total number of new lines added. */
|
/** @return total number of new lines added. */
|
||||||
@ -144,9 +147,12 @@ public class PatchList implements Serializable {
|
|||||||
if (Patch.COMMIT_MSG.equals(fileName)) {
|
if (Patch.COMMIT_MSG.equals(fileName)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (isMerge && Patch.MERGE_LIST.equals(fileName)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int high = patches.length;
|
int high = patches.length;
|
||||||
int low = 1;
|
int low = isMerge ? 2 : 1;
|
||||||
while (low < high) {
|
while (low < high) {
|
||||||
final int mid = (low + high) >>> 1;
|
final int mid = (low + high) >>> 1;
|
||||||
final int cmp = patches[mid].getNewName().compareTo(fileName);
|
final int cmp = patches[mid].getNewName().compareTo(fileName);
|
||||||
@ -166,7 +172,8 @@ public class PatchList implements Serializable {
|
|||||||
try (DeflaterOutputStream out = new DeflaterOutputStream(buf)) {
|
try (DeflaterOutputStream out = new DeflaterOutputStream(buf)) {
|
||||||
writeCanBeNull(out, oldId);
|
writeCanBeNull(out, oldId);
|
||||||
writeNotNull(out, newId);
|
writeNotNull(out, newId);
|
||||||
writeVarInt32(out, againstParent ? 1 : 0);
|
writeVarInt32(out, isMerge ? 1 : 0);
|
||||||
|
comparisonType.writeTo(out);
|
||||||
writeVarInt32(out, insertions);
|
writeVarInt32(out, insertions);
|
||||||
writeVarInt32(out, deletions);
|
writeVarInt32(out, deletions);
|
||||||
writeVarInt32(out, patches.length);
|
writeVarInt32(out, patches.length);
|
||||||
@ -182,7 +189,8 @@ public class PatchList implements Serializable {
|
|||||||
try (InflaterInputStream in = new InflaterInputStream(buf)) {
|
try (InflaterInputStream in = new InflaterInputStream(buf)) {
|
||||||
oldId = readCanBeNull(in);
|
oldId = readCanBeNull(in);
|
||||||
newId = readNotNull(in);
|
newId = readNotNull(in);
|
||||||
againstParent = readVarInt32(in) != 0;
|
isMerge = readVarInt32(in) != 0;
|
||||||
|
comparisonType = ComparisonType.readFrom(in);
|
||||||
insertions = readVarInt32(in);
|
insertions = readVarInt32(in);
|
||||||
deletions = readVarInt32(in);
|
deletions = readVarInt32(in);
|
||||||
final int cnt = readVarInt32(in);
|
final int cnt = readVarInt32(in);
|
||||||
|
@ -35,7 +35,7 @@ import java.io.Serializable;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public class PatchListKey implements Serializable {
|
public class PatchListKey implements Serializable {
|
||||||
public static final long serialVersionUID = 22L;
|
public static final long serialVersionUID = 24L;
|
||||||
|
|
||||||
public static final BiMap<Whitespace, Character> WHITESPACE_TYPES = ImmutableBiMap.of(
|
public static final BiMap<Whitespace, Character> WHITESPACE_TYPES = ImmutableBiMap.of(
|
||||||
Whitespace.IGNORE_NONE, 'N',
|
Whitespace.IGNORE_NONE, 'N',
|
||||||
@ -138,6 +138,10 @@ public class PatchListKey implements Serializable {
|
|||||||
n.append("..");
|
n.append("..");
|
||||||
n.append(newId.name());
|
n.append(newId.name());
|
||||||
n.append(" ");
|
n.append(" ");
|
||||||
|
if (parentNum != null) {
|
||||||
|
n.append(parentNum);
|
||||||
|
n.append(" ");
|
||||||
|
}
|
||||||
n.append(whitespace.name());
|
n.append(whitespace.name());
|
||||||
n.append("]");
|
n.append("]");
|
||||||
return n.toString();
|
return n.toString();
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
package com.google.gerrit.server.patch;
|
package com.google.gerrit.server.patch;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkArgument;
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
|
|
||||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||||
import static java.util.stream.Collectors.toSet;
|
import static java.util.stream.Collectors.toSet;
|
||||||
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
|
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
|
||||||
@ -156,14 +155,19 @@ public class PatchListLoader implements Callable<PatchList> {
|
|||||||
|
|
||||||
if (a == null) {
|
if (a == null) {
|
||||||
// TODO(sop) Remove this case.
|
// TODO(sop) Remove this case.
|
||||||
// This is a merge commit, compared to its ancestor.
|
// This is an octopus merge commit which should be compared against the
|
||||||
|
// auto-merge. However since we don't support computing the auto-merge
|
||||||
|
// for octopus merge commits, we fall back to diffing against the first
|
||||||
|
// parent, even though this wasn't what was requested.
|
||||||
//
|
//
|
||||||
PatchListEntry[] entries = new PatchListEntry[1];
|
ComparisonType comparisonType = ComparisonType.againstParent(1);
|
||||||
|
PatchListEntry[] entries = new PatchListEntry[2];
|
||||||
entries[0] = newCommitMessage(cmp, reader, null, b);
|
entries[0] = newCommitMessage(cmp, reader, null, b);
|
||||||
return new PatchList(a, b, true, entries);
|
entries[1] = newMergeList(cmp, reader, null, b, comparisonType);
|
||||||
|
return new PatchList(a, b, true, comparisonType, entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean againstParent = isAgainstParent(a, b);
|
ComparisonType comparisonType = getComparisonType(a, b);
|
||||||
|
|
||||||
RevCommit aCommit = a instanceof RevCommit ? (RevCommit) a : null;
|
RevCommit aCommit = a instanceof RevCommit ? (RevCommit) a : null;
|
||||||
RevTree aTree = rw.parseTree(a);
|
RevTree aTree = rw.parseTree(a);
|
||||||
@ -190,7 +194,13 @@ public class PatchListLoader implements Callable<PatchList> {
|
|||||||
int cnt = diffEntries.size();
|
int cnt = diffEntries.size();
|
||||||
List<PatchListEntry> entries = new ArrayList<>();
|
List<PatchListEntry> entries = new ArrayList<>();
|
||||||
entries.add(newCommitMessage(cmp, reader,
|
entries.add(newCommitMessage(cmp, reader,
|
||||||
againstParent ? null : aCommit, b));
|
comparisonType.isAgainstParentOrAutoMerge() ? null : aCommit, b));
|
||||||
|
boolean isMerge = b.getParentCount() > 1;
|
||||||
|
if (isMerge) {
|
||||||
|
entries.add(newMergeList(cmp, reader,
|
||||||
|
comparisonType.isAgainstParentOrAutoMerge() ? null : aCommit, b,
|
||||||
|
comparisonType));
|
||||||
|
}
|
||||||
for (int i = 0; i < cnt; i++) {
|
for (int i = 0; i < cnt; i++) {
|
||||||
DiffEntry e = diffEntries.get(i);
|
DiffEntry e = diffEntries.get(i);
|
||||||
if (paths == null || paths.contains(e.getNewPath())
|
if (paths == null || paths.contains(e.getNewPath())
|
||||||
@ -204,19 +214,23 @@ public class PatchListLoader implements Callable<PatchList> {
|
|||||||
entries.add(newEntry(aTree, fh, newSize, newSize - oldSize));
|
entries.add(newEntry(aTree, fh, newSize, newSize - oldSize));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new PatchList(a, b, againstParent,
|
return new PatchList(a, b, isMerge, comparisonType,
|
||||||
entries.toArray(new PatchListEntry[entries.size()]));
|
entries.toArray(new PatchListEntry[entries.size()]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isAgainstParent(RevObject a, RevCommit b) {
|
private ComparisonType getComparisonType(RevObject a, RevCommit b) {
|
||||||
for (int i = 0; i < b.getParentCount(); i++) {
|
for (int i = 0; i < b.getParentCount(); i++) {
|
||||||
if (b.getParent(i).equals(a)) {
|
if (b.getParent(i).equals(a)) {
|
||||||
return true;
|
return ComparisonType.againstParent(i + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
if (key.getOldId() == null && b.getParentCount() > 0) {
|
||||||
|
return ComparisonType.againstAutoMerge();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ComparisonType.againstOtherPatchSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long getFileSize(ObjectReader reader,
|
private static long getFileSize(ObjectReader reader,
|
||||||
@ -278,32 +292,30 @@ public class PatchListLoader implements Callable<PatchList> {
|
|||||||
return diffFormatter.toFileHeader(diffEntry);
|
return diffFormatter.toFileHeader(diffEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
private PatchListEntry newCommitMessage(final RawTextComparator cmp,
|
private PatchListEntry newCommitMessage(RawTextComparator cmp,
|
||||||
final ObjectReader reader,
|
ObjectReader reader, RevCommit aCommit, RevCommit bCommit)
|
||||||
final RevCommit aCommit, final RevCommit bCommit) throws IOException {
|
throws IOException {
|
||||||
StringBuilder hdr = new StringBuilder();
|
Text aText = aCommit != null
|
||||||
|
? Text.forCommit(reader, aCommit)
|
||||||
hdr.append("diff --git");
|
: Text.EMPTY;
|
||||||
if (aCommit != null) {
|
|
||||||
hdr.append(" a/").append(Patch.COMMIT_MSG);
|
|
||||||
} else {
|
|
||||||
hdr.append(" ").append(FileHeader.DEV_NULL);
|
|
||||||
}
|
|
||||||
hdr.append(" b/").append(Patch.COMMIT_MSG);
|
|
||||||
hdr.append("\n");
|
|
||||||
|
|
||||||
if (aCommit != null) {
|
|
||||||
hdr.append("--- a/").append(Patch.COMMIT_MSG).append("\n");
|
|
||||||
} else {
|
|
||||||
hdr.append("--- ").append(FileHeader.DEV_NULL).append("\n");
|
|
||||||
}
|
|
||||||
hdr.append("+++ b/").append(Patch.COMMIT_MSG).append("\n");
|
|
||||||
|
|
||||||
Text aText =
|
|
||||||
aCommit != null ? Text.forCommit(reader, aCommit) : Text.EMPTY;
|
|
||||||
Text bText = Text.forCommit(reader, bCommit);
|
Text bText = Text.forCommit(reader, bCommit);
|
||||||
|
return createPatchListEntry(cmp, aCommit, aText, bText, Patch.COMMIT_MSG);
|
||||||
|
}
|
||||||
|
|
||||||
byte[] rawHdr = hdr.toString().getBytes(UTF_8);
|
private PatchListEntry newMergeList(RawTextComparator cmp,
|
||||||
|
ObjectReader reader, RevCommit aCommit, RevCommit bCommit,
|
||||||
|
ComparisonType comparisonType) throws IOException {
|
||||||
|
Text aText = aCommit != null
|
||||||
|
? Text.forMergeList(comparisonType, reader, aCommit)
|
||||||
|
: Text.EMPTY;
|
||||||
|
Text bText =
|
||||||
|
Text.forMergeList(comparisonType, reader, bCommit);
|
||||||
|
return createPatchListEntry(cmp, aCommit, aText, bText, Patch.MERGE_LIST);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PatchListEntry createPatchListEntry(RawTextComparator cmp,
|
||||||
|
RevCommit aCommit, Text aText, Text bText, String fileName) {
|
||||||
|
byte[] rawHdr = getRawHeader(aCommit != null, fileName);
|
||||||
byte[] aContent = aText.getContent();
|
byte[] aContent = aText.getContent();
|
||||||
byte[] bContent = bText.getContent();
|
byte[] bContent = bText.getContent();
|
||||||
long size = bContent.length;
|
long size = bContent.length;
|
||||||
@ -315,6 +327,26 @@ public class PatchListLoader implements Callable<PatchList> {
|
|||||||
return new PatchListEntry(fh, edits, size, sizeDelta);
|
return new PatchListEntry(fh, edits, size, sizeDelta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static byte[] getRawHeader(boolean hasA, String fileName) {
|
||||||
|
StringBuilder hdr = new StringBuilder();
|
||||||
|
hdr.append("diff --git");
|
||||||
|
if (hasA) {
|
||||||
|
hdr.append(" a/").append(fileName);
|
||||||
|
} else {
|
||||||
|
hdr.append(" ").append(FileHeader.DEV_NULL);
|
||||||
|
}
|
||||||
|
hdr.append(" b/").append(fileName);
|
||||||
|
hdr.append("\n");
|
||||||
|
|
||||||
|
if (hasA) {
|
||||||
|
hdr.append("--- a/").append(fileName).append("\n");
|
||||||
|
} else {
|
||||||
|
hdr.append("--- ").append(FileHeader.DEV_NULL).append("\n");
|
||||||
|
}
|
||||||
|
hdr.append("+++ b/").append(fileName).append("\n");
|
||||||
|
return hdr.toString().getBytes(UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
private PatchListEntry newEntry(RevTree aTree, FileHeader fileHeader,
|
private PatchListEntry newEntry(RevTree aTree, FileHeader fileHeader,
|
||||||
long size, long sizeDelta) {
|
long size, long sizeDelta) {
|
||||||
if (aTree == null // want combined diff
|
if (aTree == null // want combined diff
|
||||||
|
@ -66,7 +66,7 @@ class PatchScriptBuilder {
|
|||||||
private ObjectReader reader;
|
private ObjectReader reader;
|
||||||
private Change change;
|
private Change change;
|
||||||
private DiffPreferencesInfo diffPrefs;
|
private DiffPreferencesInfo diffPrefs;
|
||||||
private boolean againstParent;
|
private ComparisonType comparisonType;
|
||||||
private ObjectId aId;
|
private ObjectId aId;
|
||||||
private ObjectId bId;
|
private ObjectId bId;
|
||||||
|
|
||||||
@ -79,7 +79,8 @@ class PatchScriptBuilder {
|
|||||||
private int context;
|
private int context;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
PatchScriptBuilder(final FileTypeRegistry ftr, final PatchListCache plc) {
|
PatchScriptBuilder(FileTypeRegistry ftr,
|
||||||
|
PatchListCache plc) {
|
||||||
a = new Side();
|
a = new Side();
|
||||||
b = new Side();
|
b = new Side();
|
||||||
registry = ftr;
|
registry = ftr;
|
||||||
@ -106,8 +107,8 @@ class PatchScriptBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setTrees(final boolean ap, final ObjectId a, final ObjectId b) {
|
void setTrees(final ComparisonType ct, final ObjectId a, final ObjectId b) {
|
||||||
againstParent = ap;
|
comparisonType = ct;
|
||||||
aId = a;
|
aId = a;
|
||||||
bId = b;
|
bId = b;
|
||||||
}
|
}
|
||||||
@ -435,7 +436,8 @@ class PatchScriptBuilder {
|
|||||||
try {
|
try {
|
||||||
final boolean reuse;
|
final boolean reuse;
|
||||||
if (Patch.COMMIT_MSG.equals(path)) {
|
if (Patch.COMMIT_MSG.equals(path)) {
|
||||||
if (againstParent && (aId == within || within.equals(aId))) {
|
if (comparisonType.isAgainstParentOrAutoMerge()
|
||||||
|
&& (aId == within || within.equals(aId))) {
|
||||||
id = ObjectId.zeroId();
|
id = ObjectId.zeroId();
|
||||||
src = Text.EMPTY;
|
src = Text.EMPTY;
|
||||||
srcContent = Text.NO_BYTES;
|
srcContent = Text.NO_BYTES;
|
||||||
@ -453,7 +455,26 @@ class PatchScriptBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
reuse = false;
|
reuse = false;
|
||||||
|
} else if (Patch.MERGE_LIST.equals(path)) {
|
||||||
|
if (comparisonType.isAgainstParentOrAutoMerge()
|
||||||
|
&& (aId == within || within.equals(aId))) {
|
||||||
|
id = ObjectId.zeroId();
|
||||||
|
src = Text.EMPTY;
|
||||||
|
srcContent = Text.NO_BYTES;
|
||||||
|
mode = FileMode.MISSING;
|
||||||
|
displayMethod = DisplayMethod.NONE;
|
||||||
|
} else {
|
||||||
|
id = within;
|
||||||
|
src = Text.forMergeList(comparisonType, reader, within);
|
||||||
|
srcContent = src.getContent();
|
||||||
|
if (src == Text.EMPTY) {
|
||||||
|
mode = FileMode.MISSING;
|
||||||
|
displayMethod = DisplayMethod.NONE;
|
||||||
|
} else {
|
||||||
|
mode = FileMode.REGULAR_FILE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reuse = false;
|
||||||
} else {
|
} else {
|
||||||
final TreeWalk tw = find(within);
|
final TreeWalk tw = find(within);
|
||||||
|
|
||||||
|
@ -260,7 +260,7 @@ public class PatchScriptFactory implements Callable<PatchScript> {
|
|||||||
b.setRepository(git, project);
|
b.setRepository(git, project);
|
||||||
b.setChange(change);
|
b.setChange(change);
|
||||||
b.setDiffPrefs(diffPrefs);
|
b.setDiffPrefs(diffPrefs);
|
||||||
b.setTrees(list.isAgainstParent(), list.getOldId(), list.getNewId());
|
b.setTrees(list.getComparisonType(), list.getOldId(), list.getNewId());
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,6 +87,36 @@ public class Text extends RawText {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Text forMergeList(ComparisonType comparisonType,
|
||||||
|
ObjectReader reader, AnyObjectId commitId) throws IOException {
|
||||||
|
try (RevWalk rw = new RevWalk(reader)) {
|
||||||
|
RevCommit c = rw.parseCommit(commitId);
|
||||||
|
StringBuilder b = new StringBuilder();
|
||||||
|
switch (c.getParentCount()) {
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case 1: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
int uniterestingParent = comparisonType.isAgainstParent()
|
||||||
|
? comparisonType.getParentNum()
|
||||||
|
: 1;
|
||||||
|
|
||||||
|
b.append("Merge List:\n\n");
|
||||||
|
for (RevCommit commit : MergeListBuilder.build(rw, c,
|
||||||
|
uniterestingParent)) {
|
||||||
|
b.append("* ");
|
||||||
|
b.append(reader.abbreviate(commit, 8).name());
|
||||||
|
b.append(" ");
|
||||||
|
b.append(commit.getShortMessage());
|
||||||
|
b.append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new Text(b.toString().getBytes(UTF_8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void appendPersonIdent(StringBuilder b, String field,
|
private static void appendPersonIdent(StringBuilder b, String field,
|
||||||
PersonIdent person) {
|
PersonIdent person) {
|
||||||
if (person != null) {
|
if (person != null) {
|
||||||
|
@ -47,7 +47,7 @@ public class FilesInCommitCollection implements
|
|||||||
@Override
|
@Override
|
||||||
public FileResource parse(CommitResource parent, IdString id)
|
public FileResource parse(CommitResource parent, IdString id)
|
||||||
throws ResourceNotFoundException, IOException {
|
throws ResourceNotFoundException, IOException {
|
||||||
if (Patch.COMMIT_MSG.equals(id.get())) {
|
if (Patch.isMagic(id.get())) {
|
||||||
return new FileResource(parent.getProject(), parent.getCommit(),
|
return new FileResource(parent.getProject(), parent.getCommit(),
|
||||||
id.get());
|
id.get());
|
||||||
}
|
}
|
||||||
|
@ -599,7 +599,7 @@ public class ChangeData {
|
|||||||
|
|
||||||
r = new ArrayList<>(p.get().getPatches().size());
|
r = new ArrayList<>(p.get().getPatches().size());
|
||||||
for (PatchListEntry e : p.get().getPatches()) {
|
for (PatchListEntry e : p.get().getPatches()) {
|
||||||
if (Patch.COMMIT_MSG.equals(e.getNewName())) {
|
if (Patch.isMagic(e.getNewName())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
switch (e.getChangeType()) {
|
switch (e.getChangeType()) {
|
||||||
|
@ -14,8 +14,10 @@
|
|||||||
|
|
||||||
package gerrit;
|
package gerrit;
|
||||||
|
|
||||||
|
import com.google.gerrit.reviewdb.client.Patch;
|
||||||
import com.google.gerrit.rules.StoredValues;
|
import com.google.gerrit.rules.StoredValues;
|
||||||
import com.google.gerrit.server.patch.PatchList;
|
import com.google.gerrit.server.patch.PatchList;
|
||||||
|
import com.google.gerrit.server.patch.PatchListEntry;
|
||||||
|
|
||||||
import com.googlecode.prolog_cafe.exceptions.PrologException;
|
import com.googlecode.prolog_cafe.exceptions.PrologException;
|
||||||
import com.googlecode.prolog_cafe.lang.IntegerTerm;
|
import com.googlecode.prolog_cafe.lang.IntegerTerm;
|
||||||
@ -24,6 +26,8 @@ import com.googlecode.prolog_cafe.lang.Predicate;
|
|||||||
import com.googlecode.prolog_cafe.lang.Prolog;
|
import com.googlecode.prolog_cafe.lang.Prolog;
|
||||||
import com.googlecode.prolog_cafe.lang.Term;
|
import com.googlecode.prolog_cafe.lang.Term;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exports basic commit statistics.
|
* Exports basic commit statistics.
|
||||||
*
|
*
|
||||||
@ -48,7 +52,11 @@ public class PRED_commit_stats_3 extends Predicate.P3 {
|
|||||||
Term a3 = arg3.dereference();
|
Term a3 = arg3.dereference();
|
||||||
|
|
||||||
PatchList pl = StoredValues.PATCH_LIST.get(engine);
|
PatchList pl = StoredValues.PATCH_LIST.get(engine);
|
||||||
if (!a1.unify(new IntegerTerm(pl.getPatches().size() - 1),engine.trail)) { //Account for /COMMIT_MSG.
|
// Account for magic files
|
||||||
|
if (!a1.unify(
|
||||||
|
new IntegerTerm(
|
||||||
|
pl.getPatches().size() - countMagicFiles(pl.getPatches())),
|
||||||
|
engine.trail)) {
|
||||||
return engine.fail();
|
return engine.fail();
|
||||||
}
|
}
|
||||||
if (!a2.unify(new IntegerTerm(pl.getInsertions()),engine.trail)) {
|
if (!a2.unify(new IntegerTerm(pl.getInsertions()),engine.trail)) {
|
||||||
@ -59,4 +67,14 @@ public class PRED_commit_stats_3 extends Predicate.P3 {
|
|||||||
}
|
}
|
||||||
return cont;
|
return cont;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int countMagicFiles(List<PatchListEntry> entries) {
|
||||||
|
int count = 0;
|
||||||
|
for (PatchListEntry e : entries) {
|
||||||
|
if (Patch.isMagic(e.getNewName())) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user