Merge "Set patchset description to 'Rebase' when rebasing"
diff --git a/Documentation/dev-intellij.txt b/Documentation/dev-intellij.txt
index f7e0987..1fe912a 100644
--- a/Documentation/dev-intellij.txt
+++ b/Documentation/dev-intellij.txt
@@ -1,7 +1,7 @@
= Gerrit Code Review - IntelliJ Setup
== Prerequisites
-You need an installation of IntelliJ of version 2016.2 or newer.
+You need an installation of IntelliJ of version 2016.2.
In addition, Java 8 must be specified on your path or via `JAVA_HOME` so that
building with Bazel via the Bazel plugin is possible.
diff --git a/gerrit-elasticsearch/BUILD b/gerrit-elasticsearch/BUILD
index 9323bf0..c0ffd5b 100644
--- a/gerrit-elasticsearch/BUILD
+++ b/gerrit-elasticsearch/BUILD
@@ -34,6 +34,7 @@
testonly = 1,
srcs = glob(["src/test/java/**/ElasticTestUtils.java"]),
deps = [
+ ":elasticsearch",
"//gerrit-extension-api:api",
"//gerrit-server:server",
"//lib:gson",
@@ -51,11 +52,9 @@
size = "large",
srcs = glob(["src/test/java/**/*Test.java"]),
flaky = 1,
- #TODO(davido): Re-enable the tests on the CI when they are fixed
tags = [
"elastic",
"flaky",
- "noci",
],
deps = [
":elasticsearch",
diff --git a/gerrit-elasticsearch/src/test/java/com/google/gerrit/elasticsearch/ElasticQueryAccountsTest.java b/gerrit-elasticsearch/src/test/java/com/google/gerrit/elasticsearch/ElasticQueryAccountsTest.java
index 62c1a57..68759df 100644
--- a/gerrit-elasticsearch/src/test/java/com/google/gerrit/elasticsearch/ElasticQueryAccountsTest.java
+++ b/gerrit-elasticsearch/src/test/java/com/google/gerrit/elasticsearch/ElasticQueryAccountsTest.java
@@ -14,11 +14,7 @@
package com.google.gerrit.elasticsearch;
-import static com.google.gerrit.elasticsearch.ElasticAccountIndex.ACCOUNTS_PREFIX;
-
-import com.google.gerrit.elasticsearch.ElasticAccountIndex.AccountMapping;
import com.google.gerrit.elasticsearch.ElasticTestUtils.ElasticNodeInfo;
-import com.google.gerrit.server.index.account.AccountSchemaDefinitions;
import com.google.gerrit.server.query.account.AbstractQueryAccountsTest;
import com.google.gerrit.testutil.InMemoryModule;
import com.google.inject.Guice;
@@ -32,9 +28,6 @@
import java.util.concurrent.ExecutionException;
public class ElasticQueryAccountsTest extends AbstractQueryAccountsTest {
- private static final String INDEX_NAME =
- String.format("%s%04d", ACCOUNTS_PREFIX,
- AccountSchemaDefinitions.INSTANCE.getLatest().getVersion());
private static ElasticNodeInfo nodeInfo;
@BeforeClass
@@ -45,21 +38,7 @@
return;
}
nodeInfo = ElasticTestUtils.startElasticsearchNode();
- createIndexes();
- }
-
- private static void createIndexes() {
- AccountMapping accountMapping =
- new AccountMapping(AccountSchemaDefinitions.INSTANCE.getLatest());
- nodeInfo.node
- .client()
- .admin()
- .indices()
- .prepareCreate(INDEX_NAME)
- .addMapping(ElasticAccountIndex.ACCOUNTS,
- ElasticTestUtils.gson.toJson(accountMapping))
- .execute()
- .actionGet();
+ ElasticTestUtils.createAllIndexes(nodeInfo);
}
@AfterClass
@@ -74,8 +53,8 @@
@After
public void cleanupIndex() {
if (nodeInfo != null) {
- ElasticTestUtils.deleteIndexes(nodeInfo.node, INDEX_NAME);
- createIndexes();
+ ElasticTestUtils.deleteAllIndexes(nodeInfo);
+ ElasticTestUtils.createAllIndexes(nodeInfo);
}
}
diff --git a/gerrit-elasticsearch/src/test/java/com/google/gerrit/elasticsearch/ElasticQueryChangesTest.java b/gerrit-elasticsearch/src/test/java/com/google/gerrit/elasticsearch/ElasticQueryChangesTest.java
index 4b76e4b..95dbe5b 100644
--- a/gerrit-elasticsearch/src/test/java/com/google/gerrit/elasticsearch/ElasticQueryChangesTest.java
+++ b/gerrit-elasticsearch/src/test/java/com/google/gerrit/elasticsearch/ElasticQueryChangesTest.java
@@ -14,13 +14,7 @@
package com.google.gerrit.elasticsearch;
-import static com.google.gerrit.elasticsearch.ElasticChangeIndex.CHANGES_PREFIX;
-import static com.google.gerrit.elasticsearch.ElasticChangeIndex.CLOSED_CHANGES;
-import static com.google.gerrit.elasticsearch.ElasticChangeIndex.OPEN_CHANGES;
-
-import com.google.gerrit.elasticsearch.ElasticChangeIndex.ChangeMapping;
import com.google.gerrit.elasticsearch.ElasticTestUtils.ElasticNodeInfo;
-import com.google.gerrit.server.index.change.ChangeSchemaDefinitions;
import com.google.gerrit.server.query.change.AbstractQueryChangesTest;
import com.google.gerrit.testutil.InMemoryModule;
import com.google.gerrit.testutil.InMemoryRepositoryManager.Repo;
@@ -37,9 +31,6 @@
import java.util.concurrent.ExecutionException;
public class ElasticQueryChangesTest extends AbstractQueryChangesTest {
- private static final String INDEX_NAME =
- String.format("%s%04d", CHANGES_PREFIX,
- ChangeSchemaDefinitions.INSTANCE.getLatest().getVersion());
private static ElasticNodeInfo nodeInfo;
@BeforeClass
@@ -51,14 +42,14 @@
}
nodeInfo = ElasticTestUtils.startElasticsearchNode();
- createIndexes();
+ ElasticTestUtils.createAllIndexes(nodeInfo);
}
@After
public void cleanupIndex() {
if (nodeInfo != null) {
- ElasticTestUtils.deleteIndexes(nodeInfo.node, INDEX_NAME);
- createIndexes();
+ ElasticTestUtils.deleteAllIndexes(nodeInfo);
+ ElasticTestUtils.createAllIndexes(nodeInfo);
}
}
@@ -80,26 +71,6 @@
new InMemoryModule(elasticsearchConfig, notesMigration));
}
- private static void createIndexes() {
- ChangeMapping openChangesMapping =
- new ChangeMapping(ChangeSchemaDefinitions.INSTANCE.getLatest());
- ChangeMapping closedChangesMapping =
- new ChangeMapping(ChangeSchemaDefinitions.INSTANCE.getLatest());
- openChangesMapping.closedChanges = null;
- closedChangesMapping.openChanges = null;
- nodeInfo.node
- .client()
- .admin()
- .indices()
- .prepareCreate(INDEX_NAME)
- .addMapping(OPEN_CHANGES,
- ElasticTestUtils.gson.toJson(openChangesMapping))
- .addMapping(CLOSED_CHANGES,
- ElasticTestUtils.gson.toJson(closedChangesMapping))
- .execute()
- .actionGet();
- }
-
@Test
public void byOwnerInvalidQuery() throws Exception {
TestRepository<Repo> repo = createProject("repo");
diff --git a/gerrit-elasticsearch/src/test/java/com/google/gerrit/elasticsearch/ElasticTestUtils.java b/gerrit-elasticsearch/src/test/java/com/google/gerrit/elasticsearch/ElasticTestUtils.java
index 7c26edc..9d6c808 100644
--- a/gerrit-elasticsearch/src/test/java/com/google/gerrit/elasticsearch/ElasticTestUtils.java
+++ b/gerrit-elasticsearch/src/test/java/com/google/gerrit/elasticsearch/ElasticTestUtils.java
@@ -15,10 +15,21 @@
package com.google.gerrit.elasticsearch;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.elasticsearch.ElasticAccountIndex.ACCOUNTS_PREFIX;
+import static com.google.gerrit.elasticsearch.ElasticChangeIndex.CHANGES_PREFIX;
+import static com.google.gerrit.elasticsearch.ElasticChangeIndex.CLOSED_CHANGES;
+import static com.google.gerrit.elasticsearch.ElasticChangeIndex.OPEN_CHANGES;
import com.google.common.base.Strings;
import com.google.common.io.Files;
+import com.google.gerrit.elasticsearch.ElasticAccountIndex.AccountMapping;
+import com.google.gerrit.elasticsearch.ElasticChangeIndex.ChangeMapping;
+import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.index.IndexModule.IndexType;
+import com.google.gerrit.server.index.Schema;
+import com.google.gerrit.server.index.account.AccountSchemaDefinitions;
+import com.google.gerrit.server.index.change.ChangeSchemaDefinitions;
+import com.google.gerrit.server.query.change.ChangeData;
import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@@ -100,8 +111,8 @@
return new ElasticNodeInfo(node, elasticDir, getHttpPort(node));
}
- static void deleteIndexes(Node node, String index) {
- node.client().admin().indices().prepareDelete(index).execute();
+ static void deleteAllIndexes(ElasticNodeInfo nodeInfo) {
+ nodeInfo.node.client().admin().indices().prepareDelete("_all").execute();
}
static class NodeInfo {
@@ -112,6 +123,39 @@
Map<String, NodeInfo> nodes;
}
+ static void createAllIndexes(ElasticNodeInfo nodeInfo) {
+ Schema<ChangeData> changeSchema =
+ ChangeSchemaDefinitions.INSTANCE.getLatest();
+ ChangeMapping openChangesMapping = new ChangeMapping(changeSchema);
+ ChangeMapping closedChangesMapping = new ChangeMapping(changeSchema);
+ openChangesMapping.closedChanges = null;
+ closedChangesMapping.openChanges = null;
+ nodeInfo.node
+ .client()
+ .admin()
+ .indices()
+ .prepareCreate(
+ String.format("%s%04d", CHANGES_PREFIX, changeSchema.getVersion()))
+ .addMapping(OPEN_CHANGES, gson.toJson(openChangesMapping))
+ .addMapping(CLOSED_CHANGES, gson.toJson(closedChangesMapping))
+ .execute()
+ .actionGet();
+
+ Schema<AccountState> accountSchema =
+ AccountSchemaDefinitions.INSTANCE.getLatest();
+ AccountMapping accountMapping = new AccountMapping(accountSchema);
+ nodeInfo.node
+ .client()
+ .admin()
+ .indices()
+ .prepareCreate(
+ String.format(
+ "%s%04d", ACCOUNTS_PREFIX, accountSchema.getVersion()))
+ .addMapping(ElasticAccountIndex.ACCOUNTS, gson.toJson(accountMapping))
+ .execute()
+ .actionGet();
+ }
+
private static String getHttpPort(Node node)
throws InterruptedException, ExecutionException {
String nodes = node.client().admin().cluster()
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 f03b1f7..24e6094 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
@@ -34,6 +34,7 @@
public String inReplyTo;
public Timestamp updated;
public String message;
+ public boolean unresolved;
public static class Range {
public int startLine;
@@ -101,7 +102,8 @@
&& Objects.equals(range, c.range)
&& Objects.equals(inReplyTo, c.inReplyTo)
&& Objects.equals(updated, c.updated)
- && Objects.equals(message, c.message);
+ && Objects.equals(message, c.message)
+ && Objects.equals(unresolved, c.unresolved);
}
return false;
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/LocalComments.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/LocalComments.java
index f6022f9..44316bc 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/LocalComments.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/LocalComments.java
@@ -216,7 +216,7 @@
} else {
line = Integer.parseInt(elements[offset + 4]);
}
- CommentInfo info = CommentInfo.create(path, side, line, range);
+ CommentInfo info = CommentInfo.create(path, side, line, range, false);
info.message(storage.getItem(key));
if (key.startsWith("patchReply-")) {
info.inReplyTo(elements[1]);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/CommentInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/CommentInfo.java
index d42c344..2800b0b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/CommentInfo.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/CommentInfo.java
@@ -24,12 +24,12 @@
public class CommentInfo extends JavaScriptObject {
public static CommentInfo create(String path, Side side,
- int line, CommentRange range) {
- return create(path, side, 0, line, range);
+ int line, CommentRange range, Boolean unresolved) {
+ return create(path, side, 0, line, range, unresolved);
}
public static CommentInfo create(String path, Side side, int parent,
- int line, CommentRange range) {
+ int line, CommentRange range, boolean unresolved) {
CommentInfo n = createObject().cast();
n.path(path);
n.side(side);
@@ -40,6 +40,7 @@
} else if (line > 0) {
n.line(line);
}
+ n.unresolved(unresolved);
return n;
}
@@ -55,6 +56,7 @@
} else if (r.hasLine()) {
n.line(r.line());
}
+ n.unresolved(r.unresolved());
return n;
}
@@ -72,6 +74,7 @@
} else if (s.hasLine()) {
n.line(s.line());
}
+ n.unresolved(s.unresolved());
return n;
}
@@ -81,6 +84,7 @@
public final native void range(CommentRange r) /*-{ this.range = r }-*/;
public final native void inReplyTo(String i) /*-{ this.in_reply_to = i }-*/;
public final native void message(String m) /*-{ this.message = m }-*/;
+ public final native void unresolved(boolean b) /*-{ this.unresolved = b }-*/;
public final void side(Side side) {
sideRaw(side.toString());
@@ -93,6 +97,7 @@
public final native String id() /*-{ return this.id }-*/;
public final native String inReplyTo() /*-{ return this.in_reply_to }-*/;
public final native int patchSet() /*-{ return this.patch_set }-*/;
+ public final native boolean unresolved() /*-{ return this.unresolved }-*/;
public final Side side() {
String s = sideRaw();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentManager.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentManager.java
index 4c01941..1d1ead9 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentManager.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentManager.java
@@ -196,7 +196,8 @@
getStoredSideFromDisplaySide(side),
getParentNumFromDisplaySide(side),
line,
- null)).setEdit(true);
+ null,
+ false)).setEdit(true);
}
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySideCommentManager.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySideCommentManager.java
index fab6e6b..1981ed0 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySideCommentManager.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySideCommentManager.java
@@ -87,7 +87,8 @@
getStoredSideFromDisplaySide(cm.side()),
getParentNumFromDisplaySide(cm.side()),
line,
- CommentRange.create(fromTo))).setEdit(true);
+ CommentRange.create(fromTo),
+ false)).setEdit(true);
cm.setCursor(fromTo.to());
cm.setSelection(cm.getCursor());
} else {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/UnifiedCommentManager.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/UnifiedCommentManager.java
index 21356fc..cc23aca 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/UnifiedCommentManager.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/UnifiedCommentManager.java
@@ -176,7 +176,8 @@
getPath(),
getStoredSideFromDisplaySide(side),
to.line() + 1,
- CommentRange.create(fromTo))).setEdit(true);
+ CommentRange.create(fromTo),
+ false)).setEdit(true);
cm.setCursor(Pos.create(host.getCmLine(to.line(), side), to.ch()));
cm.setSelection(cm.getCursor());
} else {
diff --git a/gerrit-plugin-api/BUCK b/gerrit-plugin-api/BUCK
index 4b2d677..a949d03 100644
--- a/gerrit-plugin-api/BUCK
+++ b/gerrit-plugin-api/BUCK
@@ -57,6 +57,7 @@
'//lib/guice:javax-inject',
'//lib/guice:multibindings',
'//lib/guice:guice-servlet',
+ "//lib/httpcomponents:httpclient",
'//lib/jgit/org.eclipse.jgit:jgit',
'//lib/jgit/org.eclipse.jgit.http.server:jgit-servlet',
'//lib/joda:joda-time',
diff --git a/gerrit-plugin-api/BUILD b/gerrit-plugin-api/BUILD
index 78f065b..c117eeb 100644
--- a/gerrit-plugin-api/BUILD
+++ b/gerrit-plugin-api/BUILD
@@ -26,6 +26,7 @@
"//lib/guice:guice-servlet",
"//lib/guice:javax-inject",
"//lib/guice:multibindings",
+ "//lib/httpcomponents:httpclient",
"//lib/jgit/org.eclipse.jgit.http.server:jgit-servlet",
"//lib/jgit/org.eclipse.jgit:jgit",
"//lib/joda:joda-time",
@@ -45,7 +46,7 @@
"//lib:jsch",
"//lib:mime-util",
"//lib:protobuf",
- "//lib:servlet-api-3_1",
+ "//lib:servlet-api-3_1-without-neverlink",
"//lib:soy",
"//lib:velocity",
]
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/CommentsUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/CommentsUtil.java
index aac8c66..5d160d9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/CommentsUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/CommentsUtil.java
@@ -148,7 +148,7 @@
Comment c = new Comment(
new Comment.Key(ChangeUtil.messageUUID(ctx.getDb()), path, psId.get()),
ctx.getUser().getAccountId(), ctx.getWhen(), side, message, serverId,
- true);
+ false);
ctx.getUser().updateRealAccountId(c::setRealAuthor);
return c;
}
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 d7c0110..4ad9f15 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
@@ -66,6 +66,7 @@
import com.google.gerrit.common.data.SubmitTypeRecord;
import com.google.gerrit.extensions.api.changes.FixInput;
import com.google.gerrit.extensions.client.ListChangesOption;
+import com.google.gerrit.extensions.client.ReviewerState;
import com.google.gerrit.extensions.common.AccountInfo;
import com.google.gerrit.extensions.common.ApprovalInfo;
import com.google.gerrit.extensions.common.ChangeInfo;
@@ -517,7 +518,6 @@
? permittedLabels(ctl, cd)
: ImmutableMap.of();
}
- out.removableReviewers = removableReviewers(ctl, out.labels.values());
out.reviewers = new HashMap<>();
for (Map.Entry<ReviewerStateInternal, Map<Account.Id, Timestamp>> e
@@ -525,6 +525,8 @@
out.reviewers.put(e.getKey().asReviewerState(),
toAccountInfo(e.getValue().keySet()));
}
+
+ out.removableReviewers = removableReviewers(ctl, out);
}
if (has(REVIEWER_UPDATES)) {
@@ -1030,7 +1032,18 @@
}
private Collection<AccountInfo> removableReviewers(ChangeControl ctl,
- Collection<LabelInfo> labels) {
+ ChangeInfo out) {
+ // Although this is called removableReviewers, this method also determines
+ // which CCs are removable.
+ //
+ // For reviewers, we need to look at each approval, because the reviewer
+ // should only be considered removable if *all* of their approvals can be
+ // removed. First, add all reviewers with *any* removable approval to the
+ // "removable" set. Along the way, if we encounter a non-removable approval,
+ // add the reviewer to the "fixed" set. Before we return, remove all members
+ // of "fixed" from "removable", because not all of their approvals can be
+ // removed.
+ Collection<LabelInfo> labels = out.labels.values();
Set<Account.Id> fixed = Sets.newHashSetWithExpectedSize(labels.size());
Set<Account.Id> removable = Sets.newHashSetWithExpectedSize(labels.size());
for (LabelInfo label : labels) {
@@ -1046,6 +1059,24 @@
}
}
}
+
+ // CCs are simpler than reviewers. They are removable if the ChangeControl
+ // would permit a non-negative approval by that account to be removed, in
+ // which case add them to removable. We don't need to add unremovable CCs to
+ // "fixed" because we only visit each CC once here.
+ Collection<AccountInfo> ccs = out.reviewers.get(ReviewerState.CC);
+ if (ccs != null) {
+ for (AccountInfo ai : ccs) {
+ Account.Id id = new Account.Id(ai._accountId);
+ if (ctl.canRemoveReviewer(id, 0)) {
+ removable.add(id);
+ }
+ }
+ }
+
+ // Subtract any reviewers with non-removable approvals from the "removable"
+ // set. This also subtracts any CCs that for some reason also hold
+ // unremovable approvals.
removable.removeAll(fixed);
List<AccountInfo> result = Lists.newArrayListWithCapacity(removable.size());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/CommentJson.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/CommentJson.java
index 82d932c..cd5195f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/CommentJson.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/CommentJson.java
@@ -18,6 +18,7 @@
import com.google.common.base.Strings;
import com.google.common.collect.FluentIterable;
+import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.client.Comment.Range;
import com.google.gerrit.extensions.client.Side;
import com.google.gerrit.extensions.common.CommentInfo;
@@ -147,6 +148,7 @@
r.updated = c.writtenOn;
r.range = toRange(c.range);
r.tag = c.tag;
+ r.unresolved = c.unresolved;
if (loader != null) {
r.author = loader.get(c.author.getId());
}
@@ -192,8 +194,8 @@
}
private List<FixSuggestionInfo> toFixSuggestionInfos(
- List<FixSuggestion> fixSuggestions) {
- if (fixSuggestions.isEmpty()) {
+ @Nullable List<FixSuggestion> fixSuggestions) {
+ if (fixSuggestions == null || fixSuggestions.isEmpty()) {
return null;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/EmailReviewComments.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/EmailReviewComments.java
index 2c65e4d..9994085 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/EmailReviewComments.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/EmailReviewComments.java
@@ -17,6 +17,7 @@
import static com.google.gerrit.server.CommentsUtil.COMMENT_ORDER;
import com.google.common.collect.Multimap;
+import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.api.changes.NotifyHandling;
import com.google.gerrit.extensions.api.changes.RecipientType;
import com.google.gerrit.reviewdb.client.Account;
@@ -30,6 +31,7 @@
import com.google.gerrit.server.mail.send.CommentSender;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.patch.PatchSetInfoFactory;
+import com.google.gerrit.server.util.LabelVote;
import com.google.gerrit.server.util.RequestContext;
import com.google.gerrit.server.util.ThreadLocalRequestContext;
import com.google.gwtorm.server.OrmException;
@@ -56,7 +58,9 @@
PatchSet patchSet,
IdentifiedUser user,
ChangeMessage message,
- List<Comment> comments);
+ List<Comment> comments,
+ String patchSetComment,
+ List<LabelVote> labels);
}
private final ExecutorService sendEmailsExecutor;
@@ -72,6 +76,8 @@
private final IdentifiedUser user;
private final ChangeMessage message;
private final List<Comment> comments;
+ private final String patchSetComment;
+ private final List<LabelVote> labels;
private ReviewDb db;
@Inject
@@ -87,7 +93,9 @@
@Assisted PatchSet patchSet,
@Assisted IdentifiedUser user,
@Assisted ChangeMessage message,
- @Assisted List<Comment> comments) {
+ @Assisted List<Comment> comments,
+ @Nullable @Assisted String patchSetComment,
+ @Assisted List<LabelVote> labels) {
this.sendEmailsExecutor = executor;
this.patchSetInfoFactory = patchSetInfoFactory;
this.commentSenderFactory = commentSenderFactory;
@@ -100,6 +108,8 @@
this.user = user;
this.message = message;
this.comments = COMMENT_ORDER.sortedCopy(comments);
+ this.patchSetComment = patchSetComment;
+ this.labels = labels;
}
void sendAsync() {
@@ -118,6 +128,8 @@
patchSetInfoFactory.get(notes.getProjectName(), patchSet));
cm.setChangeMessage(message.getMessage(), message.getWrittenOn());
cm.setComments(comments);
+ cm.setPatchSetComment(patchSetComment);
+ cm.setLabels(labels);
cm.setNotify(notify);
cm.setAccountsToNotify(accountsToNotify);
cm.send();
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 21783af..b71d771 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
@@ -658,7 +658,7 @@
private PatchSet ps;
private ChangeMessage message;
private List<Comment> comments = new ArrayList<>();
- private List<String> labelDelta = new ArrayList<>();
+ private List<LabelVote> labelDelta = new ArrayList<>();
private Map<String, Short> approvals = new HashMap<>();
private Map<String, Short> oldApprovals = new HashMap<>();
@@ -699,7 +699,9 @@
ps,
user,
message,
- comments).sendAsync();
+ comments,
+ in.message,
+ labelDelta).sendAsync();
}
commentAdded.fire(
notes.getChange(), ps, user.getAccount(), message.getMessage(),
@@ -1198,8 +1200,8 @@
String msg = Strings.nullToEmpty(in.message).trim();
StringBuilder buf = new StringBuilder();
- for (String d : labelDelta) {
- buf.append(" ").append(d);
+ for (LabelVote d : labelDelta) {
+ buf.append(" ").append(d.format());
}
if (comments.size() == 1) {
buf.append("\n\n(1 comment)");
@@ -1221,7 +1223,7 @@
}
private void addLabelDelta(String name, short value) {
- labelDelta.add(LabelVote.create(name, value).format());
+ labelDelta.add(LabelVote.create(name, value));
}
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/send/CommentSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/send/CommentSender.java
index 0cc4152..a4d0e24 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/send/CommentSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/send/CommentSender.java
@@ -31,6 +31,7 @@
import com.google.gerrit.server.patch.PatchFile;
import com.google.gerrit.server.patch.PatchList;
import com.google.gerrit.server.patch.PatchListNotAvailableException;
+import com.google.gerrit.server.util.LabelVote;
import com.google.gwtorm.client.KeyUtil;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
@@ -103,6 +104,8 @@
}
private List<Comment> inlineComments = Collections.emptyList();
+ private String patchSetComment = null;
+ private List<LabelVote> labels = Collections.emptyList();
private final CommentsUtil commentsUtil;
@Inject
@@ -126,6 +129,14 @@
changeData.setCurrentFilePaths(Ordering.natural().sortedCopy(paths));
}
+ public void setPatchSetComment(String comment) {
+ this.patchSetComment = comment;
+ }
+
+ public void setLabels(List<LabelVote> labels) {
+ this.labels = labels;
+ }
+
@Override
protected void init() throws EmailException {
super.init();
@@ -595,6 +606,10 @@
hasComments = !files.isEmpty();
}
+ soyContext.put("patchSetCommentBlocks",
+ commentBlocksToSoyData(CommentFormatter.parse(patchSetComment)));
+ soyContext.put("labels", getLabelVoteSoyData(labels));
+ soyContext.put("commentCount", inlineComments.size());
soyContext.put("commentTimestamp", getCommentTimestamp());
soyContext.put("coverLetterBlocks",
commentBlocksToSoyData(CommentFormatter.parse(getCoverLetter())));
@@ -623,6 +638,20 @@
}
}
+ private List<Map<String, Object>> getLabelVoteSoyData(List<LabelVote> votes) {
+ List<Map<String, Object>> result = new ArrayList<>();
+ for (LabelVote vote : votes) {
+ Map<String, Object> data = new HashMap<>();
+ data.put("label", vote.label());
+
+ // Soy needs the short to be cast as an int for it to get converted to the
+ // correct tamplate type.
+ data.put("value", (int) vote.value());
+ result.add(data);
+ }
+ return result;
+ }
+
private String getCommentTimestamp() {
// Grouping is currently done by timestamp.
return MailUtil.rfcDateformatter.format(
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNoteUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNoteUtil.java
index ff5e8ee..ce73142 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNoteUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNoteUtil.java
@@ -249,9 +249,16 @@
boolean hasParent =
(RawParseUtils.match(note, curr.value, PARENT.getBytes(UTF_8))) != -1;
String parentUUID = null;
+ boolean unresolved = false;
if (hasParent) {
parentUUID = parseStringField(note, curr, changeId, PARENT);
}
+ boolean hasUnresolved =
+ (RawParseUtils.match(note, curr.value,
+ UNRESOLVED.getBytes(UTF_8))) != -1;
+ if (hasUnresolved) {
+ unresolved = parseBooleanField(note, curr, changeId, UNRESOLVED);
+ }
String uuid = parseStringField(note, curr, changeId, UUID);
@@ -277,7 +284,7 @@
: (short) 1,
message,
serverId,
- false);
+ unresolved);
c.lineNbr = range.getEndLine();
c.parentUuid = parentUUID;
c.tag = tag;
@@ -458,6 +465,17 @@
return checkResult(commentLength, "comment length", changeId);
}
+ private boolean parseBooleanField(byte[] note, MutableInteger curr,
+ Change.Id changeId, String fieldName) throws ConfigInvalidException {
+ String str = parseStringField(note, curr, changeId, fieldName);
+ if ("true".equalsIgnoreCase(str)) {
+ return true;
+ } else if ("false".equalsIgnoreCase(str)) {
+ return false;
+ }
+ throw parseException(changeId, "invalid boolean for %s: %s", fieldName, str);
+ }
+
private static <T> T checkResult(T o, String fieldName,
Change.Id changeId) throws ConfigInvalidException {
if (o == null) {
@@ -590,6 +608,7 @@
appendHeaderField(writer, PARENT, parent);
}
+ appendHeaderField(writer, UNRESOLVED, Boolean.toString(c.unresolved));
appendHeaderField(writer, UUID, c.key.uuid);
if (c.tag != null) {
diff --git a/gerrit-server/src/main/resources/com/google/gerrit/server/mail/CommentHtml.soy b/gerrit-server/src/main/resources/com/google/gerrit/server/mail/CommentHtml.soy
index 75492d6..4e67d4e 100644
--- a/gerrit-server/src/main/resources/com/google/gerrit/server/mail/CommentHtml.soy
+++ b/gerrit-server/src/main/resources/com/google/gerrit/server/mail/CommentHtml.soy
@@ -18,10 +18,12 @@
/**
* @param commentFiles
- * @param coverLetter
- * @param coverLetterBlocks
+ * @param commentCount
* @param email
* @param fromName
+ * @param labels
+ * @param patchSet
+ * @param patchSetCommentBlocks
*/
{template .CommentHtml autoescape="strict" kind="html"}
{let $commentHeaderStyle kind="css"}
@@ -39,6 +41,28 @@
padding-left: 20px;
{/let}
+ {let $voteStyle kind="css"}
+ border-radius: 3px;
+ display: inline-block;
+ margin: 0 2px;
+ padding: 4px;
+ {/let}
+
+ {let $positiveVoteStyle kind="css"}
+ {$voteStyle}
+ background-color: #d4ffd4;
+ {/let}
+
+ {let $negativeVoteStyle kind="css"}
+ {$voteStyle}
+ background-color: #ffd4d4;
+ {/let}
+
+ {let $neutralVoteStyle kind="css"}
+ {$voteStyle}
+ background-color: #ddd;
+ {/let}
+
<p>
{$fromName} <strong>posted comments</strong> on this change.
</p>
@@ -49,8 +73,33 @@
</p>
{/if}
- {if $coverLetter}
- {call .WikiFormat}{param content: $coverLetterBlocks /}{/call}
+ <p>
+ Patch set {$patchSet.patchSetId}:
+ {foreach $label in $labels}
+ {if $label.value > 0}
+ <span style="{$positiveVoteStyle}">
+ {$label.label}{sp}+{$label.value}
+ </span>
+ {elseif $label.value < 0}
+ <span style="{$negativeVoteStyle}">
+ {$label.label}{sp}{$label.value}
+ </span>
+ {else}
+ <span style="{$neutralVoteStyle}">
+ -{$label.label}
+ </span>
+ {/if}
+ {/foreach}
+ </p>
+
+ {if $patchSetCommentBlocks}
+ {call .WikiFormat}{param content: $patchSetCommentBlocks /}{/call}
+ {/if}
+
+ {if $commentCount == 1}
+ <p>(1 comment)</p>
+ {elseif $commentCount > 1}
+ <p>({$commentCount} comments)</p>
{/if}
<ul style="{$ulStyle}">
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/mail/receive/AbstractParserTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/mail/receive/AbstractParserTest.java
index 8b6e55e..dc1c054 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/mail/receive/AbstractParserTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/mail/receive/AbstractParserTest.java
@@ -59,7 +59,7 @@
protected static Comment newComment(String uuid, String file,
String message, int line) {
Comment c = new Comment(new Comment.Key(uuid, file, 1),
- new Account.Id(0), new Timestamp(0l), (short) 0, message, "", false);
+ new Account.Id(0), new Timestamp(0L), (short) 0, message, "", false);
c.lineNbr = line;
return c;
}
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/notedb/AbstractChangeNotesTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/notedb/AbstractChangeNotesTest.java
index fdf58d1..d827e6c 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/notedb/AbstractChangeNotesTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/notedb/AbstractChangeNotesTest.java
@@ -251,7 +251,8 @@
protected Comment newComment(PatchSet.Id psId, String filename, String UUID,
CommentRange range, int line, IdentifiedUser commenter, String parentUUID,
- Timestamp t, String message, short side, String commitSHA1) {
+ Timestamp t, String message, short side, String commitSHA1,
+ boolean unresolved) {
Comment c = new Comment(
new Comment.Key(UUID, filename, psId.get()),
commenter.getAccountId(),
@@ -259,7 +260,7 @@
side,
message,
serverId,
- false);
+ unresolved);
c.lineNbr = line;
c.parentUuid = parentUUID;
c.revId = commitSHA1;
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/notedb/ChangeNotesTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/notedb/ChangeNotesTest.java
index a648276..f43eeb3 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/notedb/ChangeNotesTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/notedb/ChangeNotesTest.java
@@ -128,7 +128,7 @@
update.putComment(Status.PUBLISHED,
newComment(c.currentPatchSetId(), "a.txt", "uuid1",
new CommentRange(1, 2, 3, 4), 1, changeOwner, null,
- TimeUtil.nowTs(), "Comment", (short) 1, commit.name()));
+ TimeUtil.nowTs(), "Comment", (short) 1, commit.name(), false));
update.setTag(tag);
update.commit();
@@ -183,7 +183,7 @@
update.putComment(Status.PUBLISHED,
newComment(c.currentPatchSetId(), "a.txt", "uuid1",
new CommentRange(1, 2, 3, 4), 1, changeOwner, null,
- TimeUtil.nowTs(), "Comment", (short) 1, commit.name()));
+ TimeUtil.nowTs(), "Comment", (short) 1, commit.name(), false));
update.setChangeMessage("coverage verification");
update.setTag(coverageTag);
update.commit();
@@ -1039,7 +1039,7 @@
update.putComment(Status.PUBLISHED,
newComment(c.currentPatchSetId(), "a.txt", "uuid1",
new CommentRange(1, 2, 3, 4), 1, changeOwner, null,
- TimeUtil.nowTs(), "Comment", (short) 1, commit.name()));
+ TimeUtil.nowTs(), "Comment", (short) 1, commit.name(), false));
update.commit();
ChangeNotes notes = newNotes(c);
@@ -1137,7 +1137,7 @@
Timestamp ts = TimeUtil.nowTs();
update.putComment(Status.PUBLISHED,
newComment(psId2, "a.txt", "uuid1", new CommentRange(1, 2, 3, 4), 1,
- changeOwner, null, ts, "Comment", (short) 1, commit.name()));
+ changeOwner, null, ts, "Comment", (short) 1, commit.name(), false));
update.commit();
notes = newNotes(c);
@@ -1157,6 +1157,7 @@
+ "1:2-3:4\n"
+ ChangeNoteUtil.formatTime(serverIdent, ts) + "\n"
+ "Author: Change Owner <1@gerrit>\n"
+ + "Unresolved: false\n"
+ "UUID: uuid1\n"
+ "Bytes: 7\n"
+ "Comment\n"
@@ -1217,7 +1218,7 @@
updateManagerFactory.create(project)) {
Comment comment1 = newComment(psId, "file1",
uuid1, range1, range1.getEndLine(), otherUser, null, time1, message1,
- (short) 0, "abcd1234abcd1234abcd1234abcd1234abcd1234");
+ (short) 0, "abcd1234abcd1234abcd1234abcd1234abcd1234", false);
update1.setPatchSetId(psId);
update1.putComment(Status.PUBLISHED, comment1);
updateManager.add(update1);
@@ -1444,7 +1445,7 @@
Comment comment = newComment(psId, "file1",
"uuid", null, 0, otherUser, null,
- TimeUtil.nowTs(), "message", (short) 1, revId.get());
+ TimeUtil.nowTs(), "message", (short) 1, revId.get(), false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment);
update.commit();
@@ -1464,7 +1465,7 @@
Comment comment = newComment(psId, "file1",
"uuid", range, range.getEndLine(), otherUser, null,
- TimeUtil.nowTs(), "message", (short) 1, revId.get());
+ TimeUtil.nowTs(), "message", (short) 1, revId.get(), false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment);
update.commit();
@@ -1484,7 +1485,7 @@
Comment comment = newComment(psId, "file",
"uuid", range, range.getEndLine(), otherUser, null,
- TimeUtil.nowTs(), "message", (short) 1, revId.get());
+ TimeUtil.nowTs(), "message", (short) 1, revId.get(), false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment);
update.commit();
@@ -1503,7 +1504,8 @@
CommentRange range = new CommentRange(1, 2, 3, 4);
Comment comment = newComment(psId, "", "uuid", range, range.getEndLine(),
- otherUser, null, TimeUtil.nowTs(), "message", (short) 1, revId.get());
+ otherUser, null, TimeUtil.nowTs(), "message", (short) 1, revId.get(),
+ false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment);
update.commit();
@@ -1531,7 +1533,7 @@
Comment comment1 = newComment(psId, "file1", uuid1, range1,
range1.getEndLine(), otherUser, null, time1, message1, (short) 1,
- "abcd1234abcd1234abcd1234abcd1234abcd1234");
+ "abcd1234abcd1234abcd1234abcd1234abcd1234", false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment1);
update.commit();
@@ -1540,7 +1542,7 @@
CommentRange range2 = new CommentRange(2, 1, 3, 1);
Comment comment2 = newComment(psId, "file1", uuid2, range2,
range2.getEndLine(), otherUser, null, time2, message2, (short) 1,
- "abcd1234abcd1234abcd1234abcd1234abcd1234");
+ "abcd1234abcd1234abcd1234abcd1234abcd1234", false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment2);
update.commit();
@@ -1549,7 +1551,7 @@
CommentRange range3 = new CommentRange(3, 0, 4, 1);
Comment comment3 = newComment(psId, "file2", uuid3, range3,
range3.getEndLine(), otherUser, null, time3, message3, (short) 1,
- "abcd1234abcd1234abcd1234abcd1234abcd1234");
+ "abcd1234abcd1234abcd1234abcd1234abcd1234", false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment3);
update.commit();
@@ -1575,6 +1577,7 @@
+ "1:1-2:1\n"
+ ChangeNoteUtil.formatTime(serverIdent, time1) + "\n"
+ "Author: Other Account <2@gerrit>\n"
+ + "Unresolved: false\n"
+ "UUID: uuid1\n"
+ "Bytes: 9\n"
+ "comment 1\n"
@@ -1582,6 +1585,7 @@
+ "2:1-3:1\n"
+ ChangeNoteUtil.formatTime(serverIdent, time2) + "\n"
+ "Author: Other Account <2@gerrit>\n"
+ + "Unresolved: false\n"
+ "UUID: uuid2\n"
+ "Bytes: 9\n"
+ "comment 2\n"
@@ -1591,6 +1595,7 @@
+ "3:0-4:1\n"
+ ChangeNoteUtil.formatTime(serverIdent, time3) + "\n"
+ "Author: Other Account <2@gerrit>\n"
+ + "Unresolved: false\n"
+ "UUID: uuid3\n"
+ "Bytes: 9\n"
+ "comment 3\n"
@@ -1614,7 +1619,7 @@
Comment comment1 = newComment(psId, "file1",
uuid1, range1, range1.getEndLine(), otherUser, null, time1, message1,
- (short) 0, "abcd1234abcd1234abcd1234abcd1234abcd1234");
+ (short) 0, "abcd1234abcd1234abcd1234abcd1234abcd1234", false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment1);
update.commit();
@@ -1623,7 +1628,7 @@
CommentRange range2 = new CommentRange(2, 1, 3, 1);
Comment comment2 = newComment(psId, "file1",
uuid2, range2, range2.getEndLine(), otherUser, null, time2, message2,
- (short) 0, "abcd1234abcd1234abcd1234abcd1234abcd1234");
+ (short) 0, "abcd1234abcd1234abcd1234abcd1234abcd1234", false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment2);
update.commit();
@@ -1649,6 +1654,7 @@
+ "1:1-2:1\n"
+ ChangeNoteUtil.formatTime(serverIdent, time1) + "\n"
+ "Author: Other Account <2@gerrit>\n"
+ + "Unresolved: false\n"
+ "UUID: uuid1\n"
+ "Bytes: 9\n"
+ "comment 1\n"
@@ -1656,6 +1662,74 @@
+ "2:1-3:1\n"
+ ChangeNoteUtil.formatTime(serverIdent, time2) + "\n"
+ "Author: Other Account <2@gerrit>\n"
+ + "Unresolved: false\n"
+ + "UUID: uuid2\n"
+ + "Bytes: 9\n"
+ + "comment 2\n"
+ + "\n");
+ }
+ }
+ }
+
+ @Test
+ public void patchLineCommentNotesResolvedChangesValue() throws Exception {
+ Change c = newChange();
+ ChangeUpdate update = newUpdate(c, otherUser);
+ String uuid1 = "uuid1";
+ String uuid2 = "uuid2";
+ String message1 = "comment 1";
+ String message2 = "comment 2";
+ CommentRange range1 = new CommentRange(1, 1, 2, 1);
+ Timestamp time1 = TimeUtil.nowTs();
+ Timestamp time2 = TimeUtil.nowTs();
+ PatchSet.Id psId = c.currentPatchSetId();
+
+ Comment comment1 = newComment(psId, "file1",
+ uuid1, range1, range1.getEndLine(), otherUser, null, time1, message1,
+ (short) 0, "abcd1234abcd1234abcd1234abcd1234abcd1234", false);
+ update.setPatchSetId(psId);
+ update.putComment(Status.PUBLISHED, comment1);
+ update.commit();
+
+ update = newUpdate(c, otherUser);
+ Comment comment2 = newComment(psId, "file1",
+ uuid2, range1, range1.getEndLine(), otherUser, uuid1, time2, message2,
+ (short) 0, "abcd1234abcd1234abcd1234abcd1234abcd1234", true);
+ update.setPatchSetId(psId);
+ update.putComment(Status.PUBLISHED, comment2);
+ update.commit();
+
+ ChangeNotes notes = newNotes(c);
+
+ try (RevWalk walk = new RevWalk(repo)) {
+ ArrayList<Note> notesInTree =
+ Lists.newArrayList(notes.revisionNoteMap.noteMap.iterator());
+ Note note = Iterables.getOnlyElement(notesInTree);
+
+ byte[] bytes =
+ walk.getObjectReader().open(
+ note.getData(), Constants.OBJ_BLOB).getBytes();
+ String noteString = new String(bytes, UTF_8);
+
+ if (!testJson()) {
+ assertThat(noteString).isEqualTo(
+ "Revision: abcd1234abcd1234abcd1234abcd1234abcd1234\n"
+ + "Base-for-patch-set: 1\n"
+ + "File: file1\n"
+ + "\n"
+ + "1:1-2:1\n"
+ + ChangeNoteUtil.formatTime(serverIdent, time1) + "\n"
+ + "Author: Other Account <2@gerrit>\n"
+ + "Unresolved: false\n"
+ + "UUID: uuid1\n"
+ + "Bytes: 9\n"
+ + "comment 1\n"
+ + "\n"
+ + "1:1-2:1\n"
+ + ChangeNoteUtil.formatTime(serverIdent, time2) + "\n"
+ + "Author: Other Account <2@gerrit>\n"
+ + "Parent: uuid1\n"
+ + "Unresolved: true\n"
+ "UUID: uuid2\n"
+ "Bytes: 9\n"
+ "comment 2\n"
@@ -1684,13 +1758,13 @@
Comment comment1 =
newComment(psId1, "file1", uuid1, range1, range1.getEndLine(),
- otherUser, null, time, message1, (short) 0, revId.get());
+ otherUser, null, time, message1, (short) 0, revId.get(), false);
Comment comment2 =
newComment(psId1, "file1", uuid2, range2, range2.getEndLine(),
- otherUser, null, time, message2, (short) 0, revId.get());
+ otherUser, null, time, message2, (short) 0, revId.get(), false);
Comment comment3 =
newComment(psId2, "file1", uuid3, range1, range1.getEndLine(),
- otherUser, null, time, message3, (short) 0, revId.get());
+ otherUser, null, time, message3, (short) 0, revId.get(), false);
ChangeUpdate update = newUpdate(c, otherUser);
update.setPatchSetId(psId2);
@@ -1721,6 +1795,7 @@
+ "1:1-2:1\n"
+ timeStr + "\n"
+ "Author: Other Account <2@gerrit>\n"
+ + "Unresolved: false\n"
+ "UUID: uuid1\n"
+ "Bytes: 9\n"
+ "comment 1\n"
@@ -1728,6 +1803,7 @@
+ "2:1-3:1\n"
+ timeStr + "\n"
+ "Author: Other Account <2@gerrit>\n"
+ + "Unresolved: false\n"
+ "UUID: uuid2\n"
+ "Bytes: 9\n"
+ "comment 2\n"
@@ -1738,6 +1814,7 @@
+ "1:1-2:1\n"
+ timeStr + "\n"
+ "Author: Other Account <2@gerrit>\n"
+ + "Unresolved: false\n"
+ "UUID: uuid3\n"
+ "Bytes: 9\n"
+ "comment 3\n"
@@ -1766,7 +1843,7 @@
Comment comment = newComment(psId, "file", uuid, range,
range.getEndLine(), otherUser, null, time, message, (short) 1,
- revId.get());
+ revId.get(), false);
comment.setRealAuthor(changeOwner.getAccountId());
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment);
@@ -1794,6 +1871,7 @@
+ ChangeNoteUtil.formatTime(serverIdent, time) + "\n"
+ "Author: Other Account <2@gerrit>\n"
+ "Real-author: Change Owner <1@gerrit>\n"
+ + "Unresolved: false\n"
+ "UUID: uuid\n"
+ "Bytes: 7\n"
+ "comment\n"
@@ -1821,7 +1899,7 @@
Comment comment = newComment(psId, "file1", uuid, range, range.getEndLine(),
user, null, time, "comment", (short) 1,
- "abcd1234abcd1234abcd1234abcd1234abcd1234");
+ "abcd1234abcd1234abcd1234abcd1234abcd1234", false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment);
update.commit();
@@ -1848,6 +1926,7 @@
+ "1:1-2:1\n"
+ timeStr + "\n"
+ "Author: Weird\u0002User <3@gerrit>\n"
+ + "Unresolved: false\n"
+ "UUID: uuid\n"
+ "Bytes: 7\n"
+ "comment\n"
@@ -1875,7 +1954,7 @@
Comment commentForBase =
newComment(psId, "filename", uuid1, range, range.getEndLine(),
- otherUser, null, now, messageForBase, (short) 0, rev1);
+ otherUser, null, now, messageForBase, (short) 0, rev1, false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, commentForBase);
update.commit();
@@ -1884,7 +1963,7 @@
Comment commentForPS =
newComment(psId, "filename", uuid2, range, range.getEndLine(),
otherUser, null, now, messageForPS,
- (short) 1, rev2);
+ (short) 1, rev2, false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, commentForPS);
update.commit();
@@ -1911,7 +1990,7 @@
Timestamp timeForComment2 = TimeUtil.nowTs();
Comment comment1 =
newComment(psId, filename, uuid1, range, range.getEndLine(), otherUser,
- null, timeForComment1, "comment 1", side, rev);
+ null, timeForComment1, "comment 1", side, rev, false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment1);
update.commit();
@@ -1919,7 +1998,7 @@
update = newUpdate(c, otherUser);
Comment comment2 =
newComment(psId, filename, uuid2, range, range.getEndLine(), otherUser,
- null, timeForComment2, "comment 2", side, rev);
+ null, timeForComment2, "comment 2", side, rev, false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment2);
update.commit();
@@ -1946,7 +2025,7 @@
Timestamp now = TimeUtil.nowTs();
Comment comment1 = newComment(psId, filename1,
uuid, range, range.getEndLine(), otherUser, null, now, "comment 1",
- side, rev);
+ side, rev, false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment1);
update.commit();
@@ -1954,7 +2033,7 @@
update = newUpdate(c, otherUser);
Comment comment2 = newComment(psId, filename2,
uuid, range, range.getEndLine(), otherUser, null, now, "comment 2",
- side, rev);
+ side, rev, false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment2);
update.commit();
@@ -1979,7 +2058,8 @@
ChangeUpdate update = newUpdate(c, otherUser);
Timestamp now = TimeUtil.nowTs();
Comment comment1 = newComment(ps1, filename, uuid, range,
- range.getEndLine(), otherUser, null, now, "comment on ps1", side, rev1);
+ range.getEndLine(), otherUser, null, now, "comment on ps1",
+ side, rev1, false);
update.setPatchSetId(ps1);
update.putComment(Status.PUBLISHED, comment1);
update.commit();
@@ -1990,7 +2070,8 @@
update = newUpdate(c, otherUser);
now = TimeUtil.nowTs();
Comment comment2 = newComment(ps2, filename, uuid, range,
- range.getEndLine(), otherUser, null, now, "comment on ps2", side, rev2);
+ range.getEndLine(), otherUser, null, now, "comment on ps2",
+ side, rev2, false);
update.setPatchSetId(ps2);
update.putComment(Status.PUBLISHED, comment2);
update.commit();
@@ -2014,7 +2095,8 @@
ChangeUpdate update = newUpdate(c, otherUser);
Timestamp now = TimeUtil.nowTs();
Comment comment1 = newComment(ps1, filename, uuid, range,
- range.getEndLine(), otherUser, null, now, "comment on ps1", side, rev);
+ range.getEndLine(), otherUser, null, now, "comment on ps1",
+ side, rev, false);
update.setPatchSetId(ps1);
update.putComment(Status.DRAFT, comment1);
update.commit();
@@ -2053,9 +2135,11 @@
ChangeUpdate update = newUpdate(c, otherUser);
update.setPatchSetId(psId);
Comment comment1 = newComment(psId, filename, uuid1, range1,
- range1.getEndLine(), otherUser, null, now, "comment on ps1", side, rev);
+ range1.getEndLine(), otherUser, null, now, "comment on ps1",
+ side, rev, false);
Comment comment2 = newComment(psId, filename, uuid2, range2,
- range2.getEndLine(), otherUser, null, now, "other on ps1", side, rev);
+ range2.getEndLine(), otherUser, null, now, "other on ps1",
+ side, rev, false);
update.putComment(Status.DRAFT, comment1);
update.putComment(Status.DRAFT, comment2);
update.commit();
@@ -2099,10 +2183,10 @@
update.setPatchSetId(psId);
Comment baseComment =
newComment(psId, filename, uuid1, range1, range1.getEndLine(),
- otherUser, null, now, "comment on base", (short) 0, rev1);
+ otherUser, null, now, "comment on base", (short) 0, rev1, false);
Comment psComment =
newComment(psId, filename, uuid2, range2, range2.getEndLine(),
- otherUser, null, now, "comment on ps", (short) 1, rev2);
+ otherUser, null, now, "comment on ps", (short) 1, rev2, false);
update.putComment(Status.DRAFT, baseComment);
update.putComment(Status.DRAFT, psComment);
@@ -2145,7 +2229,8 @@
ChangeUpdate update = newUpdate(c, otherUser);
Timestamp now = TimeUtil.nowTs();
Comment comment = newComment(psId, filename, uuid, range,
- range.getEndLine(), otherUser, null, now, "comment on ps1", side, rev);
+ range.getEndLine(), otherUser, null, now, "comment on ps1",
+ side, rev, false);
update.setPatchSetId(psId);
update.putComment(Status.DRAFT, comment);
update.commit();
@@ -2183,7 +2268,8 @@
ChangeUpdate update = newUpdate(c, otherUser);
Timestamp now = TimeUtil.nowTs();
Comment comment1 = newComment(ps1, filename, uuid, range,
- range.getEndLine(), otherUser, null, now, "comment on ps1", side, rev1);
+ range.getEndLine(), otherUser, null, now, "comment on ps1",
+ side, rev1, false);
update.setPatchSetId(ps1);
update.putComment(Status.DRAFT, comment1);
update.commit();
@@ -2194,7 +2280,8 @@
update = newUpdate(c, otherUser);
now = TimeUtil.nowTs();
Comment comment2 = newComment(ps2, filename, uuid, range,
- range.getEndLine(), otherUser, null, now, "comment on ps2", side, rev2);
+ range.getEndLine(), otherUser, null, now, "comment on ps2",
+ side, rev2, false);
update.setPatchSetId(ps2);
update.putComment(Status.DRAFT, comment2);
update.commit();
@@ -2229,7 +2316,7 @@
ChangeUpdate update = newUpdate(c, otherUser);
Timestamp now = TimeUtil.nowTs();
Comment comment = newComment(ps1, filename, uuid, range, range.getEndLine(),
- otherUser, null, now, "comment on ps1", side, rev);
+ otherUser, null, now, "comment on ps1", side, rev, false);
update.putComment(Status.PUBLISHED, comment);
update.commit();
@@ -2252,7 +2339,7 @@
Timestamp now = TimeUtil.nowTs();
Comment draft =
newComment(ps1, filename, "uuid1", range, range.getEndLine(), otherUser,
- null, now, "draft comment on ps1", side, rev);
+ null, now, "draft comment on ps1", side, rev, false);
update.putComment(Status.DRAFT, draft);
update.commit();
@@ -2262,7 +2349,7 @@
update = newUpdate(c, otherUser);
Comment pub = newComment(ps1, filename, "uuid2", range, range.getEndLine(),
- otherUser, null, now, "comment on ps1", side, rev);
+ otherUser, null, now, "comment on ps1", side, rev, false);
update.putComment(Status.PUBLISHED, pub);
update.commit();
@@ -2280,7 +2367,7 @@
PatchSet.Id psId = c.currentPatchSetId();
Comment comment = newComment(psId, "filename", uuid, null, 0, otherUser,
- null, now, messageForBase, (short) 0, rev);
+ null, now, messageForBase, (short) 0, rev, false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment);
update.commit();
@@ -2300,7 +2387,7 @@
PatchSet.Id psId = c.currentPatchSetId();
Comment comment = newComment(psId, "filename", uuid, null, 1, otherUser,
- null, now, messageForBase, (short) 0, rev);
+ null, now, messageForBase, (short) 0, rev, false);
update.setPatchSetId(psId);
update.putComment(Status.PUBLISHED, comment);
update.commit();
@@ -2327,9 +2414,11 @@
update.setPatchSetId(ps2);
Timestamp now = TimeUtil.nowTs();
Comment comment1 = newComment(ps1, filename, uuid, range,
- range.getEndLine(), otherUser, null, now, "comment on ps1", side, rev1);
+ range.getEndLine(), otherUser, null, now, "comment on ps1",
+ side, rev1, false);
Comment comment2 = newComment(ps2, filename, uuid, range,
- range.getEndLine(), otherUser, null, now, "comment on ps2", side, rev2);
+ range.getEndLine(), otherUser, null, now, "comment on ps2",
+ side, rev2, false);
update.putComment(Status.DRAFT, comment1);
update.putComment(Status.DRAFT, comment2);
update.commit();
@@ -2361,9 +2450,11 @@
update.setPatchSetId(ps1);
Timestamp now = TimeUtil.nowTs();
Comment comment1 = newComment(ps1, "file1", "uuid1", range,
- range.getEndLine(), otherUser, null, now, "comment1", side, rev1.get());
+ range.getEndLine(), otherUser, null, now, "comment1",
+ side, rev1.get(), false);
Comment comment2 = newComment(ps1, "file2", "uuid2", range,
- range.getEndLine(), otherUser, null, now, "comment2", side, rev1.get());
+ range.getEndLine(), otherUser, null, now, "comment2",
+ side, rev1.get(), false);
update.putComment(Status.DRAFT, comment1);
update.putComment(Status.DRAFT, comment2);
update.commit();
@@ -2412,10 +2503,10 @@
Timestamp now = TimeUtil.nowTs();
Comment comment1 =
newComment(ps1, "file1", "uuid1", range, range.getEndLine(), otherUser,
- null, now, "comment on ps1", side, rev1.get());
+ null, now, "comment on ps1", side, rev1.get(), false);
Comment comment2 =
newComment(ps1, "file2", "uuid2", range, range.getEndLine(), otherUser,
- null, now, "another comment", side, rev1.get());
+ null, now, "another comment", side, rev1.get(), false);
update.putComment(Status.DRAFT, comment1);
update.putComment(Status.DRAFT, comment2);
update.commit();
@@ -2472,13 +2563,15 @@
ChangeUpdate update1 = newUpdate(c, otherUser);
Comment comment1 = newComment(c.currentPatchSetId(), "filename",
"uuid1", range, range.getEndLine(), otherUser, null,
- new Timestamp(update1.getWhen().getTime()), "comment 1", (short) 1, rev);
+ new Timestamp(update1.getWhen().getTime()), "comment 1",
+ (short) 1, rev, false);
update1.putComment(Status.PUBLISHED, comment1);
ChangeUpdate update2 = newUpdate(c, otherUser);
Comment comment2 = newComment(c.currentPatchSetId(), "filename",
"uuid2", range, range.getEndLine(), otherUser, null,
- new Timestamp(update2.getWhen().getTime()), "comment 2", (short) 1, rev);
+ new Timestamp(update2.getWhen().getTime()), "comment 2",
+ (short) 1, rev, false);
update2.putComment(Status.PUBLISHED, comment2);
try (NoteDbUpdateManager manager = updateManagerFactory.create(project)) {
@@ -2527,7 +2620,7 @@
Comment comment = newComment(update.getPatchSetId(), "filename",
"uuid", range, range.getEndLine(), changeOwner, null,
new Timestamp(update.getWhen().getTime()), "comment", (short) 1,
- "abcd1234abcd1234abcd1234abcd1234abcd1234");
+ "abcd1234abcd1234abcd1234abcd1234abcd1234", false);
update.putComment(Status.PUBLISHED, comment);
update.commit();
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
index 9c52a27..60fd2ef 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
@@ -204,7 +204,7 @@
@Before
public void setTimeForTesting() {
- resetTimeWithClockStep(1, MILLISECONDS);
+ resetTimeWithClockStep(1, SECONDS);
}
private void resetTimeWithClockStep(long clockStep, TimeUnit clockStepUnit) {
diff --git a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.js b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.js
index b331899..485c8f9 100644
--- a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.js
@@ -30,6 +30,7 @@
loggedIn: {
type: Boolean,
value: false,
+ observer: '_loggedInChanged',
},
_schemes: {
@@ -49,15 +50,6 @@
Gerrit.RESTClientBehavior,
],
- attached: function() {
- if (!this.loggedIn) { return; }
- this.$.restAPI.getPreferences().then(function(prefs) {
- if (prefs.download_scheme) {
- this._selectedScheme = prefs.download_scheme;
- }
- }.bind(this));
- },
-
focus: function() {
this.$.download.focus();
},
@@ -70,6 +62,15 @@
};
},
+ _loggedInChanged: function(loggedIn) {
+ if (!loggedIn) { return; }
+ this.$.restAPI.getPreferences().then(function(prefs) {
+ if (prefs.download_scheme) {
+ this._selectedScheme = prefs.download_scheme;
+ }
+ }.bind(this));
+ },
+
_computeDownloadCommands: function(change, patchNum, _selectedScheme) {
var commandObj;
for (var rev in change.revisions) {
diff --git a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.html b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.html
index ad5086b..fdeecd7 100644
--- a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.html
+++ b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.html
@@ -162,6 +162,22 @@
assert.isFalse(el.hasAttribute('selected'));
});
});
+
+ test('loads scheme from preferences w/o initial login', function(done) {
+ stub('gr-rest-api-interface', {
+ getPreferences: function() {
+ return Promise.resolve({download_scheme: 'repo'});
+ },
+ });
+
+ element.loggedIn = true;
+
+ assert.isTrue(element.$.restAPI.getPreferences.called);
+ element.$.restAPI.getPreferences.lastCall.returnValue.then(function() {
+ assert.equal(element._selectedScheme, 'repo');
+ done();
+ });
+ });
});
suite('gr-download-dialog tests', function() {
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.html b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.html
index 5ab7fd6..cf66b49 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.html
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.html
@@ -284,7 +284,7 @@
path="[[file.__path]]"
prefs="[[_diffPrefs]]"
project-config="[[projectConfig]]"
- view-mode="[[_diffMode]]"></gr-diff>
+ view-mode="[[diffViewMode]]"></gr-diff>
</template>
<div class="row totalChanges">
<div class="total-stats" hidden$="[[_hideChangeTotals]]">
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
index 64b232e..1bb998f 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
@@ -16,11 +16,6 @@
var COMMIT_MESSAGE_PATH = '/COMMIT_MSG';
- var DiffViewMode = {
- SIDE_BY_SIDE: 'SIDE_BY_SIDE',
- UNIFIED: 'UNIFIED_DIFF',
- };
-
Polymer({
is: 'gr-file-list',
@@ -91,10 +86,6 @@
type: Array,
computed: '_computeFilesShown(_numFilesShown, _files.*)',
},
- _diffMode: {
- type: String,
- computed: '_getDiffViewMode(diffViewMode, _userPrefs)',
- },
// Caps the number of files that can be shown and have the 'show diffs' /
// 'hide diffs' buttons still be functional.
_maxFilesForBulkActions: {
@@ -152,16 +143,10 @@
this._diffPrefs = prefs;
}.bind(this)));
- // Initialize with user's diff mode preference. Default to
- // SIDE_BY_SIDE in the meantime.
- var setDiffViewMode = this.diffViewMode === null;
- if (setDiffViewMode) {
- this.set('diffViewMode', DiffViewMode.SIDE_BY_SIDE);
- }
promises.push(this._getPreferences().then(function(prefs) {
this._userPrefs = prefs;
- if (setDiffViewMode) {
- this.set('diffViewMode', prefs.diff_view);
+ if (!this.diffViewMode) {
+ this.set('diffViewMode', prefs.default_diff_view);
}
}.bind(this)));
},
@@ -613,29 +598,6 @@
this._diffAgainst = patchRange.basePatchNum;
},
- /**
- * _getDiffViewMode: Get the diff view (side-by-side or unified) based on
- * the current state.
- *
- * The expected behavior is to use the mode specified in the user's
- * preferences unless they have manually chosen the alternative view. If the
- * user navigates up to the change view, it should clear this choice and
- * revert to the preference the next time a diff is viewed.
- *
- * Use side-by-side if the user is not logged in.
- *
- * @return {String}
- */
- _getDiffViewMode: function() {
- if (this.diffViewMode) {
- return this.diffViewMode;
- } else if (this._userPrefs && this._userPrefs.diff_view) {
- return this.diffViewMode = this._userPrefs.diff_view;
- }
-
- return DiffViewMode.SIDE_BY_SIDE;
- },
-
_fileListActionsVisible: function(numFilesShown, maxFilesForBulkActions) {
return numFilesShown <= maxFilesForBulkActions;
},
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
index f472403..04070b5 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
@@ -557,12 +557,10 @@
element.$.fileCursor.setCursorAtIndex(0);
flushAsynchronousOperations();
var diffDisplay = element.diffs[0];
- element._userPrefs = {diff_view: 'SIDE_BY_SIDE'};
- assert.equal(element._getDiffViewMode(), 'SIDE_BY_SIDE');
+ element._userPrefs = {default_diff_view: 'SIDE_BY_SIDE'};
assert.equal(element.diffViewMode, 'SIDE_BY_SIDE');
assert.equal(diffDisplay.viewMode, 'SIDE_BY_SIDE');
element.set('diffViewMode', 'UNIFIED_DIFF');
- assert.equal(element._getDiffViewMode(), 'UNIFIED_DIFF');
assert.equal(diffDisplay.viewMode, 'UNIFIED_DIFF');
});
@@ -583,7 +581,7 @@
assert.equal(select.value, 'SIDE_BY_SIDE');
// Receive the overriding preference.
- resolvePrefs({diff_view: 'UNIFIED'});
+ resolvePrefs({default_diff_view: 'UNIFIED'});
flushAsynchronousOperations();
assert.equal(select.value, 'SIDE_BY_SIDE');
document.getElementById('blank').restore();
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.html b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.html
index 9b7a11f0..5832f7f 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.html
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.html
@@ -187,11 +187,11 @@
<div class="reviewerConfirmation">
Group
<span class="groupName">
- {{_reviewerPendingConfirmation.group.name}}
+ [[_pendingConfirmationDetails.group.name]]
</span>
has
<span class="groupSize">
- {{_reviewerPendingConfirmation.count}}
+ [[_pendingConfirmationDetails.count]]
</span>
members.
<br>
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.js b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.js
index 3f27234..1cad8e5 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.js
@@ -84,6 +84,7 @@
computed: '_computeLabels(change.labels.*, _account)',
},
_owner: Object,
+ _pendingConfirmationDetails: Object,
_reviewers: Array,
_reviewerPendingConfirmation: {
type: Object,
@@ -419,6 +420,8 @@
if (reviewer === null) {
this.$.reviewerConfirmationOverlay.close();
} else {
+ this._pendingConfirmationDetails =
+ this._ccPendingConfirmation || this._reviewerPendingConfirmation;
this.$.reviewerConfirmationOverlay.open();
}
},
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.html b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.html
index 72fbaaf..23a6c86 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.html
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.html
@@ -194,12 +194,14 @@
});
}
- test('reviewer confirmation', function(done) {
+ function testConfirmationDialog(done, cc) {
var yesButton =
element.$$('.reviewerConfirmationButtons gr-button:first-child');
var noButton =
element.$$('.reviewerConfirmationButtons gr-button:last-child');
+ element.serverConfig = {note_db_enabled: true};
+ element._ccPendingConfirmation = null;
element._reviewerPendingConfirmation = null;
flushAsynchronousOperations();
assert.isFalse(isVisible(element.$.reviewerConfirmationOverlay));
@@ -209,15 +211,37 @@
var group = {
id: 'id',
name: 'name',
- count: 10,
};
- element._reviewerPendingConfirmation = {
- group: group,
- };
+ if (cc) {
+ element._ccPendingConfirmation = {
+ group: group,
+ count: 10,
+ };
+ } else {
+ element._reviewerPendingConfirmation = {
+ group: group,
+ count: 10,
+ };
+ }
+ flushAsynchronousOperations();
+
+ if (cc) {
+ assert.deepEqual(
+ element._ccPendingConfirmation,
+ element._pendingConfirmationDetails);
+ } else {
+ assert.deepEqual(
+ element._reviewerPendingConfirmation,
+ element._pendingConfirmationDetails);
+ }
observer.then(function() {
assert.isTrue(isVisible(element.$.reviewerConfirmationOverlay));
observer = overlayObserver('closed');
+ var expected = 'Group name has 10 members';
+ assert.notEqual(
+ element.$.reviewerConfirmationOverlay.innerText.indexOf(expected),
+ -1);
MockInteractions.tap(noButton); // close the overlay
return observer;
}).then(function() {
@@ -226,14 +250,23 @@
// We should be focused on account entry input.
assert.equal(getActiveElement().id, 'input');
- // No reviewer should have been added.
- assert.deepEqual(element.$.reviewers.additions(), []);
+ // No reviewer/CC should have been added.
+ assert.equal(element.$$('#ccs').additions().length, 0);
+ assert.equal(element.$.reviewers.additions().length, 0);
// Reopen confirmation dialog.
observer = overlayObserver('opened');
- element._reviewerPendingConfirmation = {
- group: group,
- };
+ if (cc) {
+ element._ccPendingConfirmation = {
+ group: group,
+ count: 10,
+ };
+ } else {
+ element._reviewerPendingConfirmation = {
+ group: group,
+ count: 10,
+ };
+ }
return observer;
}).then(function() {
assert.isTrue(isVisible(element.$.reviewerConfirmationOverlay));
@@ -242,14 +275,16 @@
return observer;
}).then(function() {
assert.isFalse(isVisible(element.$.reviewerConfirmationOverlay));
+ var additions = cc ?
+ element.$$('#ccs').additions() :
+ element.$.reviewers.additions();
assert.deepEqual(
- element.$.reviewers.additions(),
+ additions,
[
{
group: {
id: 'id',
name: 'name',
- count: 10,
confirmed: true,
_group: true,
_pendingAdd: true,
@@ -260,6 +295,14 @@
// We should be focused on account entry input.
assert.equal(getActiveElement().id, 'input');
}).then(done);
+ };
+
+ test('cc confirmation', function(done) {
+ testConfirmationDialog(done, true);
+ });
+
+ test('reviewer confirmation', function(done) {
+ testConfirmationDialog(done, false);
});
test('_getStorageLocation', function() {
diff --git a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.html b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.html
index 76a1c1f..c3d9b16 100644
--- a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.html
+++ b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.html
@@ -46,7 +46,7 @@
cursor: default;
display: inline-block;
margin-left: 1em;
- padding: .5em 0;
+ padding: 0;
position: relative;
}
.linksTitle {
@@ -70,6 +70,7 @@
border-top-color: #666;
}
.rightItems {
+ align-items: center;
display: flex;
flex: 1;
justify-content: flex-end;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.html b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.html
index 864294b..0f00e18 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.html
@@ -25,7 +25,6 @@
background-color: #ffd;
border: 1px solid #bbb;
display: block;
- padding: 0 .7em;
white-space: normal;
}
</style>
@@ -38,10 +37,11 @@
draft="[[comment.__draft]]"
show-actions="[[_showActions]]"
project-config="[[projectConfig]]"
- on-reply="_handleCommentReply"
on-comment-discard="_handleCommentDiscard"
- on-ack="_handleCommentAck"
- on-done="_handleCommentDone"></gr-diff-comment>
+ on-create-ack-comment="_handleCommentAck"
+ on-create-done-comment="_handleCommentDone"
+ on-create-fix-comment="_handleCommentFix"
+ on-create-reply-comment="_handleCommentReply"></gr-diff-comment>
</template>
</div>
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.js b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.js
index a094253..04dc547 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.js
@@ -14,6 +14,8 @@
(function() {
'use strict';
+ var NEWLINE_PATTERN = /\n/g;
+
Polymer({
is: 'gr-diff-comment-thread',
@@ -154,41 +156,50 @@
}
},
+ _createReplyComment: function(parent, content, opt_isEditing) {
+ var reply = this._newReply(parent.id, parent.line, content);
+
+ if (opt_isEditing) {
+ reply.__editing = true;
+ }
+
+ this.push('comments', reply);
+
+ if (!opt_isEditing) {
+ // Allow the reply to render in the dom-repeat.
+ this.async(function() {
+ var commentEl = this._commentElWithDraftID(reply.__draftID);
+ commentEl.save();
+ }, 1);
+ }
+ },
+
_handleCommentReply: function(e) {
var comment = e.detail.comment;
var quoteStr;
if (e.detail.quote) {
var msg = comment.message;
- var quoteStr = msg.split('\n').map(
- function(line) { return '> ' + line; }).join('\n') + '\n\n';
+ quoteStr = '> ' + msg.replace(NEWLINE_PATTERN, '\n> ') + '\n\n';
}
- var reply = this._newReply(comment.id, comment.line, quoteStr);
- reply.__editing = true;
- this.push('comments', reply);
+ this._createReplyComment(comment, quoteStr, true);
},
_handleCommentAck: function(e) {
var comment = e.detail.comment;
- var reply = this._newReply(comment.id, comment.line, 'Ack');
- this.push('comments', reply);
-
- // Allow the reply to render in the dom-repeat.
- this.async(function() {
- var commentEl = this._commentElWithDraftID(reply.__draftID);
- commentEl.save();
- }.bind(this), 1);
+ this._createReplyComment(comment, 'Ack');
},
_handleCommentDone: function(e) {
var comment = e.detail.comment;
- var reply = this._newReply(comment.id, comment.line, 'Done');
- this.push('comments', reply);
+ this._createReplyComment(comment, 'Done');
+ },
- // Allow the reply to render in the dom-repeat.
- this.async(function() {
- var commentEl = this._commentElWithDraftID(reply.__draftID);
- commentEl.save();
- }.bind(this), 1);
+ _handleCommentFix: function(e) {
+ var comment = e.detail.comment;
+ var msg = comment.message;
+ var quoteStr = '> ' + msg.replace(NEWLINE_PATTERN, '\n> ') + '\n\n';
+ var response = quoteStr + 'Please Fix';
+ this._createReplyComment(comment, response);
},
_commentElWithDraftID: function(id) {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread_test.html b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread_test.html
index b694a75..5e65bc8 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread_test.html
@@ -152,7 +152,7 @@
test('reply', function(done) {
var commentEl = element.$$('gr-diff-comment');
assert.ok(commentEl);
- commentEl.addEventListener('reply', function() {
+ commentEl.addEventListener('create-reply-comment', function() {
var drafts = element._orderedComments.filter(function(c) {
return c.__draft == true;
});
@@ -161,13 +161,14 @@
assert.equal(drafts[0].in_reply_to, 'baf0414d_60047215');
done();
});
- commentEl.fire('reply', {comment: commentEl.comment}, {bubbles: false});
+ commentEl.fire('create-reply-comment', {comment: commentEl.comment},
+ {bubbles: false});
});
test('quote reply', function(done) {
var commentEl = element.$$('gr-diff-comment');
assert.ok(commentEl);
- commentEl.addEventListener('reply', function() {
+ commentEl.addEventListener('create-reply-comment', function() {
var drafts = element._orderedComments.filter(function(c) {
return c.__draft == true;
});
@@ -176,8 +177,37 @@
assert.equal(drafts[0].in_reply_to, 'baf0414d_60047215');
done();
});
- commentEl.fire('reply', {comment: commentEl.comment, quote: true},
- {bubbles: false});
+ commentEl.fire('create-reply-comment', {comment: commentEl.comment,
+ quote: true}, {bubbles: false});
+ });
+
+ test('quote reply multiline', function(done) {
+ element.comments = [{
+ author: {
+ name: 'Mr. Peanutbutter',
+ email: 'tenn1sballchaser@aol.com',
+ },
+ id: 'baf0414d_60047215',
+ line: 5,
+ message: 'is this a crossover episode!?\nIt might be!',
+ updated: '2015-12-08 19:48:33.843000000',
+ }];
+ flushAsynchronousOperations();
+
+ var commentEl = element.$$('gr-diff-comment');
+ assert.ok(commentEl);
+ commentEl.addEventListener('create-reply-comment', function() {
+ var drafts = element._orderedComments.filter(function(c) {
+ return c.__draft == true;
+ });
+ assert.equal(drafts.length, 1);
+ assert.equal(drafts[0].message,
+ '> is this a crossover episode!?\n> It might be!\n\n');
+ assert.equal(drafts[0].in_reply_to, 'baf0414d_60047215');
+ done();
+ });
+ commentEl.fire('create-reply-comment', {comment: commentEl.comment,
+ quote: true}, {bubbles: false});
});
test('ack', function(done) {
@@ -185,7 +215,7 @@
element.patchNum = '1';
var commentEl = element.$$('gr-diff-comment');
assert.ok(commentEl);
- commentEl.addEventListener('ack', function() {
+ commentEl.addEventListener('create-ack-comment', function() {
var drafts = element._orderedComments.filter(function(c) {
return c.__draft == true;
});
@@ -194,7 +224,8 @@
assert.equal(drafts[0].in_reply_to, 'baf0414d_60047215');
done();
});
- commentEl.fire('ack', {comment: commentEl.comment}, {bubbles: false});
+ commentEl.fire('create-ack-comment', {comment: commentEl.comment},
+ {bubbles: false});
});
test('done', function(done) {
@@ -202,7 +233,7 @@
element.patchNum = '1';
var commentEl = element.$$('gr-diff-comment');
assert.ok(commentEl);
- commentEl.addEventListener('done', function() {
+ commentEl.addEventListener('create-done-comment', function() {
var drafts = element._orderedComments.filter(function(c) {
return c.__draft == true;
});
@@ -211,7 +242,27 @@
assert.equal(drafts[0].in_reply_to, 'baf0414d_60047215');
done();
});
- commentEl.fire('done', {comment: commentEl.comment}, {bubbles: false});
+ commentEl.fire('create-done-comment', {comment: commentEl.comment},
+ {bubbles: false});
+ });
+
+ test('please fix', function(done) {
+ element.changeNum = '42';
+ element.patchNum = '1';
+ var commentEl = element.$$('gr-diff-comment');
+ assert.ok(commentEl);
+ commentEl.addEventListener('create-fix-comment', function() {
+ var drafts = element._orderedComments.filter(function(c) {
+ return c.__draft == true;
+ });
+ assert.equal(drafts.length, 1);
+ assert.equal(
+ drafts[0].message, '> is this a crossover episode!?\n\nPlease Fix');
+ assert.equal(drafts[0].in_reply_to, 'baf0414d_60047215');
+ done();
+ });
+ commentEl.fire('create-fix-comment', {comment: commentEl.comment},
+ {bubbles: false});
});
test('discard', function(done) {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.html b/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.html
index a1c73db..2bde4e7 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.html
@@ -28,17 +28,20 @@
:host {
display: block;
font-family: var(--font-family);
- margin: .7em 0;
+ padding: .7em .7em;
--iron-autogrow-textarea: {
padding: 2px;
};
}
- :host([disabled]) {
+ :host[disabled] {
pointer-events: none;
}
- :host([disabled]) .container {
+ :host[disabled] .container {
opacity: .5;
}
+ :host[is-robot-comment] {
+ background-color: #cfe8fc;
+ }
.header {
cursor: pointer;
display: flex;
@@ -93,7 +96,7 @@
.danger .action {
margin-right: 0;
}
- .container:not(.draft) .actions :not(.reply):not(.quote):not(.ack):not(.done) {
+ .container:not(.draft) .actions .hideOnPublished {
display: none;
}
.draft .reply,
@@ -124,6 +127,20 @@
.show-hide {
margin-left: .4em;
}
+ .robotId {
+ color: #808080;
+ margin-bottom: .8em;
+ margin-top: -.4em;
+ }
+ .runIdInformation {
+ margin-bottom: .5em;
+ }
+ .robotRun {
+ margin-left: .5em;
+ }
+ .robotRunLink {
+ margin-left: .5em;
+ }
input.show-hide {
display: none;
}
@@ -178,6 +195,11 @@
</label>
</div>
</div>
+ <template is="dom-if" if="[[comment.robot_id]]">
+ <div class="robotId" hidden$="[[collapsed]]"">
+ [[comment.robot_id]]
+ </div>
+ </template>
<iron-autogrow-textarea
id="editTextarea"
class="editMessage"
@@ -190,19 +212,36 @@
content="[[comment.message]]"
collapsed="[[collapsed]]"
config="[[projectConfig.commentlinks]]"></gr-formatted-text>
- <div class="actions" hidden$="[[!showActions]]">
+ <div hidden$="[[!comment.robot_run_id]]">
+ <div class="runIdInformation" hidden$="[[collapsed]]">
+ Run ID:
+ <a class="robotRunLink" href$="[[comment.url]]">
+ <span class="robotRun">[[comment.robot_run_id]]</span>
+ </a>
+ </div>
+ </div>
+ <div class="actions humanActions" hidden$="[[!_showHumanActions]]">
<gr-button class="action reply" on-tap="_handleReply">Reply</gr-button>
<gr-button class="action quote" on-tap="_handleQuote">Quote</gr-button>
<gr-button class="action ack" on-tap="_handleAck">Ack</gr-button>
- <gr-button class="action done" on-tap="_handleDone">Done</gr-button>
- <gr-button class="action edit" on-tap="_handleEdit">Edit</gr-button>
- <gr-button class="action save" on-tap="_handleSave"
+ <gr-button class="action done" on-tap="_handleDone">
+ Done</gr-button>
+ <gr-button class="action edit hideOnPublished" on-tap="_handleEdit">
+ Edit</gr-button>
+ <gr-button class="action save hideOnPublished" on-tap="_handleSave"
disabled$="[[_computeSaveDisabled(_messageText)]]">Save</gr-button>
- <gr-button class="action cancel" on-tap="_handleCancel" hidden>Cancel</gr-button>
+ <gr-button class="action cancel hideOnPublished"
+ on-tap="_handleCancel" hidden>Cancel</gr-button>
<div class="danger">
- <gr-button class="action discard" on-tap="_handleDiscard">Discard</gr-button>
+ <gr-button class="action discard hideOnPublished"
+ on-tap="_handleDiscard">Discard</gr-button>
</div>
</div>
+ <div class="actions robotActions" hidden$="[[!_showRobotActions]]">
+ <gr-button class="action fix" on-tap="_handleFix">
+ Please Fix
+ </gr-button>
+ </div>
</div>
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
<gr-storage id="storage"></gr-storage>
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.js b/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.js
index 72138ff..cbf20e8 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.js
@@ -22,19 +22,25 @@
/**
* Fired when the Reply action is triggered.
*
- * @event reply
+ * @event create-reply-comment
*/
/**
* Fired when the Ack action is triggered.
*
- * @event ack
+ * @event create-ack-comment
*/
/**
* Fired when the Done action is triggered.
*
- * @event done
+ * @event create-done-comment
+ */
+
+ /**
+ * Fired when the create fix comment action is triggered.
+ *
+ * @event create-fix-comment
*/
/**
@@ -70,6 +76,11 @@
notify: true,
observer: '_commentChanged',
},
+ isRobotComment: {
+ type: Boolean,
+ value: false,
+ reflectToAttribute: true,
+ },
disabled: {
type: Boolean,
value: false,
@@ -85,8 +96,11 @@
value: false,
observer: '_editingChanged',
},
+ hasChildren: Boolean,
patchNum: String,
showActions: Boolean,
+ _showHumanActions: Boolean,
+ _showRobotActions: Boolean,
collapsed: {
type: Boolean,
value: true,
@@ -105,6 +119,8 @@
observers: [
'_commentMessageChanged(comment.message)',
'_loadLocalDraft(changeNum, patchNum, comment)',
+ '_isRobotComment(comment)',
+ '_calculateActionstoShow(showActions, isRobotComment)',
],
attached: function() {
@@ -121,6 +137,15 @@
return collapsed ? '◀' : '▼';
},
+ _calculateActionstoShow: function(showActions, isRobotComment) {
+ this._showHumanActions = showActions && !isRobotComment;
+ this._showRobotActions = showActions && isRobotComment;
+ },
+
+ _isRobotComment: function(comment) {
+ this.isRobotComment = !!comment.robot_id;
+ },
+
save: function() {
this.comment.message = this._messageText;
this.disabled = true;
@@ -290,23 +315,32 @@
_handleReply: function(e) {
e.preventDefault();
- this.fire('reply', this._getEventPayload(), {bubbles: false});
+ this.fire('create-reply-comment', this._getEventPayload(),
+ {bubbles: false});
},
_handleQuote: function(e) {
e.preventDefault();
- this.fire(
- 'reply', this._getEventPayload({quote: true}), {bubbles: false});
+ this.fire( 'create-reply-comment', this._getEventPayload({quote: true}),
+ {bubbles: false});
+ },
+
+ _handleFix: function(e) {
+ e.preventDefault();
+ this.fire('create-fix-comment', this._getEventPayload({quote: true}),
+ {bubbles: false});
},
_handleAck: function(e) {
e.preventDefault();
- this.fire('ack', this._getEventPayload(), {bubbles: false});
+ this.fire('create-ack-comment', this._getEventPayload(),
+ {bubbles: false});
},
_handleDone: function(e) {
e.preventDefault();
- this.fire('done', this._getEventPayload(), {bubbles: false});
+ this.fire('create-done-comment', this._getEventPayload(),
+ {bubbles: false});
},
_handleEdit: function(e) {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment_test.html b/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment_test.html
index f562d3a..6793144 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment_test.html
@@ -99,7 +99,7 @@
});
test('proper event fires on reply', function(done) {
- element.addEventListener('reply', function(e) {
+ element.addEventListener('create-reply-comment', function(e) {
assert.ok(e.detail.comment);
done();
});
@@ -107,7 +107,7 @@
});
test('proper event fires on quote', function(done) {
- element.addEventListener('reply', function(e) {
+ element.addEventListener('create-reply-comment', function(e) {
assert.ok(e.detail.comment);
assert.isTrue(e.detail.quote);
done();
@@ -116,19 +116,26 @@
});
test('proper event fires on ack', function(done) {
- element.addEventListener('ack', function(e) {
+ element.addEventListener('create-ack-comment', function(e) {
done();
});
MockInteractions.tap(element.$$('.ack'));
});
test('proper event fires on done', function(done) {
- element.addEventListener('done', function(e) {
+ element.addEventListener('create-done-comment', function(e) {
done();
});
MockInteractions.tap(element.$$('.done'));
});
+ test('proper event fires on fix', function(done) {
+ element.addEventListener('create-fix-comment', function(e) {
+ done();
+ });
+ MockInteractions.tap(element.$$('.fix'));
+ });
+
test('clicking on date link does not trigger nav', function() {
var showStub = sinon.stub(page, 'show');
var dateEl = element.$$('.date');
@@ -229,9 +236,12 @@
test('button visibility states', function() {
element.showActions = false;
- assert.isTrue(element.$$('.actions').hasAttribute('hidden'));
+ assert.isTrue(element.$$('.humanActions').hasAttribute('hidden'));
+ assert.isTrue(element.$$('.robotActions').hasAttribute('hidden'));
+
element.showActions = true;
- assert.isFalse(element.$$('.actions').hasAttribute('hidden'));
+ assert.isFalse(element.$$('.humanActions').hasAttribute('hidden'));
+ assert.isTrue(element.$$('.robotActions').hasAttribute('hidden'));
element.draft = true;
assert.isTrue(isVisible(element.$$('.edit')), 'edit is visible');
@@ -242,6 +252,8 @@
assert.isFalse(isVisible(element.$$('.quote')), 'quote is not visible');
assert.isFalse(isVisible(element.$$('.ack')), 'ack is not visible');
assert.isFalse(isVisible(element.$$('.done')), 'done is not visible');
+ assert.isFalse(element.$$('.humanActions').hasAttribute('hidden'));
+ assert.isTrue(element.$$('.robotActions').hasAttribute('hidden'));
element.editing = true;
assert.isFalse(isVisible(element.$$('.edit')), 'edit is not visible');
@@ -252,6 +264,8 @@
assert.isFalse(isVisible(element.$$('.quote')), 'quote is not visible');
assert.isFalse(isVisible(element.$$('.ack')), 'ack is not visible');
assert.isFalse(isVisible(element.$$('.done')), 'done is not visible');
+ assert.isFalse(element.$$('.humanActions').hasAttribute('hidden'));
+ assert.isTrue(element.$$('.robotActions').hasAttribute('hidden'));
element.draft = false;
element.editing = false;
@@ -264,11 +278,26 @@
assert.isTrue(isVisible(element.$$('.quote')), 'quote is visible');
assert.isTrue(isVisible(element.$$('.ack')), 'ack is visible');
assert.isTrue(isVisible(element.$$('.done')), 'done is visible');
+ assert.isFalse(element.$$('.humanActions').hasAttribute('hidden'));
+ assert.isTrue(element.$$('.robotActions').hasAttribute('hidden'));
element.comment.id = 'foo';
element.draft = true;
element.editing = true;
assert.isTrue(isVisible(element.$$('.cancel')), 'cancel is visible');
+ assert.isFalse(element.$$('.humanActions').hasAttribute('hidden'));
+ assert.isTrue(element.$$('.robotActions').hasAttribute('hidden'));
+
+ element.isRobotComment = true;
+ element.draft = true;
+ assert.isTrue(element.$$('.humanActions').hasAttribute('hidden'));
+ assert.isFalse(element.$$('.robotActions').hasAttribute('hidden'));
+
+ // It is not expected to see Robot comment drafts, but if they appear,
+ // they will behave the same as non-drafts.
+ element.draft = false;
+ assert.isTrue(element.$$('.humanActions').hasAttribute('hidden'));
+ assert.isFalse(element.$$('.robotActions').hasAttribute('hidden'));
});
test('collapsible drafts', function() {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_test.html b/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_test.html
index a7d98e6..f1f3810 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_test.html
@@ -70,6 +70,10 @@
return Promise.resolve({baseComments: [], comments: []});
});
+ sinon.stub(diffElement, '_getDiffRobotComments', function() {
+ return Promise.resolve({baseComments: [], comments: []});
+ });
+
var setupDone = function() {
cursorElement.moveToFirstChunk();
done();
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 a087c57..5dc1d95 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
@@ -16,13 +16,6 @@
var COMMIT_MESSAGE_PATH = '/COMMIT_MSG';
- var MAX_UNIFIED_DEFAULT_WINDOW_WIDTH_PX = 900;
-
- var DiffViewMode = {
- SIDE_BY_SIDE: 'SIDE_BY_SIDE',
- UNIFIED: 'UNIFIED_DIFF',
- };
-
var DiffSides = {
LEFT: 'left',
RIGHT: 'right',
@@ -125,16 +118,9 @@
}.bind(this));
if (this.changeViewState.diffMode === null) {
// If screen size is small, always default to unified view.
- if (this._getWindowWidth() < MAX_UNIFIED_DEFAULT_WINDOW_WIDTH_PX) {
- this.set('changeViewState.diffMode', DiffViewMode.UNIFIED);
- } else {
- // Initialize with user's diff mode preference. Default to
- // SIDE_BY_SIDE in the meantime.
- this.set('changeViewState.diffMode', DiffViewMode.SIDE_BY_SIDE);
- this.$.restAPI.getPreferences().then(function(prefs) {
- this.set('changeViewState.diffMode', prefs.diff_view);
- }.bind(this));
- }
+ this.$.restAPI.getPreferences().then(function(prefs) {
+ this.set('changeViewState.diffMode', prefs.default_diff_view);
+ }.bind(this));
}
if (this._path) {
@@ -573,9 +559,10 @@
* the current state.
*
* The expected behavior is to use the mode specified in the user's
- * preferences unless they have manually chosen the alternative view. If the
- * user navigates up to the change view, it should clear this choice and
- * revert to the preference the next time a diff is viewed.
+ * preferences unless they have manually chosen the alternative view or they
+ * are on a mobile device. If the user navigates up to the change view, it
+ * should clear this choice and revert to the preference the next time a
+ * diff is viewed.
*
* Use side-by-side if the user is not logged in.
*
@@ -584,11 +571,12 @@
_getDiffViewMode: function() {
if (this.changeViewState.diffMode) {
return this.changeViewState.diffMode;
- } else if (this._userPrefs && this._userPrefs.diff_view) {
- return this.changeViewState.diffMode = this._userPrefs.diff_view;
+ } else if (this._userPrefs) {
+ return this.changeViewState.diffMode =
+ this._userPrefs.default_diff_view;
+ } else {
+ return 'SIDE_BY_SIDE';
}
-
- return DiffViewMode.SIDE_BY_SIDE;
},
_computeModeSelectHidden: function() {
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 cb8c095..29dd8ae 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
@@ -457,7 +457,7 @@
test('diff mode selector correctly toggles the diff', function() {
var select = element.$.modeSelect;
var diffDisplay = element.$.diff;
- element._userPrefs = {diff_view: 'SIDE_BY_SIDE'};
+ element._userPrefs = {default_diff_view: 'SIDE_BY_SIDE'};
// The mode selected in the view state reflects the selected option.
assert.equal(element._getDiffViewMode(), select.value);
@@ -496,42 +496,11 @@
assert.equal(select.value, 'SIDE_BY_SIDE');
// Receive the overriding preference.
- resolvePrefs({diff_view: 'UNIFIED'});
+ resolvePrefs({default_diff_view: 'UNIFIED'});
flushAsynchronousOperations();
assert.equal(select.value, 'SIDE_BY_SIDE');
});
- test('unified view is always default on small screens', function() {
- var resolvePrefs;
- var prefsPromise = new Promise(function(resolve) {
- resolvePrefs = resolve;
- });
-
- var getPreferencesStub = sandbox.stub(element.$.restAPI, 'getPreferences',
- function() { return prefsPromise; });
-
- // Attach a new gr-diff-view so we can intercept the preferences fetch.
- var view = document.createElement('gr-diff-view');
-
- view.changeViewState = {diffMode: null};
-
- sandbox.stub(view, '_getWindowWidth', function() { return 800; });
-
- var select = view.$.modeSelect;
- fixture('blank').appendChild(view);
- flushAsynchronousOperations();
-
- // At this point the diff mode doesn't yet have the user's preference.
- assert.equal(select.value, 'UNIFIED_DIFF');
-
- // Receive the overriding preference.
- resolvePrefs({diff_view: 'SIDE_BY_SIDE'});
- flushAsynchronousOperations();
-
- // On small screens, unified should override user perferences
- assert.equal(select.value, 'UNIFIED_DIFF');
- });
-
test('_loadHash', function() {
assert.isNotOk(element.$.cursor.initialLineNumber);
@@ -598,5 +567,18 @@
assert.equal(element._getDiffURL(changeNum, patchRange, path),
'/c/123/123..456/c%252B%252B/cpp.cpp');
});
+
+ test('_getDiffViewMode', function() {
+ // No user prefs or change view state set.
+ assert.equal(element._getDiffViewMode(), 'SIDE_BY_SIDE');
+
+ // User prefs but no change view state set.
+ element._userPrefs = {default_diff_view: 'UNIFIED_DIFF'};
+ assert.equal(element._getDiffViewMode(), 'UNIFIED_DIFF');
+
+ // User prefs and change view state set.
+ element.changeViewState = {diffMode: 'SIDE_BY_SIDE'};
+ assert.equal(element._getDiffViewMode(), 'SIDE_BY_SIDE');
+ });
});
</script>
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js
index 4c9d021..4b5e381 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js
@@ -453,14 +453,24 @@
}.bind(this));
},
+ _getDiffRobotComments: function() {
+ return this.$.restAPI.getDiffRobotComments(
+ this.changeNum,
+ this.patchRange.basePatchNum,
+ this.patchRange.patchNum,
+ this.path);
+ },
+
_getDiffCommentsAndDrafts: function() {
var promises = [];
promises.push(this._getDiffComments());
promises.push(this._getDiffDrafts());
+ promises.push(this._getDiffRobotComments());
return Promise.all(promises).then(function(results) {
return Promise.resolve({
comments: results[0],
drafts: results[1],
+ robotComments: results[2],
});
}).then(this._normalizeDiffCommentsAndDrafts.bind(this));
},
@@ -472,6 +482,9 @@
}
var baseDrafts = results.drafts.baseComments.map(markAsDraft);
var drafts = results.drafts.comments.map(markAsDraft);
+
+ var baseRobotComments = results.robotComments.baseComments;
+ var robotComments = results.robotComments.comments;
return Promise.resolve({
meta: {
path: this.path,
@@ -479,8 +492,10 @@
patchRange: this.patchRange,
projectConfig: this.projectConfig,
},
- left: results.comments.baseComments.concat(baseDrafts),
- right: results.comments.comments.concat(drafts),
+ left: results.comments.baseComments.concat(baseDrafts)
+ .concat(baseRobotComments),
+ right: results.comments.comments.concat(drafts)
+ .concat(robotComments),
});
},
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html
index 306f283..9e10bf9 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html
@@ -77,6 +77,19 @@
});
});
+ test('get robot comments', function(done) {
+ element.patchRange = {basePatchNum: 0, patchNum: 0};
+
+ var getDraftsStub = sinon.stub(element.$.restAPI,
+ 'getDiffRobotComments');
+ element._getDiffDrafts().then(function(result) {
+ assert.deepEqual(result, {baseComments: [], comments: []});
+ sinon.assert.notCalled(getDraftsStub);
+ getDraftsStub.restore();
+ done();
+ });
+ });
+
test('loads files weblinks', function(done) {
var diffStub = sinon.stub(element.$.restAPI, 'getDiff').returns(
Promise.resolve({
@@ -403,9 +416,24 @@
{id: 'd2'},
],
};
+
var diffDraftsStub = sinon.stub(element, '_getDiffDrafts',
function() { return Promise.resolve(drafts); });
+ var robotComments = {
+ baseComments: [
+ {id: 'br1'},
+ {id: 'br2'},
+ ],
+ comments: [
+ {id: 'r1'},
+ {id: 'r2'},
+ ],
+ };
+
+ var diffRobotCommentStub = sinon.stub(element, '_getDiffRobotComments',
+ function() { return Promise.resolve(robotComments); });
+
element.changeNum = '42';
element.patchRange = {
basePatchNum: 'PARENT',
@@ -430,17 +458,22 @@
{id: 'bc2'},
{id: 'bd1', __draft: true},
{id: 'bd2', __draft: true},
+ {id: 'br1'},
+ {id: 'br2'},
],
right: [
{id: 'c1'},
{id: 'c2'},
{id: 'd1', __draft: true},
{id: 'd2', __draft: true},
+ {id: 'r1'},
+ {id: 'r2'},
],
});
diffCommentsStub.restore();
diffDraftsStub.restore();
+ diffRobotCommentStub.restore();
done();
});
});
diff --git a/polygerrit-ui/app/elements/gr-app.html b/polygerrit-ui/app/elements/gr-app.html
index c0c967d..d62571d 100644
--- a/polygerrit-ui/app/elements/gr-app.html
+++ b/polygerrit-ui/app/elements/gr-app.html
@@ -47,13 +47,14 @@
gr-main-header,
footer {
color: var(--primary-text-color);
- padding: .5rem var(--default-horizontal-margin);
}
gr-main-header {
background-color: var(--header-background-color, #eee);
+ padding: 0 var(--default-horizontal-margin);
}
footer {
background-color: var(--footer-background-color, #eee);
+ padding: .5rem var(--default-horizontal-margin);
}
main {
flex: 1;
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.html b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.html
index 1d99caa..55209af 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.html
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.html
@@ -43,6 +43,9 @@
width: 2em;
vertical-align: middle;
}
+ gr-button[link] {
+ padding: 1em 0;
+ }
ul {
list-style: none;
}
@@ -77,7 +80,7 @@
</gr-button>
<iron-dropdown id="dropdown"
vertical-align="top"
- vertical-offset="25"
+ vertical-offset="40"
allow-outside-scroll="true"
horizontal-align="[[horizontalAlign]]"
on-tap="_handleDropdownTap">
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
index 48682e9..dee0cad 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
@@ -14,7 +14,12 @@
(function() {
'use strict';
+ var DiffViewMode = {
+ SIDE_BY_SIDE: 'SIDE_BY_SIDE',
+ UNIFIED: 'UNIFIED_DIFF',
+ };
var JSON_PREFIX = ')]}\'';
+ var MAX_UNIFIED_DEFAULT_WINDOW_WIDTH_PX = 900;
var PARENT_PATCH_NUM = 'PARENT';
// Must be kept in sync with the ListChangesOption enum and protobuf.
@@ -295,11 +300,21 @@
getPreferences: function() {
return this.getLoggedIn().then(function(loggedIn) {
if (loggedIn) {
- return this._fetchSharedCacheURL('/accounts/self/preferences');
+ return this._fetchSharedCacheURL('/accounts/self/preferences').then(
+ function(res) {
+ if (this._isNarrowScreen()) {
+ res.default_diff_view = DiffViewMode.UNIFIED;
+ } else {
+ res.default_diff_view = res.diff_view;
+ }
+ return Promise.resolve(res);
+ }.bind(this));
}
return Promise.resolve({
changes_per_page: 25,
+ default_diff_view: this._isNarrowScreen() ?
+ DiffViewMode.UNIFIED : DiffViewMode.SIDE_BY_SIDE,
diff_view: 'SIDE_BY_SIDE',
});
}.bind(this));
@@ -344,6 +359,10 @@
return this._sharedFetchPromises[url];
},
+ _isNarrowScreen: function() {
+ return window.innerWidth < MAX_UNIFIED_DEFAULT_WINDOW_WIDTH_PX;
+ },
+
getChanges: function(changesPerPage, opt_query, opt_offset) {
var options = this._listChangesOptionsToHex(
ListChangesOption.LABELS,
@@ -671,6 +690,12 @@
opt_patchNum, opt_path);
},
+ getDiffRobotComments: function(changeNum, basePatchNum, patchNum,
+ opt_path) {
+ return this._getDiffComments(changeNum, '/robotcomments', basePatchNum,
+ patchNum, opt_path);
+ },
+
getDiffDrafts: function(changeNum, opt_basePatchNum, opt_patchNum,
opt_path) {
return this._getDiffComments(changeNum, '/drafts', opt_basePatchNum,
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html
index d07968f..27d5d32 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html
@@ -339,5 +339,78 @@
assert.isTrue(sendStub.called);
assert.notOk(element._cache[cacheKey]);
});
+
+ var preferenceSetup = function(testJSON, loggedIn, smallScreen) {
+ sandbox.stub(element, 'getLoggedIn', function() {
+ return Promise.resolve(loggedIn);
+ });
+ sandbox.stub(element, '_isNarrowScreen', function() {
+ return smallScreen;
+ });
+ sandbox.stub(element, '_fetchSharedCacheURL', function() {
+ return Promise.resolve(testJSON);
+ });
+ };
+
+ test('getPreferences returns correctly on small screens logged in',
+ function(done) {
+
+ var testJSON = {diff_view: 'SIDE_BY_SIDE'};
+ var loggedIn = true;
+ var smallScreen = true;
+
+ preferenceSetup(testJSON, loggedIn, smallScreen);
+
+ element.getPreferences().then(function(obj) {
+ assert.equal(obj.default_diff_view, 'UNIFIED_DIFF');
+ assert.equal(obj.diff_view, 'SIDE_BY_SIDE');
+ done();
+ });
+ });
+
+ test('getPreferences returns correctly on small screens not logged in',
+ function(done) {
+
+ var testJSON = {diff_view: 'SIDE_BY_SIDE'};
+ var loggedIn = false;
+ var smallScreen = true;
+
+ preferenceSetup(testJSON, loggedIn, smallScreen);
+ element.getPreferences().then(function(obj) {
+ assert.equal(obj.default_diff_view, 'UNIFIED_DIFF');
+ assert.equal(obj.diff_view, 'SIDE_BY_SIDE');
+ done();
+ });
+ });
+
+ test('getPreferences returns correctly on larger screens logged in',
+ function(done) {
+ var testJSON = {diff_view: 'UNIFIED_DIFF'};
+ var loggedIn = true;
+ var smallScreen = false;
+
+ preferenceSetup(testJSON, loggedIn, smallScreen);
+
+ element.getPreferences().then(function(obj) {
+ assert.equal(obj.default_diff_view, 'UNIFIED_DIFF');
+ assert.equal(obj.diff_view, 'UNIFIED_DIFF');
+ done();
+ });
+ });
+
+ test('getPreferences returns correctly on larger screens not logged in',
+ function(done) {
+ var testJSON = {diff_view: 'UNIFIED_DIFF'};
+ var loggedIn = false;
+ var smallScreen = false;
+
+ preferenceSetup(testJSON, loggedIn, smallScreen);
+
+ element.getPreferences().then(function(obj) {
+ assert.equal(obj.default_diff_view, 'SIDE_BY_SIDE');
+ assert.equal(obj.diff_view, 'SIDE_BY_SIDE');
+ done();
+ });
+ });
});
</script>