Add reviewers by email to ChangeIndex
This change adds reviewers by email to the ChangeIndex and adds tests for the new code. It also expands the 'reviewer' and 'cc' queries to match on reviewerByEmail as well. Bug: Issue 4134 Change-Id: Iae9ada56e2ab9a03b6d5c20de4bca53ec27a4767
This commit is contained in:
@@ -19,6 +19,7 @@ import static com.google.common.truth.TruthJUnit.assume;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.gerrit.acceptance.AbstractDaemonTest;
|
||||
import com.google.gerrit.acceptance.NoHttpd;
|
||||
import com.google.gerrit.acceptance.PushOneCommit;
|
||||
@@ -239,6 +240,34 @@ public class ChangeReviewersByEmailIT extends AbstractDaemonTest {
|
||||
gApi.changes().id(r.getChangeId()).addReviewer("Foo Bar <foo.bar@gerritcodereview.com>");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void reviewersByEmailAreServedFromIndex() throws Exception {
|
||||
assume().that(notesMigration.enabled()).isTrue();
|
||||
AccountInfo acc = new AccountInfo("Foo Bar", "foo.bar@gerritcodereview.com");
|
||||
|
||||
for (ReviewerState state : ImmutableList.of(ReviewerState.CC, ReviewerState.REVIEWER)) {
|
||||
PushOneCommit.Result r = createChange();
|
||||
|
||||
AddReviewerInput input = new AddReviewerInput();
|
||||
input.reviewer = toRfcAddressString(acc);
|
||||
input.state = state;
|
||||
gApi.changes().id(r.getChangeId()).addReviewer(input);
|
||||
|
||||
notesMigration.setFailOnLoad(true);
|
||||
try {
|
||||
ChangeInfo info =
|
||||
Iterables.getOnlyElement(
|
||||
gApi.changes()
|
||||
.query(r.getChangeId())
|
||||
.withOption(ListChangesOption.DETAILED_LABELS)
|
||||
.get());
|
||||
assertThat(info.reviewers).isEqualTo(ImmutableMap.of(state, ImmutableList.of(acc)));
|
||||
} finally {
|
||||
notesMigration.setFailOnLoad(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String toRfcAddressString(AccountInfo info) {
|
||||
return (new Address(info.name, info.email)).toString();
|
||||
}
|
||||
|
@@ -34,6 +34,7 @@ import com.google.gerrit.reviewdb.client.Change;
|
||||
import com.google.gerrit.reviewdb.client.Change.Id;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.reviewdb.server.ReviewDb;
|
||||
import com.google.gerrit.server.ReviewerByEmailSet;
|
||||
import com.google.gerrit.server.ReviewerSet;
|
||||
import com.google.gerrit.server.config.GerritServerConfig;
|
||||
import com.google.gerrit.server.config.SitePaths;
|
||||
@@ -342,6 +343,16 @@ class ElasticChangeIndex extends AbstractElasticIndex<Change.Id, ChangeData>
|
||||
cd.setReviewers(ReviewerSet.empty());
|
||||
}
|
||||
|
||||
if (source.get(ChangeField.REVIEWER_BY_EMAIL.getName()) != null) {
|
||||
cd.setReviewersByEmail(
|
||||
ChangeField.parseReviewerByEmailFieldValues(
|
||||
FluentIterable.from(
|
||||
source.get(ChangeField.REVIEWER_BY_EMAIL.getName()).getAsJsonArray())
|
||||
.transform(JsonElement::getAsString)));
|
||||
} else if (fields.contains(ChangeField.REVIEWER_BY_EMAIL.getName())) {
|
||||
cd.setReviewersByEmail(ReviewerByEmailSet.empty());
|
||||
}
|
||||
|
||||
decodeSubmitRecords(
|
||||
source,
|
||||
ChangeField.STORED_SUBMIT_RECORD_STRICT.getName(),
|
||||
|
@@ -121,6 +121,7 @@ public class LuceneChangeIndex implements ChangeIndex {
|
||||
private static final String REF_STATE_PATTERN_FIELD = ChangeField.REF_STATE_PATTERN.getName();
|
||||
private static final String REVIEWEDBY_FIELD = ChangeField.REVIEWEDBY.getName();
|
||||
private static final String REVIEWER_FIELD = ChangeField.REVIEWER.getName();
|
||||
private static final String REVIEWER_BY_EMAIL_FIELD = ChangeField.REVIEWER_BY_EMAIL.getName();
|
||||
private static final String HASHTAG_FIELD = ChangeField.HASHTAG_CASE_AWARE.getName();
|
||||
private static final String STAR_FIELD = ChangeField.STAR.getName();
|
||||
private static final String SUBMIT_RECORD_LENIENT_FIELD =
|
||||
@@ -459,6 +460,9 @@ public class LuceneChangeIndex implements ChangeIndex {
|
||||
if (fields.contains(REVIEWER_FIELD)) {
|
||||
decodeReviewers(doc, cd);
|
||||
}
|
||||
if (fields.contains(REVIEWER_BY_EMAIL_FIELD)) {
|
||||
decodeReviewersByEmail(doc, cd);
|
||||
}
|
||||
decodeSubmitRecords(
|
||||
doc, SUBMIT_RECORD_STRICT_FIELD, ChangeField.SUBMIT_RULE_OPTIONS_STRICT, cd);
|
||||
decodeSubmitRecords(
|
||||
@@ -555,6 +559,13 @@ public class LuceneChangeIndex implements ChangeIndex {
|
||||
FluentIterable.from(doc.get(REVIEWER_FIELD)).transform(IndexableField::stringValue)));
|
||||
}
|
||||
|
||||
private void decodeReviewersByEmail(ListMultimap<String, IndexableField> doc, ChangeData cd) {
|
||||
cd.setReviewersByEmail(
|
||||
ChangeField.parseReviewerByEmailFieldValues(
|
||||
FluentIterable.from(doc.get(REVIEWER_BY_EMAIL_FIELD))
|
||||
.transform(IndexableField::stringValue)));
|
||||
}
|
||||
|
||||
private void decodeSubmitRecords(
|
||||
ListMultimap<String, IndexableField> doc,
|
||||
String field,
|
||||
|
@@ -532,9 +532,8 @@ public class ChangeJson {
|
||||
cd.reviewers().asTable().rowMap().entrySet()) {
|
||||
out.reviewers.put(e.getKey().asReviewerState(), toAccountInfo(e.getValue().keySet()));
|
||||
}
|
||||
// TODO(hiesel) Load from ChangeData instead after the data was added there
|
||||
for (Map.Entry<ReviewerStateInternal, Map<Address, Timestamp>> e :
|
||||
cd.notes().getReviewersByEmail().asTable().rowMap().entrySet()) {
|
||||
cd.reviewersByEmail().asTable().rowMap().entrySet()) {
|
||||
out.reviewers.put(
|
||||
e.getKey().asReviewerState(), toAccountInfoByEmail(e.getValue().keySet()));
|
||||
}
|
||||
|
@@ -46,6 +46,7 @@ import com.google.gerrit.reviewdb.client.PatchSetApproval;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.reviewdb.client.RefNames;
|
||||
import com.google.gerrit.server.OutputFormat;
|
||||
import com.google.gerrit.server.ReviewerByEmailSet;
|
||||
import com.google.gerrit.server.ReviewerSet;
|
||||
import com.google.gerrit.server.StarredChangesUtil;
|
||||
import com.google.gerrit.server.index.FieldDef;
|
||||
@@ -53,6 +54,7 @@ import com.google.gerrit.server.index.FieldDef.FillArgs;
|
||||
import com.google.gerrit.server.index.SchemaUtil;
|
||||
import com.google.gerrit.server.index.change.StalenessChecker.RefState;
|
||||
import com.google.gerrit.server.index.change.StalenessChecker.RefStatePattern;
|
||||
import com.google.gerrit.server.mail.Address;
|
||||
import com.google.gerrit.server.notedb.ChangeNotes;
|
||||
import com.google.gerrit.server.notedb.NoteDbChangeState.PrimaryStorage;
|
||||
import com.google.gerrit.server.notedb.ReviewerStateInternal;
|
||||
@@ -184,6 +186,12 @@ public class ChangeField {
|
||||
public static final FieldDef<ChangeData, Iterable<String>> REVIEWER =
|
||||
exact("reviewer2").stored().buildRepeatable(cd -> getReviewerFieldValues(cd.reviewers()));
|
||||
|
||||
/** Reviewer(s) associated with the change that do not have a gerrit account. */
|
||||
public static final FieldDef<ChangeData, Iterable<String>> REVIEWER_BY_EMAIL =
|
||||
exact("reviewer_by_email")
|
||||
.stored()
|
||||
.buildRepeatable(cd -> getReviewerByEmailFieldValues(cd.reviewersByEmail()));
|
||||
|
||||
@VisibleForTesting
|
||||
static List<String> getReviewerFieldValues(ReviewerSet reviewers) {
|
||||
List<String> r = new ArrayList<>(reviewers.asTable().size() * 2);
|
||||
@@ -200,6 +208,27 @@ public class ChangeField {
|
||||
return state.toString() + ',' + id;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static List<String> getReviewerByEmailFieldValues(ReviewerByEmailSet reviewersByEmail) {
|
||||
List<String> r = new ArrayList<>(reviewersByEmail.asTable().size() * 2);
|
||||
for (Table.Cell<ReviewerStateInternal, Address, Timestamp> c :
|
||||
reviewersByEmail.asTable().cellSet()) {
|
||||
String v = getReviewerByEmailFieldValue(c.getRowKey(), c.getColumnKey());
|
||||
r.add(v);
|
||||
if (c.getColumnKey().getName() != null) {
|
||||
// Add another entry without the name to provide search functionality on the email
|
||||
Address emailOnly = new Address(c.getColumnKey().getEmail());
|
||||
r.add(getReviewerByEmailFieldValue(c.getRowKey(), emailOnly));
|
||||
}
|
||||
r.add(v + ',' + c.getValue().getTime());
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
public static String getReviewerByEmailFieldValue(ReviewerStateInternal state, Address adr) {
|
||||
return state.toString() + ',' + adr;
|
||||
}
|
||||
|
||||
public static ReviewerSet parseReviewerFieldValues(Iterable<String> values) {
|
||||
ImmutableTable.Builder<ReviewerStateInternal, Account.Id, Timestamp> b =
|
||||
ImmutableTable.builder();
|
||||
@@ -220,6 +249,25 @@ public class ChangeField {
|
||||
return ReviewerSet.fromTable(b.build());
|
||||
}
|
||||
|
||||
public static ReviewerByEmailSet parseReviewerByEmailFieldValues(Iterable<String> values) {
|
||||
ImmutableTable.Builder<ReviewerStateInternal, Address, Timestamp> b = ImmutableTable.builder();
|
||||
for (String v : values) {
|
||||
int f = v.indexOf(',');
|
||||
if (f < 0) {
|
||||
continue;
|
||||
}
|
||||
int l = v.lastIndexOf(',');
|
||||
if (l == f) {
|
||||
continue;
|
||||
}
|
||||
b.put(
|
||||
ReviewerStateInternal.valueOf(v.substring(0, f)),
|
||||
Address.parse(v.substring(f + 1, l)),
|
||||
new Timestamp(Long.valueOf(v.substring(l + 1, v.length()))));
|
||||
}
|
||||
return ReviewerByEmailSet.fromTable(b.build());
|
||||
}
|
||||
|
||||
/** Commit ID of any patch set on the change, using prefix match. */
|
||||
public static final FieldDef<ChangeData, Iterable<String>> COMMIT =
|
||||
prefix(ChangeQueryBuilder.FIELD_COMMIT).buildRepeatable(ChangeField::getRevisions);
|
||||
|
@@ -92,7 +92,9 @@ public class ChangeSchemaDefinitions extends SchemaDefinitions<ChangeData> {
|
||||
|
||||
@Deprecated static final Schema<ChangeData> V39 = schema(V38);
|
||||
|
||||
static final Schema<ChangeData> V40 = schema(V39, ChangeField.PRIVATE);
|
||||
@Deprecated static final Schema<ChangeData> V40 = schema(V39, ChangeField.PRIVATE);
|
||||
|
||||
static final Schema<ChangeData> V41 = schema(V40, ChangeField.REVIEWER_BY_EMAIL);
|
||||
|
||||
public static final String NAME = "changes";
|
||||
public static final ChangeSchemaDefinitions INSTANCE = new ChangeSchemaDefinitions();
|
||||
|
@@ -183,13 +183,11 @@ public abstract class ChangeEmail extends NotificationEmail {
|
||||
|
||||
if (notify.ordinal() >= NotifyHandling.OWNER_REVIEWERS.ordinal()) {
|
||||
try {
|
||||
// TODO(hiesel) Load from index instead
|
||||
addByEmail(
|
||||
RecipientType.CC,
|
||||
changeData.notes().getReviewersByEmail().byState(ReviewerStateInternal.CC));
|
||||
RecipientType.CC, changeData.reviewersByEmail().byState(ReviewerStateInternal.CC));
|
||||
addByEmail(
|
||||
RecipientType.TO,
|
||||
changeData.notes().getReviewersByEmail().byState(ReviewerStateInternal.REVIEWER));
|
||||
changeData.reviewersByEmail().byState(ReviewerStateInternal.REVIEWER));
|
||||
} catch (OrmException e) {
|
||||
throw new EmailException("Failed to add unregistered CCs " + change.getChangeId(), e);
|
||||
}
|
||||
|
@@ -52,6 +52,7 @@ import com.google.gerrit.server.CommentsUtil;
|
||||
import com.google.gerrit.server.CurrentUser;
|
||||
import com.google.gerrit.server.IdentifiedUser;
|
||||
import com.google.gerrit.server.PatchSetUtil;
|
||||
import com.google.gerrit.server.ReviewerByEmailSet;
|
||||
import com.google.gerrit.server.ReviewerSet;
|
||||
import com.google.gerrit.server.ReviewerStatusUpdate;
|
||||
import com.google.gerrit.server.StarredChangesUtil;
|
||||
@@ -352,6 +353,7 @@ public class ChangeData {
|
||||
private StarsOf starsOf;
|
||||
private ImmutableMap<Account.Id, StarRef> starRefs;
|
||||
private ReviewerSet reviewers;
|
||||
private ReviewerByEmailSet reviewersByEmail;
|
||||
private List<ReviewerStatusUpdate> reviewerUpdates;
|
||||
private PersonIdent author;
|
||||
private PersonIdent committer;
|
||||
@@ -954,6 +956,24 @@ public class ChangeData {
|
||||
return reviewers;
|
||||
}
|
||||
|
||||
public ReviewerByEmailSet reviewersByEmail() throws OrmException {
|
||||
if (reviewersByEmail == null) {
|
||||
if (!lazyLoad) {
|
||||
return ReviewerByEmailSet.empty();
|
||||
}
|
||||
reviewersByEmail = notes().getReviewersByEmail();
|
||||
}
|
||||
return reviewersByEmail;
|
||||
}
|
||||
|
||||
public void setReviewersByEmail(ReviewerByEmailSet reviewersByEmail) {
|
||||
this.reviewersByEmail = reviewersByEmail;
|
||||
}
|
||||
|
||||
public ReviewerByEmailSet getReviewersByEmail() {
|
||||
return reviewersByEmail;
|
||||
}
|
||||
|
||||
public List<ReviewerStatusUpdate> reviewerUpdates() throws OrmException {
|
||||
if (reviewerUpdates == null) {
|
||||
if (!lazyLoad) {
|
||||
|
@@ -14,9 +14,12 @@
|
||||
|
||||
package com.google.gerrit.server.query.change;
|
||||
|
||||
import com.google.gerrit.reviewdb.client.Change;
|
||||
import com.google.gerrit.server.index.FieldDef;
|
||||
import com.google.gerrit.server.index.IndexPredicate;
|
||||
import com.google.gerrit.server.query.Matchable;
|
||||
import com.google.gerrit.server.query.Predicate;
|
||||
import com.google.gerrit.server.query.change.ChangeQueryBuilder.Arguments;
|
||||
|
||||
public abstract class ChangeIndexPredicate extends IndexPredicate<ChangeData>
|
||||
implements Matchable<ChangeData> {
|
||||
@@ -27,4 +30,11 @@ public abstract class ChangeIndexPredicate extends IndexPredicate<ChangeData>
|
||||
protected ChangeIndexPredicate(FieldDef<ChangeData, ?> def, String name, String value) {
|
||||
super(def, name, value);
|
||||
}
|
||||
|
||||
protected static Predicate<ChangeData> create(Arguments args, Predicate<ChangeData> p) {
|
||||
if (!args.allowsDrafts) {
|
||||
return Predicate.and(p, Predicate.not(new ChangeStatusPredicate(Change.Status.DRAFT)));
|
||||
}
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
@@ -61,8 +61,10 @@ import com.google.gerrit.server.index.change.ChangeField;
|
||||
import com.google.gerrit.server.index.change.ChangeIndex;
|
||||
import com.google.gerrit.server.index.change.ChangeIndexCollection;
|
||||
import com.google.gerrit.server.index.change.ChangeIndexRewriter;
|
||||
import com.google.gerrit.server.mail.Address;
|
||||
import com.google.gerrit.server.notedb.ChangeNotes;
|
||||
import com.google.gerrit.server.notedb.NotesMigration;
|
||||
import com.google.gerrit.server.notedb.ReviewerStateInternal;
|
||||
import com.google.gerrit.server.patch.PatchListCache;
|
||||
import com.google.gerrit.server.project.ChangeControl;
|
||||
import com.google.gerrit.server.project.ListChildProjects;
|
||||
@@ -942,17 +944,12 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
||||
|
||||
@Operator
|
||||
public Predicate<ChangeData> reviewer(String who) throws QueryParseException, OrmException {
|
||||
return Predicate.or(
|
||||
parseAccount(who)
|
||||
.stream()
|
||||
.map(id -> ReviewerPredicate.reviewer(args, id))
|
||||
.collect(toList()));
|
||||
return reviewerByState(who, ReviewerStateInternal.REVIEWER);
|
||||
}
|
||||
|
||||
@Operator
|
||||
public Predicate<ChangeData> cc(String who) throws QueryParseException, OrmException {
|
||||
return Predicate.or(
|
||||
parseAccount(who).stream().map(id -> ReviewerPredicate.cc(args, id)).collect(toList()));
|
||||
return reviewerByState(who, ReviewerStateInternal.CC);
|
||||
}
|
||||
|
||||
@Operator
|
||||
@@ -1181,4 +1178,37 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
||||
private Account.Id self() throws QueryParseException {
|
||||
return args.getIdentifiedUser().getAccountId();
|
||||
}
|
||||
|
||||
public Predicate<ChangeData> reviewerByState(String who, ReviewerStateInternal state)
|
||||
throws QueryParseException, OrmException {
|
||||
Predicate<ChangeData> reviewerByEmailPredicate = null;
|
||||
if (args.index.getSchema().hasField(ChangeField.REVIEWER_BY_EMAIL)) {
|
||||
Address address = Address.tryParse(who);
|
||||
if (address != null) {
|
||||
reviewerByEmailPredicate = ReviewerByEmailPredicate.forState(args, address, state);
|
||||
}
|
||||
}
|
||||
|
||||
Predicate<ChangeData> reviewerPredicate = null;
|
||||
try {
|
||||
reviewerPredicate =
|
||||
Predicate.or(
|
||||
parseAccount(who)
|
||||
.stream()
|
||||
.map(id -> ReviewerPredicate.forState(args, id, state))
|
||||
.collect(toList()));
|
||||
} catch (QueryParseException e) {
|
||||
// Propagate this exception only if we can't use 'who' to query by email
|
||||
if (reviewerByEmailPredicate == null) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
if (reviewerPredicate != null && reviewerByEmailPredicate != null) {
|
||||
return Predicate.or(reviewerPredicate, reviewerByEmailPredicate);
|
||||
} else if (reviewerPredicate != null) {
|
||||
return reviewerPredicate;
|
||||
}
|
||||
return reviewerByEmailPredicate;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,55 @@
|
||||
// Copyright (C) 2017 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package com.google.gerrit.server.query.change;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
import com.google.gerrit.server.index.change.ChangeField;
|
||||
import com.google.gerrit.server.mail.Address;
|
||||
import com.google.gerrit.server.notedb.ReviewerStateInternal;
|
||||
import com.google.gerrit.server.query.Predicate;
|
||||
import com.google.gerrit.server.query.change.ChangeQueryBuilder.Arguments;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
|
||||
class ReviewerByEmailPredicate extends ChangeIndexPredicate {
|
||||
|
||||
static Predicate<ChangeData> forState(Arguments args, Address adr, ReviewerStateInternal state) {
|
||||
checkArgument(state != ReviewerStateInternal.REMOVED, "can't query by removed reviewer");
|
||||
return create(args, new ReviewerByEmailPredicate(state, adr));
|
||||
}
|
||||
|
||||
private final ReviewerStateInternal state;
|
||||
private final Address adr;
|
||||
|
||||
private ReviewerByEmailPredicate(ReviewerStateInternal state, Address adr) {
|
||||
super(ChangeField.REVIEWER_BY_EMAIL, ChangeField.getReviewerByEmailFieldValue(state, adr));
|
||||
this.state = state;
|
||||
this.adr = adr;
|
||||
}
|
||||
|
||||
Address getAddress() {
|
||||
return adr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean match(ChangeData cd) throws OrmException {
|
||||
return cd.reviewersByEmail().asTable().get(state, adr) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCost() {
|
||||
return 1;
|
||||
}
|
||||
}
|
@@ -14,10 +14,10 @@
|
||||
|
||||
package com.google.gerrit.server.query.change;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
import com.google.gerrit.reviewdb.client.Account;
|
||||
import com.google.gerrit.reviewdb.client.Change;
|
||||
import com.google.gerrit.server.index.change.ChangeField;
|
||||
import com.google.gerrit.server.notedb.ReviewerStateInternal;
|
||||
import com.google.gerrit.server.query.Predicate;
|
||||
@@ -26,6 +26,12 @@ import com.google.gwtorm.server.OrmException;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
class ReviewerPredicate extends ChangeIndexPredicate {
|
||||
static Predicate<ChangeData> forState(
|
||||
Arguments args, Account.Id id, ReviewerStateInternal state) {
|
||||
checkArgument(state != ReviewerStateInternal.REMOVED, "can't query by removed reviewer");
|
||||
return create(args, new ReviewerPredicate(state, id));
|
||||
}
|
||||
|
||||
static Predicate<ChangeData> reviewer(Arguments args, Account.Id id) {
|
||||
Predicate<ChangeData> p;
|
||||
if (args.notesMigration.readChanges()) {
|
||||
@@ -54,15 +60,6 @@ class ReviewerPredicate extends ChangeIndexPredicate {
|
||||
.collect(toList()));
|
||||
}
|
||||
|
||||
private static Predicate<ChangeData> create(Arguments args, Predicate<ChangeData> p) {
|
||||
if (!args.allowsDrafts) {
|
||||
// TODO(dborowitz): This really belongs much higher up e.g. QueryProcessor. Also, why are we
|
||||
// even doing this?
|
||||
return Predicate.and(p, Predicate.not(new ChangeStatusPredicate(Change.Status.DRAFT)));
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
private final ReviewerStateInternal state;
|
||||
private final Account.Id id;
|
||||
|
||||
|
@@ -71,6 +71,8 @@ import com.google.gerrit.server.change.ChangeInserter;
|
||||
import com.google.gerrit.server.change.ChangeTriplet;
|
||||
import com.google.gerrit.server.change.PatchSetInserter;
|
||||
import com.google.gerrit.server.config.AllUsersName;
|
||||
import com.google.gerrit.server.git.MetaDataUpdate;
|
||||
import com.google.gerrit.server.git.ProjectConfig;
|
||||
import com.google.gerrit.server.git.validators.CommitValidators;
|
||||
import com.google.gerrit.server.index.IndexConfig;
|
||||
import com.google.gerrit.server.index.QueryOptions;
|
||||
@@ -83,6 +85,7 @@ import com.google.gerrit.server.notedb.ChangeNotes;
|
||||
import com.google.gerrit.server.notedb.NoteDbChangeState;
|
||||
import com.google.gerrit.server.notedb.NoteDbChangeState.PrimaryStorage;
|
||||
import com.google.gerrit.server.project.ChangeControl;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
import com.google.gerrit.server.schema.SchemaCreator;
|
||||
import com.google.gerrit.server.update.BatchUpdate;
|
||||
import com.google.gerrit.server.util.RequestContext;
|
||||
@@ -151,6 +154,8 @@ public abstract class AbstractQueryChangesTest extends GerritServerTests {
|
||||
@Inject protected SchemaCreator schemaCreator;
|
||||
@Inject protected Sequences seq;
|
||||
@Inject protected ThreadLocalRequestContext requestContext;
|
||||
@Inject protected ProjectCache projectCache;
|
||||
@Inject protected MetaDataUpdate.Server metaDataUpdateFactory;
|
||||
|
||||
protected Injector injector;
|
||||
protected LifecycleManager lifecycle;
|
||||
@@ -1544,6 +1549,71 @@ public abstract class AbstractQueryChangesTest extends GerritServerTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void reviewerAndCcByEmail() throws Exception {
|
||||
assume().that(notesMigration.enabled()).isTrue();
|
||||
|
||||
Project.NameKey project = new Project.NameKey("repo");
|
||||
TestRepository<Repo> repo = createProject(project.get());
|
||||
ProjectConfig cfg = projectCache.checkedGet(project).getConfig();
|
||||
cfg.setEnableReviewerByEmail(true);
|
||||
saveProjectConfig(project, cfg);
|
||||
|
||||
String userByEmail = "un.registered@reviewer.com";
|
||||
String userByEmailWithName = "John Doe <" + userByEmail + ">";
|
||||
|
||||
Change change1 = insert(repo, newChange(repo));
|
||||
Change change2 = insert(repo, newChange(repo));
|
||||
insert(repo, newChange(repo));
|
||||
|
||||
AddReviewerInput rin = new AddReviewerInput();
|
||||
rin.reviewer = userByEmailWithName;
|
||||
rin.state = ReviewerState.REVIEWER;
|
||||
gApi.changes().id(change1.getId().get()).addReviewer(rin);
|
||||
|
||||
rin = new AddReviewerInput();
|
||||
rin.reviewer = userByEmailWithName;
|
||||
rin.state = ReviewerState.CC;
|
||||
gApi.changes().id(change2.getId().get()).addReviewer(rin);
|
||||
|
||||
assertQuery("reviewer:\"" + userByEmailWithName + "\"", change1);
|
||||
assertQuery("cc:\"" + userByEmailWithName + "\"", change2);
|
||||
|
||||
// Omitting the name:
|
||||
assertQuery("reviewer:\"" + userByEmail + "\"", change1);
|
||||
assertQuery("cc:\"" + userByEmail + "\"", change2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void reviewerAndCcByEmailWithQueryForDifferentUser() throws Exception {
|
||||
assume().that(notesMigration.enabled()).isTrue();
|
||||
|
||||
Project.NameKey project = new Project.NameKey("repo");
|
||||
TestRepository<Repo> repo = createProject(project.get());
|
||||
ProjectConfig cfg = projectCache.checkedGet(project).getConfig();
|
||||
cfg.setEnableReviewerByEmail(true);
|
||||
saveProjectConfig(project, cfg);
|
||||
|
||||
String userByEmail = "John Doe <un.registered@reviewer.com>";
|
||||
|
||||
Change change1 = insert(repo, newChange(repo));
|
||||
Change change2 = insert(repo, newChange(repo));
|
||||
insert(repo, newChange(repo));
|
||||
|
||||
AddReviewerInput rin = new AddReviewerInput();
|
||||
rin.reviewer = userByEmail;
|
||||
rin.state = ReviewerState.REVIEWER;
|
||||
gApi.changes().id(change1.getId().get()).addReviewer(rin);
|
||||
|
||||
rin = new AddReviewerInput();
|
||||
rin.reviewer = userByEmail;
|
||||
rin.state = ReviewerState.CC;
|
||||
gApi.changes().id(change2.getId().get()).addReviewer(rin);
|
||||
|
||||
assertQuery("reviewer:\"someone@example.com\"");
|
||||
assertQuery("cc:\"someone@example.com\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void submitRecords() throws Exception {
|
||||
Account.Id user1 = createAccount("user1");
|
||||
@@ -2027,4 +2097,12 @@ public abstract class AbstractQueryChangesTest extends GerritServerTests {
|
||||
Patch.COMMIT_MSG, ImmutableList.<ReviewInput.CommentInput>of(comment));
|
||||
gApi.changes().id(changeId).current().review(input);
|
||||
}
|
||||
|
||||
private void saveProjectConfig(Project.NameKey p, ProjectConfig cfg) throws Exception {
|
||||
try (MetaDataUpdate md = metaDataUpdateFactory.create(p)) {
|
||||
md.setAuthor(userFactory.create(userId));
|
||||
cfg.commit(md);
|
||||
}
|
||||
projectCache.evict(cfg.getProject());
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user