Fix auto-adding reviewers during push

When we converted ReceiveCommits to use BatchUpdate's parallel
functionality in I40545a4d, we lost the automatic request scope
propagation. This was mostly fine, with the notable exception of:
 - pushing a new patch set of an existing change, and
 - pushing multiple changes so work is in a background thread, and
 - mentioning a user in a footer (Signed-Off-By, etc.), and
 - not including an email address in that footer, and
 - not having the account index enabled.

This would cause AccountResolver to try to call its
Provider<ReviewDb>, which fails because it's not in request scope.

Fix this by passing a ReviewDb into AccountResolver methods. That was
the easy part; the hard part was figuring out how to write a test case
that triggered this. Since the account index is now enabled by
default, this means putting a test-only hack into LuceneIndexModule
to support disabling a specific index. (This could also be useful for
other tests, since we currently don't exercise the non-index
fallbacks.)

Change-Id: I7231be3ea4660c9ee27f09994706b39ee622488a
This commit is contained in:
Dave Borowitz
2016-08-12 16:46:55 -04:00
committed by David Pursehouse
parent 9494ca8720
commit 040c39bcb3
13 changed files with 200 additions and 86 deletions

View File

@@ -14,22 +14,22 @@
package com.google.gerrit.acceptance.git; package com.google.gerrit.acceptance.git;
import static com.google.common.collect.Iterables.getOnlyElement;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.TruthJUnit.assume; import static com.google.common.truth.TruthJUnit.assume;
import static com.google.gerrit.acceptance.GitUtil.assertPushOk; import static com.google.gerrit.acceptance.GitUtil.assertPushOk;
import static com.google.gerrit.acceptance.GitUtil.assertPushRejected; import static com.google.gerrit.acceptance.GitUtil.assertPushRejected;
import static com.google.gerrit.acceptance.GitUtil.pushHead; import static com.google.gerrit.acceptance.GitUtil.pushHead;
import static com.google.gerrit.common.FooterConstants.CHANGE_ID;
import static com.google.gerrit.server.group.SystemGroupBackend.ANONYMOUS_USERS; import static com.google.gerrit.server.group.SystemGroupBackend.ANONYMOUS_USERS;
import static com.google.gerrit.server.project.Util.category; import static com.google.gerrit.server.project.Util.category;
import static com.google.gerrit.server.project.Util.value; import static com.google.gerrit.server.project.Util.value;
import static java.util.concurrent.TimeUnit.SECONDS; import static java.util.concurrent.TimeUnit.SECONDS;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.gerrit.acceptance.AbstractDaemonTest; import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.GerritConfig;
import com.google.gerrit.acceptance.GitUtil; import com.google.gerrit.acceptance.GitUtil;
import com.google.gerrit.acceptance.PushOneCommit; import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.acceptance.TestAccount; import com.google.gerrit.acceptance.TestAccount;
@@ -49,6 +49,7 @@ import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet; import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.server.git.ProjectConfig; import com.google.gerrit.server.git.ProjectConfig;
import com.google.gerrit.server.group.SystemGroupBackend; import com.google.gerrit.server.group.SystemGroupBackend;
import com.google.gerrit.server.mail.Address;
import com.google.gerrit.server.project.Util; import com.google.gerrit.server.project.Util;
import com.google.gerrit.server.query.change.ChangeData; import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.testutil.FakeEmailSender.Message; import com.google.gerrit.testutil.FakeEmailSender.Message;
@@ -614,20 +615,7 @@ public abstract class AbstractPushForReview extends AbstractDaemonTest {
int n = 10; int n = 10;
String r = "refs/for/master"; String r = "refs/for/master";
ObjectId initialHead = testRepo.getRepository().resolve("HEAD"); ObjectId initialHead = testRepo.getRepository().resolve("HEAD");
List<RevCommit> commits = new ArrayList<>(n); List<RevCommit> commits = createChanges(n, r);
// Create and push N changes.
for (int i = 1; i <= n; i++) {
TestRepository<?>.CommitBuilder cb = testRepo.branch("HEAD").commit()
.message("Change " + i).insertChangeId();
if (!commits.isEmpty()) {
cb.parent(commits.get(commits.size() - 1));
}
RevCommit c = cb.create();
testRepo.getRevWalk().parseBody(c);
commits.add(c);
}
assertPushOk(pushHead(testRepo, r, false), r);
// Check that a change was created for each. // Check that a change was created for each.
for (RevCommit c : commits) { for (RevCommit c : commits) {
@@ -636,21 +624,7 @@ public abstract class AbstractPushForReview extends AbstractDaemonTest {
.isEqualTo(c.getShortMessage()); .isEqualTo(c.getShortMessage());
} }
// Amend each change. List<RevCommit> commits2 = amendChanges(initialHead, commits, r);
testRepo.reset(initialHead);
List<RevCommit> commits2 = new ArrayList<>(n);
for (RevCommit c : commits) {
TestRepository<?>.CommitBuilder cb = testRepo.branch("HEAD").commit()
.message(c.getShortMessage() + "v2")
.insertChangeId(getChangeId(c).substring(1));
if (!commits2.isEmpty()) {
cb.parent(commits2.get(commits2.size() - 1));
}
RevCommit c2 = cb.create();
testRepo.getRevWalk().parseBody(c2);
commits2.add(c2);
}
assertPushOk(pushHead(testRepo, r, false), r);
// Check that there are correct patch sets. // Check that there are correct patch sets.
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
@@ -766,6 +740,124 @@ public abstract class AbstractPushForReview extends AbstractDaemonTest {
return c.getId(); return c.getId();
} }
@Test
public void pushWithEmailInFooter() throws Exception {
pushWithReviewerInFooter(user.emailAddress.toString(), user);
}
@Test
public void pushWithNameInFooter() throws Exception {
pushWithReviewerInFooter(user.fullName, user);
}
@Test
public void pushWithEmailInFooterNotFound() throws Exception {
pushWithReviewerInFooter(
new Address("No Body", "notarealuser@example.com").toString(),
null);
}
@Test
public void pushWithNameInFooterNotFound() throws Exception {
pushWithReviewerInFooter("Notauser", null);
}
@Test
// TODO(dborowitz): This is to exercise a specific case in the database search
// path. Once the account index becomes obligatory this method can be removed.
@GerritConfig(name = "index.testDisable", value = "accounts")
public void pushWithNameInFooterNotFoundWithDbSearch() throws Exception {
pushWithReviewerInFooter("Notauser", null);
}
private void pushWithReviewerInFooter(String nameEmail,
TestAccount expectedReviewer) throws Exception {
int n = 5;
String r = "refs/for/master";
ObjectId initialHead = testRepo.getRepository().resolve("HEAD");
List<RevCommit> commits =
createChanges(n, r, ImmutableList.of("Acked-By: " + nameEmail));
for (int i = 0; i < n; i++) {
RevCommit c = commits.get(i);
ChangeData cd = byCommit(c);
String name = "reviewers for " + (i + 1);
if (expectedReviewer != null) {
assertThat(cd.reviewers().all()).named(name)
.containsExactly(expectedReviewer.getId());
gApi.changes()
.id(cd.getId().get())
.reviewer(expectedReviewer.getId().toString())
.remove();
}
assertThat(byCommit(c).reviewers().all()).named(name).isEmpty();
}
List<RevCommit> commits2 = amendChanges(initialHead, commits, r);
for (int i = 0; i < n; i++) {
RevCommit c = commits2.get(i);
ChangeData cd = byCommit(c);
String name = "reviewers for " + (i + 1);
if (expectedReviewer != null) {
assertThat(cd.reviewers().all()).named(name)
.containsExactly(expectedReviewer.getId());
} else {
assertThat(byCommit(c).reviewers().all()).named(name).isEmpty();
}
}
}
private List<RevCommit> createChanges(int n, String refsFor)
throws Exception {
return createChanges(n, refsFor, ImmutableList.<String>of());
}
private List<RevCommit> createChanges(int n, String refsFor,
List<String> footerLines) throws Exception {
List<RevCommit> commits = new ArrayList<>(n);
for (int i = 1; i <= n; i++) {
String msg = "Change " + i;
if (!footerLines.isEmpty()) {
StringBuilder sb = new StringBuilder(msg).append("\n\n");
for (String line : footerLines) {
sb.append(line).append('\n');
}
msg = sb.toString();
}
TestRepository<?>.CommitBuilder cb = testRepo.branch("HEAD").commit()
.message(msg).insertChangeId();
if (!commits.isEmpty()) {
cb.parent(commits.get(commits.size() - 1));
}
RevCommit c = cb.create();
testRepo.getRevWalk().parseBody(c);
commits.add(c);
}
assertPushOk(pushHead(testRepo, refsFor, false), refsFor);
return commits;
}
private List<RevCommit> amendChanges(ObjectId initialHead,
List<RevCommit> origCommits, String refsFor) throws Exception {
testRepo.reset(initialHead);
List<RevCommit> newCommits = new ArrayList<>(origCommits.size());
for (RevCommit c : origCommits) {
String msg = c.getShortMessage() + "v2";
if (!c.getShortMessage().equals(c.getFullMessage())) {
msg = msg + c.getFullMessage().substring(c.getShortMessage().length());
}
TestRepository<?>.CommitBuilder cb = testRepo.branch("HEAD").commit()
.message(msg);
if (!newCommits.isEmpty()) {
cb.parent(origCommits.get(newCommits.size() - 1));
}
RevCommit c2 = cb.create();
testRepo.getRevWalk().parseBody(c2);
newCommits.add(c2);
}
assertPushOk(pushHead(testRepo, refsFor, false), refsFor);
return newCommits;
}
private static Map<Integer, String> getPatchSetRevisions(ChangeData cd) private static Map<Integer, String> getPatchSetRevisions(ChangeData cd)
throws Exception { throws Exception {
Map<Integer, String> revisions = new HashMap<>(); Map<Integer, String> revisions = new HashMap<>();
@@ -786,8 +878,4 @@ public abstract class AbstractPushForReview extends AbstractDaemonTest {
assertThat(cds).named("change " + id).hasSize(1); assertThat(cds).named("change " + id).hasSize(1);
return cds.get(0); return cds.get(0);
} }
private static String getChangeId(RevCommit c) {
return getOnlyElement(c.getFooterLines(CHANGE_ID));
}
} }

