diff --git a/.mailmap b/.mailmap index cbf1f3b69e..c86384760b 100644 --- a/.mailmap +++ b/.mailmap @@ -12,6 +12,7 @@ Bruce Zu Carlos Eduardo Baldacin carloseduardo.baldacin Changcheng Xiao xchangcheng Dariusz Luksza +Darrien Glasser darrien Dave Borowitz David Ostrovsky David Ostrovsky diff --git a/Documentation/cmd-review.txt b/Documentation/cmd-review.txt index 5417901e1f..6fe24815d1 100644 --- a/Documentation/cmd-review.txt +++ b/Documentation/cmd-review.txt @@ -21,7 +21,7 @@ _ssh_ -p _gerrit review_ [--verified ] [--code-review ] [--label Label-Name=] [--tag TAG] - {COMMIT | CHANGEID,PATCHSET}... + {COMMIT | CHANGENUMBER,PATCHSET}... -- == DESCRIPTION @@ -147,16 +147,21 @@ Approve the change with commit c0ff33 as "Verified +1" $ 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 @@ $ ssh -p 29418 review.example.com gerrit review \ 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 75cf3a6780..0eaa75e7ba 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 @@ public interface RevisionApi { RelatedChangesInfo related() throws RestApiException; + /** Returns votes on the revision. */ + ListMultimap votes() throws RestApiException; + abstract class MergeListRequest { private boolean addLinks; private int uninterestingParent = 1; @@ -377,6 +382,11 @@ public interface RevisionApi { throw new NotImplementedException(); } + @Override + public ListMultimap 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 703235dd33..e40004bcc4 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 class ApprovalInfo extends AccountInfo { } 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 91f711e3a0..b08842ed57 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 @@ public class Daemon extends SiteProgram { } private String myVersion() { - return com.google.gerrit.common.Version.getVersion(); + List 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 3f03b576b1..dff29b0079 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.common.base.Preconditions.checkArgument; 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.RobotCommentApi; 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.BinaryResult; 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.gerrit.server.restapi.change.TestSubmitType; 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 @@ class RevisionApiImpl implements RevisionApi { private final GetRelated getRelated; private final PutDescription putDescription; private final GetDescription getDescription; + private final ApprovalsUtil approvalsUtil; + private final Provider db; + private final AccountLoader.Factory accountLoaderFactory; @Inject RevisionApiImpl( @@ -175,6 +187,9 @@ class RevisionApiImpl implements RevisionApi { GetRelated getRelated, PutDescription putDescription, GetDescription getDescription, + ApprovalsUtil approvalsUtil, + Provider db, + AccountLoader.Factory accountLoaderFactory, @Assisted RevisionResource r) { this.repoManager = repoManager; this.changes = changes; @@ -214,6 +229,9 @@ class RevisionApiImpl implements RevisionApi { this.getRelated = getRelated; this.putDescription = putDescription; this.getDescription = getDescription; + this.approvalsUtil = approvalsUtil; + this.db = db; + this.accountLoaderFactory = accountLoaderFactory; this.revision = r; } @@ -603,6 +621,37 @@ class RevisionApiImpl implements RevisionApi { } } + @Override + public ListMultimap votes() throws RestApiException { + ListMultimap result = + ListMultimapBuilder.treeKeys().arrayListValues().build(); + try { + Iterable 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(); diff --git a/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java b/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java index 4594689372..86908cbb97 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.ImmutableMap; 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 @@ public class RevisionIT extends AbstractDaemonTest { .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 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 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 97151f2c31..b5d3daed5a 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",