Replace Mute/Unmute by Mark as Reviewed/Unreviewed (Part 1)
Muting a change de-highlights the change on the dashboard until a new patch set is uploaded. Most users were confused about mute since they had different expections of what mute would do. E.g. they expected that mute would behave more similar to how mute in Gmail works, and that the change would disappear from the dashboard until a new patch is uploaded (see issue 7237). Mute as it is implemented now behaves more as "Mark as Read" in email clients. To make this function more intuitive for users this change adds "Mark as Reviewed" as a replacement for "Mute". It's named "Mark as Reviewed" as opposed to "Mark as Read" to be consistent with the existing "reviewed" field in ChangeInfo. For muted changes the "reviewed" flag is always set to true. The Mute / Unmute REST endpoints are still kept to allow a migrating Gerrit hosts at *.googlesource.com. The REST endpoint for setting a change as reviewed is: PUT /changes/<change-id>/reviewed This name was chosen to stay consistent with the REST endpoint for setting reviewed flags on files which is: PUT /changes/<change>/revisions/<revision>/files/<file>/reviewed Mute is represented by a star label called 'mute'. The new MarkAsReviewed REST endpoint uses the new 'reviewed' label instead. A follow-up change will add a schema migration that takes care about renaming the existing mute labels. The Unmute action removes the "mute" label from the change, so that the "reviewed" flag is no longer overwritten with true. Without mute star label the "reviewed" flag is again computed based on the change state. This means renaming "Unmute" to "Mark as Unreviewed" would be confusing since users would expect from "Mark as Unreviewed" that the change is non-reviewed afterwards (and not automatically computed which can result in reviewed = true). This is why "Mark as Unreviewed" sets a "unreviewed" star label on the change (in addition to removing the "reviewed" label). This way we have 3 states: 1. neither "reviewed" nor "unreviewed" label: whether the change is highlighted in the dashboard is automatically computed based on the change state 2. "reviewed" label: change is not highlighted in the dashboard 3. "unreviewed" label: change is highlighted in the dashboard Having the "reviewed" and "unreviewed" labels on a change (for the same patch set) at the same time is invalid and is rejected by the server. This means MarkAsReviewed moves the change from state 1 or 3 to state 2, MarkAsUnreviewed moves the change from state 1 or 2 to state 3. We could also support DELETE requests on /changes/<change>/reviewed and /changes/<change>/unreviewed for moving the change from state 2 and 3 back to state 1 but we don't have a need for this at the moment, hence this is not implemented in this change. The change will automatically move back to state 1 when a new patch set is added. If manually going back to state 1 is necessary one can always use the generic stars API to remove the "reviewed" / "unreviewed" star. Mute is not allowed on own changes and on changes which are ignored. This limitation is removed for "Mark as Reviewed" so that this funtion is completely orthogonal to the ignore functionality. The migration to replace Mute/Unmute by Mark as Reviewed/Unreviewed is done in multiple steps: 1. Add new REST endpoints for Mark As Reviewed/Unreviewed (this change) 2. Adapt PolyGerrit to use Mark As Reviewed/Unreviewed instead of Mute/Unmute 3. Run migration for Gerrit hosts at *.googlesource.com that renames existing mute labels 4. Remove Mute/Unmute functionality and add schema migration that renames existing mute labels Bug: Issue 7237 Change-Id: I59f4156688dbf1582a33cb4e18f0adb54a73fe35 Signed-off-by: Edwin Kempin <ekempin@google.com>
This commit is contained in:
@@ -3409,6 +3409,103 @@ public class ChangeIT extends AbstractDaemonTest {
|
||||
gApi.changes().id(changeId).mute(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void markAsReviewed() throws Exception {
|
||||
TestAccount user2 = accountCreator.user2();
|
||||
|
||||
PushOneCommit.Result r = createChange();
|
||||
|
||||
AddReviewerInput in = new AddReviewerInput();
|
||||
in.reviewer = user.email;
|
||||
gApi.changes().id(r.getChangeId()).addReviewer(in);
|
||||
|
||||
setApiUser(user);
|
||||
assertThat(gApi.changes().id(r.getChangeId()).get().reviewed).isNull();
|
||||
gApi.changes().id(r.getChangeId()).markAsReviewed(true);
|
||||
assertThat(gApi.changes().id(r.getChangeId()).get().reviewed).isTrue();
|
||||
|
||||
setApiUser(user2);
|
||||
sender.clear();
|
||||
amendChange(r.getChangeId());
|
||||
|
||||
setApiUser(user);
|
||||
assertThat(gApi.changes().id(r.getChangeId()).get().reviewed).isNull();
|
||||
|
||||
List<Message> messages = sender.getMessages();
|
||||
assertThat(messages).hasSize(1);
|
||||
assertThat(messages.get(0).rcpt()).containsExactly(user.emailAddress);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cannotSetUnreviewedLabelForPatchSetThatAlreadyHasReviewedLabel() throws Exception {
|
||||
String changeId = createChange().getChangeId();
|
||||
|
||||
setApiUser(user);
|
||||
gApi.changes().id(changeId).markAsReviewed(true);
|
||||
assertThat(gApi.changes().id(changeId).get().reviewed).isTrue();
|
||||
|
||||
exception.expect(BadRequestException.class);
|
||||
exception.expectMessage(
|
||||
"The labels "
|
||||
+ StarredChangesUtil.REVIEWED_LABEL
|
||||
+ "/"
|
||||
+ 1
|
||||
+ " and "
|
||||
+ StarredChangesUtil.UNREVIEWED_LABEL
|
||||
+ "/"
|
||||
+ 1
|
||||
+ " are mutually exclusive. Only one of them can be set.");
|
||||
gApi.accounts()
|
||||
.self()
|
||||
.setStars(
|
||||
changeId, new StarsInput(ImmutableSet.of(StarredChangesUtil.UNREVIEWED_LABEL + "/1")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cannotSetReviewedLabelForPatchSetThatAlreadyHasUnreviewedLabel() throws Exception {
|
||||
String changeId = createChange().getChangeId();
|
||||
|
||||
setApiUser(user);
|
||||
gApi.changes().id(changeId).markAsReviewed(false);
|
||||
assertThat(gApi.changes().id(changeId).get().reviewed).isNull();
|
||||
|
||||
exception.expect(BadRequestException.class);
|
||||
exception.expectMessage(
|
||||
"The labels "
|
||||
+ StarredChangesUtil.REVIEWED_LABEL
|
||||
+ "/"
|
||||
+ 1
|
||||
+ " and "
|
||||
+ StarredChangesUtil.UNREVIEWED_LABEL
|
||||
+ "/"
|
||||
+ 1
|
||||
+ " are mutually exclusive. Only one of them can be set.");
|
||||
gApi.accounts()
|
||||
.self()
|
||||
.setStars(
|
||||
changeId, new StarsInput(ImmutableSet.of(StarredChangesUtil.REVIEWED_LABEL + "/1")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setReviewedAndUnreviewedLabelsForDifferentPatchSets() throws Exception {
|
||||
String changeId = createChange().getChangeId();
|
||||
|
||||
setApiUser(user);
|
||||
gApi.changes().id(changeId).markAsReviewed(true);
|
||||
assertThat(gApi.changes().id(changeId).get().reviewed).isTrue();
|
||||
|
||||
amendChange(changeId);
|
||||
assertThat(gApi.changes().id(changeId).get().reviewed).isNull();
|
||||
|
||||
gApi.changes().id(changeId).markAsReviewed(false);
|
||||
assertThat(gApi.changes().id(changeId).get().reviewed).isNull();
|
||||
|
||||
assertThat(gApi.accounts().self().getStars(changeId))
|
||||
.containsExactly(
|
||||
StarredChangesUtil.REVIEWED_LABEL + "/" + 1,
|
||||
StarredChangesUtil.UNREVIEWED_LABEL + "/" + 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cannotSetInvalidLabel() throws Exception {
|
||||
String changeId = createChange().getChangeId();
|
||||
|
Reference in New Issue
Block a user