Migrate contributor agreements to All-Projects.

Added a new schema to move the ContributorAgreement, AccountAgreement,
and AccountGroupAgreement information into the All-Projects
project.config.

Updated VersionedMetaData to expose a way to do batch commits to the
meta data.

Change-Id: Ifb3fdd8c0d6a0c988941d6949f6501b8f8856412
This commit is contained in:
Colby Ranger
2012-04-18 16:16:30 -07:00
parent fb1039c287
commit 1eee2c9d8f
7 changed files with 601 additions and 69 deletions

View File

@@ -80,9 +80,14 @@ public final class AccountGroupMemberAudit {
public AccountGroupMemberAudit(final AccountGroupMember m, public AccountGroupMemberAudit(final AccountGroupMember m,
final Account.Id adder) { final Account.Id adder) {
this(m, adder, now());
}
public AccountGroupMemberAudit(final AccountGroupMember m,
final Account.Id adder, Timestamp addedOn) {
final Account.Id who = m.getAccountId(); final Account.Id who = m.getAccountId();
final AccountGroup.Id group = m.getAccountGroupId(); final AccountGroup.Id group = m.getAccountGroupId();
key = new AccountGroupMemberAudit.Key(who, group, now()); key = new AccountGroupMemberAudit.Key(who, group, addedOn);
addedBy = adder; addedBy = adder;
} }

View File

@@ -177,9 +177,7 @@ public class ProjectConfig extends VersionedMetaData {
} }
public void replace(ContributorAgreement section) { public void replace(ContributorAgreement section) {
if (section.getAutoVerify() != null) { section.setAutoVerify(resolve(section.getAutoVerify()));
resolve(section.getAutoVerify());
}
for (PermissionRule rule : section.getAccepted()) { for (PermissionRule rule : section.getAccepted()) {
rule.setGroup(resolve(rule.getGroup())); rule.setGroup(resolve(rule.getGroup()));
} }

View File

@@ -14,6 +14,7 @@
package com.google.gerrit.server.git; package com.google.gerrit.server.git;
import com.google.common.base.Objects;
import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheBuilder; import org.eclipse.jgit.dircache.DirCacheBuilder;
import org.eclipse.jgit.dircache.DirCacheEditor; import org.eclipse.jgit.dircache.DirCacheEditor;
@@ -23,7 +24,7 @@ import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.errors.ConfigInvalidException; import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.errors.UnmergedPathException; import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.CommitBuilder; import org.eclipse.jgit.lib.CommitBuilder;
import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Constants;
@@ -150,72 +151,130 @@ public abstract class VersionedMetaData {
* executed as requested. * executed as requested.
*/ */
public boolean commit(MetaDataUpdate update) throws IOException { public boolean commit(MetaDataUpdate update) throws IOException {
final Repository db = update.getRepository(); BatchMetaDataUpdate batch = openUpdate(update);
final CommitBuilder commit = update.getCommitBuilder();
reader = db.newObjectReader();
inserter = db.newObjectInserter();
try { try {
final RevWalk rw = new RevWalk(reader); batch.write(update.getCommitBuilder());
final RevTree src = revision != null ? rw.parseTree(revision) : null; return batch.commit();
final ObjectId res = writeTree(src, commit);
if (res.equals(src)) {
// If there are no changes to the content, don't create the commit.
return true;
}
commit.setTreeId(res);
if (revision != null) {
commit.setParentId(revision);
}
RefUpdate ru = db.updateRef(getRefName());
if (revision != null) {
ru.setExpectedOldObjectId(revision);
} else {
ru.setExpectedOldObjectId(ObjectId.zeroId());
}
ru.setNewObjectId(inserter.insert(commit));
ru.disableRefLog();
inserter.flush();
switch (ru.update(rw)) {
case NEW:
case FAST_FORWARD:
revision = rw.parseCommit(ru.getNewObjectId());
update.replicate(ru.getName());
return true;
case LOCK_FAILURE:
return false;
default:
throw new IOException("Cannot update " + ru.getName() + " in "
+ db.getDirectory() + ": " + ru.getResult());
}
} catch (ConfigInvalidException e) {
throw new IOException("Cannot update " + getRefName() + " in "
+ db.getDirectory() + ": " + e.getMessage(), e);
} finally { } finally {
inserter.release(); batch.close();
inserter = null;
reader.release();
reader = null;
} }
} }
private ObjectId writeTree(RevTree srcTree, CommitBuilder commit) public interface BatchMetaDataUpdate {
throws IOException, MissingObjectException, IncorrectObjectTypeException, void write(CommitBuilder commit) throws IOException;
UnmergedPathException, ConfigInvalidException { void write(VersionedMetaData config, CommitBuilder commit) throws IOException;
try { boolean commit() throws IOException;
newTree = readTree(srcTree); boolean commitAt(ObjectId revision) throws IOException;
onSave(commit); void close();
return newTree.writeTree(inserter); }
} finally {
newTree = null; public BatchMetaDataUpdate openUpdate(final MetaDataUpdate update) throws IOException {
} final Repository db = update.getRepository();
reader = db.newObjectReader();
inserter = db.newObjectInserter();
final RevWalk rw = new RevWalk(reader);
final RevTree tree = revision != null ? rw.parseTree(revision) : null;
newTree = readTree(tree);
return new BatchMetaDataUpdate() {
AnyObjectId src = revision;
AnyObjectId srcTree = tree;
@Override
public void write(CommitBuilder commit) throws IOException {
write(VersionedMetaData.this, commit);
}
private void doSave(VersionedMetaData config, CommitBuilder commit) throws IOException {
DirCache nt = config.newTree;
ObjectReader r = config.reader;
ObjectInserter i = config.inserter;
try {
config.newTree = newTree;
config.reader = reader;
config.inserter = inserter;
config.onSave(commit);
} catch (ConfigInvalidException e) {
throw new IOException("Cannot update " + getRefName() + " in "
+ db.getDirectory() + ": " + e.getMessage(), e);
} finally {
config.newTree = nt;
config.reader = r;
config.inserter = i;
}
}
@Override
public void write(VersionedMetaData config, CommitBuilder commit) throws IOException {
doSave(config, commit);
final ObjectId res = newTree.writeTree(inserter);
if (res.equals(srcTree)) {
// If there are no changes to the content, don't create the commit.
return;
}
commit.setTreeId(res);
if (src != null) {
commit.addParentId(src);
}
src = inserter.insert(commit);
srcTree = res;
}
@Override
public boolean commit() throws IOException {
return commitAt(revision);
}
@Override
public boolean commitAt(ObjectId expected) throws IOException {
if (Objects.equal(src, expected)) {
return true;
}
RefUpdate ru = db.updateRef(getRefName());
if (expected != null) {
ru.setExpectedOldObjectId(expected);
} else {
ru.setExpectedOldObjectId(ObjectId.zeroId());
}
ru.setNewObjectId(src);
ru.disableRefLog();
inserter.flush();
switch (ru.update(rw)) {
case NEW:
case FAST_FORWARD:
revision = rw.parseCommit(ru.getNewObjectId());
update.replicate(ru.getName());
return true;
case LOCK_FAILURE:
return false;
default:
throw new IOException("Cannot update " + ru.getName() + " in "
+ db.getDirectory() + ": " + ru.getResult());
}
}
@Override
public void close() {
newTree = null;
if (inserter != null) {
inserter.release();
inserter = null;
}
if (reader != null) {
reader.release();
reader = null;
}
}
};
} }
private DirCache readTree(RevTree tree) throws IOException, private DirCache readTree(RevTree tree) throws IOException,

View File

@@ -32,7 +32,7 @@ import java.util.List;
/** A version of the database schema. */ /** A version of the database schema. */
public abstract class SchemaVersion { public abstract class SchemaVersion {
/** The current schema version. */ /** The current schema version. */
public static final Class<Schema_64> C = Schema_64.class; public static final Class<Schema_65> C = Schema_65.class;
public static class Module extends AbstractModule { public static class Module extends AbstractModule {
@Override @Override

View File

@@ -0,0 +1,458 @@
// Copyright (C) 2012 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.schema;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.gerrit.common.data.AccessSection;
import com.google.gerrit.common.data.ContributorAgreement;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.common.data.GroupReference;
import com.google.gerrit.common.data.PermissionRule;
import com.google.gerrit.common.data.PermissionRule.Action;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroupMember;
import com.google.gerrit.reviewdb.client.AccountGroupMemberAudit;
import com.google.gerrit.reviewdb.client.AccountGroupName;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.account.GroupUUID;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.AnonymousCowardName;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.MetaDataUpdate;
import com.google.gerrit.server.git.NoReplication;
import com.google.gerrit.server.git.ProjectConfig;
import com.google.gerrit.server.git.VersionedMetaData.BatchMetaDataUpdate;
import com.google.gwtorm.jdbc.JdbcSchema;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.CommitBuilder;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.util.SystemReader;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
public class Schema_65 extends SchemaVersion {
private final AllProjectsName allProjects;
private final GitRepositoryManager mgr;
private final PersonIdent serverUser;
private final @AnonymousCowardName String anonymousCowardName;
@Inject
Schema_65(Provider<Schema_64> prior,
AllProjectsName allProjects,
GitRepositoryManager mgr,
@GerritPersonIdent PersonIdent serverUser,
@AnonymousCowardName String anonymousCowardName) {
super(prior);
this.allProjects = allProjects;
this.mgr = mgr;
this.serverUser = serverUser;
this.anonymousCowardName = anonymousCowardName;
}
@Override
protected void migrateData(ReviewDb db, UpdateUI ui)
throws OrmException, SQLException {
Repository git;
try {
git = mgr.openRepository(allProjects);
} catch (RepositoryNotFoundException e) {
throw new OrmException(e);
}
try {
MetaDataUpdate md =
new MetaDataUpdate(new NoReplication(), allProjects, git);
ProjectConfig config = ProjectConfig.read(md);
Map<Integer, ContributorAgreement> agreements = getAgreementToAdd(db, config);
if (agreements.isEmpty()) {
return;
}
ui.message("Moved contributor agreements to project.config");
// Create the auto verify groups.
List<AccountGroup.Id> adminGroupIds = getAdministrateServerGroups(db, config);
for (ContributorAgreement agreement : agreements.values()) {
if (agreement.getAutoVerify() != null) {
getOrCreateGroupForIndividuals(db, config, adminGroupIds, agreement);
}
}
// Scan AccountAgreement
long minTime = addAccountAgreements(db, config, adminGroupIds, agreements);
ProjectConfig base = ProjectConfig.read(md, null);
for (ContributorAgreement agreement : agreements.values()) {
base.replace(agreement);
}
base.getAccountsSection().setSameGroupVisibility(
config.getAccountsSection().getSameGroupVisibility());
BatchMetaDataUpdate batch = base.openUpdate(md);
try {
// Scan AccountGroupAgreement
List<AccountGroupAgreement> groupAgreements =
getAccountGroupAgreements(db, agreements);
// Find the earliest change
for (AccountGroupAgreement aga : groupAgreements) {
minTime = Math.min(minTime, aga.getTime());
}
minTime -= 60 * 1000; // 1 Minute
CommitBuilder commit = new CommitBuilder();
commit.setAuthor(new PersonIdent(serverUser, new Date(minTime)));
commit.setCommitter(new PersonIdent(serverUser, new Date(minTime)));
commit.setMessage("Add the ContributorAgreements for upgrade to Gerrit Code Review schema 65\n");
batch.write(commit);
for (AccountGroupAgreement aga : groupAgreements) {
AccountGroup group = db.accountGroups().get(aga.groupId);
if (group == null) {
continue;
}
ContributorAgreement agreement = agreements.get(aga.claId);
agreement.getAccepted().add(new PermissionRule(config.resolve(group)));
base.replace(agreement);
PersonIdent ident = null;
if (aga.reviewedBy != null) {
Account ua = db.accounts().get(aga.reviewedBy);
if (ua != null) {
String name = ua.getFullName();
String email = ua.getPreferredEmail();
if (email == null || email.isEmpty()) {
// No preferred email is configured. Use a generic identity so we
// don't leak an address the user may have given us, but doesn't
// necessarily want to publish through Git records.
//
String user = ua.getUserName();
if (user == null || user.isEmpty()) {
user = "account-" + ua.getId().toString();
}
String host = SystemReader.getInstance().getHostname();
email = user + "@" + host;
}
if (name == null || name.isEmpty()) {
final int at = email.indexOf('@');
if (0 < at) {
name = email.substring(0, at);
} else {
name = anonymousCowardName;
}
}
ident = new PersonIdent(name, email, new Date(aga.getTime()), TimeZone.getDefault());
}
}
if (ident == null) {
ident = new PersonIdent(serverUser, new Date(aga.getTime()));
}
// Build the commits such that it keeps track of the date added and
// who added it.
commit = new CommitBuilder();
commit.setAuthor(ident);
commit.setCommitter(new PersonIdent(serverUser, new Date(aga.getTime())));
String msg = String.format("Accept %s contributor agreement for %s\n",
agreement.getName(), group.getName());
if (!Strings.isNullOrEmpty(aga.reviewComments)) {
msg += "\n" + aga.reviewComments + "\n";
}
commit.setMessage(msg);
batch.write(commit);
}
// Merge the agreements with the other data in project.config.
commit = new CommitBuilder();
commit.setAuthor(serverUser);
commit.setCommitter(serverUser);
commit.setMessage("Upgrade to Gerrit Code Review schema 65\n");
commit.addParentId(config.getRevision());
batch.write(config, commit);
// Save the the final metadata.
if (!batch.commitAt(config.getRevision())) {
throw new OrmException("Cannot update " + allProjects);
}
} finally {
batch.close();
}
} catch (IOException e) {
throw new OrmException(e);
} catch (ConfigInvalidException e) {
throw new OrmException(e);
} finally {
git.close();
}
}
private Map<Integer, ContributorAgreement> getAgreementToAdd(
ReviewDb db, ProjectConfig config) throws SQLException {
Statement stmt = ((JdbcSchema) db).getConnection().createStatement();
try {
ResultSet rs = stmt.executeQuery(
"SELECT short_name, id, require_contact_information," +
" short_description, agreement_url, auto_verify " +
"FROM contributor_agreements WHERE active = 'Y'");
try {
Map<Integer, ContributorAgreement> agreements = Maps.newHashMap();
while (rs.next()) {
String name = rs.getString(1);
if (config.getContributorAgreement(name) != null) {
continue; // already exists
}
ContributorAgreement a = config.getContributorAgreement(name, true);
agreements.put(rs.getInt(2), a);
a.setRequireContactInformation("Y".equals(rs.getString(3)));
a.setDescription(rs.getString(4));
a.setAgreementUrl(rs.getString(5));
if ("Y".equals(rs.getString(6))) {
a.setAutoVerify(new GroupReference(null, null));
}
}
return agreements;
} finally {
rs.close();
}
} finally {
stmt.close();
}
}
private AccountGroup createGroup(ReviewDb db, String groupName,
AccountGroup.Id adminGroupId, String description)
throws OrmException {
final AccountGroup.Id groupId =
new AccountGroup.Id(db.nextAccountGroupId());
final AccountGroup.NameKey nameKey = new AccountGroup.NameKey(groupName);
final AccountGroup.UUID uuid = GroupUUID.make(groupName, serverUser);
final AccountGroup group = new AccountGroup(nameKey, groupId, uuid);
group.setOwnerGroupId(adminGroupId);
group.setDescription(description);
final AccountGroupName gn = new AccountGroupName(group);
// first insert the group name to validate that the group name hasn't
// already been used to create another group
db.accountGroupNames().insert(Collections.singleton(gn));
db.accountGroups().insert(Collections.singleton(group));
return group;
}
private List<AccountGroup.Id> getAdministrateServerGroups(
ReviewDb db, ProjectConfig cfg) throws OrmException {
List<PermissionRule> rules = cfg.getAccessSection(AccessSection.GLOBAL_CAPABILITIES)
.getPermission(GlobalCapability.ADMINISTRATE_SERVER)
.getRules();
List<AccountGroup.Id> groups =
Lists.newArrayListWithExpectedSize(rules.size());
for (PermissionRule rule : rules) {
if (rule.getAction() == Action.ALLOW) {
groups.add(db.accountGroups()
.byUUID(rule.getGroup().getUUID())
.toList()
.get(0)
.getId());
}
}
if (groups.isEmpty()) {
throw new IllegalStateException("no administrator group found");
}
return groups;
}
private GroupReference getOrCreateGroupForIndividuals(ReviewDb db,
ProjectConfig config, List<AccountGroup.Id> adminGroupIds,
ContributorAgreement agreement)
throws OrmException {
if (!agreement.getAccepted().isEmpty()) {
return agreement.getAccepted().get(0).getGroup();
}
String name = "CLA Accepted - " + agreement.getName();
AccountGroupName agn =
db.accountGroupNames().get(new AccountGroup.NameKey(name));
AccountGroup ag;
if (agn != null) {
ag = db.accountGroups().get(agn.getId());
if (ag == null) {
throw new IllegalStateException(
"account group name exists but account group does not: " + name);
}
if (!adminGroupIds.contains(ag.getOwnerGroupId())) {
throw new IllegalStateException(
"individual group exists with non admin owner group: " + name);
}
} else {
ag = createGroup(db, name, adminGroupIds.get(0),
String.format("Users who have accepted the %s CLA", agreement.getName()));
}
GroupReference group = config.resolve(ag);
agreement.setAccepted(Lists.newArrayList(new PermissionRule(group)));
if (agreement.getAutoVerify() != null) {
agreement.setAutoVerify(group);
}
// Don't allow accounts in the same individual CLA group to see each
// other in same group visibility mode.
List<PermissionRule> sameGroupVisibility =
config.getAccountsSection().getSameGroupVisibility();
PermissionRule rule = new PermissionRule(group);
rule.setDeny();
if (!sameGroupVisibility.contains(rule)) {
sameGroupVisibility.add(rule);
}
return group;
}
private long addAccountAgreements(ReviewDb db, ProjectConfig config,
List<AccountGroup.Id> adminGroupIds,
Map<Integer, ContributorAgreement> agreements)
throws SQLException, OrmException {
Statement stmt = ((JdbcSchema) db).getConnection().createStatement();
try {
ResultSet rs = stmt.executeQuery(
"SELECT account_id, cla_id, accepted_on, reviewed_by," +
" reviewed_on, review_comments " +
"FROM account_agreements WHERE status = 'V'");
try {
long minTime = System.currentTimeMillis();
while (rs.next()) {
Account.Id accountId = new Account.Id(rs.getInt(1));
Account.Id reviewerId = new Account.Id(rs.getInt(4));
if (rs.wasNull()) {
reviewerId = accountId;
}
int claId = rs.getInt(2);
ContributorAgreement agreement = agreements.get(claId);
if (agreement == null) {
continue; // Agreement is invalid
}
Timestamp acceptedOn = rs.getTimestamp(3);
minTime = Math.min(minTime, acceptedOn.getTime());
// Enter Agreement
GroupReference individualGroup =
getOrCreateGroupForIndividuals(db, config, adminGroupIds, agreement);
AccountGroup.Id groupId = db.accountGroups()
.byUUID(individualGroup.getUUID())
.toList()
.get(0)
.getId();
final AccountGroupMember.Key key =
new AccountGroupMember.Key(accountId, groupId);
AccountGroupMember m = db.accountGroupMembers().get(key);
if (m == null) {
m = new AccountGroupMember(key);
db.accountGroupMembersAudit().insert(
Collections.singleton(
new AccountGroupMemberAudit(m, reviewerId, acceptedOn)));
db.accountGroupMembers().insert(Collections.singleton(m));
}
}
return minTime;
} finally {
rs.close();
}
} finally {
stmt.close();
}
}
private static class AccountGroupAgreement {
private AccountGroup.Id groupId;
private int claId;
private Timestamp acceptedOn;
private Account.Id reviewedBy;
private Timestamp reviewedOn;
private String reviewComments;
private long getTime() {
return (reviewedOn == null) ? acceptedOn.getTime() : reviewedOn.getTime();
}
}
private List<AccountGroupAgreement> getAccountGroupAgreements(
ReviewDb db, Map<Integer, ContributorAgreement> agreements)
throws SQLException {
Statement stmt = ((JdbcSchema) db).getConnection().createStatement();
try {
ResultSet rs = stmt.executeQuery(
"SELECT group_id, cla_id, accepted_on, reviewed_by, reviewed_on, " +
" review_comments " +
"FROM account_group_agreements");
try {
List<AccountGroupAgreement> groupAgreements = Lists.newArrayList();
while (rs.next()) {
AccountGroupAgreement a = new AccountGroupAgreement();
a.groupId = new AccountGroup.Id(rs.getInt(1));
a.claId = rs.getInt(2);
if (!agreements.containsKey(a.claId)) {
continue; // Agreement is invalid
}
a.acceptedOn = rs.getTimestamp(3);
a.reviewedBy = new Account.Id(rs.getInt(4));
if (rs.wasNull()) {
a.reviewedBy = null;
}
a.reviewedOn = rs.getTimestamp(5);
if (rs.wasNull()) {
a.reviewedOn = null;
}
a.reviewComments = rs.getString(6);
if (rs.wasNull()) {
a.reviewComments = null;
}
groupAgreements.add(a);
}
return groupAgreements;
} finally {
rs.close();
}
} finally {
stmt.close();
}
}
}

View File

@@ -19,6 +19,9 @@ import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.GerritPersonIdent; import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.GerritPersonIdentProvider; import com.google.gerrit.server.GerritPersonIdentProvider;
import com.google.gerrit.server.config.AllProjectsName; import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.AnonymousCowardName;
import com.google.gerrit.server.config.AnonymousCowardNameProvider;
import com.google.gerrit.server.config.FactoryModule;
import com.google.gerrit.server.config.GerritServerConfig; import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.SitePaths; import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.git.GitRepositoryManager; import com.google.gerrit.server.git.GitRepositoryManager;
@@ -27,7 +30,6 @@ import com.google.gerrit.testutil.InMemoryDatabase;
import com.google.gwtorm.server.OrmException; import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.SchemaFactory; import com.google.gwtorm.server.SchemaFactory;
import com.google.gwtorm.server.StatementExecutor; import com.google.gwtorm.server.StatementExecutor;
import com.google.inject.AbstractModule;
import com.google.inject.Guice; import com.google.inject.Guice;
import com.google.inject.TypeLiteral; import com.google.inject.TypeLiteral;
@@ -63,7 +65,7 @@ public class SchemaUpdaterTest extends TestCase {
final File site = new File(UUID.randomUUID().toString()); final File site = new File(UUID.randomUUID().toString());
final SitePaths paths = new SitePaths(site); final SitePaths paths = new SitePaths(site);
SchemaUpdater u = Guice.createInjector(new AbstractModule() { SchemaUpdater u = Guice.createInjector(new FactoryModule() {
@Override @Override
protected void configure() { protected void configure() {
bind(new TypeLiteral<SchemaFactory<ReviewDb>>() {}).toInstance(db); bind(new TypeLiteral<SchemaFactory<ReviewDb>>() {}).toInstance(db);
@@ -88,6 +90,10 @@ public class SchemaUpdaterTest extends TestCase {
bind(GitRepositoryManager.class) // bind(GitRepositoryManager.class) //
.to(LocalDiskRepositoryManager.class); .to(LocalDiskRepositoryManager.class);
bind(String.class) //
.annotatedWith(AnonymousCowardName.class) //
.toProvider(AnonymousCowardNameProvider.class);
} }
}).getInstance(SchemaUpdater.class); }).getInstance(SchemaUpdater.class);

View File

@@ -20,6 +20,8 @@ import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.GerritPersonIdent; import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.GerritPersonIdentProvider; import com.google.gerrit.server.GerritPersonIdentProvider;
import com.google.gerrit.server.config.AllProjectsName; import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.AnonymousCowardName;
import com.google.gerrit.server.config.AnonymousCowardNameProvider;
import com.google.gerrit.server.config.GerritServerConfig; import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.SitePath; import com.google.gerrit.server.config.SitePath;
import com.google.gerrit.server.git.GitRepositoryManager; import com.google.gerrit.server.git.GitRepositoryManager;
@@ -122,6 +124,10 @@ public class InMemoryDatabase implements SchemaFactory<ReviewDb> {
bind(GitRepositoryManager.class) // bind(GitRepositoryManager.class) //
.to(LocalDiskRepositoryManager.class); .to(LocalDiskRepositoryManager.class);
bind(String.class) //
.annotatedWith(AnonymousCowardName.class) //
.toProvider(AnonymousCowardNameProvider.class);
} }
}).getBinding(Key.get(SchemaVersion.class, Current.class)) }).getBinding(Key.get(SchemaVersion.class, Current.class))
.getProvider().get(); .getProvider().get();