View File

@@ -20,11 +20,13 @@ import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
import com.google.gerrit.extensions.registration.DynamicItem; import com.google.gerrit.extensions.registration.DynamicItem;
import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.CurrentUser; import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.account.AccountResolver; import com.google.gerrit.server.account.AccountResolver;
import com.google.gerrit.server.config.AuthConfig; import com.google.gerrit.server.config.AuthConfig;
import com.google.gwtorm.server.OrmException; import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton; import com.google.inject.Singleton;
import com.google.inject.servlet.ServletModule; import com.google.inject.servlet.ServletModule;
@@ -55,14 +57,17 @@ class RunAsFilter implements Filter {
} }
} }
private final Provider<ReviewDb> db;
private final boolean enabled; private final boolean enabled;
private final DynamicItem<WebSession> session; private final DynamicItem<WebSession> session;
private final AccountResolver accountResolver; private final AccountResolver accountResolver;
@Inject @Inject
RunAsFilter(AuthConfig config, RunAsFilter(Provider<ReviewDb> db,
AuthConfig config,
DynamicItem<WebSession> session, DynamicItem<WebSession> session,
AccountResolver accountResolver) { AccountResolver accountResolver) {
this.db = db;
this.enabled = config.isRunAsEnabled(); this.enabled = config.isRunAsEnabled();
this.session = session; this.session = session;
this.accountResolver = accountResolver; this.accountResolver = accountResolver;
@@ -95,7 +100,7 @@ class RunAsFilter implements Filter {
Account target; Account target;
try { try {
target = accountResolver.find(runas); target = accountResolver.find(db.get(), runas);
} catch (OrmException e) { } catch (OrmException e) {
log.warn("cannot resolve account for " + RUN_AS, e); log.warn("cannot resolve account for " + RUN_AS, e);
replyError(req, res, replyError(req, res,

View File

@@ -15,6 +15,7 @@
package com.google.gerrit.lucene; package com.google.gerrit.lucene;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.gerrit.extensions.events.LifecycleListener; import com.google.gerrit.extensions.events.LifecycleListener;
import com.google.gerrit.lifecycle.LifecycleModule; import com.google.gerrit.lifecycle.LifecycleModule;
import com.google.gerrit.server.config.GerritServerConfig; import com.google.gerrit.server.config.GerritServerConfig;
@@ -39,6 +40,7 @@ import org.eclipse.jgit.lib.Config;
import java.util.Collection; import java.util.Collection;
import java.util.Map; import java.util.Map;
import java.util.Set;
public class LuceneIndexModule extends LifecycleModule { public class LuceneIndexModule extends LifecycleModule {
private static final String SINGLE_VERSIONS = private static final String SINGLE_VERSIONS =
@@ -115,15 +117,20 @@ public class LuceneIndexModule extends LifecycleModule {
@Singleton @Singleton
static class SingleVersionListener implements LifecycleListener { static class SingleVersionListener implements LifecycleListener {
private final Set<String> disabled;
private final Collection<IndexDefinition<?, ?, ?>> defs; private final Collection<IndexDefinition<?, ?, ?>> defs;
private final Map<String, Integer> singleVersions; private final Map<String, Integer> singleVersions;
@Inject @Inject
SingleVersionListener( SingleVersionListener(
@GerritServerConfig Config cfg,
Collection<IndexDefinition<?, ?, ?>> defs, Collection<IndexDefinition<?, ?, ?>> defs,
@Named(SINGLE_VERSIONS) Map<String, Integer> singleVersions) { @Named(SINGLE_VERSIONS) Map<String, Integer> singleVersions) {
this.defs = defs; this.defs = defs;
this.singleVersions = singleVersions; this.singleVersions = singleVersions;
disabled = ImmutableSet.copyOf(
cfg.getStringList("index", null, "testDisable"));
} }
@Override @Override
@@ -135,6 +142,9 @@ public class LuceneIndexModule extends LifecycleModule {
private <K, V, I extends Index<K, V>> void start( private <K, V, I extends Index<K, V>> void start(
IndexDefinition<K, V, I> def) { IndexDefinition<K, V, I> def) {
if (disabled.contains(def.getName())) {
return;
}
Schema<V> schema; Schema<V> schema;
Integer v = singleVersions.get(def.getName()); Integer v = singleVersions.get(def.getName());
if (v == null) { if (v == null) {

View File

@@ -40,21 +40,18 @@ public class AccountResolver {
private final AccountCache byId; private final AccountCache byId;
private final AccountIndexCollection accountIndexes; private final AccountIndexCollection accountIndexes;
private final Provider<InternalAccountQuery> accountQueryProvider; private final Provider<InternalAccountQuery> accountQueryProvider;
private final Provider<ReviewDb> schema;
@Inject @Inject
AccountResolver(Realm realm, AccountResolver(Realm realm,
AccountByEmailCache byEmail, AccountByEmailCache byEmail,
AccountCache byId, AccountCache byId,
AccountIndexCollection accountIndexes, AccountIndexCollection accountIndexes,
Provider<InternalAccountQuery> accountQueryProvider, Provider<InternalAccountQuery> accountQueryProvider) {
Provider<ReviewDb> schema) {
this.realm = realm; this.realm = realm;
this.byEmail = byEmail; this.byEmail = byEmail;
this.byId = byId; this.byId = byId;
this.accountIndexes = accountIndexes; this.accountIndexes = accountIndexes;
this.accountQueryProvider = accountQueryProvider; this.accountQueryProvider = accountQueryProvider;
this.schema = schema;
} }
/** /**
@@ -67,8 +64,8 @@ public class AccountResolver {
* @return the single account that matches; null if no account matches or * @return the single account that matches; null if no account matches or
* there are multiple candidates. * there are multiple candidates.
*/ */
public Account find(final String nameOrEmail) throws OrmException { public Account find(ReviewDb db, String nameOrEmail) throws OrmException {
Set<Account.Id> r = findAll(nameOrEmail); Set<Account.Id> r = findAll(db, nameOrEmail);
if (r.size() == 1) { if (r.size() == 1) {
return byId.get(r.iterator().next()).getAccount(); return byId.get(r.iterator().next()).getAccount();
} }
@@ -90,17 +87,19 @@ public class AccountResolver {
/** /**
* Find all accounts matching the name or name/email string. * Find all accounts matching the name or name/email string.
* *
* @param db open database handle.
* @param nameOrEmail a string of the format * @param nameOrEmail a string of the format
* "Full Name &lt;email@example&gt;", just the email address * "Full Name &lt;email@example&gt;", just the email address
* ("email@example"), a full name ("Full Name"), an account id * ("email@example"), a full name ("Full Name"), an account id
* ("18419") or an user name ("username"). * ("18419") or an user name ("username").
* @return the accounts that match, empty collection if none. Never null. * @return the accounts that match, empty collection if none. Never null.
*/ */
public Set<Account.Id> findAll(String nameOrEmail) throws OrmException { public Set<Account.Id> findAll(ReviewDb db, String nameOrEmail)
throws OrmException {
Matcher m = Pattern.compile("^.* \\(([1-9][0-9]*)\\)$").matcher(nameOrEmail); Matcher m = Pattern.compile("^.* \\(([1-9][0-9]*)\\)$").matcher(nameOrEmail);
if (m.matches()) { if (m.matches()) {
Account.Id id = Account.Id.parse(m.group(1)); Account.Id id = Account.Id.parse(m.group(1));
if (exists(id)) { if (exists(db, id)) {
return Collections.singleton(id); return Collections.singleton(id);
} }
return Collections.emptySet(); return Collections.emptySet();
@@ -108,7 +107,7 @@ public class AccountResolver {
if (nameOrEmail.matches("^[1-9][0-9]*$")) { if (nameOrEmail.matches("^[1-9][0-9]*$")) {
Account.Id id = Account.Id.parse(nameOrEmail); Account.Id id = Account.Id.parse(nameOrEmail);
if (exists(id)) { if (exists(db, id)) {
return Collections.singleton(id); return Collections.singleton(id);
} }
return Collections.emptySet(); return Collections.emptySet();
@@ -121,40 +120,42 @@ public class AccountResolver {
} }
} }
return findAllByNameOrEmail(nameOrEmail); return findAllByNameOrEmail(db, nameOrEmail);
} }
private boolean exists(Account.Id id) throws OrmException { private boolean exists(ReviewDb db, Account.Id id) throws OrmException {
return schema.get().accounts().get(id) != null; return db.accounts().get(id) != null;
} }
/** /**
* Locate exactly one account matching the name or name/email string. * Locate exactly one account matching the name or name/email string.
* *
* @param db open database handle.
* @param nameOrEmail a string of the format * @param nameOrEmail a string of the format
* "Full Name &lt;email@example&gt;", just the email address * "Full Name &lt;email@example&gt;", just the email address
* ("email@example"), a full name ("Full Name"). * ("email@example"), a full name ("Full Name").
* @return the single account that matches; null if no account matches or * @return the single account that matches; null if no account matches or
* there are multiple candidates. * there are multiple candidates.
*/ */
public Account findByNameOrEmail(final String nameOrEmail) public Account findByNameOrEmail(ReviewDb db, String nameOrEmail)
throws OrmException { throws OrmException {
Set<Account.Id> r = findAllByNameOrEmail(nameOrEmail); Set<Account.Id> r = findAllByNameOrEmail(db, nameOrEmail);
return r.size() == 1 ? byId.get(r.iterator().next()).getAccount() : null; return r.size() == 1 ? byId.get(r.iterator().next()).getAccount() : null;
} }
/** /**
* Locate exactly one account matching the name or name/email string. * Locate exactly one account matching the name or name/email string.
* *
* @param db open database handle.
* @param nameOrEmail a string of the format * @param nameOrEmail a string of the format
* "Full Name &lt;email@example&gt;", just the email address * "Full Name &lt;email@example&gt;", just the email address
* ("email@example"), a full name ("Full Name"). * ("email@example"), a full name ("Full Name").
* @return the accounts that match, empty collection if none. Never null. * @return the accounts that match, empty collection if none. Never null.
*/ */
public Set<Account.Id> findAllByNameOrEmail(final String nameOrEmail) public Set<Account.Id> findAllByNameOrEmail(ReviewDb db, String nameOrEmail)
throws OrmException { throws OrmException {
final int lt = nameOrEmail.indexOf('<'); int lt = nameOrEmail.indexOf('<');
final int gt = nameOrEmail.indexOf('>'); int gt = nameOrEmail.indexOf('>');
if (lt >= 0 && gt > lt && nameOrEmail.contains("@")) { if (lt >= 0 && gt > lt && nameOrEmail.contains("@")) {
Set<Account.Id> ids = byEmail.get(nameOrEmail.substring(lt + 1, gt)); Set<Account.Id> ids = byEmail.get(nameOrEmail.substring(lt + 1, gt));
if (ids.isEmpty() || ids.size() == 1) { if (ids.isEmpty() || ids.size() == 1) {
@@ -177,7 +178,7 @@ public class AccountResolver {
return byEmail.get(nameOrEmail); return byEmail.get(nameOrEmail);
} }
final Account.Id id = realm.lookup(nameOrEmail); Account.Id id = realm.lookup(nameOrEmail);
if (id != null) { if (id != null) {
return Collections.singleton(id); return Collections.singleton(id);
} }
@@ -200,7 +201,7 @@ public class AccountResolver {
}).toSet(); }).toSet();
} }
List<Account> m = schema.get().accounts().byFullName(nameOrEmail).toList(); List<Account> m = db.accounts().byFullName(nameOrEmail).toList();
if (m.size() == 1) { if (m.size() == 1) {
return Collections.singleton(m.get(0).getId()); return Collections.singleton(m.get(0).getId());
} }
@@ -210,18 +211,16 @@ public class AccountResolver {
Set<Account.Id> result = new HashSet<>(); Set<Account.Id> result = new HashSet<>();
String a = nameOrEmail; String a = nameOrEmail;
String b = nameOrEmail + "\u9fa5"; String b = nameOrEmail + "\u9fa5";
for (Account act : schema.get().accounts().suggestByFullName(a, b, 10)) { for (Account act : db.accounts().suggestByFullName(a, b, 10)) {
result.add(act.getId()); result.add(act.getId());
} }
for (AccountExternalId extId : schema for (AccountExternalId extId : db.accountExternalIds()
.get()
.accountExternalIds()
.suggestByKey( .suggestByKey(
new AccountExternalId.Key(AccountExternalId.SCHEME_USERNAME, a), new AccountExternalId.Key(AccountExternalId.SCHEME_USERNAME, a),
new AccountExternalId.Key(AccountExternalId.SCHEME_USERNAME, b), 10)) { new AccountExternalId.Key(AccountExternalId.SCHEME_USERNAME, b), 10)) {
result.add(extId.getAccountId()); result.add(extId.getAccountId());
} }
for (AccountExternalId extId : schema.get().accountExternalIds() for (AccountExternalId extId : db.accountExternalIds()
.suggestByEmailAddress(a, b, 10)) { .suggestByEmailAddress(a, b, 10)) {
result.add(extId.getAccountId()); result.add(extId.getAccountId());
} }

View File

@@ -24,6 +24,7 @@ import com.google.gerrit.extensions.restapi.RestView;
import com.google.gerrit.extensions.restapi.TopLevelResource; import com.google.gerrit.extensions.restapi.TopLevelResource;
import com.google.gerrit.extensions.restapi.UnprocessableEntityException; import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.AnonymousUser; import com.google.gerrit.server.AnonymousUser;
import com.google.gerrit.server.CurrentUser; import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.IdentifiedUser;
@@ -36,6 +37,7 @@ import com.google.inject.Singleton;
public class AccountsCollection implements public class AccountsCollection implements
RestCollection<TopLevelResource, AccountResource>, RestCollection<TopLevelResource, AccountResource>,
AcceptsCreate<TopLevelResource> { AcceptsCreate<TopLevelResource> {
private final Provider<ReviewDb> db;
private final Provider<CurrentUser> self; private final Provider<CurrentUser> self;
private final AccountResolver resolver; private final AccountResolver resolver;
private final AccountControl.Factory accountControlFactory; private final AccountControl.Factory accountControlFactory;
@@ -45,13 +47,15 @@ public class AccountsCollection implements
private final CreateAccount.Factory createAccountFactory; private final CreateAccount.Factory createAccountFactory;
@Inject @Inject
AccountsCollection(Provider<CurrentUser> self, AccountsCollection(Provider<ReviewDb> db,
Provider<CurrentUser> self,
AccountResolver resolver, AccountResolver resolver,
AccountControl.Factory accountControlFactory, AccountControl.Factory accountControlFactory,
IdentifiedUser.GenericFactory userFactory, IdentifiedUser.GenericFactory userFactory,
Provider<QueryAccounts> list, Provider<QueryAccounts> list,
DynamicMap<RestView<AccountResource>> views, DynamicMap<RestView<AccountResource>> views,
CreateAccount.Factory createAccountFactory) { CreateAccount.Factory createAccountFactory) {
this.db = db;
this.self = self; this.self = self;
this.resolver = resolver; this.resolver = resolver;
this.accountControlFactory = accountControlFactory; this.accountControlFactory = accountControlFactory;
@@ -122,7 +126,7 @@ public class AccountsCollection implements
} }
} }
Account match = resolver.find(id); Account match = resolver.find(db.get(), id);
if (match == null) { if (match == null) {
return null; return null;
} }

View File

@@ -16,6 +16,7 @@ package com.google.gerrit.server.args4j;
import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AuthType; import com.google.gerrit.reviewdb.client.AuthType;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.account.AccountException; import com.google.gerrit.server.account.AccountException;
import com.google.gerrit.server.account.AccountManager; import com.google.gerrit.server.account.AccountManager;
import com.google.gerrit.server.account.AccountResolver; import com.google.gerrit.server.account.AccountResolver;
@@ -23,6 +24,7 @@ import com.google.gerrit.server.account.AuthRequest;
import com.google.gerrit.server.config.AuthConfig; import com.google.gerrit.server.config.AuthConfig;
import com.google.gwtorm.server.OrmException; import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.assistedinject.Assisted; import com.google.inject.assistedinject.Assisted;
import org.kohsuke.args4j.CmdLineException; import org.kohsuke.args4j.CmdLineException;
@@ -35,29 +37,34 @@ import org.kohsuke.args4j.spi.Setter;
import java.io.IOException; import java.io.IOException;
public class AccountIdHandler extends OptionHandler<Account.Id> { public class AccountIdHandler extends OptionHandler<Account.Id> {
private final Provider<ReviewDb> db;
private final AccountResolver accountResolver; private final AccountResolver accountResolver;
private final AccountManager accountManager; private final AccountManager accountManager;
private final AuthType authType; private final AuthType authType;
@Inject @Inject
public AccountIdHandler(final AccountResolver accountResolver, public AccountIdHandler(
final AccountManager accountManager, Provider<ReviewDb> db,
final AuthConfig authConfig, AccountResolver accountResolver,
@Assisted final CmdLineParser parser, @Assisted final OptionDef option, AccountManager accountManager,
@Assisted final Setter<Account.Id> setter) { AuthConfig authConfig,
@Assisted CmdLineParser parser,
@Assisted OptionDef option,
@Assisted Setter<Account.Id> setter) {
super(parser, option, setter); super(parser, option, setter);
this.db = db;
this.accountResolver = accountResolver; this.accountResolver = accountResolver;
this.accountManager = accountManager; this.accountManager = accountManager;
this.authType = authConfig.getAuthType(); this.authType = authConfig.getAuthType();
} }
@Override @Override
public final int parseArguments(final Parameters params) public int parseArguments(Parameters params)
throws CmdLineException { throws CmdLineException {
final String token = params.getParameter(0); String token = params.getParameter(0);
final Account.Id accountId; Account.Id accountId;
try { try {
final Account a = accountResolver.find(token); Account a = accountResolver.find(db.get(), token);
if (a != null) { if (a != null) {
accountId = a.getId(); accountId = a.getId();
} else { } else {

View File

@@ -214,7 +214,7 @@ public class PublishDraftPatchSet implements RestModifyView<RevisionResource, In
List<FooterLine> footerLines = commit.getFooterLines(); List<FooterLine> footerLines = commit.getFooterLines();
recipients = getRecipientsFromFooters( recipients = getRecipientsFromFooters(
accountResolver, patchSet.isDraft(), footerLines); ctx.getDb(), accountResolver, patchSet.isDraft(), footerLines);
recipients.remove(ctx.getAccountId()); recipients.remove(ctx.getAccountId());
approvalsUtil.addReviewers(ctx.getDb(), ctx.getUpdate(psId), labelTypes, approvalsUtil.addReviewers(ctx.getDb(), ctx.getUpdate(psId), labelTypes,
change, patchSet, patchSetInfo, recipients.getReviewers(), change, patchSet, patchSetInfo, recipients.getReviewers(),

View File

@@ -1891,7 +1891,7 @@ public class ReceiveCommits {
recipients.add(magicBranch.getMailRecipients()); recipients.add(magicBranch.getMailRecipients());
approvals = magicBranch.labels; approvals = magicBranch.labels;
recipients.add(getRecipientsFromFooters( recipients.add(getRecipientsFromFooters(
accountResolver, magicBranch.draft, footerLines)); db, accountResolver, magicBranch.draft, footerLines));
recipients.remove(me); recipients.remove(me);
StringBuilder msg = new StringBuilder( StringBuilder msg = new StringBuilder(
ApprovalsUtil.renderMessageWithApprovals( ApprovalsUtil.renderMessageWithApprovals(

View File

@@ -247,7 +247,7 @@ public class ReplaceOp extends BatchUpdate.Op {
: null); : null);
recipients.add(getRecipientsFromFooters( recipients.add(getRecipientsFromFooters(
accountResolver, draft, commit.getFooterLines())); ctx.getDb(), accountResolver, draft, commit.getFooterLines()));
recipients.remove(ctx.getAccountId()); recipients.remove(ctx.getAccountId());
ChangeData cd = changeDataFactory.create(ctx.getDb(), ctx.getControl()); ChangeData cd = changeDataFactory.create(ctx.getDb(), ctx.getControl());
MailRecipients oldRecipients = MailRecipients oldRecipients =

View File

@@ -153,7 +153,7 @@ public class AddMembers implements RestModifyView<GroupResource, Input> {
case HTTP_LDAP: case HTTP_LDAP:
case CLIENT_SSL_CERT_LDAP: case CLIENT_SSL_CERT_LDAP:
case LDAP: case LDAP:
if (accountResolver.find(nameOrEmail) == null) { if (accountResolver.find(db.get(), nameOrEmail) == null) {
// account does not exist, try to create it // account does not exist, try to create it
Account a = createAccountByLdap(nameOrEmail); Account a = createAccountByLdap(nameOrEmail);
if (a != null) { if (a != null) {

View File

@@ -20,6 +20,7 @@ import static com.google.gerrit.server.notedb.ReviewerStateInternal.REVIEWER;
import com.google.gerrit.common.FooterConstants; import com.google.gerrit.common.FooterConstants;
import com.google.gerrit.common.errors.NoSuchAccountException; import com.google.gerrit.common.errors.NoSuchAccountException;
import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.ReviewerSet; import com.google.gerrit.server.ReviewerSet;
import com.google.gerrit.server.account.AccountResolver; import com.google.gerrit.server.account.AccountResolver;
import com.google.gwtorm.server.OrmException; import com.google.gwtorm.server.OrmException;
@@ -33,19 +34,18 @@ import java.util.List;
import java.util.Set; import java.util.Set;
public class MailUtil { public class MailUtil {
public static MailRecipients getRecipientsFromFooters( public static MailRecipients getRecipientsFromFooters(
AccountResolver accountResolver, boolean draftPatchSet, ReviewDb db, AccountResolver accountResolver, boolean draftPatchSet,
List<FooterLine> footerLines) throws OrmException { List<FooterLine> footerLines) throws OrmException {
MailRecipients recipients = new MailRecipients(); MailRecipients recipients = new MailRecipients();
if (!draftPatchSet) { if (!draftPatchSet) {
for (FooterLine footerLine : footerLines) { for (FooterLine footerLine : footerLines) {
try { try {
if (isReviewer(footerLine)) { if (isReviewer(footerLine)) {
recipients.reviewers.add(toAccountId(accountResolver, footerLine recipients.reviewers.add(toAccountId(db, accountResolver, footerLine
.getValue().trim())); .getValue().trim()));
} else if (footerLine.matches(FooterKey.CC)) { } else if (footerLine.matches(FooterKey.CC)) {
recipients.cc.add(toAccountId(accountResolver, footerLine recipients.cc.add(toAccountId(db, accountResolver, footerLine
.getValue().trim())); .getValue().trim()));
} }
} catch (NoSuchAccountException e) { } catch (NoSuchAccountException e) {
@@ -64,9 +64,10 @@ public class MailUtil {
return recipients; return recipients;
} }
private static Account.Id toAccountId(final AccountResolver accountResolver, private static Account.Id toAccountId(ReviewDb db,
final String nameOrEmail) throws OrmException, NoSuchAccountException { AccountResolver accountResolver, String nameOrEmail)
final Account a = accountResolver.findByNameOrEmail(nameOrEmail); throws OrmException, NoSuchAccountException {
Account a = accountResolver.findByNameOrEmail(db, nameOrEmail);
if (a == null) { if (a == null) {
throw new NoSuchAccountException("\"" + nameOrEmail throw new NoSuchAccountException("\"" + nameOrEmail
+ "\" is not registered"); + "\" is not registered");

View File

@@ -749,7 +749,7 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
if ("self".equals(who)) { if ("self".equals(who)) {
return is_visible(); return is_visible();
} }
Set<Account.Id> m = args.accountResolver.findAll(who); Set<Account.Id> m = args.accountResolver.findAll(args.db.get(), who);
if (!m.isEmpty()) { if (!m.isEmpty()) {
List<Predicate<ChangeData>> p = Lists.newArrayListWithCapacity(m.size()); List<Predicate<ChangeData>> p = Lists.newArrayListWithCapacity(m.size());
for (Account.Id id : m) { for (Account.Id id : m) {
@@ -1008,7 +1008,7 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
if ("self".equals(who)) { if ("self".equals(who)) {
return Collections.singleton(self()); return Collections.singleton(self());
} }
Set<Account.Id> matches = args.accountResolver.findAll(who); Set<Account.Id> matches = args.accountResolver.findAll(args.db.get(), who);
if (matches.isEmpty()) { if (matches.isEmpty()) {
throw error("User " + who + " not found"); throw error("User " + who + " not found");
} }

View File

@@ -85,7 +85,7 @@ public class LsUserRefs extends SshCommand {
protected void run() throws Failure { protected void run() throws Failure {
Account userAccount; Account userAccount;
try { try {
userAccount = accountResolver.find(userName); userAccount = accountResolver.find(db, userName);
} catch (OrmException e) { } catch (OrmException e) {
throw die(e); throw die(e);
} }