Include a UUID portion in NoteDb author identities
Author identities include per-server specific account IDs, so it is not safe to mix IDs from different servers. Ensure each server only ever produces identities with one ID during its lifetime, by writing out a random UUID to gerrit.config as gerrit.serverId. This happens during init, and optionally lazily during startup. For now NoteDb changes can be migrated between servers as long as this file is kept intact. Eventually, when federating changes between servers, we will need come up with some mechanism for coalescing various per-server identities into a single account, like the current AccountExternalId mapping (except not exactly that because Shawn regrets it). Such a mechanism will simply need to know how to handle this kind of UUID format. Change-Id: I9492c9c561892488703d15f7cde6094aa03f957b
This commit is contained in:
@@ -62,6 +62,7 @@ import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
import com.google.gerrit.server.git.MetaDataUpdate;
|
||||
import com.google.gerrit.server.git.ProjectConfig;
|
||||
import com.google.gerrit.server.index.ChangeIndexer;
|
||||
import com.google.gerrit.server.notedb.ChangeNoteUtil;
|
||||
import com.google.gerrit.server.notedb.ChangeNotes;
|
||||
import com.google.gerrit.server.project.ChangeControl;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
@@ -191,6 +192,9 @@ public abstract class AbstractDaemonTest {
|
||||
@Inject
|
||||
protected FakeEmailSender sender;
|
||||
|
||||
@Inject
|
||||
protected ChangeNoteUtil changeNoteUtil;
|
||||
|
||||
protected TestRepository<InMemoryRepository> testRepo;
|
||||
protected GerritServer server;
|
||||
protected TestAccount admin;
|
||||
|
@@ -43,6 +43,7 @@ import com.google.gwtorm.server.SchemaFactory;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Key;
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.ProvisionException;
|
||||
import com.google.inject.Singleton;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
||||
@@ -50,6 +51,8 @@ import org.apache.sshd.common.keyprovider.KeyPairProvider;
|
||||
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
|
||||
import org.eclipse.jgit.lib.Config;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
@@ -67,9 +70,11 @@ class InMemoryTestingDatabaseModule extends LifecycleModule {
|
||||
.toInstance(cfg);
|
||||
|
||||
// TODO(dborowitz): Use jimfs.
|
||||
Path p = Paths.get(cfg.getString("gerrit", null, "tempSiteDir"));
|
||||
bind(Path.class)
|
||||
.annotatedWith(SitePath.class)
|
||||
.toInstance(Paths.get(cfg.getString("gerrit", null, "tempSiteDir")));
|
||||
.toInstance(p);
|
||||
makeSiteDirs(p);
|
||||
|
||||
bind(GitRepositoryManager.class)
|
||||
.toInstance(new InMemoryRepositoryManager());
|
||||
@@ -135,4 +140,14 @@ class InMemoryTestingDatabaseModule extends LifecycleModule {
|
||||
mem.drop();
|
||||
}
|
||||
}
|
||||
|
||||
private static void makeSiteDirs(Path p) {
|
||||
try {
|
||||
Files.createDirectories(p.resolve("etc"));
|
||||
} catch (IOException e) {
|
||||
ProvisionException pe = new ProvisionException(e.getMessage());
|
||||
pe.initCause(e);
|
||||
throw pe;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1082,7 +1082,7 @@ public class ChangeIT extends AbstractDaemonTest {
|
||||
|
||||
assertThat(commitPatchSetCreation.getShortMessage())
|
||||
.isEqualTo("Create patch set 2");
|
||||
PersonIdent expectedAuthor = ChangeNoteUtil.newIdent(
|
||||
PersonIdent expectedAuthor = changeNoteUtil.newIdent(
|
||||
accountCache.get(admin.id).getAccount(), c.updated,
|
||||
serverIdent.get(), AnonymousCowardNameProvider.DEFAULT);
|
||||
assertThat(commitPatchSetCreation.getAuthorIdent())
|
||||
@@ -1095,7 +1095,7 @@ public class ChangeIT extends AbstractDaemonTest {
|
||||
rw.parseCommit(commitPatchSetCreation.getParent(0));
|
||||
assertThat(commitChangeCreation.getShortMessage())
|
||||
.isEqualTo("Create change");
|
||||
expectedAuthor = ChangeNoteUtil.newIdent(
|
||||
expectedAuthor = changeNoteUtil.newIdent(
|
||||
accountCache.get(admin.id).getAccount(), c.created, serverIdent.get(),
|
||||
AnonymousCowardNameProvider.DEFAULT);
|
||||
assertThat(commitChangeCreation.getAuthorIdent())
|
||||
|
@@ -127,7 +127,7 @@ public class CreateChangeIT extends AbstractDaemonTest {
|
||||
|
||||
assertThat(commit.getShortMessage()).isEqualTo("Create change");
|
||||
|
||||
PersonIdent expectedAuthor = ChangeNoteUtil.newIdent(
|
||||
PersonIdent expectedAuthor = changeNoteUtil.newIdent(
|
||||
accountCache.get(admin.id).getAccount(), c.created, serverIdent.get(),
|
||||
AnonymousCowardNameProvider.DEFAULT);
|
||||
assertThat(commit.getAuthorIdent()).isEqualTo(expectedAuthor);
|
||||
|
@@ -21,6 +21,7 @@ import com.google.common.collect.Sets;
|
||||
import com.google.gerrit.pgm.init.api.ConsoleUI;
|
||||
import com.google.gerrit.pgm.init.api.InitStep;
|
||||
import com.google.gerrit.pgm.init.api.Section;
|
||||
import com.google.gerrit.server.api.config.GerritServerIdProvider;
|
||||
import com.google.gerrit.server.config.SitePaths;
|
||||
import com.google.inject.Binding;
|
||||
import com.google.inject.Guice;
|
||||
@@ -43,6 +44,7 @@ class InitDatabase implements InitStep {
|
||||
private final SitePaths site;
|
||||
private final Libraries libraries;
|
||||
private final Section database;
|
||||
private final Section idSection;
|
||||
|
||||
@Inject
|
||||
InitDatabase(final ConsoleUI ui, final SitePaths site, final Libraries libraries,
|
||||
@@ -51,6 +53,7 @@ class InitDatabase implements InitStep {
|
||||
this.site = site;
|
||||
this.libraries = libraries;
|
||||
this.database = sections.get("database", null);
|
||||
this.idSection = sections.get(GerritServerIdProvider.SECTION, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -91,6 +94,13 @@ class InitDatabase implements InitStep {
|
||||
}
|
||||
|
||||
dci.initConfig(database);
|
||||
|
||||
// Initialize UUID for NoteDb on first init.
|
||||
String id = idSection.get(GerritServerIdProvider.KEY);
|
||||
if (Strings.isNullOrEmpty(id)) {
|
||||
idSection.set(
|
||||
GerritServerIdProvider.KEY, GerritServerIdProvider.generate());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -0,0 +1,67 @@
|
||||
// Copyright (C) 2016 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.api.config;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.gerrit.server.config.GerritServerConfig;
|
||||
import com.google.gerrit.server.config.SitePaths;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
|
||||
import org.eclipse.jgit.errors.ConfigInvalidException;
|
||||
import org.eclipse.jgit.lib.Config;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.UUID;
|
||||
|
||||
public class GerritServerIdProvider implements Provider<String> {
|
||||
public static final String SECTION = "gerrit";
|
||||
public static final String KEY = "serverId";
|
||||
|
||||
public static String generate() {
|
||||
return UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
private final String id;
|
||||
|
||||
@Inject
|
||||
GerritServerIdProvider(@GerritServerConfig Config cfg,
|
||||
SitePaths sitePaths) throws IOException, ConfigInvalidException {
|
||||
String origId = cfg.getString(SECTION, null, KEY);
|
||||
if (!Strings.isNullOrEmpty(origId)) {
|
||||
id = origId;
|
||||
return;
|
||||
}
|
||||
|
||||
// We're not generally supposed to do work in provider constructors, but
|
||||
// this is a bit of a special case because we really need to have the ID
|
||||
// available by the time the dbInjector is created. This even applies during
|
||||
// RebuildNoteDb, which otherwise would have been a reasonable place to do
|
||||
// the ID generation. Fortunately, it's not much work, and it happens once.
|
||||
id = generate();
|
||||
Config cfgCopy = new Config();
|
||||
cfgCopy.fromText(cfg.toText());
|
||||
cfg.setString(SECTION, null, KEY, id);
|
||||
Files.write(sitePaths.gerrit_config, cfg.toText().getBytes(UTF_8));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get() {
|
||||
return id;
|
||||
}
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
// Copyright (C) 2016 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.config;
|
||||
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
import com.google.inject.BindingAnnotation;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
|
||||
/**
|
||||
* Marker on a string holding a unique identifier for the server.
|
||||
* <p>
|
||||
* This value is generated on first use and stored in {@code
|
||||
* $site_path/etc/uuid}.
|
||||
*/
|
||||
@Retention(RUNTIME)
|
||||
@BindingAnnotation
|
||||
public @interface GerritServerId {
|
||||
}
|
@@ -44,6 +44,7 @@ public abstract class AbstractChangeUpdate {
|
||||
protected final GitRepositoryManager repoManager;
|
||||
protected final ChangeControl ctl;
|
||||
protected final String anonymousCowardName;
|
||||
protected final ChangeNoteUtil changeNoteUtil;
|
||||
protected final Date when;
|
||||
private final PersonIdent serverIdent;
|
||||
|
||||
@@ -55,12 +56,14 @@ public abstract class AbstractChangeUpdate {
|
||||
ChangeControl ctl,
|
||||
PersonIdent serverIdent,
|
||||
String anonymousCowardName,
|
||||
ChangeNoteUtil changeNoteUtil,
|
||||
Date when) {
|
||||
this.migration = migration;
|
||||
this.repoManager = repoManager;
|
||||
this.ctl = ctl;
|
||||
this.serverIdent = serverIdent;
|
||||
this.anonymousCowardName = anonymousCowardName;
|
||||
this.changeNoteUtil = changeNoteUtil;
|
||||
this.when = when;
|
||||
checkArgument(
|
||||
(ctl.getUser() instanceof IdentifiedUser)
|
||||
@@ -96,7 +99,7 @@ public abstract class AbstractChangeUpdate {
|
||||
private PersonIdent newAuthorIdent() {
|
||||
CurrentUser u = getUser();
|
||||
if (u instanceof IdentifiedUser) {
|
||||
return ChangeNoteUtil.newIdent(u.asIdentifiedUser().getAccount(), when,
|
||||
return changeNoteUtil.newIdent(u.asIdentifiedUser().getAccount(), when,
|
||||
serverIdent, anonymousCowardName);
|
||||
} else if (u instanceof InternalUser) {
|
||||
return serverIdent;
|
||||
@@ -105,7 +108,7 @@ public abstract class AbstractChangeUpdate {
|
||||
}
|
||||
|
||||
protected PersonIdent newIdent(Account author, Date when) {
|
||||
return ChangeNoteUtil.newIdent(author, when, serverIdent,
|
||||
return changeNoteUtil.newIdent(author, when, serverIdent,
|
||||
anonymousCowardName);
|
||||
}
|
||||
|
||||
|
@@ -91,10 +91,12 @@ public class ChangeDraftUpdate extends AbstractChangeUpdate {
|
||||
GitRepositoryManager repoManager,
|
||||
NotesMigration migration,
|
||||
AllUsersName allUsers,
|
||||
ChangeNoteUtil changeNoteUtil,
|
||||
CommentsInNotesUtil commentsUtil,
|
||||
@Assisted ChangeControl ctl,
|
||||
@Assisted Date when) {
|
||||
super(migration, repoManager, ctl, serverIdent, anonymousCowardName, when);
|
||||
super(migration, repoManager, ctl, serverIdent, anonymousCowardName,
|
||||
changeNoteUtil, when);
|
||||
this.draftsProject = allUsers;
|
||||
this.commentsUtil = commentsUtil;
|
||||
checkState(ctl.getUser().isIdentifiedUser(),
|
||||
@@ -195,7 +197,7 @@ public class ChangeDraftUpdate extends AbstractChangeUpdate {
|
||||
// Even though reading from changes might not be enabled, we need to
|
||||
// parse any existing revision notes so we can merge them.
|
||||
return RevisionNoteMap.parse(
|
||||
ctl.getId(), rw.getObjectReader(), noteMap, true);
|
||||
commentsUtil, ctl.getId(), rw.getObjectReader(), noteMap, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -14,20 +14,23 @@
|
||||
|
||||
package com.google.gerrit.server.notedb;
|
||||
|
||||
import static com.google.gerrit.server.notedb.ChangeNotes.parseException;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.primitives.Ints;
|
||||
import com.google.gerrit.reviewdb.client.Account;
|
||||
import com.google.gerrit.reviewdb.client.Change;
|
||||
import com.google.gerrit.reviewdb.client.RefNames;
|
||||
import com.google.gerrit.server.config.GerritServerId;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import org.eclipse.jgit.errors.ConfigInvalidException;
|
||||
import org.eclipse.jgit.lib.PersonIdent;
|
||||
import org.eclipse.jgit.revwalk.FooterKey;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class ChangeNoteUtil {
|
||||
static final String GERRIT_PLACEHOLDER_HOST = "gerrit";
|
||||
|
||||
static final FooterKey FOOTER_BRANCH = new FooterKey("Branch");
|
||||
static final FooterKey FOOTER_CHANGE_ID = new FooterKey("Change-id");
|
||||
static final FooterKey FOOTER_COMMIT = new FooterKey("Commit");
|
||||
@@ -57,28 +60,36 @@ public class ChangeNoteUtil {
|
||||
return r.toString();
|
||||
}
|
||||
|
||||
private final String serverId;
|
||||
|
||||
@Inject
|
||||
ChangeNoteUtil(@GerritServerId String serverId) {
|
||||
this.serverId = serverId;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static PersonIdent newIdent(Account author, Date when,
|
||||
public PersonIdent newIdent(Account author, Date when,
|
||||
PersonIdent serverIdent, String anonymousCowardName) {
|
||||
return new PersonIdent(
|
||||
author.getName(anonymousCowardName),
|
||||
author.getId().get() + "@" + GERRIT_PLACEHOLDER_HOST,
|
||||
author.getId().get() + "@" + serverId,
|
||||
when, serverIdent.getTimeZone());
|
||||
}
|
||||
|
||||
public static Account.Id parseIdent(PersonIdent ident) {
|
||||
public Account.Id parseIdent(PersonIdent ident, Change.Id changeId)
|
||||
throws ConfigInvalidException {
|
||||
String email = ident.getEmailAddress();
|
||||
int at = email.indexOf('@');
|
||||
if (at >= 0) {
|
||||
String host = email.substring(at + 1, email.length());
|
||||
if (host.equals(serverId)) {
|
||||
Integer id = Ints.tryParse(email.substring(0, at));
|
||||
if (id != null && host.equals(GERRIT_PLACEHOLDER_HOST)) {
|
||||
if (id != null) {
|
||||
return new Account.Id(id);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private ChangeNoteUtil() {
|
||||
throw parseException(changeId, "invalid identity, expected <id>@%s: %s",
|
||||
serverId, email);
|
||||
}
|
||||
}
|
||||
|
@@ -17,7 +17,6 @@ package com.google.gerrit.server.notedb;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.gerrit.server.notedb.ChangeNoteUtil.GERRIT_PLACEHOLDER_HOST;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Function;
|
||||
@@ -36,7 +35,6 @@ import com.google.common.collect.ListMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.Multimaps;
|
||||
import com.google.common.collect.Ordering;
|
||||
import com.google.common.primitives.Ints;
|
||||
import com.google.common.util.concurrent.AsyncFunction;
|
||||
import com.google.common.util.concurrent.CheckedFuture;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
@@ -70,7 +68,6 @@ import com.google.inject.Singleton;
|
||||
import org.eclipse.jgit.errors.ConfigInvalidException;
|
||||
import org.eclipse.jgit.lib.CommitBuilder;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.eclipse.jgit.lib.PersonIdent;
|
||||
import org.eclipse.jgit.lib.Ref;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.revwalk.RevWalk;
|
||||
@@ -113,21 +110,6 @@ public class ChangeNotes extends AbstractChangeNotes<ChangeNotes> {
|
||||
+ String.format(fmt, args));
|
||||
}
|
||||
|
||||
public static Account.Id parseIdent(PersonIdent ident, Change.Id changeId)
|
||||
throws ConfigInvalidException {
|
||||
String email = ident.getEmailAddress();
|
||||
int at = email.indexOf('@');
|
||||
if (at >= 0) {
|
||||
String host = email.substring(at + 1, email.length());
|
||||
Integer id = Ints.tryParse(email.substring(0, at));
|
||||
if (id != null && host.equals(GERRIT_PLACEHOLDER_HOST)) {
|
||||
return new Account.Id(id);
|
||||
}
|
||||
}
|
||||
throw parseException(changeId, "invalid identity, expected <id>@%s: %s",
|
||||
GERRIT_PLACEHOLDER_HOST, email);
|
||||
}
|
||||
|
||||
@Singleton
|
||||
public static class Factory {
|
||||
private static final Logger log = LoggerFactory.getLogger(Factory.class);
|
||||
@@ -137,6 +119,8 @@ public class ChangeNotes extends AbstractChangeNotes<ChangeNotes> {
|
||||
private final AllUsersName allUsers;
|
||||
private final Provider<InternalChangeQuery> queryProvider;
|
||||
private final ProjectCache projectCache;
|
||||
private final ChangeNoteUtil changeNoteUtil;
|
||||
private final CommentsInNotesUtil commentsUtil;
|
||||
|
||||
@VisibleForTesting
|
||||
@Inject
|
||||
@@ -144,12 +128,16 @@ public class ChangeNotes extends AbstractChangeNotes<ChangeNotes> {
|
||||
NotesMigration migration,
|
||||
AllUsersName allUsers,
|
||||
Provider<InternalChangeQuery> queryProvider,
|
||||
ProjectCache projectCache) {
|
||||
ProjectCache projectCache,
|
||||
ChangeNoteUtil changeNoteUtil,
|
||||
CommentsInNotesUtil commentsUtil) {
|
||||
this.repoManager = repoManager;
|
||||
this.migration = migration;
|
||||
this.allUsers = allUsers;
|
||||
this.queryProvider = queryProvider;
|
||||
this.projectCache = projectCache;
|
||||
this.changeNoteUtil = changeNoteUtil;
|
||||
this.commentsUtil = commentsUtil;
|
||||
}
|
||||
|
||||
public ChangeNotes createChecked(ReviewDb db, Change c)
|
||||
@@ -194,8 +182,8 @@ public class ChangeNotes extends AbstractChangeNotes<ChangeNotes> {
|
||||
project, changeId, change.getProject());
|
||||
// TODO: Throw NoSuchChangeException when the change is not found in the
|
||||
// database
|
||||
return new ChangeNotes(repoManager, migration, allUsers, project,
|
||||
change).load();
|
||||
return new ChangeNotes(repoManager, migration, allUsers, changeNoteUtil,
|
||||
commentsUtil, project, change).load();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -207,13 +195,13 @@ public class ChangeNotes extends AbstractChangeNotes<ChangeNotes> {
|
||||
* @return change notes
|
||||
*/
|
||||
public ChangeNotes createFromIndexedChange(Change change) {
|
||||
return new ChangeNotes(repoManager, migration, allUsers,
|
||||
change.getProject(), change);
|
||||
return new ChangeNotes(repoManager, migration, allUsers, changeNoteUtil,
|
||||
commentsUtil, change.getProject(), change);
|
||||
}
|
||||
|
||||
public ChangeNotes createForNew(Change change) throws OrmException {
|
||||
return new ChangeNotes(repoManager, migration, allUsers,
|
||||
change.getProject(), change).load();
|
||||
return new ChangeNotes(repoManager, migration, allUsers, changeNoteUtil,
|
||||
commentsUtil, change.getProject(), change).load();
|
||||
}
|
||||
|
||||
// TODO(dborowitz): Remove when deleting index schemas <27.
|
||||
@@ -222,8 +210,8 @@ public class ChangeNotes extends AbstractChangeNotes<ChangeNotes> {
|
||||
checkState(!migration.readChanges(), "do not call"
|
||||
+ " createFromIdOnlyWhenNotedbDisabled when notedb is enabled");
|
||||
Change change = unwrap(db).changes().get(changeId);
|
||||
return new ChangeNotes(repoManager, migration, allUsers,
|
||||
change.getProject(), change).load();
|
||||
return new ChangeNotes(repoManager, migration, allUsers, changeNoteUtil,
|
||||
commentsUtil, change.getProject(), change).load();
|
||||
}
|
||||
|
||||
// TODO(ekempin): Remove when database backend is deleted
|
||||
@@ -235,8 +223,8 @@ public class ChangeNotes extends AbstractChangeNotes<ChangeNotes> {
|
||||
throws OrmException {
|
||||
checkState(!migration.readChanges(), "do not call"
|
||||
+ " createFromChangeWhenNotedbDisabled when notedb is enabled");
|
||||
return new ChangeNotes(repoManager, migration, allUsers,
|
||||
change.getProject(), change).load();
|
||||
return new ChangeNotes(repoManager, migration, allUsers, changeNoteUtil,
|
||||
commentsUtil, change.getProject(), change).load();
|
||||
}
|
||||
|
||||
public CheckedFuture<ChangeNotes, OrmException> createAsync(
|
||||
@@ -255,8 +243,8 @@ public class ChangeNotes extends AbstractChangeNotes<ChangeNotes> {
|
||||
"passed project %s when creating ChangeNotes for %s,"
|
||||
+ " but actual project is %s",
|
||||
project, changeId, change.getProject());
|
||||
return new ChangeNotes(repoManager, migration,
|
||||
allUsers, project, change).load();
|
||||
return new ChangeNotes(repoManager, migration, allUsers,
|
||||
changeNoteUtil, commentsUtil, project, change).load();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -395,6 +383,8 @@ public class ChangeNotes extends AbstractChangeNotes<ChangeNotes> {
|
||||
}
|
||||
}
|
||||
|
||||
private final ChangeNoteUtil changeNoteUtil;
|
||||
private final CommentsInNotesUtil commentsUtil;
|
||||
private final Project.NameKey project;
|
||||
private final Change change;
|
||||
private ImmutableSortedMap<PatchSet.Id, PatchSet> patchSets;
|
||||
@@ -416,10 +406,13 @@ public class ChangeNotes extends AbstractChangeNotes<ChangeNotes> {
|
||||
|
||||
@VisibleForTesting
|
||||
public ChangeNotes(GitRepositoryManager repoManager, NotesMigration migration,
|
||||
AllUsersName allUsers, Project.NameKey project,
|
||||
AllUsersName allUsers, ChangeNoteUtil changeNoteUtil,
|
||||
CommentsInNotesUtil commentsUtil, Project.NameKey project,
|
||||
Change change) {
|
||||
super(repoManager, migration, change != null ? change.getId() : null);
|
||||
this.allUsers = allUsers;
|
||||
this.changeNoteUtil = changeNoteUtil;
|
||||
this.commentsUtil = commentsUtil;
|
||||
this.project = project;
|
||||
this.change = change != null ? new Change(change) : null;
|
||||
}
|
||||
@@ -517,7 +510,7 @@ public class ChangeNotes extends AbstractChangeNotes<ChangeNotes> {
|
||||
if (draftCommentNotes == null ||
|
||||
!author.equals(draftCommentNotes.getAuthor())) {
|
||||
draftCommentNotes = new DraftCommentNotes(repoManager, migration,
|
||||
allUsers, getChangeId(), author);
|
||||
allUsers, commentsUtil, getChangeId(), author);
|
||||
draftCommentNotes.load();
|
||||
}
|
||||
}
|
||||
@@ -564,7 +557,8 @@ public class ChangeNotes extends AbstractChangeNotes<ChangeNotes> {
|
||||
}
|
||||
try (RevWalk walk = new RevWalk(reader);
|
||||
ChangeNotesParser parser = new ChangeNotesParser(project,
|
||||
change.getId(), rev, walk, repoManager)) {
|
||||
change.getId(), rev, walk, repoManager, changeNoteUtil,
|
||||
commentsUtil)) {
|
||||
parser.parseAll();
|
||||
|
||||
if (parser.status != null) {
|
||||
|
@@ -26,7 +26,6 @@ import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_SUBJECT;
|
||||
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_SUBMISSION_ID;
|
||||
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_SUBMITTED_WITH;
|
||||
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_TOPIC;
|
||||
import static com.google.gerrit.server.notedb.ChangeNoteUtil.GERRIT_PLACEHOLDER_HOST;
|
||||
|
||||
import com.google.common.base.Enums;
|
||||
import com.google.common.base.Function;
|
||||
@@ -115,6 +114,8 @@ class ChangeNotesParser implements AutoCloseable {
|
||||
PatchSet.Id currentPatchSetId;
|
||||
RevisionNoteMap revisionNoteMap;
|
||||
|
||||
private final ChangeNoteUtil changeNoteUtil;
|
||||
private final CommentsInNotesUtil commentsUtil;
|
||||
private final Change.Id id;
|
||||
private final ObjectId tip;
|
||||
private final RevWalk walk;
|
||||
@@ -125,12 +126,15 @@ class ChangeNotesParser implements AutoCloseable {
|
||||
private final Multimap<PatchSet.Id, ChangeMessage> changeMessagesByPatchSet;
|
||||
|
||||
ChangeNotesParser(Project.NameKey project, Change.Id changeId, ObjectId tip,
|
||||
RevWalk walk, GitRepositoryManager repoManager)
|
||||
RevWalk walk, GitRepositoryManager repoManager,
|
||||
ChangeNoteUtil changeNoteUtil, CommentsInNotesUtil commentsUtil)
|
||||
throws RepositoryNotFoundException, IOException {
|
||||
this.id = changeId;
|
||||
this.tip = tip;
|
||||
this.walk = walk;
|
||||
this.repo = repoManager.openMetadataRepository(project);
|
||||
this.changeNoteUtil = changeNoteUtil;
|
||||
this.commentsUtil = commentsUtil;
|
||||
approvals = Maps.newHashMap();
|
||||
reviewers = Maps.newLinkedHashMap();
|
||||
allPastReviewers = Lists.newArrayList();
|
||||
@@ -501,7 +505,7 @@ class ChangeNotesParser implements AutoCloseable {
|
||||
ObjectReader reader = walk.getObjectReader();
|
||||
RevCommit tipCommit = walk.parseCommit(tip);
|
||||
revisionNoteMap = RevisionNoteMap.parse(
|
||||
id, reader, NoteMap.read(reader, tipCommit), false);
|
||||
commentsUtil, id, reader, NoteMap.read(reader, tipCommit), false);
|
||||
Map<RevId, RevisionNote> rns = revisionNoteMap.revisionNotes;
|
||||
|
||||
for (Map.Entry<RevId, RevisionNote> e : rns.entrySet()) {
|
||||
@@ -540,7 +544,7 @@ class ChangeNotesParser implements AutoCloseable {
|
||||
labelVoteStr = line.substring(0, s);
|
||||
PersonIdent ident = RawParseUtils.parsePersonIdent(line.substring(s + 1));
|
||||
checkFooter(ident != null, FOOTER_LABEL, line);
|
||||
accountId = parseIdent(ident);
|
||||
accountId = changeNoteUtil.parseIdent(ident, id);
|
||||
} else {
|
||||
labelVoteStr = line;
|
||||
accountId = committerId;
|
||||
@@ -578,7 +582,7 @@ class ChangeNotesParser implements AutoCloseable {
|
||||
label = line.substring(1, s);
|
||||
PersonIdent ident = RawParseUtils.parsePersonIdent(line.substring(s + 1));
|
||||
checkFooter(ident != null, FOOTER_LABEL, line);
|
||||
accountId = parseIdent(ident);
|
||||
accountId = changeNoteUtil.parseIdent(ident, id);
|
||||
} else {
|
||||
label = line.substring(1);
|
||||
accountId = committerId;
|
||||
@@ -661,7 +665,7 @@ class ChangeNotesParser implements AutoCloseable {
|
||||
PersonIdent ident =
|
||||
RawParseUtils.parsePersonIdent(line.substring(c2 + 2));
|
||||
checkFooter(ident != null, FOOTER_SUBMITTED_WITH, line);
|
||||
label.appliedBy = parseIdent(ident);
|
||||
label.appliedBy = changeNoteUtil.parseIdent(ident, id);
|
||||
} else {
|
||||
label.label = line.substring(c + 2);
|
||||
}
|
||||
@@ -679,17 +683,7 @@ class ChangeNotesParser implements AutoCloseable {
|
||||
&& a.getEmailAddress().equals(c.getEmailAddress())) {
|
||||
return null;
|
||||
}
|
||||
return parseIdent(commit.getAuthorIdent());
|
||||
}
|
||||
|
||||
private Account.Id parseIdent(PersonIdent ident)
|
||||
throws ConfigInvalidException {
|
||||
Account.Id id = ChangeNoteUtil.parseIdent(ident);
|
||||
if (id == null) {
|
||||
throw parseException("invalid identity, expected <id>@%s: %s",
|
||||
GERRIT_PLACEHOLDER_HOST, ident.getEmailAddress());
|
||||
}
|
||||
return id;
|
||||
return changeNoteUtil.parseIdent(commit.getAuthorIdent(), id);
|
||||
}
|
||||
|
||||
private void parseReviewer(ReviewerStateInternal state, String line)
|
||||
@@ -698,7 +692,7 @@ class ChangeNotesParser implements AutoCloseable {
|
||||
if (ident == null) {
|
||||
throw invalidFooter(state.getFooterKey(), line);
|
||||
}
|
||||
Account.Id accountId = parseIdent(ident);
|
||||
Account.Id accountId = changeNoteUtil.parseIdent(ident, id);
|
||||
if (!reviewers.containsKey(accountId)) {
|
||||
reviewers.put(accountId, state);
|
||||
}
|
||||
|
@@ -56,6 +56,7 @@ import com.google.gwtorm.server.SchemaFactory;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.util.Providers;
|
||||
|
||||
import org.eclipse.jgit.errors.ConfigInvalidException;
|
||||
import org.eclipse.jgit.lib.Constants;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.eclipse.jgit.lib.ObjectInserter;
|
||||
@@ -89,6 +90,7 @@ public class ChangeRebuilder {
|
||||
private final ChangeUpdate.Factory updateFactory;
|
||||
private final ChangeDraftUpdate.Factory draftUpdateFactory;
|
||||
private final NoteDbUpdateManager.Factory updateManagerFactory;
|
||||
private final ChangeNoteUtil changeNoteUtil;
|
||||
|
||||
@Inject
|
||||
ChangeRebuilder(SchemaFactory<ReviewDb> schemaFactory,
|
||||
@@ -99,7 +101,8 @@ public class ChangeRebuilder {
|
||||
PatchListCache patchListCache,
|
||||
ChangeUpdate.Factory updateFactory,
|
||||
ChangeDraftUpdate.Factory draftUpdateFactory,
|
||||
NoteDbUpdateManager.Factory updateManagerFactory) {
|
||||
NoteDbUpdateManager.Factory updateManagerFactory,
|
||||
ChangeNoteUtil changeNoteUtil) {
|
||||
this.schemaFactory = schemaFactory;
|
||||
this.repoManager = repoManager;
|
||||
this.controlFactory = controlFactory;
|
||||
@@ -109,6 +112,7 @@ public class ChangeRebuilder {
|
||||
this.updateFactory = updateFactory;
|
||||
this.draftUpdateFactory = draftUpdateFactory;
|
||||
this.updateManagerFactory = updateManagerFactory;
|
||||
this.changeNoteUtil = changeNoteUtil;
|
||||
}
|
||||
|
||||
public ListenableFuture<?> rebuildAsync(final Change.Id id,
|
||||
@@ -125,7 +129,8 @@ public class ChangeRebuilder {
|
||||
}
|
||||
|
||||
public void rebuild(ReviewDb db, Change.Id changeId)
|
||||
throws NoSuchChangeException, IOException, OrmException {
|
||||
throws NoSuchChangeException, IOException, OrmException,
|
||||
ConfigInvalidException {
|
||||
Change change = db.changes().get(changeId);
|
||||
if (change == null) {
|
||||
return;
|
||||
@@ -254,7 +259,7 @@ public class ChangeRebuilder {
|
||||
}
|
||||
|
||||
private List<HashtagsEvent> getHashtagsEvents(Change change,
|
||||
NoteDbUpdateManager manager) throws IOException {
|
||||
NoteDbUpdateManager manager) throws IOException, ConfigInvalidException {
|
||||
String refName = ChangeNoteUtil.changeRefName(change.getId());
|
||||
ObjectId old = manager.getChangeCommands()
|
||||
.getObjectId(manager.getChangeRepo(), refName);
|
||||
@@ -268,7 +273,7 @@ public class ChangeRebuilder {
|
||||
rw.markStart(rw.parseCommit(old));
|
||||
for (RevCommit commit : rw) {
|
||||
Account.Id authorId =
|
||||
ChangeNoteUtil.parseIdent(commit.getAuthorIdent());
|
||||
changeNoteUtil.parseIdent(commit.getAuthorIdent(), change.getId());
|
||||
PatchSet.Id psId = parsePatchSetId(change, commit);
|
||||
Set<String> hashtags = parseHashtags(commit);
|
||||
if (authorId == null || psId == null || hashtags == null) {
|
||||
|
@@ -136,10 +136,11 @@ public class ChangeUpdate extends AbstractChangeUpdate {
|
||||
ChangeDraftUpdate.Factory draftUpdateFactory,
|
||||
ProjectCache projectCache,
|
||||
@Assisted ChangeControl ctl,
|
||||
CommentsInNotesUtil commentsUtil) {
|
||||
CommentsInNotesUtil commentsUtil,
|
||||
ChangeNoteUtil changeNoteUtil) {
|
||||
this(serverIdent, anonymousCowardName, repoManager, migration, accountCache,
|
||||
updateManagerFactory, draftUpdateFactory,
|
||||
projectCache, ctl, serverIdent.getWhen(), commentsUtil);
|
||||
projectCache, ctl, serverIdent.getWhen(), commentsUtil, changeNoteUtil);
|
||||
}
|
||||
|
||||
@AssistedInject
|
||||
@@ -154,12 +155,13 @@ public class ChangeUpdate extends AbstractChangeUpdate {
|
||||
ProjectCache projectCache,
|
||||
@Assisted ChangeControl ctl,
|
||||
@Assisted Date when,
|
||||
CommentsInNotesUtil commentsUtil) {
|
||||
CommentsInNotesUtil commentsUtil,
|
||||
ChangeNoteUtil changeNoteUtil) {
|
||||
this(serverIdent, anonymousCowardName, repoManager, migration, accountCache,
|
||||
updateManagerFactory, draftUpdateFactory, ctl,
|
||||
when,
|
||||
projectCache.get(getProjectName(ctl)).getLabelTypes().nameComparator(),
|
||||
commentsUtil);
|
||||
commentsUtil, changeNoteUtil);
|
||||
}
|
||||
|
||||
private static Project.NameKey getProjectName(ChangeControl ctl) {
|
||||
@@ -178,9 +180,10 @@ public class ChangeUpdate extends AbstractChangeUpdate {
|
||||
@Assisted ChangeControl ctl,
|
||||
@Assisted Date when,
|
||||
@Assisted Comparator<String> labelNameComparator,
|
||||
CommentsInNotesUtil commentsUtil) {
|
||||
CommentsInNotesUtil commentsUtil,
|
||||
ChangeNoteUtil changeNoteUtil) {
|
||||
super(migration, repoManager, ctl, serverIdent,
|
||||
anonymousCowardName, when);
|
||||
anonymousCowardName, changeNoteUtil, when);
|
||||
this.accountCache = accountCache;
|
||||
this.commentsUtil = commentsUtil;
|
||||
this.draftUpdateFactory = draftUpdateFactory;
|
||||
@@ -401,7 +404,7 @@ public class ChangeUpdate extends AbstractChangeUpdate {
|
||||
// Even though reading from changes might not be enabled, we need to
|
||||
// parse any existing revision notes so we can merge them.
|
||||
return RevisionNoteMap.parse(
|
||||
ctl.getId(), rw.getObjectReader(), noteMap, false);
|
||||
commentsUtil, ctl.getId(), rw.getObjectReader(), noteMap, false);
|
||||
}
|
||||
|
||||
private void checkComments(Map<RevId, RevisionNote> existingNotes,
|
||||
|
@@ -15,13 +15,11 @@
|
||||
package com.google.gerrit.server.notedb;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.gerrit.server.notedb.ChangeNoteUtil.GERRIT_PLACEHOLDER_HOST;
|
||||
import static com.google.gerrit.server.notedb.ChangeNotes.parseException;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.primitives.Ints;
|
||||
import com.google.gerrit.reviewdb.client.Account;
|
||||
import com.google.gerrit.reviewdb.client.Change;
|
||||
import com.google.gerrit.reviewdb.client.CommentRange;
|
||||
@@ -52,7 +50,6 @@ import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.sql.Timestamp;
|
||||
import java.text.ParseException;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
@@ -72,7 +69,30 @@ public class CommentsInNotesUtil {
|
||||
private static final String REVISION = "Revision";
|
||||
private static final String UUID = "UUID";
|
||||
|
||||
public static List<PatchLineComment> parseNote(byte[] note, MutableInteger p,
|
||||
public static String formatTime(PersonIdent ident, Timestamp t) {
|
||||
GitDateFormatter dateFormatter = new GitDateFormatter(Format.DEFAULT);
|
||||
// TODO(dborowitz): Use a ThreadLocal or use Joda.
|
||||
PersonIdent newIdent = new PersonIdent(ident, t);
|
||||
return dateFormatter.formatDate(newIdent);
|
||||
}
|
||||
|
||||
private final AccountCache accountCache;
|
||||
private final PersonIdent serverIdent;
|
||||
private final String anonymousCowardName;
|
||||
private final ChangeNoteUtil changeNoteUtil;
|
||||
|
||||
@Inject
|
||||
public CommentsInNotesUtil(AccountCache accountCache,
|
||||
@GerritPersonIdent PersonIdent serverIdent,
|
||||
@AnonymousCowardName String anonymousCowardName,
|
||||
ChangeNoteUtil changeNoteUtil) {
|
||||
this.accountCache = accountCache;
|
||||
this.serverIdent = serverIdent;
|
||||
this.anonymousCowardName = anonymousCowardName;
|
||||
this.changeNoteUtil = changeNoteUtil;
|
||||
}
|
||||
|
||||
public List<PatchLineComment> parseNote(byte[] note, MutableInteger p,
|
||||
Change.Id changeId, Status status) throws ConfigInvalidException {
|
||||
if (p.value >= note.length) {
|
||||
return ImmutableList.of();
|
||||
@@ -99,14 +119,7 @@ public class CommentsInNotesUtil {
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String formatTime(PersonIdent ident, Timestamp t) {
|
||||
GitDateFormatter dateFormatter = new GitDateFormatter(Format.DEFAULT);
|
||||
// TODO(dborowitz): Use a ThreadLocal or use Joda.
|
||||
PersonIdent newIdent = new PersonIdent(ident, t);
|
||||
return dateFormatter.formatDate(newIdent);
|
||||
}
|
||||
|
||||
private static PatchLineComment parseComment(byte[] note, MutableInteger curr,
|
||||
private PatchLineComment parseComment(byte[] note, MutableInteger curr,
|
||||
String currentFileName, PatchSet.Id psId, RevId revId, boolean isForBase,
|
||||
Status status) throws ConfigInvalidException {
|
||||
Change.Id changeId = psId.getParentKey();
|
||||
@@ -273,14 +286,14 @@ public class CommentsInNotesUtil {
|
||||
return checkResult(commentTime, "comment timestamp", changeId);
|
||||
}
|
||||
|
||||
private static Account.Id parseAuthor(byte[] note, MutableInteger curr,
|
||||
private Account.Id parseAuthor(byte[] note, MutableInteger curr,
|
||||
Change.Id changeId) throws ConfigInvalidException {
|
||||
checkHeaderLineFormat(note, curr, AUTHOR, changeId);
|
||||
int startOfAccountId =
|
||||
RawParseUtils.endOfFooterLineKey(note, curr.value) + 2;
|
||||
PersonIdent ident =
|
||||
RawParseUtils.parsePersonIdent(note, startOfAccountId);
|
||||
Account.Id aId = parseIdent(ident, changeId);
|
||||
Account.Id aId = changeNoteUtil.parseIdent(ident, changeId);
|
||||
curr.value = RawParseUtils.nextLF(note, curr.value);
|
||||
return checkResult(aId, "comment author", changeId);
|
||||
}
|
||||
@@ -317,28 +330,6 @@ public class CommentsInNotesUtil {
|
||||
return i;
|
||||
}
|
||||
|
||||
private PersonIdent newIdent(Account author, Date when) {
|
||||
return new PersonIdent(
|
||||
author.getName(anonymousCowardName),
|
||||
author.getId().get() + "@" + GERRIT_PLACEHOLDER_HOST,
|
||||
when, serverIdent.getTimeZone());
|
||||
}
|
||||
|
||||
private static Account.Id parseIdent(PersonIdent ident, Change.Id changeId)
|
||||
throws ConfigInvalidException {
|
||||
String email = ident.getEmailAddress();
|
||||
int at = email.indexOf('@');
|
||||
if (at >= 0) {
|
||||
String host = email.substring(at + 1, email.length());
|
||||
Integer id = Ints.tryParse(email.substring(0, at));
|
||||
if (id != null && host.equals(GERRIT_PLACEHOLDER_HOST)) {
|
||||
return new Account.Id(id);
|
||||
}
|
||||
}
|
||||
throw parseException(changeId, "invalid identity, expected <id>@%s: %s",
|
||||
GERRIT_PLACEHOLDER_HOST, email);
|
||||
}
|
||||
|
||||
private void appendHeaderField(PrintWriter writer,
|
||||
String field, String value) {
|
||||
writer.print(field);
|
||||
@@ -360,19 +351,6 @@ public class CommentsInNotesUtil {
|
||||
}
|
||||
}
|
||||
|
||||
private final AccountCache accountCache;
|
||||
private final PersonIdent serverIdent;
|
||||
private final String anonymousCowardName;
|
||||
|
||||
@Inject
|
||||
public CommentsInNotesUtil(AccountCache accountCache,
|
||||
@GerritPersonIdent PersonIdent serverIdent,
|
||||
@AnonymousCowardName String anonymousCowardName) {
|
||||
this.accountCache = accountCache;
|
||||
this.serverIdent = serverIdent;
|
||||
this.anonymousCowardName = anonymousCowardName;
|
||||
}
|
||||
|
||||
public byte[] buildNote(List<PatchLineComment> comments) {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
buildNote(comments, out);
|
||||
@@ -448,8 +426,8 @@ public class CommentsInNotesUtil {
|
||||
writer.print("\n");
|
||||
|
||||
PersonIdent ident =
|
||||
newIdent(accountCache.get(c.getAuthor()).getAccount(),
|
||||
c.getWrittenOn());
|
||||
changeNoteUtil.newIdent(accountCache.get(c.getAuthor()).getAccount(),
|
||||
c.getWrittenOn(), serverIdent, anonymousCowardName);
|
||||
String nameString = ident.getName() + " <" + ident.getEmailAddress()
|
||||
+ ">";
|
||||
appendHeaderField(writer, AUTHOR, nameString);
|
||||
|
@@ -48,34 +48,40 @@ public class DraftCommentNotes extends AbstractChangeNotes<DraftCommentNotes> {
|
||||
private final GitRepositoryManager repoManager;
|
||||
private final NotesMigration migration;
|
||||
private final AllUsersName draftsProject;
|
||||
private final CommentsInNotesUtil commentsUtil;
|
||||
|
||||
@VisibleForTesting
|
||||
@Inject
|
||||
public Factory(GitRepositoryManager repoManager,
|
||||
NotesMigration migration,
|
||||
AllUsersName allUsers) {
|
||||
AllUsersName allUsers,
|
||||
CommentsInNotesUtil commentsUtil) {
|
||||
this.repoManager = repoManager;
|
||||
this.migration = migration;
|
||||
this.draftsProject = allUsers;
|
||||
this.commentsUtil = commentsUtil;
|
||||
}
|
||||
|
||||
public DraftCommentNotes create(Change.Id changeId, Account.Id accountId) {
|
||||
return new DraftCommentNotes(repoManager, migration, draftsProject,
|
||||
changeId, accountId);
|
||||
commentsUtil, changeId, accountId);
|
||||
}
|
||||
}
|
||||
|
||||
private final AllUsersName draftsProject;
|
||||
private final CommentsInNotesUtil commentsUtil;
|
||||
private final Account.Id author;
|
||||
|
||||
private ImmutableListMultimap<RevId, PatchLineComment> comments;
|
||||
private RevisionNoteMap revisionNoteMap;
|
||||
|
||||
DraftCommentNotes(GitRepositoryManager repoManager, NotesMigration migration,
|
||||
AllUsersName draftsProject, Change.Id changeId, Account.Id author) {
|
||||
AllUsersName draftsProject, CommentsInNotesUtil commentsUtil,
|
||||
Change.Id changeId, Account.Id author) {
|
||||
super(repoManager, migration, changeId);
|
||||
this.draftsProject = draftsProject;
|
||||
this.author = author;
|
||||
this.commentsUtil = commentsUtil;
|
||||
}
|
||||
|
||||
RevisionNoteMap getRevisionNoteMap() {
|
||||
@@ -116,7 +122,8 @@ public class DraftCommentNotes extends AbstractChangeNotes<DraftCommentNotes> {
|
||||
try (RevWalk walk = new RevWalk(reader)) {
|
||||
RevCommit tipCommit = walk.parseCommit(rev);
|
||||
revisionNoteMap = RevisionNoteMap.parse(
|
||||
getChangeId(), reader, NoteMap.read(reader, tipCommit), true);
|
||||
commentsUtil, getChangeId(), reader, NoteMap.read(reader, tipCommit),
|
||||
true);
|
||||
Multimap<RevId, PatchLineComment> cs = ArrayListMultimap.create();
|
||||
for (RevisionNote rn : revisionNoteMap.revisionNotes.values()) {
|
||||
for (PatchLineComment c : rn.comments) {
|
||||
|
@@ -63,8 +63,9 @@ class RevisionNote {
|
||||
final ImmutableList<PatchLineComment> comments;
|
||||
final String pushCert;
|
||||
|
||||
RevisionNote(Change.Id changeId, ObjectReader reader, ObjectId noteId,
|
||||
boolean draftsOnly) throws ConfigInvalidException, IOException {
|
||||
RevisionNote(CommentsInNotesUtil commentsUtil, Change.Id changeId,
|
||||
ObjectReader reader, ObjectId noteId, boolean draftsOnly)
|
||||
throws ConfigInvalidException, IOException {
|
||||
byte[] bytes = reader.open(noteId, OBJ_BLOB).getCachedBytes(MAX_NOTE_SZ);
|
||||
MutableInteger p = new MutableInteger();
|
||||
trimLeadingEmptyLines(bytes, p);
|
||||
@@ -78,6 +79,6 @@ class RevisionNote {
|
||||
? PatchLineComment.Status.DRAFT
|
||||
: PatchLineComment.Status.PUBLISHED;
|
||||
comments = ImmutableList.copyOf(
|
||||
CommentsInNotesUtil.parseNote(bytes, p, changeId, status));
|
||||
commentsUtil.parseNote(bytes, p, changeId, status));
|
||||
}
|
||||
}
|
||||
|
@@ -31,13 +31,13 @@ class RevisionNoteMap {
|
||||
final NoteMap noteMap;
|
||||
final ImmutableMap<RevId, RevisionNote> revisionNotes;
|
||||
|
||||
static RevisionNoteMap parse(Change.Id changeId, ObjectReader reader,
|
||||
NoteMap noteMap, boolean draftsOnly)
|
||||
throws ConfigInvalidException, IOException {
|
||||
static RevisionNoteMap parse(CommentsInNotesUtil commentsUtil,
|
||||
Change.Id changeId, ObjectReader reader, NoteMap noteMap,
|
||||
boolean draftsOnly) throws ConfigInvalidException, IOException {
|
||||
Map<RevId, RevisionNote> result = new HashMap<>();
|
||||
for (Note note : noteMap) {
|
||||
RevisionNote rn =
|
||||
new RevisionNote(changeId, reader, note.getData(), draftsOnly);
|
||||
RevisionNote rn = new RevisionNote(
|
||||
commentsUtil, changeId, reader, note.getData(), draftsOnly);
|
||||
result.put(new RevId(note.name()), rn);
|
||||
}
|
||||
return new RevisionNoteMap(noteMap, ImmutableMap.copyOf(result));
|
||||
|
@@ -19,12 +19,14 @@ import static com.google.inject.Scopes.SINGLETON;
|
||||
import com.google.gerrit.extensions.config.FactoryModule;
|
||||
import com.google.gerrit.server.GerritPersonIdent;
|
||||
import com.google.gerrit.server.GerritPersonIdentProvider;
|
||||
import com.google.gerrit.server.api.config.GerritServerIdProvider;
|
||||
import com.google.gerrit.server.config.AllProjectsName;
|
||||
import com.google.gerrit.server.config.AllProjectsNameProvider;
|
||||
import com.google.gerrit.server.config.AllUsersName;
|
||||
import com.google.gerrit.server.config.AllUsersNameProvider;
|
||||
import com.google.gerrit.server.config.AnonymousCowardName;
|
||||
import com.google.gerrit.server.config.AnonymousCowardNameProvider;
|
||||
import com.google.gerrit.server.config.GerritServerId;
|
||||
|
||||
import org.eclipse.jgit.lib.PersonIdent;
|
||||
|
||||
@@ -45,5 +47,9 @@ public class SchemaModule extends FactoryModule {
|
||||
|
||||
bind(String.class).annotatedWith(AnonymousCowardName.class).toProvider(
|
||||
AnonymousCowardNameProvider.class);
|
||||
|
||||
bind(String.class).annotatedWith(GerritServerId.class)
|
||||
.toProvider(GerritServerIdProvider.class)
|
||||
.in(SINGLETON);
|
||||
}
|
||||
}
|
||||
|
@@ -46,6 +46,7 @@ import com.google.gerrit.server.config.AnonymousCowardNameProvider;
|
||||
import com.google.gerrit.server.config.CanonicalWebUrl;
|
||||
import com.google.gerrit.server.config.DisableReverseDnsLookup;
|
||||
import com.google.gerrit.server.config.GerritServerConfig;
|
||||
import com.google.gerrit.server.config.GerritServerId;
|
||||
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
|
||||
import com.google.gerrit.server.git.GitModule;
|
||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
@@ -106,6 +107,12 @@ public abstract class AbstractChangeNotesTest extends GerritBaseTests {
|
||||
@Inject
|
||||
protected AllUsersName allUsers;
|
||||
|
||||
@Inject
|
||||
protected ChangeNoteUtil changeNoteUtil;
|
||||
|
||||
@Inject
|
||||
protected CommentsInNotesUtil commentsUtil;
|
||||
|
||||
private Injector injector;
|
||||
private String systemTimeZone;
|
||||
|
||||
@@ -137,6 +144,8 @@ public abstract class AbstractChangeNotesTest extends GerritBaseTests {
|
||||
install(new GitModule());
|
||||
factory(NoteDbUpdateManager.Factory.class);
|
||||
bind(AllUsersName.class).toProvider(AllUsersNameProvider.class);
|
||||
bind(String.class).annotatedWith(GerritServerId.class)
|
||||
.toInstance("gerrit");
|
||||
bind(NotesMigration.class).toInstance(MIGRATION);
|
||||
bind(GitRepositoryManager.class).toInstance(repoManager);
|
||||
bind(ProjectCache.class).toProvider(Providers.<ProjectCache> of(null));
|
||||
@@ -198,8 +207,8 @@ public abstract class AbstractChangeNotesTest extends GerritBaseTests {
|
||||
}
|
||||
|
||||
protected ChangeNotes newNotes(Change c) throws OrmException {
|
||||
return new ChangeNotes(repoManager, MIGRATION, allUsers, c.getProject(), c)
|
||||
.load();
|
||||
return new ChangeNotes(repoManager, MIGRATION, allUsers, changeNoteUtil,
|
||||
commentsUtil, c.getProject(), c).load();
|
||||
}
|
||||
|
||||
protected static SubmitRecord submitRecord(String status,
|
||||
|
@@ -415,7 +415,7 @@ public class ChangeNotesParserTest extends AbstractChangeNotesTest {
|
||||
}
|
||||
|
||||
private RevCommit writeCommit(String body) throws Exception {
|
||||
return writeCommit(body, ChangeNoteUtil.newIdent(
|
||||
return writeCommit(body, changeNoteUtil.newIdent(
|
||||
changeOwner.getAccount(), TimeUtil.nowTs(), serverIdent,
|
||||
"Anonymous Coward"));
|
||||
}
|
||||
@@ -462,6 +462,6 @@ public class ChangeNotesParserTest extends AbstractChangeNotesTest {
|
||||
private ChangeNotesParser newParser(ObjectId tip) throws Exception {
|
||||
Change c = newChange();
|
||||
return new ChangeNotesParser(c.getProject(), c.getId(), tip, walk,
|
||||
repoManager);
|
||||
repoManager, changeNoteUtil, commentsUtil);
|
||||
}
|
||||
}
|
||||
|
@@ -910,7 +910,8 @@ public class ChangeNotesTest extends AbstractChangeNotesTest {
|
||||
|
||||
try (RevWalk rw = new RevWalk(repo)) {
|
||||
try (ChangeNotesParser notesWithComments = new ChangeNotesParser(project,
|
||||
c.getId(), commitWithComments.copy(), rw, repoManager)) {
|
||||
c.getId(), commitWithComments.copy(), rw, repoManager, changeNoteUtil,
|
||||
commentsUtil)) {
|
||||
notesWithComments.parseAll();
|
||||
ImmutableListMultimap<PatchSet.Id, PatchSetApproval> approvals1 =
|
||||
notesWithComments.buildApprovals();
|
||||
@@ -921,7 +922,8 @@ public class ChangeNotesTest extends AbstractChangeNotesTest {
|
||||
|
||||
try (RevWalk rw = new RevWalk(repo)) {
|
||||
try (ChangeNotesParser notesWithApprovals = new ChangeNotesParser(project,
|
||||
c.getId(), commitWithApprovals.copy(), rw, repoManager)) {
|
||||
c.getId(), commitWithApprovals.copy(), rw, repoManager,
|
||||
changeNoteUtil, commentsUtil)) {
|
||||
notesWithApprovals.parseAll();
|
||||
ImmutableListMultimap<PatchSet.Id, PatchSetApproval> approvals2 =
|
||||
notesWithApprovals.buildApprovals();
|
||||
|
@@ -39,6 +39,7 @@ import com.google.gerrit.server.config.CanonicalWebUrlModule;
|
||||
import com.google.gerrit.server.config.CanonicalWebUrlProvider;
|
||||
import com.google.gerrit.server.config.GerritGlobalModule;
|
||||
import com.google.gerrit.server.config.GerritServerConfig;
|
||||
import com.google.gerrit.server.config.GerritServerId;
|
||||
import com.google.gerrit.server.config.SitePath;
|
||||
import com.google.gerrit.server.config.TrackingFooters;
|
||||
import com.google.gerrit.server.config.TrackingFootersProvider;
|
||||
@@ -153,6 +154,9 @@ public class InMemoryModule extends FactoryModule {
|
||||
bind(String.class)
|
||||
.annotatedWith(AnonymousCowardName.class)
|
||||
.toProvider(AnonymousCowardNameProvider.class);
|
||||
bind(String.class)
|
||||
.annotatedWith(GerritServerId.class)
|
||||
.toInstance("gerrit");
|
||||
bind(AllProjectsName.class)
|
||||
.toProvider(AllProjectsNameProvider.class);
|
||||
bind(AllUsersName.class)
|
||||
|
@@ -31,8 +31,10 @@ import com.google.gerrit.server.CurrentUser;
|
||||
import com.google.gerrit.server.config.AllUsersName;
|
||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
import com.google.gerrit.server.notedb.ChangeDraftUpdate;
|
||||
import com.google.gerrit.server.notedb.ChangeNoteUtil;
|
||||
import com.google.gerrit.server.notedb.ChangeNotes;
|
||||
import com.google.gerrit.server.notedb.ChangeUpdate;
|
||||
import com.google.gerrit.server.notedb.CommentsInNotesUtil;
|
||||
import com.google.gerrit.server.notedb.NotesMigration;
|
||||
import com.google.gerrit.server.project.ChangeControl;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
@@ -90,15 +92,21 @@ public class TestChanges {
|
||||
GitRepositoryManager repoManager, NotesMigration migration, Change c,
|
||||
final AllUsersName allUsers, final CurrentUser user)
|
||||
throws Exception {
|
||||
ChangeUpdate update = injector.createChildInjector(new FactoryModule() {
|
||||
injector = injector.createChildInjector(new FactoryModule() {
|
||||
@Override
|
||||
public void configure() {
|
||||
factory(ChangeUpdate.Factory.class);
|
||||
factory(ChangeDraftUpdate.Factory.class);
|
||||
bind(CurrentUser.class).toInstance(user);
|
||||
}
|
||||
}).getInstance(ChangeUpdate.Factory.class).create(
|
||||
stubChangeControl(repoManager, migration, c, allUsers, user),
|
||||
});
|
||||
ChangeUpdate update = injector.getInstance(ChangeUpdate.Factory.class)
|
||||
.create(
|
||||
stubChangeControl(
|
||||
repoManager, migration, c, allUsers,
|
||||
injector.getInstance(ChangeNoteUtil.class),
|
||||
injector.getInstance(CommentsInNotesUtil.class),
|
||||
user),
|
||||
TimeUtil.nowTs(), Ordering.<String> natural());
|
||||
|
||||
ChangeNotes notes = update.getChangeNotes();
|
||||
@@ -131,15 +139,15 @@ public class TestChanges {
|
||||
|
||||
private static ChangeControl stubChangeControl(
|
||||
GitRepositoryManager repoManager, NotesMigration migration,
|
||||
Change c, AllUsersName allUsers,
|
||||
CurrentUser user) throws OrmException {
|
||||
Change c, AllUsersName allUsers, ChangeNoteUtil changeNoteUtil,
|
||||
CommentsInNotesUtil commentsUtil, CurrentUser user) throws OrmException {
|
||||
ChangeControl ctl = EasyMock.createMock(ChangeControl.class);
|
||||
expect(ctl.getChange()).andStubReturn(c);
|
||||
expect(ctl.getProject()).andStubReturn(new Project(c.getProject()));
|
||||
expect(ctl.getUser()).andStubReturn(user);
|
||||
ChangeNotes notes =
|
||||
new ChangeNotes(repoManager, migration, allUsers, c.getProject(), c)
|
||||
.load();
|
||||
new ChangeNotes(repoManager, migration, allUsers, changeNoteUtil,
|
||||
commentsUtil, c.getProject(), c).load();
|
||||
expect(ctl.getNotes()).andStubReturn(notes);
|
||||
expect(ctl.getId()).andStubReturn(c.getId());
|
||||
EasyMock.replay(ctl);
|
||||
|
Reference in New Issue
Block a user