Merge branch 'stable-2.15' into stable-2.16
* stable-2.15:
Disable "prefer-promise-reject-errors" in eslint
Set version to 2.15.10
Daemon: Show status of slave and headless mode in 'ready' log
Daemon: Don't install online reindexer in slave mode
RevisionApi: Add method to list votes per revision
ChangeJson#getApprovalInfo: Add @Nullable annotations
cmd-review: Add another example to clarify review using change number and PS
Update .mailmap
Update cmd-review documentation
Daemon: use regular binding for auditModule
CommitValidators: trim "ERROR" shouting from "forge committer" check
ReceiveCommits: uniformize commit validation error messages.
Inline "Change-Id" string into error messages
Always end the "Change-Id missing" error message with \n.
Print only one hint about Change-Ids at a time
Clean up Change-Id hint text
CommitValidators: Replace indexOf calls with String#contains
CommitValidators: Prefer using Splitter to String.split
Changes I0bfe06bd and I58f8a0e5 are intentionally omitted because
they do not apply to the structure of the stable-2.16 branch.
Change-Id: I711837f062aeefeafa3631601b0150448e879575
diff --git a/.mailmap b/.mailmap
index cbf1f3b..c863847 100644
--- a/.mailmap
+++ b/.mailmap
@@ -12,6 +12,7 @@
Carlos Eduardo Baldacin <carloseduardo.baldacin@sonyericsson.com> carloseduardo.baldacin <carloseduardo.baldacin@sonyericsson.com>
Changcheng Xiao <xchangcheng@google.com> xchangcheng
Dariusz Luksza <dluksza@collab.net> <dariusz@luksza.org>
+Darrien Glasser <darrien@arista.com> darrien <darrien@arista.com>
Dave Borowitz <dborowitz@google.com> <dborowitz@google.com>
David Ostrovsky <david@ostrovsky.org> <d.ostrovsky@gmx.de>
David Ostrovsky <david@ostrovsky.org> <david.ostrovsky@gmail.com>
diff --git a/Documentation/cmd-review.txt b/Documentation/cmd-review.txt
index 5417901..6fe24815 100644
--- a/Documentation/cmd-review.txt
+++ b/Documentation/cmd-review.txt
@@ -21,7 +21,7 @@
[--verified <N>] [--code-review <N>]
[--label Label-Name=<N>]
[--tag TAG]
- {COMMIT | CHANGEID,PATCHSET}...
+ {COMMIT | CHANGENUMBER,PATCHSET}...
--
== DESCRIPTION
@@ -147,16 +147,21 @@
$ ssh -p 29418 review.example.com gerrit review --verified +1 c0ff33
----
+Approve the change with change number 8242 and patch set 2 as "Code-Review +2"
+----
+$ ssh -p 29418 review.example.com gerrit review --code-review +2 8242,2
+----
+
Vote on the project specific label "mylabel":
----
-$ ssh -p 29418 review.example.com gerrit review --label mylabel=+1 c0ff33
+$ ssh -p 29418 review.example.com gerrit review --label mylabel=+1 8242,2
----
Append the message "Build Successful". Notice two levels of quoting is
required, one for the local shell, and another for the argument parser
inside the Gerrit server:
----
-$ ssh -p 29418 review.example.com gerrit review -m '"Build Successful"' c0ff33
+$ ssh -p 29418 review.example.com gerrit review -m '"Build Successful"' 8242,2
----
Mark the unmerged commits both "Verified +1" and "Code-Review +2" and
@@ -172,7 +177,7 @@
Abandon an active change:
----
-$ ssh -p 29418 review.example.com gerrit review --abandon c0ff33
+$ ssh -p 29418 review.example.com gerrit review --abandon 8242,2
----
== SEE ALSO
diff --git a/java/com/google/gerrit/extensions/api/changes/RevisionApi.java b/java/com/google/gerrit/extensions/api/changes/RevisionApi.java
index 75cf3a6..0eaa75e 100644
--- a/java/com/google/gerrit/extensions/api/changes/RevisionApi.java
+++ b/java/com/google/gerrit/extensions/api/changes/RevisionApi.java
@@ -14,8 +14,10 @@
package com.google.gerrit.extensions.api.changes;
+import com.google.common.collect.ListMultimap;
import com.google.gerrit.extensions.client.SubmitType;
import com.google.gerrit.extensions.common.ActionInfo;
+import com.google.gerrit.extensions.common.ApprovalInfo;
import com.google.gerrit.extensions.common.CherryPickChangeInfo;
import com.google.gerrit.extensions.common.CommentInfo;
import com.google.gerrit.extensions.common.CommitInfo;
@@ -135,6 +137,9 @@
RelatedChangesInfo related() throws RestApiException;
+ /** Returns votes on the revision. */
+ ListMultimap<String, ApprovalInfo> votes() throws RestApiException;
+
abstract class MergeListRequest {
private boolean addLinks;
private int uninterestingParent = 1;
@@ -378,6 +383,11 @@
}
@Override
+ public ListMultimap<String, ApprovalInfo> votes() throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
public void description(String description) throws RestApiException {
throw new NotImplementedException();
}
diff --git a/java/com/google/gerrit/extensions/common/ApprovalInfo.java b/java/com/google/gerrit/extensions/common/ApprovalInfo.java
index 703235d..e40004b 100644
--- a/java/com/google/gerrit/extensions/common/ApprovalInfo.java
+++ b/java/com/google/gerrit/extensions/common/ApprovalInfo.java
@@ -14,6 +14,7 @@
package com.google.gerrit.extensions.common;
+import com.google.gerrit.common.Nullable;
import java.sql.Timestamp;
public class ApprovalInfo extends AccountInfo {
@@ -28,7 +29,11 @@
}
public ApprovalInfo(
- Integer id, Integer value, VotingRangeInfo permittedVotingRange, String tag, Timestamp date) {
+ Integer id,
+ Integer value,
+ @Nullable VotingRangeInfo permittedVotingRange,
+ @Nullable String tag,
+ Timestamp date) {
super(id);
this.value = value;
this.permittedVotingRange = permittedVotingRange;
diff --git a/java/com/google/gerrit/pgm/Daemon.java b/java/com/google/gerrit/pgm/Daemon.java
index 91f711e..b08842e 100644
--- a/java/com/google/gerrit/pgm/Daemon.java
+++ b/java/com/google/gerrit/pgm/Daemon.java
@@ -14,11 +14,13 @@
package com.google.gerrit.pgm;
+import static com.google.gerrit.common.Version.getVersion;
import static com.google.gerrit.server.schema.DataSourceProvider.Context.MULTI_USER;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Objects.requireNonNull;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Joiner;
import com.google.common.base.MoreObjects;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
@@ -388,7 +390,15 @@
}
private String myVersion() {
- return com.google.gerrit.common.Version.getVersion();
+ List<String> versionParts = new ArrayList<>();
+ if (slave) {
+ versionParts.add("[slave]");
+ }
+ if (headless) {
+ versionParts.add("[headless]");
+ }
+ versionParts.add(getVersion());
+ return Joiner.on(" ").join(versionParts);
}
private Injector createCfgInjector() {
diff --git a/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java b/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java
index 3f03b57..dff29b0 100644
--- a/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java
+++ b/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java
@@ -18,6 +18,8 @@
import static com.google.gerrit.server.api.ApiUtil.asRestApiException;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ListMultimap;
+import com.google.common.collect.MultimapBuilder.ListMultimapBuilder;
import com.google.gerrit.extensions.api.changes.ChangeApi;
import com.google.gerrit.extensions.api.changes.Changes;
import com.google.gerrit.extensions.api.changes.CherryPickInput;
@@ -35,6 +37,7 @@
import com.google.gerrit.extensions.api.changes.SubmitInput;
import com.google.gerrit.extensions.client.SubmitType;
import com.google.gerrit.extensions.common.ActionInfo;
+import com.google.gerrit.extensions.common.ApprovalInfo;
import com.google.gerrit.extensions.common.CherryPickChangeInfo;
import com.google.gerrit.extensions.common.CommentInfo;
import com.google.gerrit.extensions.common.CommitInfo;
@@ -50,6 +53,11 @@
import com.google.gerrit.extensions.restapi.IdString;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.restapi.RestModifyView;
+import com.google.gerrit.reviewdb.client.PatchSetApproval;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.ApprovalsUtil;
+import com.google.gerrit.server.account.AccountDirectory.FillOptions;
+import com.google.gerrit.server.account.AccountLoader;
import com.google.gerrit.server.change.FileResource;
import com.google.gerrit.server.change.RebaseUtil;
import com.google.gerrit.server.change.RevisionResource;
@@ -84,6 +92,7 @@
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.assistedinject.Assisted;
+import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -134,6 +143,9 @@
private final GetRelated getRelated;
private final PutDescription putDescription;
private final GetDescription getDescription;
+ private final ApprovalsUtil approvalsUtil;
+ private final Provider<ReviewDb> db;
+ private final AccountLoader.Factory accountLoaderFactory;
@Inject
RevisionApiImpl(
@@ -175,6 +187,9 @@
GetRelated getRelated,
PutDescription putDescription,
GetDescription getDescription,
+ ApprovalsUtil approvalsUtil,
+ Provider<ReviewDb> db,
+ AccountLoader.Factory accountLoaderFactory,
@Assisted RevisionResource r) {
this.repoManager = repoManager;
this.changes = changes;
@@ -214,6 +229,9 @@
this.getRelated = getRelated;
this.putDescription = putDescription;
this.getDescription = getDescription;
+ this.approvalsUtil = approvalsUtil;
+ this.db = db;
+ this.accountLoaderFactory = accountLoaderFactory;
this.revision = r;
}
@@ -604,6 +622,37 @@
}
@Override
+ public ListMultimap<String, ApprovalInfo> votes() throws RestApiException {
+ ListMultimap<String, ApprovalInfo> result =
+ ListMultimapBuilder.treeKeys().arrayListValues().build();
+ try {
+ Iterable<PatchSetApproval> approvals =
+ approvalsUtil.byPatchSet(
+ db.get(), revision.getNotes(), revision.getPatchSet().getId(), null, null);
+ AccountLoader accountLoader =
+ accountLoaderFactory.create(
+ EnumSet.of(
+ FillOptions.ID, FillOptions.NAME, FillOptions.EMAIL, FillOptions.USERNAME));
+ for (PatchSetApproval approval : approvals) {
+ String label = approval.getLabel();
+ ApprovalInfo info =
+ new ApprovalInfo(
+ approval.getAccountId().get(),
+ Integer.valueOf(approval.getValue()),
+ null,
+ approval.getTag(),
+ approval.getGranted());
+ accountLoader.put(info);
+ result.get(label).add(info);
+ }
+ accountLoader.fill();
+ } catch (Exception e) {
+ throw asRestApiException("Cannot get votes", e);
+ }
+ return result;
+ }
+
+ @Override
public void description(String description) throws RestApiException {
DescriptionInput in = new DescriptionInput();
in.description = description;
diff --git a/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java b/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java
index 4594689..86908cb 100644
--- a/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java
@@ -35,6 +35,7 @@
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
+import com.google.common.collect.ListMultimap;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.acceptance.RestResponse;
@@ -1475,6 +1476,47 @@
.containsExactlyElementsIn(ImmutableSet.of(admin.getId(), user.getId()));
}
+ @Test
+ public void listVotesByRevision() throws Exception {
+ // Create patch set 1 and vote on it
+ String changeId = createChange().getChangeId();
+ ListMultimap<String, ApprovalInfo> votes = gApi.changes().id(changeId).current().votes();
+ assertThat(votes).isEmpty();
+ recommend(changeId);
+ votes = gApi.changes().id(changeId).current().votes();
+ assertThat(votes.keySet()).containsExactly("Code-Review");
+ List<ApprovalInfo> approvals = votes.get("Code-Review");
+ assertThat(approvals).hasSize(1);
+ ApprovalInfo approval = approvals.get(0);
+ assertThat(approval._accountId).isEqualTo(admin.id.get());
+ assertThat(approval.email).isEqualTo(admin.email);
+ assertThat(approval.username).isEqualTo(admin.username);
+
+ // Also vote on it with another user
+ setApiUser(user);
+ gApi.changes().id(changeId).current().review(ReviewInput.dislike());
+
+ // Patch set 1 has 2 votes on Code-Review
+ setApiUser(admin);
+ votes = gApi.changes().id(changeId).current().votes();
+ assertThat(votes.keySet()).containsExactly("Code-Review");
+ approvals = votes.get("Code-Review");
+ assertThat(approvals).hasSize(2);
+ assertThat(approvals.stream().map(a -> a._accountId))
+ .containsExactlyElementsIn(ImmutableList.of(admin.id.get(), user.id.get()));
+
+ // Create a new patch set which does not have any votes
+ amendChange(changeId);
+ votes = gApi.changes().id(changeId).current().votes();
+ assertThat(votes).isEmpty();
+
+ // Votes are still returned for ps 1
+ votes = gApi.changes().id(changeId).revision(1).votes();
+ assertThat(votes.keySet()).containsExactly("Code-Review");
+ approvals = votes.get("Code-Review");
+ assertThat(approvals).hasSize(2);
+ }
+
private static void assertCherryPickResult(
ChangeInfo changeInfo, CherryPickInput input, String srcChangeId) throws Exception {
assertThat(changeInfo.changeId).isEqualTo(srcChangeId);
diff --git a/polygerrit-ui/app/.eslintrc.json b/polygerrit-ui/app/.eslintrc.json
index 97151f2..b5d3dae 100644
--- a/polygerrit-ui/app/.eslintrc.json
+++ b/polygerrit-ui/app/.eslintrc.json
@@ -63,6 +63,7 @@
"object-shorthand": ["error", "always"],
"prefer-arrow-callback": "error",
"prefer-const": "error",
+ "prefer-promise-reject-errors": "off",
"prefer-spread": "error",
"quote-props": ["error", "consistent-as-needed"],
"require-jsdoc": "off",