Merge "Fix font for gr-button 'links'"
diff --git a/Documentation/note-db.txt b/Documentation/note-db.txt
index 728d630..815cda8 100644
--- a/Documentation/note-db.txt
+++ b/Documentation/note-db.txt
@@ -137,14 +137,23 @@
To continue with the full migration after running the trial migration, use
either the online or offline migration steps as normal. To revert to
ReviewDb-only, remove `noteDb.changes.read` and `noteDb.changes.write` from
-`gerrit.config` and restart Gerrit.
+`notedb.config` and restart Gerrit.
== Configuration
-The migration process works by setting a configuration option in `gerrit.config`
+The migration process works by setting a configuration option in `notedb.config`
for each step in the process, then performing the corresponding data migration.
-In general, users should not set these options manually; this section serves
-primarily as a reference.
+
+Config options are read from `notedb.config` first, falling back to
+`gerrit.config`. If editing config manually, you may edit either file, but the
+migration process itself only touches `notedb.config`. This means if your
+`gerrit.config` is managed with Puppet or a similar tool, it can overwrite
+`gerrit.config` without affecting the migration process. You should not manage
+`notedb.config` with Puppet, but you may copy values back into `gerrit.config`
+and delete `notedb.config` at some later point after completing the migration.
+
+In general, users should not set the options described below manually; this
+section serves primarily as a reference.
- `noteDb.changes.write=true`: During a ReviewDb write, the state of the change
in NoteDb is written to the `note_db_state` field in the `Change` entity.
diff --git a/gerrit-acceptance-framework/BUILD b/gerrit-acceptance-framework/BUILD
index 5a7f3b7..8a95346 100644
--- a/gerrit-acceptance-framework/BUILD
+++ b/gerrit-acceptance-framework/BUILD
@@ -1,6 +1,12 @@
load("//tools/bzl:java.bzl", "java_library2")
+load("//tools/bzl:junit.bzl", "junit_tests")
-SRCS = glob(["src/test/java/com/google/gerrit/acceptance/*.java"])
+TEST_SRCS = ["src/test/java/com/google/gerrit/acceptance/MergeableFileBasedConfigTest.java"]
+
+SRCS = glob(
+ ["src/test/java/com/google/gerrit/acceptance/*.java"],
+ exclude = TEST_SRCS,
+)
PROVIDED = [
"//gerrit-common:annotations",
@@ -77,3 +83,14 @@
title = "Gerrit Acceptance Test Framework Documentation",
visibility = ["//visibility:public"],
)
+
+junit_tests(
+ name = "acceptance_framework_tests",
+ srcs = TEST_SRCS,
+ deps = [
+ ":lib",
+ "//lib:guava",
+ "//lib:truth",
+ "//lib/jgit/org.eclipse.jgit:jgit",
+ ],
+)
diff --git a/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/MergeableFileBasedConfig.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/MergeableFileBasedConfig.java
index c651d48..bd4f653 100644
--- a/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/MergeableFileBasedConfig.java
+++ b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/MergeableFileBasedConfig.java
@@ -40,7 +40,7 @@
}
for (String section : s.getSections()) {
for (String subsection : s.getSubsections(section)) {
- for (String name : s.getNames(section, subsection)) {
+ for (String name : s.getNames(section, subsection, true)) {
setStringList(
section,
subsection,
diff --git a/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/MergeableFileBasedConfigTest.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/MergeableFileBasedConfigTest.java
new file mode 100644
index 0000000..49c23e3
--- /dev/null
+++ b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/MergeableFileBasedConfigTest.java
@@ -0,0 +1,118 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.acceptance;
+
+import static com.google.common.truth.Truth.assertThat;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import com.google.common.collect.ImmutableList;
+import java.io.File;
+import java.nio.file.Files;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.util.FS;
+import org.junit.Test;
+
+public class MergeableFileBasedConfigTest {
+ @Test
+ public void mergeNull() throws Exception {
+ MergeableFileBasedConfig cfg = newConfig();
+ cfg.setString("foo", null, "bar", "value");
+ String expected = "[foo]\n\tbar = value\n";
+ assertConfig(cfg, expected);
+ cfg.merge(null);
+ assertConfig(cfg, expected);
+ }
+
+ @Test
+ public void mergeFlatConfig() throws Exception {
+ MergeableFileBasedConfig cfg = newConfig();
+ cfg.setString("foo", null, "bar1", "value1");
+ cfg.setString("foo", null, "bar2", "value2");
+ cfg.setString("foo", "sub", "bar1", "value1");
+ cfg.setString("foo", "sub", "bar2", "value2");
+
+ assertConfig(
+ cfg,
+ "[foo]\n"
+ + "\tbar1 = value1\n"
+ + "\tbar2 = value2\n"
+ + "[foo \"sub\"]\n"
+ + "\tbar1 = value1\n"
+ + "\tbar2 = value2\n");
+
+ Config toMerge = new Config();
+ toMerge.setStringList("foo", null, "bar2", ImmutableList.of("merge1", "merge2"));
+ toMerge.setStringList("foo", "sub", "bar2", ImmutableList.of("merge1", "merge2"));
+ cfg.merge(toMerge);
+
+ assertConfig(
+ cfg,
+ "[foo]\n"
+ + "\tbar1 = value1\n"
+ + "\tbar2 = merge1\n"
+ + "\tbar2 = merge2\n"
+ + "[foo \"sub\"]\n"
+ + "\tbar1 = value1\n"
+ + "\tbar2 = merge1\n"
+ + "\tbar2 = merge2\n");
+ }
+
+ @Test
+ public void mergeStackedConfig() throws Exception {
+ MergeableFileBasedConfig cfg = newConfig();
+ cfg.setString("foo", null, "bar1", "value1");
+ cfg.setString("foo", null, "bar2", "value2");
+ cfg.setString("foo", "sub", "bar1", "value1");
+ cfg.setString("foo", "sub", "bar2", "value2");
+
+ assertConfig(
+ cfg,
+ "[foo]\n"
+ + "\tbar1 = value1\n"
+ + "\tbar2 = value2\n"
+ + "[foo \"sub\"]\n"
+ + "\tbar1 = value1\n"
+ + "\tbar2 = value2\n");
+
+ Config base = new Config();
+ Config toMerge = new Config(base);
+ base.setStringList("foo", null, "bar2", ImmutableList.of("merge1", "merge2"));
+ base.setStringList("foo", "sub", "bar2", ImmutableList.of("merge1", "merge2"));
+ cfg.merge(toMerge);
+
+ assertConfig(
+ cfg,
+ "[foo]\n"
+ + "\tbar1 = value1\n"
+ + "\tbar2 = merge1\n"
+ + "\tbar2 = merge2\n"
+ + "[foo \"sub\"]\n"
+ + "\tbar1 = value1\n"
+ + "\tbar2 = merge1\n"
+ + "\tbar2 = merge2\n");
+ }
+
+ private MergeableFileBasedConfig newConfig() throws Exception {
+ File f = File.createTempFile(getClass().getSimpleName(), ".config");
+ f.deleteOnExit();
+ return new MergeableFileBasedConfig(f, FS.detect());
+ }
+
+ private void assertConfig(MergeableFileBasedConfig cfg, String expected) throws Exception {
+ assertThat(cfg.toText()).isEqualTo(expected);
+ cfg.save();
+ assertThat(new String(Files.readAllBytes(cfg.getFile().toPath()), UTF_8)).isEqualTo(expected);
+ }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/pgm/StandaloneNoteDbMigrationIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/pgm/StandaloneNoteDbMigrationIT.java
index 0517675..8c50b90 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/pgm/StandaloneNoteDbMigrationIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/pgm/StandaloneNoteDbMigrationIT.java
@@ -61,6 +61,7 @@
@NoHttpd
public class StandaloneNoteDbMigrationIT extends StandaloneSiteTest {
private StoredConfig gerritConfig;
+ private StoredConfig noteDbConfig;
private Project.NameKey project;
private Change.Id changeId;
@@ -69,10 +70,14 @@
public void setUp() throws Exception {
assume().that(NoteDbMode.get()).isEqualTo(NoteDbMode.OFF);
gerritConfig = new FileBasedConfig(sitePaths.gerrit_config.toFile(), FS.detect());
+ // Unlike in the running server, for tests, we don't stack notedb.config on gerrit.config.
+ noteDbConfig = new FileBasedConfig(sitePaths.notedb_config.toFile(), FS.detect());
}
@Test
public void rebuildOneChangeTrialMode() throws Exception {
+ assertNoAutoMigrateConfig(gerritConfig);
+ assertNoAutoMigrateConfig(noteDbConfig);
assertNotesMigrationState(NotesMigrationState.REVIEW_DB);
setUpOneChange();
@@ -101,6 +106,8 @@
@Test
public void migrateOneChange() throws Exception {
+ assertNoAutoMigrateConfig(gerritConfig);
+ assertNoAutoMigrateConfig(noteDbConfig);
assertNotesMigrationState(NotesMigrationState.REVIEW_DB);
setUpOneChange();
@@ -128,6 +135,8 @@
assertThat(db.changes().get(id2)).isNull();
}
}
+ assertNoAutoMigrateConfig(gerritConfig);
+ assertAutoMigrateConfig(noteDbConfig, false);
}
@Test
@@ -151,6 +160,40 @@
@Test
public void onlineMigrationViaDaemon() throws Exception {
+ assertNoAutoMigrateConfig(gerritConfig);
+ assertNoAutoMigrateConfig(noteDbConfig);
+
+ testOnlineMigration(u -> startServer(u.module(), "--migrate-to-note-db", "true"));
+
+ assertNoAutoMigrateConfig(gerritConfig);
+ assertAutoMigrateConfig(noteDbConfig, false);
+ }
+
+ @Test
+ public void onlineMigrationViaConfig() throws Exception {
+ assertNoAutoMigrateConfig(gerritConfig);
+ assertNoAutoMigrateConfig(noteDbConfig);
+
+ testOnlineMigration(
+ u -> {
+ gerritConfig.setBoolean("noteDb", "changes", "autoMigrate", true);
+ gerritConfig.save();
+ return startServer(u.module());
+ });
+
+ // Auto-migration is turned off in notedb.config, which takes precedence, but is still on in
+ // gerrit.config. This means Puppet can continue overwriting gerrit.config without turning
+ // auto-migration back on.
+ assertAutoMigrateConfig(gerritConfig, true);
+ assertAutoMigrateConfig(noteDbConfig, false);
+ }
+
+ @FunctionalInterface
+ private interface StartServerWithMigration {
+ ServerContext start(IndexUpgradeController u) throws Exception;
+ }
+
+ private void testOnlineMigration(StartServerWithMigration start) throws Exception {
assertNotesMigrationState(NotesMigrationState.REVIEW_DB);
int prevVersion = ChangeSchemaDefinitions.INSTANCE.getPrevious().getVersion();
int currVersion = ChangeSchemaDefinitions.INSTANCE.getLatest().getVersion();
@@ -166,7 +209,7 @@
setOnlineUpgradeConfig(true);
IndexUpgradeController u = new IndexUpgradeController(1);
- try (ServerContext ctx = startServer(u.module(), "--migrate-to-note-db", "true")) {
+ try (ServerContext ctx = start.start(u)) {
ChangeIndexCollection indexes = ctx.getInjector().getInstance(ChangeIndexCollection.class);
assertThat(indexes.getSearchIndex().getSchema().getVersion()).isEqualTo(prevVersion);
@@ -199,8 +242,8 @@
}
private void assertNotesMigrationState(NotesMigrationState expected) throws Exception {
- gerritConfig.load();
- assertThat(NotesMigrationState.forConfig(gerritConfig)).hasValue(expected);
+ noteDbConfig.load();
+ assertThat(NotesMigrationState.forConfig(noteDbConfig)).hasValue(expected);
}
private ReviewDb openUnderlyingReviewDb(ServerContext ctx) throws Exception {
@@ -209,6 +252,17 @@
.open();
}
+ private static void assertNoAutoMigrateConfig(StoredConfig cfg) throws Exception {
+ cfg.load();
+ assertThat(cfg.getString("noteDb", "changes", "autoMigrate")).isNull();
+ }
+
+ private static void assertAutoMigrateConfig(StoredConfig cfg, boolean expected) throws Exception {
+ cfg.load();
+ assertThat(cfg.getString("noteDb", "changes", "autoMigrate")).isNotNull();
+ assertThat(cfg.getBoolean("noteDb", "changes", "autoMigrate", false)).isEqualTo(expected);
+ }
+
private void setOnlineUpgradeConfig(boolean enable) throws Exception {
gerritConfig.load();
gerritConfig.setBoolean("index", null, "onlineUpgrade", enable);
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/notedb/OnlineNoteDbMigrationIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/notedb/OnlineNoteDbMigrationIT.java
index f08a16e..8aa2497 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/notedb/OnlineNoteDbMigrationIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/notedb/OnlineNoteDbMigrationIT.java
@@ -32,6 +32,7 @@
import com.google.gerrit.acceptance.NoHttpd;
import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.acceptance.Sandboxed;
+import com.google.gerrit.acceptance.UseLocalDisk;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.RefNames;
@@ -65,6 +66,7 @@
import org.junit.Test;
@Sandboxed
+@UseLocalDisk
@NoHttpd
public class OnlineNoteDbMigrationIT extends AbstractDaemonTest {
private static final String INVALID_STATE = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
@@ -85,12 +87,13 @@
@Inject private Provider<NoteDbMigrator.Builder> migratorBuilderProvider;
@Inject private Sequences sequences;
- private FileBasedConfig gerritConfig;
+ private FileBasedConfig noteDbConfig;
@Before
public void setUp() throws Exception {
assume().that(NoteDbMode.get()).isEqualTo(NoteDbMode.OFF);
- gerritConfig = new FileBasedConfig(sitePaths.gerrit_config.toFile(), FS.detect());
+ // Unlike in the running server, for tests, we don't stack notedb.config on gerrit.config.
+ noteDbConfig = new FileBasedConfig(sitePaths.notedb_config.toFile(), FS.detect());
assertNotesMigrationState(REVIEW_DB);
}
@@ -365,27 +368,27 @@
migrate(b -> b.setStopAtStateForTesting(WRITE));
assertNotesMigrationState(WRITE);
- assertThat(NoteDbMigrator.getAutoMigrate(gerritConfig)).isFalse();
+ assertThat(NoteDbMigrator.getAutoMigrate(noteDbConfig)).isFalse();
migrate(b -> b.setAutoMigrate(true).setStopAtStateForTesting(READ_WRITE_NO_SEQUENCE));
assertNotesMigrationState(READ_WRITE_NO_SEQUENCE);
- assertThat(NoteDbMigrator.getAutoMigrate(gerritConfig)).isTrue();
+ assertThat(NoteDbMigrator.getAutoMigrate(noteDbConfig)).isTrue();
migrate(b -> b);
assertNotesMigrationState(NOTE_DB);
- assertThat(NoteDbMigrator.getAutoMigrate(gerritConfig)).isFalse();
+ assertThat(NoteDbMigrator.getAutoMigrate(noteDbConfig)).isFalse();
}
private void assertNotesMigrationState(NotesMigrationState expected) throws Exception {
assertThat(NotesMigrationState.forNotesMigration(notesMigration)).hasValue(expected);
- gerritConfig.load();
- assertThat(NotesMigrationState.forConfig(gerritConfig)).hasValue(expected);
+ noteDbConfig.load();
+ assertThat(NotesMigrationState.forConfig(noteDbConfig)).hasValue(expected);
}
private void setNotesMigrationState(NotesMigrationState state) throws Exception {
- gerritConfig.load();
- state.setConfigValues(gerritConfig);
- gerritConfig.save();
+ noteDbConfig.load();
+ state.setConfigValues(noteDbConfig);
+ noteDbConfig.save();
notesMigration.setFrom(state);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritConfig.java
index fdc3b7f..0715f8e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritConfig.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritConfig.java
@@ -18,10 +18,12 @@
import org.eclipse.jgit.lib.Config;
class GerritConfig extends Config {
+ private final Config gerritConfig;
private final SecureStore secureStore;
- GerritConfig(Config baseConfig, SecureStore secureStore) {
- super(baseConfig);
+ GerritConfig(Config noteDbConfigOverGerritConfig, Config gerritConfig, SecureStore secureStore) {
+ super(noteDbConfigOverGerritConfig);
+ this.gerritConfig = gerritConfig;
this.secureStore = secureStore;
}
@@ -42,4 +44,11 @@
}
return super.getStringList(section, subsection, name);
}
+
+ @Override
+ public String toText() {
+ // Only show the contents of gerrit.config, hiding the implementation detail that some values
+ // may come from secure.config (or another secure store) and notedb.config.
+ return gerritConfig.toText();
+ }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritServerConfigProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritServerConfigProvider.java
index 494b63a..1a59c52 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritServerConfigProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritServerConfigProvider.java
@@ -14,11 +14,18 @@
package com.google.gerrit.server.config;
+import static java.util.stream.Collectors.joining;
+
+import com.google.gerrit.common.Nullable;
+import com.google.gerrit.server.notedb.NotesMigration;
import com.google.gerrit.server.securestore.SecureStore;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.ProvisionException;
import java.io.IOException;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.storage.file.FileBasedConfig;
@@ -41,19 +48,46 @@
@Override
public Config get() {
- FileBasedConfig cfg = new FileBasedConfig(site.gerrit_config.toFile(), FS.DETECTED);
-
- if (!cfg.getFile().exists()) {
+ FileBasedConfig baseConfig = loadConfig(null, site.gerrit_config);
+ if (!baseConfig.getFile().exists()) {
log.info("No " + site.gerrit_config.toAbsolutePath() + "; assuming defaults");
- return new GerritConfig(cfg, secureStore);
}
+ FileBasedConfig noteDbConfigOverBaseConfig = loadConfig(baseConfig, site.notedb_config);
+ checkNoteDbConfig(noteDbConfigOverBaseConfig);
+
+ return new GerritConfig(noteDbConfigOverBaseConfig, baseConfig, secureStore);
+ }
+
+ private static FileBasedConfig loadConfig(@Nullable Config base, Path path) {
+ FileBasedConfig cfg = new FileBasedConfig(base, path.toFile(), FS.DETECTED);
try {
cfg.load();
} catch (IOException | ConfigInvalidException e) {
throw new ProvisionException(e.getMessage(), e);
}
+ return cfg;
+ }
- return new GerritConfig(cfg, secureStore);
+ private static void checkNoteDbConfig(FileBasedConfig noteDbConfig) {
+ List<String> bad = new ArrayList<>();
+ for (String section : noteDbConfig.getSections()) {
+ if (section.equals(NotesMigration.SECTION_NOTE_DB)) {
+ continue;
+ }
+ for (String subsection : noteDbConfig.getSubsections(section)) {
+ noteDbConfig
+ .getNames(section, subsection, false)
+ .forEach(n -> bad.add(section + "." + subsection + "." + n));
+ }
+ noteDbConfig.getNames(section, false).forEach(n -> bad.add(section + "." + n));
+ }
+ if (!bad.isEmpty()) {
+ throw new ProvisionException(
+ "Non-NoteDb config options not allowed in "
+ + noteDbConfig.getFile()
+ + ":\n"
+ + bad.stream().collect(joining("\n")));
+ }
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/SitePaths.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/SitePaths.java
index c27f5b9..3748bfd 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/SitePaths.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/SitePaths.java
@@ -53,6 +53,7 @@
public final Path gerrit_config;
public final Path secure_config;
+ public final Path notedb_config;
public final Path ssl_keystore;
public final Path ssh_key;
@@ -100,6 +101,7 @@
gerrit_config = etc_dir.resolve("gerrit.config");
secure_config = etc_dir.resolve("secure.config");
+ notedb_config = etc_dir.resolve("notedb.config");
ssl_keystore = etc_dir.resolve("keystore");
ssh_key = etc_dir.resolve("ssh_host_key");
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ChangeReportFormatter.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ChangeReportFormatter.java
new file mode 100644
index 0000000..6b1fd85
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ChangeReportFormatter.java
@@ -0,0 +1,87 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.git;
+
+import com.google.gerrit.reviewdb.client.Change;
+
+public interface ChangeReportFormatter {
+ public static class Input {
+ private final Change change;
+ private String subject;
+ private Boolean draft;
+ private Boolean edit;
+ private Boolean isPrivate;
+ private Boolean wip;
+
+ public Input(Change change) {
+ this.change = change;
+ }
+
+ public Input setPrivate(boolean isPrivate) {
+ this.isPrivate = isPrivate;
+ return this;
+ }
+
+ public Input setDraft(boolean draft) {
+ this.draft = draft;
+ return this;
+ }
+
+ public Input setEdit(boolean edit) {
+ this.edit = edit;
+ return this;
+ }
+
+ public Input setWorkInProgress(boolean wip) {
+ this.wip = wip;
+ return this;
+ }
+
+ public Input setSubject(String subject) {
+ this.subject = subject;
+ return this;
+ }
+
+ public Change getChange() {
+ return change;
+ }
+
+ public String getSubject() {
+ return subject == null ? change.getSubject() : subject;
+ }
+
+ public boolean isDraft() {
+ return draft == null ? Change.Status.DRAFT == change.getStatus() : draft;
+ }
+
+ public boolean isEdit() {
+ return edit == null ? false : edit;
+ }
+
+ public boolean isPrivate() {
+ return isPrivate == null ? change.isPrivate() : isPrivate;
+ }
+
+ public boolean isWorkInProgress() {
+ return wip == null ? change.isWorkInProgress() : wip;
+ }
+ }
+
+ String newChange(Input input);
+
+ String changeUpdated(Input input);
+
+ String changeClosed(Input input);
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/DefaultChangeReportFormatter.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/DefaultChangeReportFormatter.java
new file mode 100644
index 0000000..297770c
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/DefaultChangeReportFormatter.java
@@ -0,0 +1,66 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.git;
+
+import com.google.gerrit.server.ChangeUtil;
+import com.google.gerrit.server.config.CanonicalWebUrl;
+import com.google.inject.Inject;
+
+public class DefaultChangeReportFormatter implements ChangeReportFormatter {
+ private final String canonicalWebUrl;
+
+ @Inject
+ DefaultChangeReportFormatter(@CanonicalWebUrl String canonicalWebUrl) {
+ this.canonicalWebUrl = canonicalWebUrl;
+ }
+
+ @Override
+ public String newChange(ChangeReportFormatter.Input input) {
+ return formatChangeUrl(canonicalWebUrl, input);
+ }
+
+ @Override
+ public String changeUpdated(ChangeReportFormatter.Input input) {
+ return formatChangeUrl(canonicalWebUrl, input);
+ }
+
+ @Override
+ public String changeClosed(ChangeReportFormatter.Input input) {
+ return String.format(
+ "change %s closed", ChangeUtil.formatChangeUrl(canonicalWebUrl, input.getChange()));
+ }
+
+ private String formatChangeUrl(String url, Input input) {
+ StringBuilder m =
+ new StringBuilder()
+ .append(" ")
+ .append(ChangeUtil.formatChangeUrl(url, input.getChange()))
+ .append(" ")
+ .append(ChangeUtil.cropSubject(input.getSubject()));
+ if (input.isDraft()) {
+ m.append(" [DRAFT]");
+ }
+ if (input.isEdit()) {
+ m.append(" [EDIT]");
+ }
+ if (input.isPrivate()) {
+ m.append(" [PRIVATE]");
+ }
+ if (input.isWorkInProgress()) {
+ m.append(" [WIP]");
+ }
+ return m.toString();
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/GitModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/GitModule.java
index 15a9d74..92514da 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/GitModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/GitModule.java
@@ -15,6 +15,7 @@
package com.google.gerrit.server.git;
import com.google.gerrit.extensions.config.FactoryModule;
+import com.google.gerrit.extensions.registration.DynamicItem;
import com.google.gerrit.extensions.registration.DynamicSet;
import org.eclipse.jgit.transport.PostUploadHook;
@@ -26,5 +27,7 @@
factory(MetaDataUpdate.InternalFactory.class);
bind(MetaDataUpdate.Server.class);
DynamicSet.bind(binder(), PostUploadHook.class).to(UploadPackMetricsHook.class);
+ DynamicItem.itemOf(binder(), ChangeReportFormatter.class);
+ DynamicItem.bind(binder(), ChangeReportFormatter.class).to(DefaultChangeReportFormatter.class);
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/receive/ReceiveCommits.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
index 4f613af..b1edb92 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
@@ -66,6 +66,7 @@
import com.google.gerrit.extensions.api.changes.SubmitInput;
import com.google.gerrit.extensions.api.projects.ProjectConfigEntryType;
import com.google.gerrit.extensions.client.GeneralPreferencesInfo;
+import com.google.gerrit.extensions.registration.DynamicItem;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.registration.DynamicMap.Entry;
import com.google.gerrit.extensions.registration.DynamicSet;
@@ -93,13 +94,13 @@
import com.google.gerrit.server.change.ChangeInserter;
import com.google.gerrit.server.change.SetHashtagsOp;
import com.google.gerrit.server.config.AllProjectsName;
-import com.google.gerrit.server.config.CanonicalWebUrl;
import com.google.gerrit.server.config.PluginConfig;
import com.google.gerrit.server.config.ProjectConfigEntry;
import com.google.gerrit.server.edit.ChangeEdit;
import com.google.gerrit.server.edit.ChangeEditUtil;
import com.google.gerrit.server.events.CommitReceivedEvent;
import com.google.gerrit.server.git.BanCommit;
+import com.google.gerrit.server.git.ChangeReportFormatter;
import com.google.gerrit.server.git.GroupCollector;
import com.google.gerrit.server.git.MergeOp;
import com.google.gerrit.server.git.MergeOpRepoManager;
@@ -318,7 +319,6 @@
private final Sequences seq;
private final SetHashtagsOp.Factory hashtagsFactory;
private final SshInfo sshInfo;
- private final String canonicalWebUrl;
private final SubmoduleOp.Factory subOpFactory;
private final TagCache tagCache;
private final CreateRefControl createRefControl;
@@ -370,10 +370,10 @@
private Task closeProgress;
private Task commandProgress;
private MessageSender messageSender;
+ private final ChangeReportFormatter changeFormatter;
@Inject
ReceiveCommits(
- @CanonicalWebUrl String canonicalWebUrl,
AccountResolver accountResolver,
AccountsUpdate.Server accountsUpdate,
AllProjectsName allProjectsName,
@@ -406,6 +406,7 @@
SubmoduleOp.Factory subOpFactory,
TagCache tagCache,
CreateRefControl createRefControl,
+ DynamicItem<ChangeReportFormatter> changeFormatterProvider,
@Assisted ProjectControl projectControl,
@Assisted ReceivePack rp,
@Assisted AllRefsWatcher allRefsWatcher,
@@ -416,9 +417,10 @@
this.accountsUpdate = accountsUpdate;
this.allProjectsName = allProjectsName;
this.batchUpdateFactory = batchUpdateFactory;
- this.canonicalWebUrl = canonicalWebUrl;
this.changeInserterFactory = changeInserterFactory;
this.commitValidatorsFactory = commitValidatorsFactory;
+ this.changeFormatter = changeFormatterProvider.get();
+ this.user = projectControl.getUser().asIdentifiedUser();
this.db = db;
this.editUtil = editUtil;
this.hashtagsFactory = hashtagsFactory;
@@ -454,7 +456,6 @@
// Immutable fields derived from constructor arguments.
repo = rp.getRepository();
- user = projectControl.getUser().asIdentifiedUser();
project = projectControl.getProject();
labelTypes = projectControl.getProjectState().getLabelTypes();
permissions = permissionBackend.user(user).project(project.getNameKey());
@@ -604,15 +605,7 @@
addMessage("");
addMessage("New Changes:");
for (CreateRequest c : created) {
- addMessage(
- formatChangeMessage(
- canonicalWebUrl,
- c.change,
- c.change.getSubject(),
- c.change.getStatus() == Change.Status.DRAFT,
- false, // edit
- c.change.isPrivate(),
- c.change.isWorkInProgress()));
+ addMessage(changeFormatter.newChange(new ChangeReportFormatter.Input(c.change)));
}
addMessage("");
}
@@ -655,55 +648,27 @@
} else {
subject = u.info.getSubject();
}
+
if (isPrivate == null) {
isPrivate = u.notes.getChange().isPrivate();
}
if (wip == null) {
wip = u.notes.getChange().isWorkInProgress();
}
- addMessage(
- formatChangeMessage(
- canonicalWebUrl,
- u.notes.getChange(),
- subject,
- u.replaceOp != null && u.replaceOp.getPatchSet().isDraft(),
- edit,
- isPrivate,
- wip));
+
+ ChangeReportFormatter.Input input =
+ new ChangeReportFormatter.Input(u.notes.getChange())
+ .setSubject(subject)
+ .setDraft(u.replaceOp != null && u.replaceOp.getPatchSet().isDraft())
+ .setEdit(edit)
+ .setPrivate(isPrivate)
+ .setWorkInProgress(wip);
+ addMessage(changeFormatter.changeUpdated(input));
}
addMessage("");
}
}
- private static String formatChangeMessage(
- String url,
- Change change,
- String subject,
- boolean draft,
- boolean edit,
- boolean isPrivate,
- boolean wip) {
- StringBuilder m =
- new StringBuilder()
- .append(" ")
- .append(ChangeUtil.formatChangeUrl(url, change))
- .append(" ")
- .append(ChangeUtil.cropSubject(subject));
- if (draft) {
- m.append(" [DRAFT]");
- }
- if (edit) {
- m.append(" [EDIT]");
- }
- if (isPrivate) {
- m.append(" [PRIVATE]");
- }
- if (wip) {
- m.append(" [WIP]");
- }
- return m.toString();
- }
-
private void insertChangesAndPatchSets() {
ReceiveCommand magicBranchCmd = magicBranch != null ? magicBranch.cmd : null;
if (magicBranchCmd != null && magicBranchCmd.getResult() != NOT_ATTEMPTED) {
@@ -1713,7 +1678,7 @@
private boolean requestReplace(
ReceiveCommand cmd, boolean checkMergedInto, Change change, RevCommit newCommit) {
if (change.getStatus().isClosed()) {
- reject(cmd, "change " + ChangeUtil.formatChangeUrl(canonicalWebUrl, change) + " closed");
+ reject(cmd, changeFormatter.changeClosed(new ChangeReportFormatter.Input(change)));
return false;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/rebuild/NoteDbMigrator.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/rebuild/NoteDbMigrator.java
index 7323c2e..61a0cd6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/rebuild/NoteDbMigrator.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/rebuild/NoteDbMigrator.java
@@ -320,6 +320,7 @@
}
private final FileBasedConfig gerritConfig;
+ private final FileBasedConfig noteDbConfig;
private final SchemaFactory<ReviewDb> schemaFactory;
private final GitRepositoryManager repoManager;
private final AllProjectsName allProjects;
@@ -374,7 +375,6 @@
this.userFactory = userFactory;
this.globalNotesMigration = globalNotesMigration;
this.primaryStorageMigrator = primaryStorageMigrator;
- this.gerritConfig = new FileBasedConfig(sitePaths.gerrit_config.toFile(), FS.detect());
this.executor = executor;
this.projects = projects;
this.changes = changes;
@@ -384,6 +384,11 @@
this.forceRebuild = forceRebuild;
this.sequenceGap = sequenceGap;
this.autoMigrate = autoMigrate;
+
+ // Stack notedb.config over gerrit.config, in the same way as GerritServerConfigProvider.
+ this.gerritConfig = new FileBasedConfig(sitePaths.gerrit_config.toFile(), FS.detect());
+ this.noteDbConfig =
+ new FileBasedConfig(gerritConfig, sitePaths.notedb_config.toFile(), FS.detect());
}
@Override
@@ -564,9 +569,10 @@
private Optional<NotesMigrationState> loadState() throws IOException {
try {
gerritConfig.load();
- return NotesMigrationState.forConfig(gerritConfig);
+ noteDbConfig.load();
+ return NotesMigrationState.forConfig(noteDbConfig);
} catch (ConfigInvalidException | IllegalArgumentException e) {
- log.warn("error reading NoteDb migration options from " + gerritConfig.getFile(), e);
+ log.warn("error reading NoteDb migration options from " + noteDbConfig.getFile(), e);
return Optional.empty();
}
}
@@ -597,9 +603,9 @@
? "But found this state:\n" + actualOldState.get().toText()
: "But could not parse the current state"));
}
- newState.setConfigValues(gerritConfig);
- additionalUpdates.accept(gerritConfig);
- gerritConfig.save();
+ newState.setConfigValues(noteDbConfig);
+ additionalUpdates.accept(noteDbConfig);
+ noteDbConfig.save();
// Only set in-memory state once it's been persisted to storage.
globalNotesMigration.setFrom(newState);
@@ -610,9 +616,9 @@
private void enableAutoMigrate() throws MigrationException {
try {
- gerritConfig.load();
- setAutoMigrate(gerritConfig, true);
- gerritConfig.save();
+ noteDbConfig.load();
+ setAutoMigrate(noteDbConfig, true);
+ noteDbConfig.save();
} catch (ConfigInvalidException | IOException e) {
throw new MigrationException("Error saving auto-migration config", e);
}