Merge changes from topic 'bot-comments-ui-gh16'
* changes:
Hide "HideBotComments" if no bot comment is present in the history tab
Add show / hide bot comments button to ChangeScreen
diff --git a/.buckconfig b/.buckconfig
index cc3353d..60fd02a 100644
--- a/.buckconfig
+++ b/.buckconfig
@@ -25,7 +25,7 @@
[project]
allow_symlinks = allow
- ignore = .git, eclipse-out, bazel-gerrit
+ ignore = .git, eclipse-out, bazel-gerrit, bin
parallel_parsing = true
[cache]
diff --git a/Documentation/BUILD b/Documentation/BUILD
new file mode 100644
index 0000000..98b3ce4
--- /dev/null
+++ b/Documentation/BUILD
@@ -0,0 +1,7 @@
+
+load("//tools/bzl:license.bzl", "license_map")
+
+license_map(
+ name = "pgm-licenses",
+ target = "//gerrit-pgm:pgm",
+)
diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt
index e28332c..cce00ef 100644
--- a/Documentation/rest-api-changes.txt
+++ b/Documentation/rest-api-changes.txt
@@ -1275,6 +1275,10 @@
link:#current-revision[`CURRENT_REVISION`], and
link:#current-commit[`CURRENT_COMMIT`] options set.
+Standard link:#query-options[formatting options] can be specified
+with the `o` parameter, as well as the `submitted_together` specific
+option `NON_VISIBLE_CHANGES`.
+
.Response
----
HTTP/1.1 200 OK
diff --git a/ReleaseNotes/ReleaseNotes-2.13.txt b/ReleaseNotes/ReleaseNotes-2.13.txt
index d73a1bd..b875603 100644
--- a/ReleaseNotes/ReleaseNotes-2.13.txt
+++ b/ReleaseNotes/ReleaseNotes-2.13.txt
@@ -327,6 +327,18 @@
capability, or to ensure that specific groups always have administration
capabilities.
+* New configuration options to configure JGit repository cache parameters.
++
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.13/config-gerrit.html#core.repositoryCacheCleanupDelay[
+core.repositoryCacheCleanupDelay] and
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.13/config-gerrit.html#core.repositoryCacheExpireAfter[
+core.repositoryCacheExpireAfter] can be configured.
+
+* Accept `-b` as an alias of `--batch` in the
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.13/pgm-init.html[
+init program].
+
+
== Bug Fixes
* Don't add the same SSH key multiple times.
@@ -400,6 +412,22 @@
easier to track down which commit failed validation when multiple commits
are pushed at the same time.
+* Don't check mergeability of draft changes.
++
+Draft changes can be deleted but not abandoned so there is no way for
+an administrator to get rid of the them on behalf of the users. This can
+become a problem when there many draft changes because the mergeability
+check can be costly.
++
+The mergeability check is no longer done for draft changes, but will be
+done when the draft change is published.
+
+* Fix internal server error when plugin-provided file history weblink
+is null.
++
+It is valid for a plugin to provide a null weblink, but doing so resulted
+in an internal server error.
+
== Dependency updates
* Add dependency on blame-cache 0.1-9
@@ -430,7 +458,7 @@
* Upgrade Jetty to 9.2.14.v20151106
-* Upgrade JGit to 4.4.1.201607150455-r.144-gb67df51
+* Upgrade JGit to 4.5.0.201609210915-r
* Upgrade joda-convert to 1.8.1
diff --git a/WORKSPACE b/WORKSPACE
index 536c827..77d6dbc 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -172,7 +172,7 @@
maven_jar(
name = 'gwtjsonrpc',
artifact = 'com.google.gerrit:gwtjsonrpc:1.11',
- sha1 = '9587c6f88f1964f1aa61212a162c776c71d77456',
+ sha1 = '0990e7eec9eec3a15661edcf9232acbac4aeacec',
)
http_jar(
@@ -190,7 +190,7 @@
maven_jar(
name = 'gwtorm_client',
artifact = 'com.google.gerrit:gwtorm:1.16',
- sha1 = 'b91331724669f8136426f0f4846ddcec0f6eb22f',
+ sha1 = '3e41b6d7bb352fa0539ce23b9bce97cf8c26c3bf',
)
http_jar(
diff --git a/contrib/git-push-review b/contrib/git-push-review
index e77785a..aeea552 100755
--- a/contrib/git-push-review
+++ b/contrib/git-push-review
@@ -46,8 +46,8 @@
help='remote name or URL to push to')
p.add_argument('-b', '--branch', default='', metavar='BRANCH',
help='remote branch name, refs/for/BRANCH')
- p.add_argument('reviewers', nargs='*', metavar='REVIEWER',
- help='reviewer names or aliases')
+ p.add_argument('args', nargs='*', metavar='REVIEWER_OR_HASHTAG',
+ help='reviewer names or aliases, or #hashtags')
p.add_argument('-t', '--topic', default='', metavar='TOPIC',
help='topic for new changes')
p.add_argument('--dry-run', action='store_true',
@@ -68,8 +68,12 @@
args.remote = args.remote or def_remote
args.branch = args.branch or def_branch
+
opts = collections.defaultdict(list)
- opts['r'].extend((get_config('reviewer.' + r) or r) for r in args.reviewers)
+ is_hashtag = lambda x: x.startswith('#')
+ opts['r'].extend(
+ get_config('reviewer.' + r) for r in args.args if not is_hashtag(r))
+ opts['t'].extend(t[1:] for t in args.args if is_hashtag(t))
if args.topic:
opts['topic'].append(args.topic)
opts_str = ','.join('%s=%s' % (k, v) for k in opts for v in opts[k])
diff --git a/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
index 53f4599..82de9f8 100644
--- a/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
+++ b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
@@ -17,6 +17,8 @@
import static com.google.common.truth.Truth.assertThat;
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.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 org.eclipse.jgit.lib.Constants.HEAD;
@@ -48,6 +50,8 @@
import com.google.gerrit.extensions.client.SubmitType;
import com.google.gerrit.extensions.common.ActionInfo;
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.restapi.BinaryResult;
import com.google.gerrit.extensions.restapi.IdString;
@@ -67,6 +71,7 @@
import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.change.Abandon;
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.Revisions;
import com.google.gerrit.server.config.AllProjectsName;
@@ -546,21 +551,26 @@
protected PushOneCommit.Result createMergeCommitChange(String ref)
throws Exception {
+ return createMergeCommitChange(ref, "foo");
+ }
+
+ protected PushOneCommit.Result createMergeCommitChange(String ref, String file)
+ throws Exception {
ObjectId initial = repo().exactRef(HEAD).getLeaf().getObjectId();
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);
// reset HEAD in order to create a sibling of the first change
testRepo.reset(initial);
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);
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()));
PushOneCommit.Result result = m.to(ref);
result.assertOkStatus();
@@ -1086,4 +1096,45 @@
}
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();
+ }
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/GetMergeListIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/GetMergeListIT.java
deleted file mode 100644
index 0cb7d89..0000000
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/GetMergeListIT.java
+++ /dev/null
@@ -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());
- }
-}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/MergeListIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/MergeListIT.java
new file mode 100644
index 0000000..481df31
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/MergeListIT.java
@@ -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();
+ }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java
index 322cd4e..de0c3c1 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java
@@ -20,11 +20,13 @@
import static com.google.gerrit.acceptance.PushOneCommit.PATCH;
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.MERGE_LIST;
import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.eclipse.jgit.lib.Constants.HEAD;
import static org.junit.Assert.fail;
+import com.google.common.base.Joiner;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.gerrit.acceptance.AbstractDaemonTest;
@@ -45,7 +47,6 @@
import com.google.gerrit.extensions.client.SubmitType;
import com.google.gerrit.extensions.common.ChangeInfo;
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.DiffInfo;
import com.google.gerrit.extensions.common.FileInfo;
@@ -539,7 +540,7 @@
.revision(r.getCommit().name())
.files()
.keySet()
- ).containsExactly(COMMIT_MSG, "foo", "bar");
+ ).containsExactly(COMMIT_MSG, MERGE_LIST, "foo", "bar");
// list files against parent 1
assertThat(gApi.changes()
@@ -547,7 +548,7 @@
.revision(r.getCommit().name())
.files(1)
.keySet()
- ).containsExactly(COMMIT_MSG, "bar");
+ ).containsExactly(COMMIT_MSG, MERGE_LIST, "bar");
// list files against parent 2
assertThat(gApi.changes()
@@ -555,7 +556,7 @@
.revision(r.getCommit().name())
.files(2)
.keySet()
- ).containsExactly(COMMIT_MSG, "foo");
+ ).containsExactly(COMMIT_MSG, MERGE_LIST, "foo");
}
@Test
@@ -853,66 +854,40 @@
.file(path)
.diff();
- List<String> expectedLines = new ArrayList<>();
+ List<String> headers = new ArrayList<>();
if (path.equals(COMMIT_MSG)) {
RevCommit c = pushResult.getCommit();
RevCommit parentCommit = c.getParents()[0];
String parentCommitId = testRepo.getRevWalk().getObjectReader()
.abbreviate(parentCommit.getId(), 8).name();
- expectedLines.add("Parent: " + parentCommitId + " ("
+ headers.add("Parent: " + parentCommitId + " ("
+ parentCommit.getShortMessage() + ")");
SimpleDateFormat dtfmt =
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z", Locale.US);
PersonIdent author = c.getAuthorIdent();
dtfmt.setTimeZone(author.getTimeZone());
- expectedLines.add("Author: " + author.getName() + " <"
+ headers.add("Author: " + author.getName() + " <"
+ author.getEmailAddress() + ">");
- expectedLines.add("AuthorDate: "
+ headers.add("AuthorDate: "
+ dtfmt.format(Long.valueOf(author.getWhen().getTime())));
PersonIdent committer = c.getCommitterIdent();
dtfmt.setTimeZone(committer.getTimeZone());
- expectedLines.add("Commit: " + committer.getName() + " <"
+ headers.add("Commit: " + committer.getName() + " <"
+ committer.getEmailAddress() + ">");
- expectedLines.add("CommitDate: "
+ headers.add("CommitDate: "
+ dtfmt.format(Long.valueOf(committer.getWhen().getTime())));
- expectedLines.add("");
+ headers.add("");
}
- for (String line : expectedContentSideB.split("\n")) {
- expectedLines.add(line);
+ if (!headers.isEmpty()) {
+ String header = Joiner.on("\n").join(headers);
+ expectedContentSideB = header + "\n" + expectedContentSideB;
}
- 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(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();
+ assertDiffForNewFile(diff, pushResult.getCommit(), path,
+ expectedContentSideB);
}
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/CommentsIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/CommentsIT.java
index 67af6e2..5b6f3f9 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/CommentsIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/CommentsIT.java
@@ -32,9 +32,11 @@
import com.google.gerrit.extensions.client.Comment;
import com.google.gerrit.extensions.client.Side;
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.ResourceNotFoundException;
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.ChangesCollection;
import com.google.gerrit.server.change.PostReview;
@@ -148,8 +150,8 @@
@Test
public void postCommentOnMergeCommitChange() throws Exception {
for (Integer line : lines) {
- final String file = "/COMMIT_MSG";
- PushOneCommit.Result r = createMergeCommitChange("refs/for/master");
+ String file = "foo";
+ PushOneCommit.Result r = createMergeCommitChange("refs/for/master", file);
String changeId = r.getChangeId();
String revId = r.getCommit().getName();
ReviewInput input = new ReviewInput();
@@ -165,6 +167,39 @@
assertThat(Lists.transform(result.get(file), infoToInput(file)))
.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
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/SubmittedTogetherIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/SubmittedTogetherIT.java
index 06170d0..b843721 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/SubmittedTogetherIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/SubmittedTogetherIT.java
@@ -23,8 +23,11 @@
import com.google.gerrit.acceptance.TestProjectInput;
import com.google.gerrit.extensions.api.changes.SubmittedTogetherInfo;
import com.google.gerrit.extensions.client.ChangeStatus;
+import com.google.gerrit.extensions.client.ListChangesOption;
import com.google.gerrit.extensions.client.SubmitType;
import com.google.gerrit.extensions.common.ChangeInfo;
+import com.google.gerrit.extensions.common.FileInfo;
+import com.google.gerrit.extensions.common.RevisionInfo;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.testutil.ConfigSuite;
@@ -44,6 +47,63 @@
}
@Test
+ public void doesNotIncludeCurrentFiles() throws Exception {
+ RevCommit c1_1 = commitBuilder()
+ .add("a.txt", "1")
+ .message("subject: 1")
+ .create();
+ RevCommit c2_1 = commitBuilder()
+ .add("b.txt", "2")
+ .message("subject: 2")
+ .create();
+ String id2 = getChangeId(c2_1);
+ pushHead(testRepo, "refs/for/master", false);
+
+ SubmittedTogetherInfo info =
+ gApi.changes()
+ .id(id2)
+ .submittedTogether(EnumSet.of(NON_VISIBLE_CHANGES));
+ assertThat(info.changes).hasSize(2);
+ assertThat(info.changes.get(0).currentRevision).isEqualTo(c2_1.name());
+ assertThat(info.changes.get(1).currentRevision).isEqualTo(c1_1.name());
+
+ assertThat(info.changes.get(0).currentRevision).isEqualTo(c2_1.name());
+ RevisionInfo rev = info.changes.get(0).revisions.get(c2_1.name());
+ assertThat(rev.files).isNull();
+ }
+
+ @Test
+ public void returnsCurrentFilesIfOptionRequested() throws Exception {
+ RevCommit c1_1 = commitBuilder()
+ .add("a.txt", "1")
+ .message("subject: 1")
+ .create();
+ RevCommit c2_1 = commitBuilder()
+ .add("b.txt", "2")
+ .message("subject: 2")
+ .create();
+ String id2 = getChangeId(c2_1);
+ pushHead(testRepo, "refs/for/master", false);
+
+ SubmittedTogetherInfo info =
+ gApi.changes()
+ .id(id2)
+ .submittedTogether(
+ EnumSet.of(ListChangesOption.CURRENT_FILES),
+ EnumSet.of(NON_VISIBLE_CHANGES));
+ assertThat(info.changes).hasSize(2);
+ assertThat(info.changes.get(0).currentRevision).isEqualTo(c2_1.name());
+ assertThat(info.changes.get(1).currentRevision).isEqualTo(c1_1.name());
+
+ assertThat(info.changes.get(0).currentRevision).isEqualTo(c2_1.name());
+ RevisionInfo rev = info.changes.get(0).revisions.get(c2_1.name());
+ assertThat(rev).isNotNull();
+ FileInfo file = rev.files.get("b.txt");
+ assertThat(file).isNotNull();
+ assertThat(file.status).isEqualTo('A');
+ }
+
+ @Test
public void returnsAncestors() throws Exception {
// Create two commits and push.
RevCommit c1_1 = commitBuilder()
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/notedb/ChangeRebuilderIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/notedb/ChangeRebuilderIT.java
index 4f14bb1..8606ce7 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/notedb/ChangeRebuilderIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/notedb/ChangeRebuilderIT.java
@@ -715,6 +715,8 @@
rin.message = "comment";
Timestamp ts = new Timestamp(c.getCreatedOn().getTime() + 2000);
+ assertThat(ts).isGreaterThan(c.getCreatedOn());
+ assertThat(ts).isLessThan(db.patchSets().get(psId).getCreatedOn());
RevisionResource revRsrc = parseCurrentRevisionResource(r.getChangeId());
postReview.get().apply(revRsrc, rin, ts);
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java
index f656c2d..f860552 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java
@@ -97,6 +97,9 @@
List<ChangeInfo> submittedTogether() throws RestApiException;
SubmittedTogetherInfo submittedTogether(
EnumSet<SubmittedTogetherOption> options) throws RestApiException;
+ SubmittedTogetherInfo submittedTogether(
+ EnumSet<ListChangesOption> listOptions,
+ EnumSet<SubmittedTogetherOption> submitOptions) throws RestApiException;
/**
* Publishes a draft change.
@@ -360,5 +363,12 @@
EnumSet<SubmittedTogetherOption> options) throws RestApiException {
throw new NotImplementedException();
}
+
+ @Override
+ public SubmittedTogetherInfo submittedTogether(
+ EnumSet<ListChangesOption> a,
+ EnumSet<SubmittedTogetherOption> b) throws RestApiException {
+ throw new NotImplementedException();
+ }
}
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/SubmittedTogetherOption.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/SubmittedTogetherOption.java
index 8649e91f..e2cab4d 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/SubmittedTogetherOption.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/SubmittedTogetherOption.java
@@ -16,15 +16,5 @@
/** Output options available for submitted_together requests. */
public enum SubmittedTogetherOption {
- NON_VISIBLE_CHANGES(0);
-
- private final int value;
-
- SubmittedTogetherOption(int v) {
- value = v;
- }
-
- public int getValue() {
- return value;
- }
+ NON_VISIBLE_CHANGES;
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/Comment.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/Comment.java
index 7c8a3e8..78ffb82 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/Comment.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/Comment.java
@@ -59,6 +59,13 @@
}
}
+ public short side() {
+ if (side == Side.PARENT) {
+ return (short) (parent == null ? 0 : -parent.shortValue());
+ }
+ return 1;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) {
diff --git a/gerrit-gwtui-common/BUCK b/gerrit-gwtui-common/BUCK
index 4485430..d4d97a6 100644
--- a/gerrit-gwtui-common/BUCK
+++ b/gerrit-gwtui-common/BUCK
@@ -41,7 +41,7 @@
binary_jar = ':diffy_image_files_ln',
deps = [
'//lib:LICENSE-diffy',
- '//lib:LICENSE-CC-BY3.0',
+ '//lib:LICENSE-CC-BY3.0-unported',
],
visibility = ['PUBLIC'],
)
diff --git a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/FileInfo.java b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/FileInfo.java
index 9b290a5..b21126d 100644
--- a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/FileInfo.java
+++ b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/FileInfo.java
@@ -56,6 +56,12 @@
} else if (Patch.COMMIT_MSG.equals(b.path())) {
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
int s1 = a.path().lastIndexOf('.');
int s2 = b.path().lastIndexOf('.');
@@ -76,9 +82,15 @@
}
public static String getFileName(String path) {
- String fileName = Patch.COMMIT_MSG.equals(path)
- ? "Commit Message"
- : path;
+ String fileName;
+ if (Patch.COMMIT_MSG.equals(path)) {
+ fileName = "Commit Message";
+ } else if (Patch.MERGE_LIST.equals(path)) {
+ fileName = "Merge List";
+ } else {
+ fileName = path;
+ }
+
int s = fileName.lastIndexOf('/');
return s >= 0 ? fileName.substring(s + 1) : fileName;
}
diff --git a/gerrit-gwtui/BUCK b/gerrit-gwtui/BUCK
index 3ab6187..63d52b0 100644
--- a/gerrit-gwtui/BUCK
+++ b/gerrit-gwtui/BUCK
@@ -47,7 +47,6 @@
name = 'silk_icons',
deps = [
'//lib:LICENSE-silk_icons',
- '//lib:LICENSE-CC-BY3.0',
],
)
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java
index 2b4c821..cb2ac07 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java
@@ -486,7 +486,11 @@
} else if ("unified".equals(panel)) {
unified(token, baseId, id, side, line);
} 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 {
Gerrit.display(token, new NotFoundScreen());
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchSuggestOracle.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchSuggestOracle.java
index 54c5b92..24a7ed0 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchSuggestOracle.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchSuggestOracle.java
@@ -31,7 +31,7 @@
new ProjectNameSuggestOracle()),
new ParamSuggester(Arrays.asList(
"owner:", "reviewer:", "commentby:", "reviewedby:", "author:",
- "committer:", "from:"),
+ "committer:", "from:", "assignee:"),
new AccountSuggestOracle() {
@Override
public void onRequestSuggestions(final Request request, final Callback done) {
@@ -120,6 +120,8 @@
suggestions.add("is:merged");
suggestions.add("is:abandoned");
suggestions.add("is:mergeable");
+ suggestions.add("is:assigned");
+ suggestions.add("is:unassigned");
suggestions.add("status:");
suggestions.add("status:open");
@@ -139,6 +141,8 @@
suggestions.add("hashtag:");
}
+ suggestions.add("assignee:");
+
suggestions.add("AND");
suggestions.add("OR");
suggestions.add("NOT");
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileTable.java
index c0879e7..3a85b26 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileTable.java
@@ -267,11 +267,18 @@
if (table != null) {
String self = Gerrit.selfRedirect(null);
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) {
clear();
add(table);
@@ -429,7 +436,10 @@
@Override
protected void onOpenRow(int row) {
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 @@
@Override
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 @@
bytesDeleted = 0;
for (int i = 0; i < list.length(); i++) {
FileInfo info = list.get(i);
- if (!Patch.COMMIT_MSG.equals(info.path())) {
+ if (!Patch.isMagic(info.path())) {
if (!info.binary()) {
hasNonBinaryFile = true;
inserted += info.linesInserted();
@@ -628,7 +641,7 @@
private void columnDeleteRestore(SafeHtmlBuilder sb, FileInfo info) {
sb.openTd().setStyleName(R.css().restoreDelete());
if (hasUser) {
- if (!Patch.COMMIT_MSG.equals(info.path())) {
+ if (!Patch.isMagic(info.path())) {
boolean editable = isEditable(info);
sb.openDiv()
.openElement("button")
@@ -659,7 +672,7 @@
private void columnStatus(SafeHtmlBuilder sb, FileInfo info) {
sb.openTd().setStyleName(R.css().status());
- if (!Patch.COMMIT_MSG.equals(info.path())
+ if (!Patch.isMagic(info.path())
&& info.status() != null
&& !ChangeType.MODIFIED.matches(info.status())) {
sb.append(info.status());
@@ -668,20 +681,43 @@
}
private void columnPath(SafeHtmlBuilder sb, FileInfo info) {
- sb.openTd()
- .setStyleName(R.css().pathColumn())
- .openAnchor();
-
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)) {
sb.setAttribute("onclick", RESTORE + "(event," + info._row() + ")");
} else {
sb.setAttribute("href", "#" + url(info))
.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)) {
sb.append(Util.C.commitMessage());
+ } else if (Patch.MERGE_LIST.equals(path)) {
+ sb.append(Util.C.mergeList());
} else if (Gerrit.getUserPreferences().muteCommonPathPrefixes()) {
int commonPrefixLen = commonPrefix(path);
if (commonPrefixLen > 0) {
@@ -694,15 +730,6 @@
} else {
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) {
@@ -784,7 +811,7 @@
private void columnDelta1(SafeHtmlBuilder sb, FileInfo info) {
sb.openTd().setStyleName(R.css().deltaColumn1());
- if (!Patch.COMMIT_MSG.equals(info.path()) && !info.binary()) {
+ if (!Patch.isMagic(info.path()) && !info.binary()) {
if (showChangeSizeBars) {
sb.append(info.linesInserted() + info.linesDeleted());
} else if (!ChangeType.DELETED.matches(info.status())) {
@@ -813,7 +840,7 @@
private void columnDelta2(SafeHtmlBuilder sb, FileInfo info) {
sb.openTd().setStyleName(R.css().deltaColumn2());
if (showChangeSizeBars
- && !Patch.COMMIT_MSG.equals(info.path()) && !info.binary()
+ && !Patch.isMagic(info.path()) && !info.binary()
&& (info.linesInserted() != 0 || info.linesDeleted() != 0)) {
int w = 80;
int t = inserted + deleted;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Message.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Message.java
index 6c27ed9..c8735b7 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Message.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Message.java
@@ -176,6 +176,10 @@
if (l != null) {
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()) {
comments.add(new FileComments(clp, ps, e.getKey(), e.getValue()));
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ReplyBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ReplyBox.java
index e29048a..b985f43 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ReplyBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ReplyBox.java
@@ -422,12 +422,17 @@
comments.add(new FileComments(clp, psId,
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());
Collections.sort(paths);
for (String path : paths) {
- if (!path.equals(Patch.COMMIT_MSG)) {
+ if (!Patch.isMagic(path)) {
comments.add(new FileComments(clp, psId,
path, copyPath(path, m.get(path))));
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.java
index b2334d1d..4a9eea4 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.java
@@ -63,6 +63,7 @@
String patchTableColumnComments();
String patchTableColumnSize();
String commitMessage();
+ String mergeList();
String patchTablePrev();
String patchTableNext();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.properties
index b7e2677..675cd07 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.properties
@@ -45,6 +45,7 @@
patchTableColumnComments = Comments
patchTableColumnSize = Size
commitMessage = Commit Message
+mergeList = Merge List
patchTablePrev = Previous file
patchTableNext = Next file
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Header.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Header.java
index f377038..3033cbb1 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Header.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Header.java
@@ -122,6 +122,8 @@
SafeHtmlBuilder b = new SafeHtmlBuilder();
if (Patch.COMMIT_MSG.equals(path)) {
return b.append(Util.C.commitMessage());
+ } else if (Patch.MERGE_LIST.equals(path)) {
+ return b.append(Util.C.mergeList());
}
int s = path.lastIndexOf('/') + 1;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PatchSetSelectBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PatchSetSelectBox.java
index bc37abb..d45b8d8 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PatchSetSelectBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PatchSetSelectBox.java
@@ -128,7 +128,7 @@
if (meta == null) {
return;
}
- if (!Patch.COMMIT_MSG.equals(path)) {
+ if (!Patch.isMagic(path)) {
linkPanel.add(createDownloadLink());
}
if (!binary && open && idActive != null && Gerrit.isSignedIn()) {
@@ -147,7 +147,7 @@
void setUpBlame(final CodeMirror cm, final boolean isBase,
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()) {
Anchor blameIcon = createBlameIcon();
blameIcon.addClickHandler(new ClickHandler() {
diff --git a/gerrit-pgm/BUILD b/gerrit-pgm/BUILD
index ec86c9a..895b5f1 100644
--- a/gerrit-pgm/BUILD
+++ b/gerrit-pgm/BUILD
@@ -1,5 +1,6 @@
load('//tools/bzl:java.bzl', 'java_library2')
load('//tools/bzl:junit.bzl', 'junit_tests')
+load('//tools/bzl:license.bzl', 'license_test')
SRCS = 'src/main/java/com/google/gerrit/pgm/'
RSRCS = 'src/main/resources/com/google/gerrit/pgm/'
@@ -160,3 +161,7 @@
'//lib/jgit/org.eclipse.jgit.junit:junit',
],
)
+
+license_test(
+ name = "pgm_license_test",
+ target = ":pgm")
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Patch.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Patch.java
index 6a55965..309bda4 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Patch.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Patch.java
@@ -22,6 +22,22 @@
/** Magical file name which represents the commit message. */
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> {
private static final long serialVersionUID = 1L;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/PatchLineCommentsUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/PatchLineCommentsUtil.java
index 732a9b8..68065cb 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/PatchLineCommentsUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/PatchLineCommentsUtil.java
@@ -20,6 +20,7 @@
import com.google.common.base.Optional;
import com.google.common.collect.ComparisonChain;
+import com.google.common.collect.FluentIterable;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Ordering;
@@ -27,6 +28,7 @@
import com.google.gerrit.extensions.common.CommentInfo;
import com.google.gerrit.reviewdb.client.Account;
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.Status;
import com.google.gerrit.reviewdb.client.PatchSet;
@@ -37,7 +39,6 @@
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.notedb.ChangeUpdate;
-import com.google.gerrit.server.notedb.DraftCommentNotes;
import com.google.gerrit.server.notedb.NotesMigration;
import com.google.gerrit.server.patch.PatchListCache;
import com.google.gerrit.server.patch.PatchListNotAvailableException;
@@ -112,17 +113,14 @@
private final GitRepositoryManager repoManager;
private final AllUsersName allUsers;
- private final DraftCommentNotes.Factory draftFactory;
private final NotesMigration migration;
@Inject
PatchLineCommentsUtil(GitRepositoryManager repoManager,
AllUsersName allUsers,
- DraftCommentNotes.Factory draftFactory,
NotesMigration migration) {
this.repoManager = repoManager;
this.allUsers = allUsers;
- this.draftFactory = draftFactory;
this.migration = migration;
}
@@ -210,10 +208,27 @@
public List<PatchLineComment> publishedByPatchSet(ReviewDb db,
ChangeNotes notes, PatchSet.Id psId) throws OrmException {
if (!migration.readChanges()) {
- return sort(
- db.patchComments().publishedByPatchSet(psId).toList());
+ return removeCommentsOnAncestorOfCommitMessage(sort(
+ 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,
@@ -257,13 +272,14 @@
}
@Deprecated // To be used only by HasDraftByLegacyPredicate.
- public List<PatchLineComment> draftByAuthor(ReviewDb db,
+ public List<Change.Id> changesWithDraftsByAuthor(ReviewDb db,
Account.Id author) throws OrmException {
if (!migration.readChanges()) {
- return sort(db.patchComments().draftByAuthor(author).toList());
+ return FluentIterable.from(db.patchComments().draftByAuthor(author))
+ .transform(plc -> plc.getPatchSetId().getParentKey()).toList();
}
- List<PatchLineComment> comments = new ArrayList<>();
+ List<Change.Id> changes = new ArrayList<>();
try (Repository repo = repoManager.openRepository(allUsers)) {
for (String refName : repo.getRefDatabase()
.getRefs(RefNames.REFS_DRAFT_COMMENTS).keySet()) {
@@ -272,17 +288,12 @@
if (accountId == null || changeId == null) {
continue;
}
- // Avoid loading notes for all affected changes just to be able to auto-
- // rebuild. This is only used in a corner case in the search codepath,
- // so returning slightly stale values is ok.
- DraftCommentNotes notes =
- draftFactory.createWithAutoRebuildingDisabled(changeId, author);
- comments.addAll(notes.load().getComments().values());
+ changes.add(changeId);
}
} catch (IOException e) {
throw new OrmException(e);
}
- return sort(comments);
+ return changes;
}
public void putComments(ReviewDb db, ChangeUpdate update,
@@ -348,7 +359,7 @@
return sort(result);
}
- public static RevId setCommentRevId(PatchLineComment c,
+ public static void setCommentRevId(PatchLineComment c,
PatchListCache cache, Change change, PatchSet ps) throws OrmException {
checkArgument(c.getPatchSetId().equals(ps.getId()),
"cannot set RevId for patch set %s on comment %s", ps.getId(), c);
@@ -369,7 +380,6 @@
throw new OrmException(e);
}
}
- return c.getRevId();
}
public Collection<Ref> getDraftRefs(Change.Id changeId)
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/ReviewersUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/ReviewersUtil.java
index a818edd..5941c10 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/ReviewersUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/ReviewersUtil.java
@@ -68,7 +68,7 @@
public class ReviewersUtil {
private static final String MAX_SUFFIX = "\u9fa5";
private static final Ordering<SuggestedReviewerInfo> ORDERING =
- Ordering.from(comparing(
+ Ordering.<SuggestedReviewerInfo> from(comparing(
suggestedReviewerInfo -> {
if (suggestedReviewerInfo == null) {
return null;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java
index 9bfb342..9c12348 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java
@@ -61,6 +61,7 @@
import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
+import com.google.inject.Provider;
import com.google.inject.assistedinject.Assisted;
import java.io.IOException;
@@ -84,7 +85,7 @@
private final Abandon abandon;
private final Revert revert;
private final Restore restore;
- private final SubmittedTogether submittedTogether;
+ private final Provider<SubmittedTogether> submittedTogether;
private final PublishDraftPatchSet.CurrentRevision
publishDraftChange;
private final DeleteDraftChange deleteDraftChange;
@@ -111,7 +112,7 @@
Abandon abandon,
Revert revert,
Restore restore,
- SubmittedTogether submittedTogether,
+ Provider<SubmittedTogether> submittedTogether,
PublishDraftPatchSet.CurrentRevision publishDraftChange,
DeleteDraftChange deleteDraftChange,
GetTopic getTopic,
@@ -248,21 +249,29 @@
}
}
- @SuppressWarnings("unchecked")
@Override
public List<ChangeInfo> submittedTogether() throws RestApiException {
- try {
- return (List<ChangeInfo>) submittedTogether.apply(change);
- } catch (IOException | OrmException e) {
- throw new RestApiException("Cannot query submittedTogether", e);
- }
+ SubmittedTogetherInfo info = submittedTogether(
+ EnumSet.noneOf(ListChangesOption.class),
+ EnumSet.noneOf(SubmittedTogetherOption.class));
+ return info.changes;
}
@Override
public SubmittedTogetherInfo submittedTogether(
EnumSet<SubmittedTogetherOption> options) throws RestApiException {
+ return submittedTogether(EnumSet.noneOf(ListChangesOption.class), options);
+ }
+
+ @Override
+ public SubmittedTogetherInfo submittedTogether(
+ EnumSet<ListChangesOption> listOptions,
+ EnumSet<SubmittedTogetherOption> submitOptions) throws RestApiException {
try {
- return submittedTogether.apply(change, options);
+ return submittedTogether.get()
+ .addListChangesOption(listOptions)
+ .addSubmittedTogetherOption(submitOptions)
+ .applyInfo(change);
} catch (IOException | OrmException e) {
throw new RestApiException("Cannot query submittedTogether", e);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeInserter.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeInserter.java
index e8ccd25..6906fb2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeInserter.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeInserter.java
@@ -17,7 +17,6 @@
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.gerrit.reviewdb.client.Change.INITIAL_PATCH_SET_ID;
-
import static java.util.stream.Collectors.toSet;
import com.google.common.base.MoreObjects;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
index 9bd5e44..d8078ca 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
@@ -34,7 +34,6 @@
import static com.google.gerrit.extensions.client.ListChangesOption.REVIEWER_UPDATES;
import static com.google.gerrit.extensions.client.ListChangesOption.WEB_LINKS;
import static com.google.gerrit.server.CommonConverters.toGitPerson;
-
import static java.util.stream.Collectors.toList;
import com.google.auto.value.AutoValue;
@@ -1056,6 +1055,7 @@
if (has(ALL_FILES) || (out.isCurrent && has(CURRENT_FILES))) {
out.files = fileInfoJson.toFileInfoMap(c, in);
out.files.remove(Patch.COMMIT_MSG);
+ out.files.remove(Patch.MERGE_LIST);
}
if ((out.isCurrent || (out.draft != null && out.draft))
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/CreateDraftComment.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/CreateDraftComment.java
index 7cb2aac..1af87b3 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/CreateDraftComment.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/CreateDraftComment.java
@@ -15,7 +15,6 @@
package com.google.gerrit.server.change;
import static com.google.gerrit.server.PatchLineCommentsUtil.setCommentRevId;
-import static com.google.gerrit.server.change.PutDraftComment.side;
import com.google.common.base.Strings;
import com.google.gerrit.common.TimeUtil;
@@ -119,7 +118,7 @@
ChangeUtil.messageUUID(ctx.getDb())),
line, ctx.getAccountId(), Url.decode(in.inReplyTo),
ctx.getWhen());
- comment.setSide(side(in));
+ comment.setSide(in.side());
comment.setMessage(in.message.trim());
comment.setRange(in.range);
comment.setTag(in.tag);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteReviewer.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteReviewer.java
index 1f78d54..099f8e0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteReviewer.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteReviewer.java
@@ -228,7 +228,8 @@
approvalsUtil.byChange(ctx.getDb(), ctx.getNotes()).values();
}
- return Iterables.filter(approvals, accountId::equals);
+ return Iterables.filter(
+ approvals, psa -> accountId.equals(psa.getAccountId()));
}
private String formatLabelValue(short value) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/FileContentUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/FileContentUtil.java
index d145ddf..d617a70 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/FileContentUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/FileContentUtil.java
@@ -54,6 +54,7 @@
@Singleton
public class FileContentUtil {
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_GITLINK = "x-git/gitlink";
private static final int MAX_SIZE = 5 << 20;
@@ -264,6 +265,9 @@
if (Patch.COMMIT_MSG.equals(path)) {
return TEXT_X_GERRIT_COMMIT_MESSAGE;
}
+ if (Patch.MERGE_LIST.equals(path)) {
+ return TEXT_X_GERRIT_MERGE_LIST;
+ }
if (project != null) {
for (ProjectState p : project.tree()) {
String t = p.getConfig().getMimeTypes().getMimeType(path);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetContent.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetContent.java
index 5a546f3..c7044e1 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetContent.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetContent.java
@@ -24,6 +24,8 @@
import com.google.gerrit.server.PatchSetUtil;
import com.google.gerrit.server.git.GitRepositoryManager;
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.gwtorm.server.OrmException;
import com.google.inject.Inject;
@@ -68,6 +70,12 @@
return BinaryResult.create(msg)
.setContentType(FileContentUtil.TEXT_X_GERRIT_COMMIT_MESSAGE)
.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(
rsrc.getRevision().getControl().getProjectControl().getProjectState(),
@@ -92,4 +100,22 @@
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);
+ }
+ }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetMergeList.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetMergeList.java
index 4e94935..b15810c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetMergeList.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetMergeList.java
@@ -22,6 +22,7 @@
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.patch.MergeListBuilder;
import com.google.inject.Inject;
import org.eclipse.jgit.lib.ObjectId;
@@ -46,7 +47,8 @@
private boolean addLinks;
@Inject
- GetMergeList(GitRepositoryManager repoManager, ChangeJson.Factory json) {
+ GetMergeList(GitRepositoryManager repoManager,
+ ChangeJson.Factory json) {
this.repoManager = repoManager;
this.json = json;
}
@@ -62,7 +64,6 @@
@Override
public Response<List<CommitInfo>> apply(RevisionResource rsrc)
throws BadRequestException, IOException {
- List<CommitInfo> result = new ArrayList<>();
Project.NameKey p = rsrc.getChange().getProject();
try (Repository repo = repoManager.openRepository(p);
RevWalk rw = new RevWalk(repo)) {
@@ -76,26 +77,22 @@
}
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);
- RevCommit c;
- while ((c = rw.next()) != null) {
- CommitInfo info =
- changeJson.toCommit(rsrc.getControl(), rw, c, addLinks, true);
- result.add(info);
+ for (RevCommit c : commits) {
+ result.add(changeJson.toCommit(rsrc.getControl(), rw, c, addLinks, true));
}
+ return createResponse(rsrc, result);
}
+ }
+ private static Response<List<CommitInfo>> createResponse(
+ RevisionResource rsrc, List<CommitInfo> result) {
Response<List<CommitInfo>> r = Response.ok(result);
if (rsrc.isCacheable()) {
r.caching(CacheControl.PRIVATE(7, TimeUnit.DAYS));
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReview.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReview.java
index 3828041..d6819ba 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReview.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReview.java
@@ -17,7 +17,6 @@
import static com.google.common.base.MoreObjects.firstNonNull;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.gerrit.server.PatchLineCommentsUtil.setCommentRevId;
-import static com.google.gerrit.server.change.PutDraftComment.side;
import static com.google.gerrit.server.notedb.ReviewerStateInternal.REVIEWER;
import static java.nio.charset.StandardCharsets.UTF_8;
import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
@@ -324,11 +323,19 @@
while (mapItr.hasNext()) {
Map.Entry<String, List<CommentInput>> ent = mapItr.next();
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(
"file %s not found in revision %s",
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();
if (list == null) {
@@ -476,7 +483,7 @@
}
e.setStatus(PatchLineComment.Status.PUBLISHED);
e.setWrittenOn(ctx.getWhen());
- e.setSide(side(c));
+ e.setSide(c.side());
setCommentRevId(e, patchListCache, ctx.getChange(), ps);
e.setMessage(c.message);
e.setTag(in.tag);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/PutDraftComment.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/PutDraftComment.java
index 655e07d..e817d93 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/PutDraftComment.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/PutDraftComment.java
@@ -19,8 +19,6 @@
import com.google.common.base.Optional;
import com.google.gerrit.common.TimeUtil;
import com.google.gerrit.extensions.api.changes.DraftInput;
-import com.google.gerrit.extensions.client.Comment;
-import com.google.gerrit.extensions.client.Side;
import com.google.gerrit.extensions.common.CommentInfo;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
@@ -164,7 +162,7 @@
private static PatchLineComment update(PatchLineComment e, DraftInput in,
Timestamp when) {
if (in.side != null) {
- e.setSide(side(in));
+ e.setSide(in.side());
}
if (in.inReplyTo != null) {
e.setParentUuid(Url.decode(in.inReplyTo));
@@ -181,11 +179,4 @@
}
return e;
}
-
- static short side(Comment c) {
- if (c.side == Side.PARENT) {
- return (short) (c.parent == null ? 0 : -c.parent.shortValue());
- }
- return 1;
- }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/SubmittedTogether.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/SubmittedTogether.java
index 351ebf9..908929a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/SubmittedTogether.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/SubmittedTogether.java
@@ -14,6 +14,8 @@
package com.google.gerrit.server.change;
+import static com.google.gerrit.extensions.api.changes.SubmittedTogetherOption.NON_VISIBLE_CHANGES;
+
import com.google.gerrit.extensions.api.changes.SubmittedTogetherInfo;
import com.google.gerrit.extensions.api.changes.SubmittedTogetherOption;
import com.google.gerrit.extensions.client.ChangeStatus;
@@ -32,7 +34,6 @@
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
-import com.google.inject.Singleton;
import org.kohsuke.args4j.Option;
import org.slf4j.Logger;
@@ -44,13 +45,17 @@
import java.util.EnumSet;
import java.util.List;
-@Singleton
public class SubmittedTogether implements RestReadView<ChangeResource> {
private static final Logger log = LoggerFactory.getLogger(
SubmittedTogether.class);
private final EnumSet<SubmittedTogetherOption> options =
EnumSet.noneOf(SubmittedTogetherOption.class);
+
+ private final EnumSet<ListChangesOption> jsonOpt = EnumSet.of(
+ ListChangesOption.CURRENT_REVISION,
+ ListChangesOption.CURRENT_COMMIT);
+
private final ChangeJson.Factory json;
private final Provider<ReviewDb> dbProvider;
private final Provider<InternalChangeQuery> queryProvider;
@@ -58,8 +63,22 @@
private final Provider<WalkSorter> sorter;
@Option(name = "-o", usage = "Output options")
- void addOption(SubmittedTogetherOption o) {
- options.add(o);
+ void addOption(String option) {
+ for (ListChangesOption o : ListChangesOption.values()) {
+ if (o.name().equalsIgnoreCase(option)) {
+ jsonOpt.add(o);
+ return;
+ }
+ }
+
+ for (SubmittedTogetherOption o : SubmittedTogetherOption.values()) {
+ if (o.name().equalsIgnoreCase(option)) {
+ options.add(o);
+ return;
+ }
+ }
+
+ throw new IllegalArgumentException("option not recognized: " + option);
}
@Inject
@@ -75,19 +94,29 @@
this.sorter = sorter;
}
+ public SubmittedTogether addListChangesOption(EnumSet<ListChangesOption> o) {
+ jsonOpt.addAll(o);
+ return this;
+ }
+
+ public SubmittedTogether addSubmittedTogetherOption(
+ EnumSet<SubmittedTogetherOption> o) {
+ options.addAll(o);
+ return this;
+ }
+
@Override
public Object apply(ChangeResource resource)
throws AuthException, BadRequestException,
ResourceConflictException, IOException, OrmException {
- SubmittedTogetherInfo info = apply(resource, options);
+ SubmittedTogetherInfo info = applyInfo(resource);
if (options.isEmpty()) {
return info.changes;
}
return info;
}
- public SubmittedTogetherInfo apply(ChangeResource resource,
- EnumSet<SubmittedTogetherOption> options)
+ public SubmittedTogetherInfo applyInfo(ChangeResource resource)
throws AuthException, IOException, OrmException {
Change c = resource.getChange();
try {
@@ -109,7 +138,7 @@
}
if (hidden != 0
- && !options.contains(SubmittedTogetherOption.NON_VISIBLE_CHANGES)) {
+ && !options.contains(NON_VISIBLE_CHANGES)) {
throw new AuthException(
"change would be submitted with a change that you cannot see");
}
@@ -123,9 +152,7 @@
}
SubmittedTogetherInfo info = new SubmittedTogetherInfo();
- info.changes = json.create(EnumSet.of(
- ListChangesOption.CURRENT_REVISION,
- ListChangesOption.CURRENT_COMMIT))
+ info.changes = json.create(jsonOpt)
.includeSubmittable(true)
.formatChangeDatas(cds);
info.nonVisibleChanges = hidden;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/events/EventFactory.java b/gerrit-server/src/main/java/com/google/gerrit/server/events/EventFactory.java
index 676f9ff..44b5979 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/events/EventFactory.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/events/EventFactory.java
@@ -63,6 +63,14 @@
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
+
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import java.io.IOException;
import java.sql.Timestamp;
import java.util.ArrayList;
@@ -71,12 +79,6 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
-import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.PersonIdent;
-import org.eclipse.jgit.revwalk.RevCommit;
-import org.eclipse.jgit.revwalk.RevWalk;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
@Singleton
public class EventFactory {
@@ -496,7 +498,7 @@
List<Patch> list =
patchListCache.get(change, patchSet).toPatchList(pId);
for (Patch pe : list) {
- if (!Patch.COMMIT_MSG.equals(pe.getFileName())) {
+ if (!Patch.isMagic(pe.getFileName())) {
p.sizeDeletions -= pe.getDeletions();
p.sizeInsertions += pe.getInsertions();
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/SubmitStrategyOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/SubmitStrategyOp.java
index f917ba1..b35de7b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/SubmitStrategyOp.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/SubmitStrategyOp.java
@@ -50,6 +50,15 @@
import com.google.gerrit.server.notedb.ChangeUpdate;
import com.google.gerrit.server.project.ProjectState;
import com.google.gwtorm.server.OrmException;
+
+import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.transport.ReceiveCommand;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
@@ -58,13 +67,6 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
-import org.eclipse.jgit.errors.IncorrectObjectTypeException;
-import org.eclipse.jgit.errors.MissingObjectException;
-import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.Ref;
-import org.eclipse.jgit.transport.ReceiveCommand;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
abstract class SubmitStrategyOp extends BatchUpdate.Op {
private static final Logger log =
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ChangeField.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ChangeField.java
index c9706a5..0369695 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ChangeField.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ChangeField.java
@@ -15,7 +15,6 @@
package com.google.gerrit.server.index.change;
import static com.google.common.base.MoreObjects.firstNonNull;
-
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.stream.Collectors.toSet;
@@ -75,6 +74,8 @@
* characters.
*/
public class ChangeField {
+ public static final int NO_ASSIGNEE = -1;
+
/** Legacy change ID. */
public static final FieldDef<ChangeData, Integer> LEGACY_ID =
new FieldDef.Single<ChangeData, Integer>("legacy_id",
@@ -315,6 +316,18 @@
}
};
+ /** The user assigned to the change. */
+ public static final FieldDef<ChangeData, Integer> ASSIGNEE =
+ new FieldDef.Single<ChangeData, Integer>(
+ ChangeQueryBuilder.FIELD_ASSIGNEE, FieldType.INTEGER, true) {
+ @Override
+ public Integer get(ChangeData input, FillArgs args)
+ throws OrmException {
+ Account.Id id = input.assignee();
+ return id != null ? id.get() : NO_ASSIGNEE;
+ }
+ };
+
/** Reviewer(s) associated with the change. */
public static final FieldDef<ChangeData, Iterable<String>> REVIEWER =
new FieldDef.Repeatable<ChangeData, String>(
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ChangeSchemaDefinitions.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ChangeSchemaDefinitions.java
index c98d311..1ffc39c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ChangeSchemaDefinitions.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ChangeSchemaDefinitions.java
@@ -81,13 +81,17 @@
.remove(ChangeField.STARREDBY)
.build();
- @SuppressWarnings("deprecation")
+ @Deprecated
static final Schema<ChangeData> V32 = new Schema.Builder<ChangeData>()
.add(V31)
.remove(ChangeField.LEGACY_REVIEWER)
.add(ChangeField.REVIEWER)
.build();
+ @SuppressWarnings("deprecation")
+ static final Schema<ChangeData> V33 =
+ schema(V32, ChangeField.ASSIGNEE);
+
public static final String NAME = "changes";
public static final ChangeSchemaDefinitions INSTANCE =
new ChangeSchemaDefinitions();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ChangeEmail.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ChangeEmail.java
index cbd2ec9..df0f018 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ChangeEmail.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ChangeEmail.java
@@ -259,7 +259,7 @@
detail.append("---\n");
PatchList patchList = getPatchList();
for (PatchListEntry p : patchList.getPatches()) {
- if (Patch.COMMIT_MSG.equals(p.getNewName())) {
+ if (Patch.isMagic(p.getNewName())) {
continue;
}
detail.append(p.getChangeType().getCode())
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/CommentSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/CommentSender.java
index 2424a6d..c4b6869 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/CommentSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/CommentSender.java
@@ -75,7 +75,7 @@
Set<String> paths = new HashSet<>();
for (PatchLineComment c : plc) {
Patch.Key p = c.getKey().getParentKey();
- if (!Patch.COMMIT_MSG.equals(p.getFileName())) {
+ if (!Patch.isMagic(p.getFileName())) {
paths.add(p.getFileName());
}
}
@@ -137,6 +137,8 @@
}
if (Patch.COMMIT_MSG.equals(pk.get())) {
cmts.append("Commit Message:\n\n");
+ } else if (Patch.MERGE_LIST.equals(pk.get())) {
+ cmts.append("Merge List:\n\n");
} else {
cmts.append("File ").append(pk.get()).append(":\n\n");
}
@@ -144,8 +146,7 @@
if (patchList != null) {
try {
- currentFileData =
- new PatchFile(repo, patchList, pk.get());
+ currentFileData = new PatchFile(repo, patchList, pk.get());
} catch (IOException e) {
log.warn(String.format(
"Cannot load %s from %s in %s",
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeBundle.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeBundle.java
index 00726ba..fd931f5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeBundle.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeBundle.java
@@ -624,17 +624,31 @@
List<String> tempDiffs = new ArrayList<>();
String temp = "temp";
+ // ReviewDb allows timestamps before patch set was created, but NoteDb
+ // truncates this to the patch set creation timestamp.
+ Timestamp ta = a.getWrittenOn();
+ Timestamp tb = b.getWrittenOn();
+ PatchSet psa = bundleA.patchSets.get(a.getPatchSetId());
+ PatchSet psb = bundleB.patchSets.get(b.getPatchSetId());
boolean excludePatchSet = false;
+ boolean excludeWrittenOn = false;
if (bundleA.source == REVIEW_DB && bundleB.source == NOTE_DB) {
excludePatchSet = a.getPatchSetId() == null;
+ excludeWrittenOn = psa != null && psb != null
+ && ta.before(psa.getCreatedOn()) && tb.equals(psb.getCreatedOn());
} else if (bundleA.source == NOTE_DB && bundleB.source == REVIEW_DB) {
excludePatchSet = b.getPatchSetId() == null;
+ excludeWrittenOn = psa != null && psb != null
+ && tb.before(psb.getCreatedOn()) && ta.equals(psa.getCreatedOn());
}
List<String> exclude = Lists.newArrayList("key");
if (excludePatchSet) {
exclude.add("patchset");
}
+ if (excludeWrittenOn) {
+ exclude.add("writtenOn");
+ }
diffColumnsExcluding(
tempDiffs, ChangeMessage.class, temp, bundleA, a, bundleB, b, exclude);
@@ -673,7 +687,28 @@
PatchSetApproval a = as.get(k);
PatchSetApproval b = bs.get(k);
String desc = describe(k);
- diffColumns(diffs, PatchSetApproval.class, desc, bundleA, a, bundleB, b);
+
+ // ReviewDb allows timestamps before patch set was created, but NoteDb
+ // truncates this to the patch set creation timestamp.
+ Timestamp ta = a.getGranted();
+ Timestamp tb = b.getGranted();
+ PatchSet psa = checkNotNull(bundleA.patchSets.get(a.getPatchSetId()));
+ PatchSet psb = checkNotNull(bundleB.patchSets.get(b.getPatchSetId()));
+ boolean excludeGranted = false;
+ List<String> exclude = new ArrayList<>(1);
+ if (bundleA.source == REVIEW_DB && bundleB.source == NOTE_DB) {
+ excludeGranted =
+ ta.before(psa.getCreatedOn()) && tb.equals(psb.getCreatedOn());
+ } else if (bundleA.source == NOTE_DB && bundleB.source == REVIEW_DB) {
+ excludeGranted =
+ tb.before(psb.getCreatedOn()) && ta.equals(psa.getCreatedOn());
+ }
+ if (excludeGranted) {
+ exclude.add("granted");
+ }
+
+ diffColumnsExcluding(
+ diffs, PatchSetApproval.class, desc, bundleA, a, bundleB, b, exclude);
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/RevisionNote.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/RevisionNote.java
index d93336a3..4c9f702 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/RevisionNote.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/RevisionNote.java
@@ -83,7 +83,7 @@
if (isJson(raw, p.value)) {
RevisionNoteData data = parseJson(noteUtil, p.value);
- comments = data.exportComments(status);
+ comments = data.exportComments(changeId, status);
if (status == PatchLineComment.Status.PUBLISHED) {
pushCert = data.pushCert;
} else {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/RevisionNoteData.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/RevisionNoteData.java
index 8d020bdb..73083b7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/RevisionNoteData.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/RevisionNoteData.java
@@ -48,19 +48,17 @@
String uuid;
String filename;
int patchSetId;
- int changeId;
CommentKey(PatchLineComment.Key k) {
uuid = k.get();
filename = k.getParentKey().getFileName();
patchSetId = k.getParentKey().getParentKey().get();
- changeId = k.getParentKey().getParentKey().getParentKey().get();
}
- PatchLineComment.Key export() {
+ PatchLineComment.Key export(Change.Id changeId) {
return new PatchLineComment.Key(
new Patch.Key(
- new PatchSet.Id(new Change.Id(changeId), patchSetId),
+ new PatchSet.Id(changeId, patchSetId),
filename),
uuid);
}
@@ -90,7 +88,6 @@
int lineNbr;
Identity author;
Timestamp writtenOn;
- char status;
short side;
String message;
String parentUuid;
@@ -104,7 +101,6 @@
lineNbr = plc.getLine();
author = new Identity(plc.getAuthor());
writtenOn = plc.getWrittenOn();
- status = plc.getStatus().getCode();
side = plc.getSide();
message = plc.getMessage();
parentUuid = plc.getParentUuid();
@@ -114,17 +110,18 @@
this.serverId = serverId;
}
- PatchLineComment export() {
+ PatchLineComment export(Change.Id changeId,
+ PatchLineComment.Status status) {
PatchLineComment plc = new PatchLineComment(
- key.export(), lineNbr, author.export(), parentUuid, writtenOn);
+ key.export(changeId), lineNbr, author.export(), parentUuid, writtenOn);
plc.setSide(side);
- plc.setStatus(PatchLineComment.Status.forCode(status));
plc.setMessage(message);
if (range != null) {
plc.setRange(range.export());
}
plc.setTag(tag);
plc.setRevId(new RevId(revId));
+ plc.setStatus(status);
return plc;
}
}
@@ -133,16 +130,12 @@
String pushCert;
List<Comment> comments;
- ImmutableList<PatchLineComment> exportComments(
+
+ ImmutableList<PatchLineComment> exportComments(Change.Id changeId,
PatchLineComment.Status status) {
return ImmutableList.copyOf(
comments.stream()
- .map(
- c -> {
- PatchLineComment plc = c.export();
- plc.setStatus(status);
- return plc;
- })
+ .map(c -> c.export(changeId, status))
.collect(toList()));
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/rebuild/ChangeMessageEvent.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/rebuild/ChangeMessageEvent.java
index a990e19..bc8af82 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/rebuild/ChangeMessageEvent.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/rebuild/ChangeMessageEvent.java
@@ -31,11 +31,6 @@
private static final Pattern TOPIC_REMOVED_REGEXP =
Pattern.compile("^Topic (.+) removed$");
- private static final Pattern STATUS_ABANDONED_REGEXP =
- Pattern.compile("^Abandoned(\n.*)*$");
- private static final Pattern STATUS_RESTORED_REGEXP =
- Pattern.compile("^Restored(\n.*)*$");
-
private final ChangeMessage message;
private final Change noteDbChange;
@@ -57,7 +52,6 @@
checkUpdate(update);
update.setChangeMessage(message.getMessage());
setTopic(update);
- setStatus(update);
}
private void setTopic(ChangeUpdate update) {
@@ -86,21 +80,4 @@
noteDbChange.setTopic(null);
}
}
-
- private void setStatus(ChangeUpdate update) {
- String msg = message.getMessage();
- if (msg == null) {
- return;
- }
- if (STATUS_ABANDONED_REGEXP.matcher(msg).matches()) {
- update.setStatus(Change.Status.ABANDONED);
- noteDbChange.setStatus(Change.Status.ABANDONED);
- return;
- }
-
- if (STATUS_RESTORED_REGEXP.matcher(msg).matches()) {
- update.setStatus(Change.Status.NEW);
- noteDbChange.setStatus(Change.Status.NEW);
- }
- }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/rebuild/ChangeRebuilderImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/rebuild/ChangeRebuilderImpl.java
index 3389e2b..3d240c6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/rebuild/ChangeRebuilderImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/rebuild/ChangeRebuilderImpl.java
@@ -20,7 +20,6 @@
import static com.google.gerrit.reviewdb.client.RefNames.changeMetaRef;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_HASHTAGS;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_PATCH_SET;
-
import static java.util.concurrent.TimeUnit.SECONDS;
import static java.util.stream.Collectors.toList;
@@ -29,6 +28,7 @@
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Ordering;
import com.google.common.collect.Sets;
@@ -92,6 +92,7 @@
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Set;
@@ -309,8 +310,8 @@
deleteDraftRefs(change, manager.getAllUsersRepo());
Integer minPsNum = getMinPatchSetNum(bundle);
- Set<PatchSet.Id> psIds =
- Sets.newHashSetWithExpectedSize(bundle.getPatchSets().size());
+ Map<PatchSet.Id, PatchSetEvent> patchSetEvents =
+ Maps.newHashMapWithExpectedSize(bundle.getPatchSets().size());
for (PatchSet ps : bundle.getPatchSets()) {
if (ps.getId().get() > currPsId.get()) {
@@ -319,14 +320,15 @@
ps.getId(), currPsId);
continue;
}
- psIds.add(ps.getId());
- events.add(new PatchSetEvent(
- change, ps, manager.getChangeRepo().rw));
+ PatchSetEvent pse =
+ new PatchSetEvent(change, ps, manager.getChangeRepo().rw);
+ patchSetEvents.put(ps.getId(), pse);
+ events.add(pse);
for (PatchLineComment c : getPatchLineComments(bundle, ps)) {
PatchLineCommentEvent e =
new PatchLineCommentEvent(c, change, ps, patchListCache);
if (c.getStatus() == Status.PUBLISHED) {
- events.add(e);
+ events.add(e.addDep(pse));
} else {
draftCommentEvents.put(c.getAuthor(), e);
}
@@ -334,8 +336,9 @@
}
for (PatchSetApproval psa : bundle.getPatchSetApprovals()) {
- if (psIds.contains(psa.getPatchSetId())) {
- events.add(new ApprovalEvent(psa, change.getCreatedOn()));
+ PatchSetEvent pse = patchSetEvents.get(psa.getPatchSetId());
+ if (pse != null) {
+ events.add(new ApprovalEvent(psa, change.getCreatedOn()).addDep(pse));
}
}
@@ -346,10 +349,16 @@
Change noteDbChange = new Change(null, null, null, null, null);
for (ChangeMessage msg : bundle.getChangeMessages()) {
- if (msg.getPatchSetId() == null || psIds.contains(msg.getPatchSetId())) {
- events.add(
- new ChangeMessageEvent(msg, noteDbChange, change.getCreatedOn()));
+ List<Event> msgEvents = parseChangeMessage(msg, change, noteDbChange);
+ if (msg.getPatchSetId() != null) {
+ PatchSetEvent pse = patchSetEvents.get(msg.getPatchSetId());
+ if (pse != null) {
+ for (Event e : msgEvents) {
+ e.addDep(pse);
+ }
+ }
}
+ events.addAll(msgEvents);
}
sortAndFillEvents(change, noteDbChange, events, minPsNum);
@@ -378,6 +387,18 @@
}
}
+ private List<Event> parseChangeMessage(ChangeMessage msg, Change change,
+ Change noteDbChange) {
+ List<Event> events = new ArrayList<>(2);
+ events.add(new ChangeMessageEvent(msg, noteDbChange, change.getCreatedOn()));
+ Optional<StatusChangeEvent> sce =
+ StatusChangeEvent.parseFromMessage(msg, change, noteDbChange);
+ if (sce.isPresent()) {
+ events.add(sce.get());
+ }
+ return events;
+ }
+
private static Integer getMinPatchSetNum(ChangeBundle bundle) {
Integer minPsNum = null;
for (PatchSet ps : bundle.getPatchSets()) {
@@ -399,8 +420,8 @@
private void sortAndFillEvents(Change change, Change noteDbChange,
List<Event> events, Integer minPsNum) {
- new EventSorter(events).sort();
events.add(new FinalUpdatesEvent(change, noteDbChange));
+ new EventSorter(events).sort();
// Ensure the first event in the list creates the change, setting the author
// and any required footers.
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/rebuild/Event.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/rebuild/Event.java
index a72e4fa..b7b08b0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/rebuild/Event.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/rebuild/Event.java
@@ -66,8 +66,9 @@
who, update.getNullableAccountId());
}
- void addDep(Event e) {
+ Event addDep(Event e) {
deps.add(e);
+ return this;
}
/**
@@ -78,10 +79,6 @@
abstract void apply(ChangeUpdate update) throws OrmException, IOException;
- protected boolean isPatchSet() {
- return false;
- }
-
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
@@ -94,6 +91,7 @@
@Override
public int compareTo(Event other) {
return ComparisonChain.start()
+ .compareFalseFirst(this.isFinalUpdates(), other.isFinalUpdates())
.compare(this.when, other.when)
.compareTrueFirst(isPatchSet(), isPatchSet())
.compareTrueFirst(this.predatesChange, other.predatesChange)
@@ -102,4 +100,12 @@
ReviewDbUtil.intKeyOrdering().nullsLast())
.result();
}
+
+ private boolean isPatchSet() {
+ return this instanceof PatchSetEvent;
+ }
+
+ private boolean isFinalUpdates() {
+ return this instanceof FinalUpdatesEvent;
+ }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/rebuild/FinalUpdatesEvent.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/rebuild/FinalUpdatesEvent.java
index 3080be7..4e82635 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/rebuild/FinalUpdatesEvent.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/rebuild/FinalUpdatesEvent.java
@@ -46,7 +46,8 @@
// TODO(dborowitz): Stamp approximate approvals at this time.
update.fixStatus(change.getStatus());
}
- if (change.getSubmissionId() != null) {
+ if (change.getSubmissionId() != null
+ && noteDbChange.getSubmissionId() == null) {
update.setSubmissionId(change.getSubmissionId());
}
if (!update.isEmpty()) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/rebuild/PatchSetEvent.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/rebuild/PatchSetEvent.java
index 5baddd3..c3fb267 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/rebuild/PatchSetEvent.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/rebuild/PatchSetEvent.java
@@ -66,11 +66,6 @@
}
}
- @Override
- protected boolean isPatchSet() {
- return true;
- }
-
private void setRevision(ChangeUpdate update, PatchSet ps)
throws IOException {
String rev = ps.getRevision().get();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/rebuild/StatusChangeEvent.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/rebuild/StatusChangeEvent.java
new file mode 100644
index 0000000..29e0868
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/rebuild/StatusChangeEvent.java
@@ -0,0 +1,90 @@
+// 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.notedb.rebuild;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableMap;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.ChangeMessage;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.server.notedb.ChangeUpdate;
+import com.google.gwtorm.server.OrmException;
+
+import java.sql.Timestamp;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+class StatusChangeEvent extends Event {
+ private static final ImmutableMap<Change.Status, Pattern> PATTERNS =
+ ImmutableMap.of(
+ Change.Status.ABANDONED, Pattern.compile("^Abandoned(\n.*)*$"),
+ Change.Status.MERGED, Pattern.compile(
+ "^Change has been successfully"
+ + " (merged|cherry-picked|rebased|pushed).*$"),
+ Change.Status.NEW, Pattern.compile("^Restored(\n.*)*$"));
+
+ static Optional<StatusChangeEvent> parseFromMessage(ChangeMessage message,
+ Change change, Change noteDbChange) {
+ String msg = message.getMessage();
+ if (msg == null) {
+ return Optional.absent();
+ }
+ for (Map.Entry<Change.Status, Pattern> e : PATTERNS.entrySet()) {
+ if (e.getValue().matcher(msg).matches()) {
+ return Optional.of(new StatusChangeEvent(
+ message, change, noteDbChange, e.getKey()));
+ }
+ }
+ return Optional.absent();
+ }
+
+ private final Change change;
+ private final Change noteDbChange;
+ private final Change.Status status;
+
+ private StatusChangeEvent(ChangeMessage message, Change change,
+ Change noteDbChange, Change.Status status) {
+ this(message.getPatchSetId(), message.getAuthor(),
+ message.getWrittenOn(), change, noteDbChange, message.getTag(),
+ status);
+ }
+
+ private StatusChangeEvent(PatchSet.Id psId, Account.Id author,
+ Timestamp when, Change change, Change noteDbChange,
+ String tag, Change.Status status) {
+ super(psId, author, when, change.getCreatedOn(), tag);
+ this.change = change;
+ this.noteDbChange = noteDbChange;
+ this.status = status;
+ }
+
+ @Override
+ boolean uniquePerUpdate() {
+ return true;
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ void apply(ChangeUpdate update) throws OrmException {
+ checkUpdate(update);
+ update.fixStatus(status);
+ noteDbChange.setStatus(status);
+ if (status == Change.Status.MERGED) {
+ update.setSubmissionId(change.getSubmissionId());
+ noteDbChange.setSubmissionId(change.getSubmissionId());
+ }
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/ComparisonType.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/ComparisonType.java
new file mode 100644
index 0000000..abbb680
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/ComparisonType.java
@@ -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);
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/MergeListBuilder.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/MergeListBuilder.java
new file mode 100644
index 0000000..8f54e48
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/MergeListBuilder.java
@@ -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;
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchFile.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchFile.java
index f8c8b49..d2a6d2b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchFile.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchFile.java
@@ -44,9 +44,8 @@
private Text a;
private Text b;
- public PatchFile(final Repository repo, final PatchList patchList,
- final String fileName) throws MissingObjectException,
- IncorrectObjectTypeException, IOException {
+ public PatchFile(Repository repo, PatchList patchList, String fileName)
+ throws MissingObjectException, IncorrectObjectTypeException, IOException {
this.repo = repo;
this.entry = patchList.get(fileName);
@@ -55,7 +54,7 @@
final RevCommit bCommit = rw.parseCommit(patchList.getNewId());
if (Patch.COMMIT_MSG.equals(fileName)) {
- if (patchList.isAgainstParent()) {
+ if (patchList.getComparisonType().isAgainstParentOrAutoMerge()) {
a = Text.EMPTY;
} else {
// For the initial commit, we have an empty tree on Side A
@@ -68,7 +67,16 @@
aTree = 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 {
if (patchList.getOldId() != null) {
aTree = rw.parseTree(patchList.getOldId());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchList.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchList.java
index 2a4afb3..2cfd007 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchList.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchList.java
@@ -58,16 +58,19 @@
@Nullable
private transient ObjectId oldId;
private transient ObjectId newId;
- private transient boolean againstParent;
+ private transient boolean isMerge;
+ private transient ComparisonType comparisonType;
private transient int insertions;
private transient int deletions;
private transient PatchListEntry[] patches;
- public PatchList(@Nullable final AnyObjectId oldId, final AnyObjectId newId,
- final boolean againstParent, final PatchListEntry[] patches) {
+ public PatchList(@Nullable AnyObjectId oldId, AnyObjectId newId,
+ boolean isMerge, ComparisonType comparisonType,
+ PatchListEntry[] patches) {
this.oldId = oldId != null ? oldId.copy() : null;
this.newId = newId.copy();
- this.againstParent = againstParent;
+ this.isMerge = isMerge;
+ this.comparisonType = comparisonType;
// We assume index 0 contains the magic commit message entry.
if (patches.length > 1) {
@@ -97,9 +100,9 @@
return Collections.unmodifiableList(Arrays.asList(patches));
}
- /** @return true if {@link #getOldId} is {@link #getNewId}'s ancestor. */
- public boolean isAgainstParent() {
- return againstParent;
+ /** @return the comparison type */
+ public ComparisonType getComparisonType() {
+ return comparisonType;
}
/** @return total number of new lines added. */
@@ -144,9 +147,12 @@
if (Patch.COMMIT_MSG.equals(fileName)) {
return 0;
}
+ if (isMerge && Patch.MERGE_LIST.equals(fileName)) {
+ return 1;
+ }
int high = patches.length;
- int low = 1;
+ int low = isMerge ? 2 : 1;
while (low < high) {
final int mid = (low + high) >>> 1;
final int cmp = patches[mid].getNewName().compareTo(fileName);
@@ -166,7 +172,8 @@
try (DeflaterOutputStream out = new DeflaterOutputStream(buf)) {
writeCanBeNull(out, oldId);
writeNotNull(out, newId);
- writeVarInt32(out, againstParent ? 1 : 0);
+ writeVarInt32(out, isMerge ? 1 : 0);
+ comparisonType.writeTo(out);
writeVarInt32(out, insertions);
writeVarInt32(out, deletions);
writeVarInt32(out, patches.length);
@@ -182,7 +189,8 @@
try (InflaterInputStream in = new InflaterInputStream(buf)) {
oldId = readCanBeNull(in);
newId = readNotNull(in);
- againstParent = readVarInt32(in) != 0;
+ isMerge = readVarInt32(in) != 0;
+ comparisonType = ComparisonType.readFrom(in);
insertions = readVarInt32(in);
deletions = readVarInt32(in);
final int cnt = readVarInt32(in);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListKey.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListKey.java
index 43e3dce..22f7bf3 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListKey.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListKey.java
@@ -35,7 +35,7 @@
import java.util.Objects;
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(
Whitespace.IGNORE_NONE, 'N',
@@ -138,6 +138,10 @@
n.append("..");
n.append(newId.name());
n.append(" ");
+ if (parentNum != null) {
+ n.append(parentNum);
+ n.append(" ");
+ }
n.append(whitespace.name());
n.append("]");
return n.toString();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListLoader.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListLoader.java
index 0ae9a99..9616fc8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListLoader.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListLoader.java
@@ -16,7 +16,6 @@
package com.google.gerrit.server.patch;
import static com.google.common.base.Preconditions.checkArgument;
-
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.stream.Collectors.toSet;
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
@@ -156,14 +155,19 @@
if (a == null) {
// 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);
- 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;
RevTree aTree = rw.parseTree(a);
@@ -190,7 +194,13 @@
int cnt = diffEntries.size();
List<PatchListEntry> entries = new ArrayList<>();
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++) {
DiffEntry e = diffEntries.get(i);
if (paths == null || paths.contains(e.getNewPath())
@@ -204,19 +214,23 @@
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()]));
}
}
- private boolean isAgainstParent(RevObject a, RevCommit b) {
+ private ComparisonType getComparisonType(RevObject a, RevCommit b) {
for (int i = 0; i < b.getParentCount(); i++) {
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,
@@ -278,32 +292,30 @@
return diffFormatter.toFileHeader(diffEntry);
}
- private PatchListEntry newCommitMessage(final RawTextComparator cmp,
- final ObjectReader reader,
- final RevCommit aCommit, final RevCommit bCommit) throws IOException {
- StringBuilder hdr = new StringBuilder();
-
- hdr.append("diff --git");
- 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;
+ private PatchListEntry newCommitMessage(RawTextComparator cmp,
+ ObjectReader reader, RevCommit aCommit, RevCommit bCommit)
+ throws IOException {
+ Text aText = aCommit != null
+ ? Text.forCommit(reader, aCommit)
+ : Text.EMPTY;
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[] bContent = bText.getContent();
long size = bContent.length;
@@ -315,6 +327,26 @@
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,
long size, long sizeDelta) {
if (aTree == null // want combined diff
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptBuilder.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptBuilder.java
index e09d26f..7eee6a3 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptBuilder.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptBuilder.java
@@ -66,7 +66,7 @@
private ObjectReader reader;
private Change change;
private DiffPreferencesInfo diffPrefs;
- private boolean againstParent;
+ private ComparisonType comparisonType;
private ObjectId aId;
private ObjectId bId;
@@ -79,7 +79,8 @@
private int context;
@Inject
- PatchScriptBuilder(final FileTypeRegistry ftr, final PatchListCache plc) {
+ PatchScriptBuilder(FileTypeRegistry ftr,
+ PatchListCache plc) {
a = new Side();
b = new Side();
registry = ftr;
@@ -106,8 +107,8 @@
}
}
- void setTrees(final boolean ap, final ObjectId a, final ObjectId b) {
- againstParent = ap;
+ void setTrees(final ComparisonType ct, final ObjectId a, final ObjectId b) {
+ comparisonType = ct;
aId = a;
bId = b;
}
@@ -435,7 +436,8 @@
try {
final boolean reuse;
if (Patch.COMMIT_MSG.equals(path)) {
- if (againstParent && (aId == within || within.equals(aId))) {
+ if (comparisonType.isAgainstParentOrAutoMerge()
+ && (aId == within || within.equals(aId))) {
id = ObjectId.zeroId();
src = Text.EMPTY;
srcContent = Text.NO_BYTES;
@@ -453,7 +455,26 @@
}
}
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 {
final TreeWalk tw = find(within);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptFactory.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptFactory.java
index 754d995..91f8cf8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptFactory.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptFactory.java
@@ -260,7 +260,7 @@
b.setRepository(git, project);
b.setChange(change);
b.setDiffPrefs(diffPrefs);
- b.setTrees(list.isAgainstParent(), list.getOldId(), list.getNewId());
+ b.setTrees(list.getComparisonType(), list.getOldId(), list.getNewId());
return b;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/Text.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/Text.java
index 7982479..a84dd92 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/Text.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/Text.java
@@ -87,6 +87,36 @@
}
}
+ 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,
PersonIdent person) {
if (person != null) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/FilesInCommitCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/FilesInCommitCollection.java
index 64a5fb2..0f44a48 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/FilesInCommitCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/FilesInCommitCollection.java
@@ -47,7 +47,7 @@
@Override
public FileResource parse(CommitResource parent, IdString id)
throws ResourceNotFoundException, IOException {
- if (Patch.COMMIT_MSG.equals(id.get())) {
+ if (Patch.isMagic(id.get())) {
return new FileResource(parent.getProject(), parent.getCommit(),
id.get());
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AssigneePredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AssigneePredicate.java
new file mode 100644
index 0000000..f8fa8c5
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AssigneePredicate.java
@@ -0,0 +1,41 @@
+// 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.query.change;
+
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.server.index.change.ChangeField;
+import com.google.gwtorm.server.OrmException;
+
+class AssigneePredicate extends ChangeIndexPredicate {
+ private final Account.Id id;
+
+ AssigneePredicate(Account.Id id) {
+ super(ChangeField.ASSIGNEE, id.toString());
+ this.id = id;
+ }
+
+ @Override
+ public boolean match(final ChangeData object) throws OrmException {
+ if (id.get() == ChangeField.NO_ASSIGNEE) {
+ return object.notes().load().getAssignee() == null;
+ }
+ return id.equals(object.notes().load().getAssignee());
+ }
+
+ @Override
+ public int getCost() {
+ return 1;
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java
index c4e8bd7..46d7e38 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java
@@ -345,6 +345,7 @@
private Optional<ChangedLines> changedLines;
private SubmitTypeRecord submitTypeRecord;
private Boolean mergeable;
+ private Account.Id assignee;
private Set<String> hashtags;
private Set<Account.Id> editsByUser;
private Set<Account.Id> reviewedBy;
@@ -599,7 +600,7 @@
r = new ArrayList<>(p.get().getPatches().size());
for (PatchListEntry e : p.get().getPatches()) {
- if (Patch.COMMIT_MSG.equals(e.getNewName())) {
+ if (Patch.isMagic(e.getNewName())) {
continue;
}
switch (e.getChangeType()) {
@@ -1162,6 +1163,16 @@
this.reviewedBy = reviewedBy;
}
+ public Account.Id assignee() throws OrmException {
+ if (assignee == null) {
+ if (!lazyLoad) {
+ return null;
+ }
+ assignee = notes().getAssignee();
+ }
+ return assignee;
+ }
+
public Set<String> hashtags() throws OrmException {
if (hashtags == null) {
if (!lazyLoad) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
index f697d15..d59b66c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
@@ -106,6 +106,7 @@
public static final String FIELD_ADDED = "added";
public static final String FIELD_AGE = "age";
+ public static final String FIELD_ASSIGNEE = "assignee";
public static final String FIELD_AUTHOR = "author";
public static final String FIELD_BEFORE = "before";
public static final String FIELD_CHANGE = "change";
@@ -477,6 +478,14 @@
return new IsMergeablePredicate(args.fillArgs);
}
+ if ("assigned".equalsIgnoreCase(value)) {
+ return Predicate.not(new AssigneePredicate(new Account.Id(ChangeField.NO_ASSIGNEE)));
+ }
+
+ if ("unassigned".equalsIgnoreCase(value)) {
+ return new AssigneePredicate(new Account.Id(ChangeField.NO_ASSIGNEE));
+ }
+
try {
return status(value);
} catch (IllegalArgumentException e) {
@@ -796,6 +805,20 @@
}
@Operator
+ public Predicate<ChangeData> assignee(String who) throws QueryParseException,
+ OrmException {
+ return assignee(parseAccount(who));
+ }
+
+ private Predicate<ChangeData> assignee(Set<Account.Id> who) {
+ List<AssigneePredicate> p = Lists.newArrayListWithCapacity(who.size());
+ for (Account.Id id : who) {
+ p.add(new AssigneePredicate(id));
+ }
+ return Predicate.or(p);
+ }
+
+ @Operator
public Predicate<ChangeData> ownerin(String group)
throws QueryParseException {
GroupReference g = GroupBackends.findBestSuggestion(args.groupBackend, group);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HasDraftByLegacyPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HasDraftByLegacyPredicate.java
index 45a00c6..d2f6876 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HasDraftByLegacyPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HasDraftByLegacyPredicate.java
@@ -16,7 +16,6 @@
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.reviewdb.client.PatchLineComment;
import com.google.gerrit.server.query.change.ChangeQueryBuilder.Arguments;
import com.google.gwtorm.server.ListResultSet;
import com.google.gwtorm.server.OrmException;
@@ -50,9 +49,9 @@
@Override
public ResultSet<ChangeData> read() throws OrmException {
Set<Change.Id> ids = new HashSet<>();
- for (PatchLineComment sc :
- args.plcUtil.draftByAuthor(args.db.get(), accountId)) {
- ids.add(sc.getKey().getParentKey().getParentKey().getParentKey());
+ for (Change.Id changeId : args.plcUtil
+ .changesWithDraftsByAuthor(args.db.get(), accountId)) {
+ ids.add(changeId);
}
List<ChangeData> r = new ArrayList<>(ids.size());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_130.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_130.java
index d7fcc3b..cee21bd 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_130.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_130.java
@@ -59,7 +59,7 @@
cfg.removeForceFromPermission("pushTag");
cfg.save(serverUser, COMMIT_MSG);
} catch (ConfigInvalidException | IOException ex) {
- throw new OrmException(ex);
+ throw new OrmException("Cannot migrate project " + projectName, ex);
}
}
}
diff --git a/gerrit-server/src/main/java/gerrit/PRED_commit_stats_3.java b/gerrit-server/src/main/java/gerrit/PRED_commit_stats_3.java
index 1dbdb68..a855868 100644
--- a/gerrit-server/src/main/java/gerrit/PRED_commit_stats_3.java
+++ b/gerrit-server/src/main/java/gerrit/PRED_commit_stats_3.java
@@ -14,8 +14,10 @@
package gerrit;
+import com.google.gerrit.reviewdb.client.Patch;
import com.google.gerrit.rules.StoredValues;
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.lang.IntegerTerm;
@@ -24,6 +26,8 @@
import com.googlecode.prolog_cafe.lang.Prolog;
import com.googlecode.prolog_cafe.lang.Term;
+import java.util.List;
+
/**
* Exports basic commit statistics.
*
@@ -48,7 +52,11 @@
Term a3 = arg3.dereference();
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();
}
if (!a2.unify(new IntegerTerm(pl.getInsertions()),engine.trail)) {
@@ -59,4 +67,14 @@
}
return cont;
}
+
+ private int countMagicFiles(List<PatchListEntry> entries) {
+ int count = 0;
+ for (PatchListEntry e : entries) {
+ if (Patch.isMagic(e.getNewName())) {
+ count++;
+ }
+ }
+ return count;
+ }
}
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/notedb/ChangeBundleTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/notedb/ChangeBundleTest.java
index 054a82b..97bf864 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/notedb/ChangeBundleTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/notedb/ChangeBundleTest.java
@@ -1260,7 +1260,9 @@
}
private static List<PatchSet> latest(Change c) {
- return ImmutableList.of(new PatchSet(c.currentPatchSetId()));
+ PatchSet ps = new PatchSet(c.currentPatchSetId());
+ ps.setCreatedOn(c.getLastUpdatedOn());
+ return ImmutableList.of(ps);
}
private static List<PatchSetApproval> approvals(PatchSetApproval... ents) {
diff --git a/lib/BUCK b/lib/BUCK
index bc4f40b..14ae9df 100644
--- a/lib/BUCK
+++ b/lib/BUCK
@@ -8,7 +8,7 @@
define_license(name = 'asciidoctor')
define_license(name = 'automaton')
define_license(name = 'bouncycastle')
-define_license(name = 'CC-BY3.0')
+define_license(name = 'CC-BY3.0-unported')
define_license(name = 'clippy')
define_license(name = 'codemirror-minified')
define_license(name = 'codemirror-original')
diff --git a/lib/BUILD b/lib/BUILD
index 44c293d..20fa126 100644
--- a/lib/BUILD
+++ b/lib/BUILD
@@ -1,6 +1,11 @@
+exports_files([
+ "LICENSE-DO_NOT_DISTRIBUTE"
+])
+
java_library(
name = 'servlet-api-3_1',
neverlink = 1,
+ data = [ ":LICENSE-Apache2.0" ],
exports = ['@servlet_api_3_1//jar'],
visibility = ['//visibility:public'],
)
@@ -75,6 +80,7 @@
name = 'jsch',
exports = ['@jsch//jar'],
visibility = ['//visibility:public'],
+ data = [ ":LICENSE-jsch" ],
)
java_library(
diff --git a/lib/JGIT_VERSION b/lib/JGIT_VERSION
index 5817fe8..b7f7c84 100644
--- a/lib/JGIT_VERSION
+++ b/lib/JGIT_VERSION
@@ -1,6 +1,6 @@
include_defs('//lib/maven.defs')
-REPO = GERRIT # Leave here even if set to MAVEN_CENTRAL.
-VERS = '4.4.1.201607150455-r.148-gabeaafc'
-DOC_VERS = '4.4.1.201607150455-r' # Set to VERS unless using a snapshot
+REPO = MAVEN_CENTRAL # Leave here even if set to MAVEN_CENTRAL.
+VERS = '4.5.0.201609210915-r'
+DOC_VERS = VERS # Set to VERS unless using a snapshot
JGIT_DOC_URL="http://download.eclipse.org/jgit/site/" + DOC_VERS + "/apidocs"
diff --git a/lib/LICENSE-CC-BY3.0 b/lib/LICENSE-CC-BY3.0-unported
similarity index 99%
rename from lib/LICENSE-CC-BY3.0
rename to lib/LICENSE-CC-BY3.0-unported
index 39dbc91..d2f2550 100644
--- a/lib/LICENSE-CC-BY3.0
+++ b/lib/LICENSE-CC-BY3.0-unported
@@ -1,4 +1,4 @@
-link:http://creativecommons.org/licenses/by/3.0/us/[CC-BY 3.0]
+link:http://creativecommons.org/licenses/by/3.0/[CC-BY 3.0]
THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS
CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS
diff --git a/lib/LICENSE-diffy b/lib/LICENSE-diffy
index 2b58536..e837a1a 100644
--- a/lib/LICENSE-diffy
+++ b/lib/LICENSE-diffy
@@ -1 +1 @@
-link:http://creativecommons.org/licenses/by/3.0/us/[CC-BY 3.0] (c) Sara Owens, inkylabs.com
+link:http://creativecommons.org/licenses/by/3.0/[CC-BY 3.0] (c) Sara Owens, inkylabs.com
diff --git a/lib/LICENSE-silk_icons b/lib/LICENSE-silk_icons
index 2b10dde..b7417f6 100644
--- a/lib/LICENSE-silk_icons
+++ b/lib/LICENSE-silk_icons
@@ -1 +1,338 @@
-link:http://creativecommons.org/licenses/by/3.0/us/[CC-BY 3.0] (c) Mark James, link:http://famfamfam.com/lab/icons/silk/[SILK ICONS]
+link:http://creativecommons.org/licenses/by/3.0/[CC-BY 3.0] (c) Mark James, link:http://famfamfam.com/lab/icons/silk/[SILK ICONS]
+
+As an author, I would appreciate a reference to my authorship of the Silk
+icon set contents within a readme file or equivalent documentation for
+the software which includes the set or a subset of the icons contained
+within.
+
+THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS
+CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS
+PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE
+WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS
+PROHIBITED.
+
+BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND
+AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS
+LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU
+THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH
+TERMS AND CONDITIONS.
+
+1. Definitions
+
+ a. "Adaptation" means a work based upon the Work, or upon the Work
+ and other pre-existing works, such as a translation, adaptation,
+ derivative work, arrangement of music or other alterations of a
+ literary or artistic work, or phonogram or performance and
+ includes cinematographic adaptations or any other form in which
+ the Work may be recast, transformed, or adapted including in any
+ form recognizably derived from the original, except that a work
+ that constitutes a Collection will not be considered an
+ Adaptation for the purpose of this License. For the avoidance
+ of doubt, where the Work is a musical work, performance or
+ phonogram, the synchronization of the Work in timed-relation
+ with a moving image ("synching") will be considered an
+ Adaptation for the purpose of this License.
+
+ b. "Collection" means a collection of literary or artistic works,
+ such as encyclopedias and anthologies, or performances,
+ phonograms or broadcasts, or other works or subject matter other
+ than works listed in Section 1(f) below, which, by reason of the
+ selection and arrangement of their contents, constitute
+ intellectual creations, in which the Work is included in its
+ entirety in unmodified form along with one or more other
+ contributions, each constituting separate and independent works
+ in themselves, which together are assembled into a collective
+ whole. A work that constitutes a Collection will not be
+ considered an Adaptation (as defined above) for the purposes of
+ this License.
+
+ c. "Distribute" means to make available to the public the original
+ and copies of the Work or Adaptation, as appropriate, through
+ sale or other transfer of ownership.
+
+ d. "Licensor" means the individual, individuals, entity or entities
+ that offer(s) the Work under the terms of this License.
+
+ e. "Original Author" means, in the case of a literary or artistic
+ work, the individual, individuals, entity or entities who
+ created the Work or if no individual or entity can be
+ identified, the publisher; and in addition (i) in the case of a
+ performance the actors, singers, musicians, dancers, and other
+ persons who act, sing, deliver, declaim, play in, interpret or
+ otherwise perform literary or artistic works or expressions of
+ folklore; (ii) in the case of a phonogram the producer being the
+ person or legal entity who first fixes the sounds of a
+ performance or other sounds; and, (iii) in the case of
+ broadcasts, the organization that transmits the broadcast.
+
+ f. "Work" means the literary and/or artistic work offered under the
+ terms of this License including without limitation any
+ production in the literary, scientific and artistic domain,
+ whatever may be the mode or form of its expression including
+ digital form, such as a book, pamphlet and other writing; a
+ lecture, address, sermon or other work of the same nature; a
+ dramatic or dramatico-musical work; a choreographic work or
+ entertainment in dumb show; a musical composition with or
+ without words; a cinematographic work to which are assimilated
+ works expressed by a process analogous to cinematography; a work
+ of drawing, painting, architecture, sculpture, engraving or
+ lithography; a photographic work to which are assimilated works
+ expressed by a process analogous to photography; a work of
+ applied art; an illustration, map, plan, sketch or
+ three-dimensional work relative to geography, topography,
+ architecture or science; a performance; a broadcast; a
+ phonogram; a compilation of data to the extent it is protected
+ as a copyrightable work; or a work performed by a variety or
+ circus performer to the extent it is not otherwise considered a
+ literary or artistic work.
+
+ g. "You" means an individual or entity exercising rights under this
+ License who has not previously violated the terms of this
+ License with respect to the Work, or who has received express
+ permission from the Licensor to exercise rights under this
+ License despite a previous violation.
+
+ h. "Publicly Perform" means to perform public recitations of the
+ Work and to communicate to the public those public recitations,
+ by any means or process, including by wire or wireless means or
+ public digital performances; to make available to the public
+ Works in such a way that members of the public may access these
+ Works from a place and at a place individually chosen by them;
+ to perform the Work to the public by any means or process and
+ the communication to the public of the performances of the Work,
+ including by public digital performance; to broadcast and
+ rebroadcast the Work by any means including signs, sounds or
+ images.
+
+ i. "Reproduce" means to make copies of the Work by any means
+ including without limitation by sound or visual recordings and
+ the right of fixation and reproducing fixations of the Work,
+ including storage of a protected performance or phonogram in
+ digital form or other electronic medium.
+
+2. Fair Dealing Rights. Nothing in this License is intended to
+ reduce, limit, or restrict any uses free from copyright or rights
+ arising from limitations or exceptions that are provided for in
+ connection with the copyright protection under copyright law or
+ other applicable laws.
+
+3. License Grant. Subject to the terms and conditions of this
+ License, Licensor hereby grants You a worldwide, royalty-free,
+ non-exclusive, perpetual (for the duration of the applicable
+ copyright) license to exercise the rights in the Work as stated
+ below:
+
+ a. to Reproduce the Work, to incorporate the Work into one or more
+ Collections, and to Reproduce the Work as incorporated in the
+ Collections;
+
+ b. to create and Reproduce Adaptations provided that any such
+ Adaptation, including any translation in any medium, takes
+ reasonable steps to clearly label, demarcate or otherwise
+ identify that changes were made to the original Work. For
+ example, a translation could be marked "The original work was
+ translated from English to Spanish," or a modification could
+ indicate "The original work has been modified.";
+
+ c. to Distribute and Publicly Perform the Work including as
+ incorporated in Collections; and,
+
+ d. to Distribute and Publicly Perform Adaptations.
+
+ e. For the avoidance of doubt:
+
+ i. Non-waivable Compulsory License Schemes. In those
+ jurisdictions in which the right to collect royalties
+ through any statutory or compulsory licensing scheme
+ cannot be waived, the Licensor reserves the exclusive
+ right to collect such royalties for any exercise by You
+ of the rights granted under this License;
+
+ ii. Waivable Compulsory License Schemes. In those jurisdictions
+ in which the right to collect royalties through any
+ statutory or compulsory licensing scheme can be waived,
+ the Licensor waives the exclusive right to collect such
+ royalties for any exercise by You of the rights granted
+ under this License; and,
+
+ iii. Voluntary License Schemes. The Licensor waives the right to
+ collect royalties, whether individually or, in the event
+ that the Licensor is a member of a collecting society
+ that administers voluntary licensing schemes, via that
+ society, from any exercise by You of the rights granted
+ under this License.
+
+The above rights may be exercised in all media and formats whether now
+known or hereafter devised. The above rights include the right to
+make such modifications as are technically necessary to exercise the
+rights in other media and formats. Subject to Section 8(f), all
+rights not expressly granted by Licensor are hereby reserved.
+
+4. Restrictions. The license granted in Section 3 above is expressly
+ made subject to and limited by the following restrictions:
+
+ a. You may Distribute or Publicly Perform the Work only under the
+ terms of this License. You must include a copy of, or the
+ Uniform Resource Identifier (URI) for, this License with every
+ copy of the Work You Distribute or Publicly Perform. You may
+ not offer or impose any terms on the Work that restrict the
+ terms of this License or the ability of the recipient of the
+ Work to exercise the rights granted to that recipient under the
+ terms of the License. You may not sublicense the Work. You
+ must keep intact all notices that refer to this License and to
+ the disclaimer of warranties with every copy of the Work You
+ Distribute or Publicly Perform. When You Distribute or Publicly
+ Perform the Work, You may not impose any effective technological
+ measures on the Work that restrict the ability of a recipient of
+ the Work from You to exercise the rights granted to that
+ recipient under the terms of the License. This Section 4(a)
+ applies to the Work as incorporated in a Collection, but this
+ does not require the Collection apart from the Work itself to be
+ made subject to the terms of this License. If You create a
+ Collection, upon notice from any Licensor You must, to the
+ extent practicable, remove from the Collection any credit as
+ required by Section 4(b), as requested. If You create an
+ Adaptation, upon notice from any Licensor You must, to the
+ extent practicable, remove from the Adaptation any credit as
+ required by Section 4(b), as requested.
+
+ b. If You Distribute, or Publicly Perform the Work or any
+ Adaptations or Collections, You must, unless a request has been
+ made pursuant to Section 4(a), keep intact all copyright notices
+ for the Work and provide, reasonable to the medium or means You
+ are utilizing: (i) the name of the Original Author (or
+ pseudonym, if applicable) if supplied, and/or if the Original
+ Author and/or Licensor designate another party or parties (e.g.,
+ a sponsor institute, publishing entity, journal) for attribution
+ ("Attribution Parties") in Licensor's copyright notice, terms of
+ service or by other reasonable means, the name of such party or
+ parties; (ii) the title of the Work if supplied; (iii) to the
+ extent reasonably practicable, the URI, if any, that Licensor
+ specifies to be associated with the Work, unless such URI does
+ not refer to the copyright notice or licensing information for
+ the Work; and (iv) , consistent with Section 3(b), in the case
+ of an Adaptation, a credit identifying the use of the Work in
+ the Adaptation (e.g., "French translation of the Work by
+ Original Author," or "Screenplay based on original Work by
+ Original Author"). The credit required by this Section 4 (b)
+ may be implemented in any reasonable manner; provided, however,
+ that in the case of a Adaptation or Collection, at a minimum
+ such credit will appear, if a credit for all contributing
+ authors of the Adaptation or Collection appears, then as part of
+ these credits and in a manner at least as prominent as the
+ credits for the other contributing authors. For the avoidance
+ of doubt, You may only use the credit required by this Section
+ for the purpose of attribution in the manner set out above and,
+ by exercising Your rights under this License, You may not
+ implicitly or explicitly assert or imply any connection with,
+ sponsorship or endorsement by the Original Author, Licensor
+ and/or Attribution Parties, as appropriate, of You or Your use
+ of the Work, without the separate, express prior written
+ permission of the Original Author, Licensor and/or Attribution
+ Parties.
+
+ c. Except as otherwise agreed in writing by the Licensor or as may
+ be otherwise permitted by applicable law, if You Reproduce,
+ Distribute or Publicly Perform the Work either by itself or as
+ part of any Adaptations or Collections, You must not distort,
+ mutilate, modify or take other derogatory action in relation to
+ the Work which would be prejudicial to the Original Author's
+ honor or reputation. Licensor agrees that in those
+ jurisdictions (e.g. Japan), in which any exercise of the right
+ granted in Section 3(b) of this License (the right to make
+ Adaptations) would be deemed to be a distortion, mutilation,
+ modification or other derogatory action prejudicial to the
+ Original Author's honor and reputation, the Licensor will waive
+ or not assert, as appropriate, this Section, to the fullest
+ extent permitted by the applicable national law, to enable You
+ to reasonably exercise Your right under Section 3(b) of this
+ License (right to make Adaptations) but not otherwise.
+
+5. Representations, Warranties and Disclaimer
+
+UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING,
+LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR
+WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED,
+STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF
+TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE,
+NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY,
+OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE.
+SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES,
+SO SUCH EXCLUSION MAY NOT APPLY TO YOU.
+
+6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY
+ APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY
+ LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE
+ OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE
+ WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGES.
+
+7. Termination
+
+ a. This License and the rights granted hereunder will terminate
+ automatically upon any breach by You of the terms of this
+ License. Individuals or entities who have received Adaptations
+ or Collections from You under this License, however, will not
+ have their licenses terminated provided such individuals or
+ entities remain in full compliance with those licenses.
+ Sections 1, 2, 5, 6, 7, and 8 will survive any termination of
+ this License.
+
+ b. Subject to the above terms and conditions, the license granted
+ here is perpetual (for the duration of the applicable copyright
+ in the Work). Notwithstanding the above, Licensor reserves the
+ right to release the Work under different license terms or to
+ stop distributing the Work at any time; provided, however that
+ any such election will not serve to withdraw this License (or
+ any other license that has been, or is required to be, granted
+ under the terms of this License), and this License will continue
+ in full force and effect unless terminated as stated above.
+
+8. Miscellaneous
+
+ a. Each time You Distribute or Publicly Perform the Work or a
+ Collection, the Licensor offers to the recipient a license to
+ the Work on the same terms and conditions as the license granted
+ to You under this License.
+
+ b. Each time You Distribute or Publicly Perform an Adaptation,
+ Licensor offers to the recipient a license to the original Work
+ on the same terms and conditions as the license granted to You
+ under this License.
+
+ c. If any provision of this License is invalid or unenforceable
+ under applicable law, it shall not affect the validity or
+ enforceability of the remainder of the terms of this License,
+ and without further action by the parties to this agreement,
+ such provision shall be reformed to the minimum extent necessary
+ to make such provision valid and enforceable.
+
+ d. No term or provision of this License shall be deemed waived and
+ no breach consented to unless such waiver or consent shall be in
+ writing and signed by the party to be charged with such waiver
+ or consent.
+
+ e. This License constitutes the entire agreement between the
+ parties with respect to the Work licensed here. There are no
+ understandings, agreements or representations with respect to
+ the Work not specified here. Licensor shall not be bound by any
+ additional provisions that may appear in any communication from
+ You. This License may not be modified without the mutual
+ written agreement of the Licensor and You.
+
+ f. The rights granted under, and the subject matter referenced, in
+ this License were drafted utilizing the terminology of the Berne
+ Convention for the Protection of Literary and Artistic Works (as
+ amended on September 28, 1979), the Rome Convention of 1961, the
+ WIPO Copyright Treaty of 1996, the WIPO Performances and
+ Phonograms Treaty of 1996 and the Universal Copyright Convention
+ (as revised on July 24, 1971). These rights and subject matter
+ take effect in the relevant jurisdiction in which the License
+ terms are sought to be enforced according to the corresponding
+ provisions of the implementation of those treaty provisions in
+ the applicable national law. If the standard suite of rights
+ granted under applicable copyright law includes additional
+ rights not granted under this License, such additional rights
+ are deemed to be included in the License; this License is not
+ intended to restrict the license of any rights under applicable
+ law.
diff --git a/lib/jgit/org.eclipse.jgit.archive/BUCK b/lib/jgit/org.eclipse.jgit.archive/BUCK
index af0284f..7c967b3 100644
--- a/lib/jgit/org.eclipse.jgit.archive/BUCK
+++ b/lib/jgit/org.eclipse.jgit.archive/BUCK
@@ -4,7 +4,7 @@
maven_jar(
name = 'jgit-archive',
id = 'org.eclipse.jgit:org.eclipse.jgit.archive:' + VERS,
- sha1 = '73c3dd7d57c54b4ec95db6325e2d51dd3a0e6036',
+ sha1 = '2db2e7666672a31fa41b7e1dadcba51df6d30954',
license = 'jgit',
repository = REPO,
deps = ['//lib/jgit/org.eclipse.jgit:jgit'],
diff --git a/lib/jgit/org.eclipse.jgit.http.server/BUCK b/lib/jgit/org.eclipse.jgit.http.server/BUCK
index c93ea99..06865cb 100644
--- a/lib/jgit/org.eclipse.jgit.http.server/BUCK
+++ b/lib/jgit/org.eclipse.jgit.http.server/BUCK
@@ -4,7 +4,7 @@
maven_jar(
name = 'jgit-servlet',
id = 'org.eclipse.jgit:org.eclipse.jgit.http.server:' + VERS,
- sha1 = 'a85e11f0f31f71a4e4e83313c4c24167e99d330c',
+ sha1 = '6e36638888918d9941dddec7e2abe1f162cc74d9',
license = 'jgit',
repository = REPO,
deps = ['//lib/jgit/org.eclipse.jgit:jgit'],
diff --git a/lib/jgit/org.eclipse.jgit.junit/BUCK b/lib/jgit/org.eclipse.jgit.junit/BUCK
index 9d4a2dd..77b637a 100644
--- a/lib/jgit/org.eclipse.jgit.junit/BUCK
+++ b/lib/jgit/org.eclipse.jgit.junit/BUCK
@@ -4,7 +4,7 @@
maven_jar(
name = 'junit',
id = 'org.eclipse.jgit:org.eclipse.jgit.junit:' + VERS,
- sha1 = 'cd7e83bb138d0c3dad9d2dea27c238824d056a4b',
+ sha1 = 'e8fb1d81f588c3174a9730bdecdbde9faa04140a',
license = 'DO_NOT_DISTRIBUTE',
repository = REPO,
unsign = True,
diff --git a/lib/jgit/org.eclipse.jgit/BUCK b/lib/jgit/org.eclipse.jgit/BUCK
index da1ad9a..458703c 100644
--- a/lib/jgit/org.eclipse.jgit/BUCK
+++ b/lib/jgit/org.eclipse.jgit/BUCK
@@ -4,8 +4,8 @@
maven_jar(
name = 'jgit',
id = 'org.eclipse.jgit:org.eclipse.jgit:' + VERS,
- bin_sha1 = '0bbcd8846f2731e50fccfb9f3ced43e2298844d4',
- src_sha1 = '72d8aa79f8e645bb44f9f2fe74d02c6021516261',
+ bin_sha1 = '3e3d0b73dcf4ad649f37758ea8502d92f3d299de',
+ src_sha1 = 'fc352952db91a4046e4b832145eb2dc8afce8db1',
license = 'jgit',
repository = REPO,
unsign = True,
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js
index 0676595..1d87533 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js
@@ -320,6 +320,10 @@
},
_handleConfirmDialogCancel: function() {
+ this._hideAllDialogs();
+ },
+
+ _hideAllDialogs: function() {
var dialogEls =
Polymer.dom(this.root).querySelectorAll('.confirmDialog');
for (var i = 0; i < dialogEls.length; i++) {
@@ -343,7 +347,7 @@
payload.base = el.base;
}
this.$.overlay.close();
- el.hidden = false;
+ el.hidden = true;
this._fireAction('/rebase', this._revisionActions.rebase, true, payload);
},
@@ -359,7 +363,7 @@
return;
}
this.$.overlay.close();
- el.hidden = false;
+ el.hidden = true;
this._fireAction(
'/cherrypick',
this._revisionActions.cherrypick,
@@ -374,7 +378,7 @@
_handleRevertDialogConfirm: function() {
var el = this.$.confirmRevertDialog;
this.$.overlay.close();
- el.hidden = false;
+ el.hidden = true;
this._fireAction('/revert', this.actions.revert, false,
{message: el.message});
},
@@ -382,7 +386,7 @@
_handleAbandonDialogConfirm: function() {
var el = this.$.confirmAbandonDialog;
this.$.overlay.close();
- el.hidden = false;
+ el.hidden = true;
this._fireAction('/abandon', this.actions.abandon, false,
{message: el.message});
},
@@ -405,6 +409,8 @@
},
_showActionDialog: function(dialog) {
+ this._hideAllDialogs();
+
dialog.hidden = false;
this.$.overlay.open().then(function() {
if (dialog.resetFocus) {
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html
index 9b04c8a..83d5bdc 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html
@@ -42,24 +42,25 @@
method: 'DELETE',
label: 'Delete',
title: 'Delete draft revision 2',
- enabled: true
+ enabled: true,
},
cherrypick: {
method: 'POST',
label: 'Cherry Pick',
title: 'Cherry pick change to a different branch',
- enabled: true
+ enabled: true,
},
rebase: {
method: 'POST',
label: 'Rebase',
- title: 'Rebase onto tip of branch or parent change'
+ title: 'Rebase onto tip of branch or parent change',
+ enabled: true,
},
submit: {
method: 'POST',
label: 'Submit',
title: 'Submit patch set 2 into master',
- enabled: true
+ enabled: true,
},
});
},
@@ -162,6 +163,7 @@
__key: 'rebase',
__type: 'revision',
__primary: false,
+ enabled: true,
label: 'Rebase',
method: 'POST',
title: 'Rebase onto tip of branch or parent change',
@@ -187,6 +189,25 @@
});
});
+ test('two dialogs are not shown at the same time', function(done) {
+ flush(function() {
+ var rebaseButton = element.$$('gr-button[data-action-key="rebase"]');
+ assert.ok(rebaseButton);
+ MockInteractions.tap(rebaseButton);
+ flushAsynchronousOperations();
+ assert.isFalse(element.$.confirmRebase.hidden);
+
+ var cherryPickButton =
+ element.$$('gr-button[data-action-key="cherrypick"]');
+ assert.ok(cherryPickButton);
+ MockInteractions.tap(cherryPickButton);
+ flushAsynchronousOperations();
+ assert.isTrue(element.$.confirmRebase.hidden);
+ assert.isFalse(element.$.confirmCherrypick.hidden);
+ done();
+ });
+ });
+
suite('cherry-pick', function() {
var fireActionStub;
var alertStub;
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
index b5e1ef0..fe08b78 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
@@ -561,7 +561,7 @@
},
_handleReloadChange: function() {
- page.show(this.changePath(this._changeNum));
+ this._reload();
},
_handleGetChangeDetailError: function(response) {
@@ -654,9 +654,9 @@
} else {
// The patch number is reliant on the change detail request.
return detailCompletes.then(function() {
- this._reloadPatchNumDependentResources();
+ return this._reloadPatchNumDependentResources();
}.bind(this)).then(function() {
- this._reloadDetailDependentResources();
+ return this._reloadDetailDependentResources();
}.bind(this));
}
},
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.html b/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.html
index cbf63d6..57a2e1f 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.html
@@ -112,8 +112,8 @@
</div>
</div>
<div class="actions">
- <gr-button primary on-tap="_handleSave">Save</gr-button>
- <gr-button on-tap="_handleCancel">Cancel</gr-button>
+ <gr-button id="saveButton" primary on-tap="_handleSave">Save</gr-button>
+ <gr-button id="cancelButton" on-tap="_handleCancel">Cancel</gr-button>
</div>
</template>
<script src="gr-diff-preferences.js"></script>
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.js b/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.js
index 4103b2e..9bccd23 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.js
@@ -53,6 +53,17 @@
'_localPrefsChanged(localPrefs.*)',
],
+ getFocusStops: function() {
+ return {
+ start: this.$.contextSelect,
+ end: this.$.cancelButton,
+ };
+ },
+
+ resetFocus: function() {
+ this.$.contextSelect.focus();
+ },
+
_prefsChanged: function(changeRecord) {
var prefs = changeRecord.base;
// TODO(andybons): This is not supported in IE. Implement a polyfill.
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences_test.html b/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences_test.html
index 0c40d9f..3c4d457 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences_test.html
@@ -62,6 +62,14 @@
assert.isFalse(element._newPrefs.syntax_highlighting);
});
+ test('clicking save button calls _handleSave function', function() {
+ var savePrefs = sinon.stub(element, '_handleSave');
+ MockInteractions.tap(element.$.saveButton);
+ flushAsynchronousOperations();
+ assert(savePrefs.calledOnce);
+ savePrefs.restore();
+ });
+
test('events', function(done) {
var savePromise = new Promise(function(resolve) {
element.addEventListener('save', function() { resolve(); });
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html
index 76f7aec..4b91305 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html
@@ -209,6 +209,7 @@
</div>
<gr-overlay id="prefsOverlay" with-backdrop>
<gr-diff-preferences
+ id="diffPreferences"
prefs="{{_prefs}}"
local-prefs="{{_localPrefs}}"
on-save="_handlePrefsSave"
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
index 40b0ee1..efe8684 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
@@ -255,7 +255,7 @@
break;
case 188: // ','
e.preventDefault();
- this.$.prefsOverlay.open();
+ this._openPrefs();
break;
}
},
@@ -267,6 +267,15 @@
page.show(this._computeNavLinkURL(path, fileList, direction));
},
+ _openPrefs: function() {
+ this.$.prefsOverlay.open().then(function() {
+ var diffPreferences = this.$.diffPreferences;
+ var focusStops = diffPreferences.getFocusStops();
+ this.$.prefsOverlay.setFocusStops(focusStops);
+ this.$.diffPreferences.resetFocus();
+ }.bind(this));
+ },
+
/**
* @param {?string} path The path of the current file being shown.
* @param {Array.<string>} fileList The list of files in this change and
@@ -451,7 +460,7 @@
_handlePrefsTap: function(e) {
e.preventDefault();
- this.$.prefsOverlay.open();
+ this._openPrefs();
},
_handlePrefsSave: function(e) {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.html b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.html
index 979ed55..14fd2b7 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.html
@@ -36,7 +36,7 @@
<template>
<div></div>
</template>
-</text-fixture>
+</test-fixture>
<script>
suite('gr-diff-view tests', function() {
@@ -103,7 +103,9 @@
'Should navigate to /c/42/');
assert.equal(element.changeViewState.selectedFileIndex, 0);
- var showPrefsStub = sinon.stub(element.$.prefsOverlay, 'open');
+ var showPrefsStub = sinon.stub(element.$.prefsOverlay, 'open',
+ function() { return Promise.resolve({}); });
+
MockInteractions.pressAndReleaseKeyOn(element, 188); // ','
assert(showPrefsStub.calledOnce);
@@ -131,6 +133,26 @@
showStub.restore();
});
+ test('saving diff preferences', function() {
+ var savePrefs = sinon.stub(element, '_handlePrefsSave');
+ var cancelPrefs = sinon.stub(element, '_handlePrefsCancel');
+ element.$.diffPreferences._handleSave();
+ assert(savePrefs.calledOnce);
+ assert(cancelPrefs.notCalled);
+ savePrefs.restore();
+ cancelPrefs.restore();
+ });
+
+ test('cancelling diff preferences', function() {
+ var savePrefs = sinon.stub(element, '_handlePrefsSave');
+ var cancelPrefs = sinon.stub(element, '_handlePrefsCancel');
+ element.$.diffPreferences._handleCancel();
+ assert(cancelPrefs.calledOnce);
+ assert(savePrefs.notCalled);
+ savePrefs.restore();
+ cancelPrefs.restore();
+ });
+
test('keyboard shortcuts with patch range', function() {
element._changeNum = '42';
element._patchRange = {
diff --git a/polygerrit-ui/app/elements/gr-app.html b/polygerrit-ui/app/elements/gr-app.html
index 25dfaff..051ee2e 100644
--- a/polygerrit-ui/app/elements/gr-app.html
+++ b/polygerrit-ui/app/elements/gr-app.html
@@ -126,9 +126,11 @@
|
<a class="feedback"
href="https://bugs.chromium.org/p/gerrit/issues/entry?template=PolyGerrit%20Issue"
- target="_blank">
- Report PolyGerrit Bug
- </a>
+ target="_blank">Report PolyGerrit Bug</a>
+ <template is="dom-if" if="[[_computeShowGwtUiLink(_serverConfig)]]">
+ |
+ <a href="/?polygerrit=0" rel="external">GWT UI</a>
+ </template>
</footer>
<gr-overlay id="keyboardShortcuts" with-backdrop>
<gr-keyboard-shortcuts-dialog
diff --git a/polygerrit-ui/app/elements/gr-app.js b/polygerrit-ui/app/elements/gr-app.js
index f24ecfd..84467a0 100644
--- a/polygerrit-ui/app/elements/gr-app.js
+++ b/polygerrit-ui/app/elements/gr-app.js
@@ -127,6 +127,11 @@
return !!(account && Object.keys(account).length > 0);
},
+ _computeShowGwtUiLink: function(config) {
+ return config.gerrit.web_uis &&
+ config.gerrit.web_uis.indexOf('GWT') !== -1;
+ },
+
_handlePageError: function(e) {
[
'_showChangeListView',
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.html b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.html
index 32c7c70..864114f 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.html
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.html
@@ -56,7 +56,6 @@
placeholder="[[placeholder]]"
on-keydown="_handleInputKeydown"
on-focus="_onInputFocus"
- on-blur="_onInputBlur"
autocomplete="off" />
<div
id="suggestions"
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.js b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.js
index 16ba150..31918dd 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.js
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.js
@@ -117,6 +117,14 @@
},
+ attached: function() {
+ this.listen(document.body, 'click', '_handleBodyClick');
+ },
+
+ detached: function() {
+ this.unlisten(document.body, 'click', '_handleBodyClick');
+ },
+
get focusStart() {
return this.$.input;
},
@@ -144,10 +152,6 @@
this._updateSuggestions();
},
- _onInputBlur: function() {
- this._focused = false;
- },
-
_updateSuggestions: function() {
if (!this.text || this._disableSuggestions) { return; }
if (this.text.length < this.threshold) {
@@ -229,6 +233,16 @@
}
},
+ _handleBodyClick: function(e) {
+ var eventPath = Polymer.dom(e).path;
+ for (var i = 0; i < eventPath.length; i++) {
+ if (eventPath[i] === this) {
+ return;
+ }
+ }
+ this._focused = false;
+ },
+
_handleSuggestionTap: function(e) {
this.$.cursor.setCursor(e.target);
this._commit();
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.html b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.html
index abf052c..7a26e72 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.html
@@ -271,8 +271,6 @@
assert.isFalse(element._focused);
element.$.input.focus();
assert.isTrue(element._focused);
- element.$.input.blur();
- assert.isFalse(element._focused);
});
test('_focused flag shows/hides the suggestions', function() {
@@ -282,14 +280,18 @@
});
test('tap on suggestion commits and refocuses on input', function() {
- var focusStub = sinon.stub(element, 'focus');
+ var focusSpy = sinon.spy(element, 'focus');
+ var commitSpy = sinon.spy(element, '_commit');
element._focused = true;
element._suggestions = [{name: 'first suggestion'}];
assert.isFalse(element.$.suggestions.hasAttribute('hidden'));
MockInteractions.tap(element.$$('#suggestions li:first-child'));
- assert.isTrue(focusStub.called);
+ flushAsynchronousOperations();
+ assert.isTrue(focusSpy.called);
+ assert.isTrue(commitSpy.called);
assert.isTrue(element.$.suggestions.hasAttribute('hidden'));
- focusStub.restore();
+ focusSpy.restore();
+ commitSpy.restore();
});
});
</script>
diff --git a/tools/bzl/BUILD b/tools/bzl/BUILD
index e69de29..01ae92c 100644
--- a/tools/bzl/BUILD
+++ b/tools/bzl/BUILD
@@ -0,0 +1,4 @@
+
+exports_files([
+ "license-map.py",
+ "test_empty.sh"])
diff --git a/tools/bzl/license-map.py b/tools/bzl/license-map.py
new file mode 100644
index 0000000..72c7ae8
--- /dev/null
+++ b/tools/bzl/license-map.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+
+# reads a bazel query XML file, to join target names with their licenses.
+
+import sys
+import xml.etree.ElementTree as ET
+
+tree = ET.parse(sys.argv[1])
+root = tree.getroot()
+
+entries = {}
+
+for child in root:
+ rule_name = child.attrib["name"]
+ for c in child.getchildren():
+ if c.tag != "rule-input":
+ continue
+
+ license_name = c.attrib["name"]
+ if "//lib:LICENSE" in license_name:
+ assert rule_name not in entries, (license_name, entries[rule_name])
+ entries[rule_name] = license_name
+
+for k, v in sorted(entries.items()):
+ print k, v
diff --git a/tools/bzl/license.bzl b/tools/bzl/license.bzl
new file mode 100644
index 0000000..ca64438
--- /dev/null
+++ b/tools/bzl/license.bzl
@@ -0,0 +1,47 @@
+
+def license_map(name, target):
+ """Generate XML for all targets that depend directly on a LICENSE file"""
+ native.genquery(
+ name = name + ".xml",
+ scope = [ target, ],
+
+ # Find everything that depends on a license file, but remove
+ # the license files themselves from this list.
+ expression = 'rdeps(%s, filter("//lib:LICENSE.*", deps(%s)),1) - filter("//lib:LICENSE.*", deps(%s))' % (target, target, target),
+
+ # We are interested in the edges of the graph ({java_library,
+ # license-file} tuples). 'query' provides this in the XML output.
+ opts = [ "--output=xml"],
+ )
+
+ # post process the XML into our favorite format.
+ native.genrule(
+ name = "gen_license_txt_" + name,
+ cmd = "python $(location //tools/bzl:license-map.py) $(location :%s.xml) > $@" % name,
+ outs = [ name + ".txt",],
+ tools = [ "//tools/bzl:license-map.py", name + ".xml"])
+
+def license_test(name, target):
+ """Generate XML for all targets that depend directly on a LICENSE file"""
+ txt = name + "-forbidden.txt"
+
+ # fully qualify target name.
+ if target[0] not in ":/":
+ target = ":" + target
+ if target[0] != "/":
+ target = "//" + PACKAGE_NAME + target
+
+ forbidden = "//lib:LICENSE-DO_NOT_DISTRIBUTE"
+ native.genquery(
+ name = txt,
+ scope = [ target, forbidden ],
+ # Find everything that depends on a license file, but remove
+ # the license files themselves from this list.
+ expression = 'rdeps(%s, "%s", 1) - rdeps(%s, "%s", 0)' % (target, forbidden, target, forbidden),
+ )
+ native.sh_test(
+ name = name,
+ srcs = [ "//tools/bzl:test_empty.sh" ],
+ args = [ "$(location :%s)" % txt],
+ data = [ txt ],
+ )
diff --git a/tools/bzl/test_empty.sh b/tools/bzl/test_empty.sh
new file mode 100755
index 0000000..0d4398d
--- /dev/null
+++ b/tools/bzl/test_empty.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+if test -s $1
+then
+ echo "$1 not empty:"
+ cat $1
+ exit 1
+fi