use of com.google.gerrit.extensions.api.changes.ReviewerResult in project gerrit by GerritCodeReview.
the class ChangeReviewersIT method addCcGroup.
@Test
public void addCcGroup() throws Exception {
List<TestAccount> users = createAccounts(6, "addCcGroup");
List<String> usernames = new ArrayList<>(6);
for (TestAccount u : users) {
usernames.add(u.username());
}
List<TestAccount> firstUsers = users.subList(0, 3);
List<String> firstUsernames = usernames.subList(0, 3);
PushOneCommit.Result r = createChange();
String changeId = r.getChangeId();
ReviewerInput in = new ReviewerInput();
in.reviewer = groupOperations.newGroup().name("cc1").create().get();
in.state = CC;
gApi.groups().id(in.reviewer).addMembers(firstUsernames.toArray(new String[firstUsernames.size()]));
ReviewerResult result = addReviewer(changeId, in);
assertThat(result.input).isEqualTo(in.reviewer);
assertThat(result.confirm).isNull();
assertThat(result.error).isNull();
assertThat(result.reviewers).isNull();
ChangeInfo c = gApi.changes().id(r.getChangeId()).get();
assertReviewers(c, CC, firstUsers);
// Verify emails were sent to each of the group's accounts.
List<Message> messages = sender.getMessages();
assertThat(messages).hasSize(1);
Message m = messages.get(0);
List<Address> expectedAddresses = new ArrayList<>(firstUsers.size());
for (TestAccount u : firstUsers) {
expectedAddresses.add(u.getNameEmail());
}
assertThat(m.rcpt()).containsExactlyElementsIn(expectedAddresses);
// CC a group that overlaps with some existing reviewers and CCed accounts.
TestAccount reviewer = accountCreator.create(name("reviewer"), "addCcGroup-reviewer@example.com", "Reviewer", null);
result = addReviewer(changeId, reviewer.username());
assertThat(result.error).isNull();
sender.clear();
in.reviewer = groupOperations.newGroup().name("cc2").create().get();
gApi.groups().id(in.reviewer).addMembers(usernames.toArray(new String[usernames.size()]));
gApi.groups().id(in.reviewer).addMembers(reviewer.username());
result = addReviewer(changeId, in);
assertThat(result.input).isEqualTo(in.reviewer);
assertThat(result.confirm).isNull();
assertThat(result.error).isNull();
c = gApi.changes().id(r.getChangeId()).get();
assertThat(result.ccs).hasSize(3);
assertThat(result.reviewers).isNull();
assertReviewers(c, REVIEWER, reviewer);
assertReviewers(c, CC, users);
messages = sender.getMessages();
assertThat(messages).hasSize(1);
m = messages.get(0);
expectedAddresses = new ArrayList<>(4);
for (int i = 0; i < 3; i++) {
expectedAddresses.add(users.get(users.size() - i - 1).getNameEmail());
}
expectedAddresses.add(reviewer.getNameEmail());
assertThat(m.rcpt()).containsExactlyElementsIn(expectedAddresses);
}
use of com.google.gerrit.extensions.api.changes.ReviewerResult in project gerrit by GerritCodeReview.
the class ChangeIT method addReviewerThatIsInactiveByEmail.
@Test
public void addReviewerThatIsInactiveByEmail() throws Exception {
ConfigInput conf = new ConfigInput();
conf.enableReviewerByEmail = InheritableBoolean.TRUE;
gApi.projects().name(project.get()).config(conf);
PushOneCommit.Result result = createChange();
String username = "user@domain.com";
Account.Id id = accountOperations.newAccount().username(username).inactive().create();
ReviewerInput in = new ReviewerInput();
in.reviewer = username;
in.state = ReviewerState.CC;
ReviewerResult r = gApi.changes().id(result.getChangeId()).addReviewer(in);
assertThat(r.input).isEqualTo(username);
assertThat(r.error).isNull();
assertThat(r.ccs).hasSize(1);
AccountInfo reviewer = r.ccs.get(0);
assertThat(reviewer._accountId).isEqualTo(id.get());
assertThat(reviewer.username).isEqualTo(username);
}
use of com.google.gerrit.extensions.api.changes.ReviewerResult in project gerrit by GerritCodeReview.
the class ChangeIT method deleteGroupFromReviewersFails.
@Test
public void deleteGroupFromReviewersFails() throws Exception {
PushOneCommit.Result r = createChange();
// create a group named "kobe" with one user: lee
String myGroupUserEmail = "lee@example.com";
String myGroupUserFullname = "lee";
accountOperations.newAccount().username("lee").preferredEmail(myGroupUserEmail).fullname(myGroupUserFullname).create();
String groupName = "kobe";
String testGroup = groupOperations.newGroup().name(groupName).create().get();
GroupApi groupApi = gApi.groups().id(testGroup);
groupApi.description("test group");
groupApi.addMembers(myGroupUserFullname);
// add the user as reviewer.
gApi.changes().id(r.getChangeId()).addReviewer(myGroupUserFullname);
// fail to remove that user via group.
ReviewResult reviewResult = gApi.changes().id(r.getChangeId()).current().review(ReviewInput.create().reviewer(testGroup, REMOVED, /* confirmed= */
true));
assertThat(reviewResult.error).isEqualTo("error adding reviewer");
ReviewerInput in = new ReviewerInput();
in.reviewer = testGroup;
in.state = REMOVED;
ReviewerResult reviewerResult = gApi.changes().id(r.getChangeId()).addReviewer(in);
assertThat(reviewerResult.error).isEqualTo(MessageFormat.format(ChangeMessages.get().groupRemovalIsNotAllowed, groupName));
}
use of com.google.gerrit.extensions.api.changes.ReviewerResult in project gerrit by GerritCodeReview.
the class ChangeIT method addReviewerThatIsInactiveByUsername.
@Test
public void addReviewerThatIsInactiveByUsername() throws Exception {
PushOneCommit.Result result = createChange();
String username = name("new-user");
Account.Id id = accountOperations.newAccount().username(username).inactive().create();
ReviewerInput in = new ReviewerInput();
in.reviewer = username;
ReviewerResult r = gApi.changes().id(result.getChangeId()).addReviewer(in);
assertThat(r.input).isEqualTo(in.reviewer);
assertThat(r.error).isNull();
assertThat(r.reviewers).hasSize(1);
ReviewerInfo reviewer = r.reviewers.get(0);
assertThat(reviewer._accountId).isEqualTo(id.get());
assertThat(reviewer.username).isEqualTo(username);
}
use of com.google.gerrit.extensions.api.changes.ReviewerResult in project gerrit by GerritCodeReview.
the class PostReview method apply.
public Response<ReviewResult> apply(RevisionResource revision, ReviewInput input, Instant ts) throws RestApiException, UpdateException, IOException, PermissionBackendException, ConfigInvalidException, PatchListNotAvailableException {
// Respect timestamp, but truncate at change created-on time.
ts = Ordering.natural().max(ts, revision.getChange().getCreatedOn());
if (revision.getEdit().isPresent()) {
throw new ResourceConflictException("cannot post review on edit");
}
ProjectState projectState = projectCache.get(revision.getProject()).orElseThrow(illegalState(revision.getProject()));
LabelTypes labelTypes = projectState.getLabelTypes(revision.getNotes());
logger.atFine().log("strict label checking is %s", (strictLabels ? "enabled" : "disabled"));
metrics.draftHandling.increment(input.drafts == null ? "N/A" : input.drafts.name());
input.drafts = firstNonNull(input.drafts, DraftHandling.KEEP);
logger.atFine().log("draft handling = %s", input.drafts);
if (input.onBehalfOf != null) {
revision = onBehalfOf(revision, labelTypes, input);
}
if (input.labels != null) {
checkLabels(revision, labelTypes, input.labels);
}
if (input.comments != null) {
input.comments = cleanUpComments(input.comments);
checkComments(revision, input.comments);
}
if (input.draftIdsToPublish != null) {
checkDraftIds(revision, input.draftIdsToPublish, input.drafts);
}
if (input.robotComments != null) {
input.robotComments = cleanUpComments(input.robotComments);
checkRobotComments(revision, input.robotComments);
}
if (input.notify == null) {
input.notify = defaultNotify(revision.getChange(), input);
}
logger.atFine().log("notify handling = %s", input.notify);
Map<String, ReviewerResult> reviewerJsonResults = null;
List<ReviewerModification> reviewerResults = Lists.newArrayList();
boolean hasError = false;
boolean confirm = false;
if (input.reviewers != null) {
reviewerJsonResults = Maps.newHashMap();
for (ReviewerInput reviewerInput : input.reviewers) {
ReviewerModification result = reviewerModifier.prepare(revision.getNotes(), revision.getUser(), reviewerInput, true);
reviewerJsonResults.put(reviewerInput.reviewer, result.result);
if (result.result.error != null) {
logger.atFine().log("Adding %s as reviewer failed: %s", reviewerInput.reviewer, result.result.error);
hasError = true;
continue;
}
if (result.result.confirm != null) {
logger.atFine().log("Adding %s as reviewer requires confirmation", reviewerInput.reviewer);
confirm = true;
continue;
}
logger.atFine().log("Adding %s as reviewer was prepared", reviewerInput.reviewer);
reviewerResults.add(result);
}
}
ReviewResult output = new ReviewResult();
output.reviewers = reviewerJsonResults;
if (hasError || confirm) {
output.error = ERROR_ADDING_REVIEWER;
return Response.withStatusCode(SC_BAD_REQUEST, output);
}
output.labels = input.labels;
try (BatchUpdate bu = updateFactory.create(revision.getChange().getProject(), revision.getUser(), ts)) {
Account account = revision.getUser().asIdentifiedUser().getAccount();
boolean ccOrReviewer = false;
if (input.labels != null && !input.labels.isEmpty()) {
ccOrReviewer = input.labels.values().stream().anyMatch(v -> v != 0);
if (ccOrReviewer) {
logger.atFine().log("calling user is cc/reviewer on the change due to voting on a label");
}
}
if (!ccOrReviewer) {
// Check if user was already CCed or reviewing prior to this review.
ReviewerSet currentReviewers = approvalsUtil.getReviewers(revision.getChangeResource().getNotes());
ccOrReviewer = currentReviewers.all().contains(account.id());
if (ccOrReviewer) {
logger.atFine().log("calling user is already cc/reviewer on the change");
}
}
// Apply reviewer changes first. Revision emails should be sent to the
// updated set of reviewers. Also keep track of whether the user added
// themselves as a reviewer or to the CC list.
logger.atFine().log("adding reviewer additions");
for (ReviewerModification reviewerResult : reviewerResults) {
// Send a single batch email below.
reviewerResult.op.suppressEmail();
// Send events below, if possible as batch.
reviewerResult.op.suppressEvent();
bu.addOp(revision.getChange().getId(), reviewerResult.op);
if (!ccOrReviewer && reviewerResult.reviewers.contains(account)) {
logger.atFine().log("calling user is explicitly added as reviewer or CC");
ccOrReviewer = true;
}
}
if (!ccOrReviewer) {
// User posting this review isn't currently in the reviewer or CC list,
// isn't being explicitly added, and isn't voting on any label.
// Automatically CC them on this change so they receive replies.
logger.atFine().log("CCing calling user");
ReviewerModification selfAddition = reviewerModifier.ccCurrentUser(revision.getUser(), revision);
selfAddition.op.suppressEmail();
selfAddition.op.suppressEvent();
bu.addOp(revision.getChange().getId(), selfAddition.op);
}
// Add WorkInProgressOp if requested.
if ((input.ready || input.workInProgress) && didWorkInProgressChange(revision.getChange().isWorkInProgress(), input)) {
if (input.ready && input.workInProgress) {
output.error = ERROR_WIP_READY_MUTUALLY_EXCLUSIVE;
return Response.withStatusCode(SC_BAD_REQUEST, output);
}
revision.getChangeResource().permissions().check(ChangePermission.TOGGLE_WORK_IN_PROGRESS_STATE);
if (input.ready) {
output.ready = true;
}
logger.atFine().log("setting work-in-progress to %s", input.workInProgress);
WorkInProgressOp wipOp = workInProgressOpFactory.create(input.workInProgress, new WorkInProgressOp.Input());
wipOp.suppressEmail();
bu.addOp(revision.getChange().getId(), wipOp);
}
// Add the review op.
logger.atFine().log("posting review");
bu.addOp(revision.getChange().getId(), new Op(projectState, revision.getPatchSet().id(), input));
// Notify based on ReviewInput, ignoring the notify settings from any ReviewerInputs.
NotifyResolver.Result notify = notifyResolver.resolve(input.notify, input.notifyDetails);
bu.setNotify(notify);
// Adjust the attention set based on the input
replyAttentionSetUpdates.updateAttentionSet(bu, revision.getNotes(), input, revision.getUser());
bu.execute();
// Re-read change to take into account results of the update.
ChangeData cd = changeDataFactory.create(revision.getProject(), revision.getChange().getId());
for (ReviewerModification reviewerResult : reviewerResults) {
reviewerResult.gatherResults(cd);
}
// Sending emails and events from ReviewersOps was suppressed so we can send a single batch
// email/event here.
batchEmailReviewers(revision.getUser(), revision.getChange(), reviewerResults, notify);
batchReviewerEvents(revision.getUser(), cd, revision.getPatchSet(), reviewerResults, ts);
}
return Response.ok(output);
}
Aggregations