Support reading default project.config for All-Projects from etc

Respect a new optional file $site/etc/All-Projects/project.config which
serves as the base config file for project.config in All-Projects.

It may seem odd to introduce a level of inheritance above All-Projects:
if you want to change a default value and have it inherited across all
projects on your site, it should just go in All-Projects, right? Indeed,
that remains the recommended approach for a single server.

However, in the case where an administrator manages multiple Gerrit
servers, updating the defaults across all servers would require
scripting git commits and/or pushes to multiple All-Projects repos. Such
an administrator is likely already using Puppet or similar to manage
gerrit.config, so a simpler approach for them would be to edit a single
file and then push it out to all servers. This change gives them that
option.

Use a separate file from gerrit.config to maintain a clear distinction
between server-type options and project-type options. There is already
some ad-hoc "inheritance" between gerrit.config and project.config, for
example of receive.maxObjectSizeLimit. We would like to avoid the need
for such ad-hoc code, providing instead a more general mechanism.

The location under etc/All-Projects could eventually contain more files
that could provide defaults for other files in All-Projects. However,
defining inheritance semantics for file types other than git config
files is nontrivial, so punt for now, documenting the limitations.

Change-Id: I572dbfb6b57c6bb45adc96dc5b10071299deeb0d
This commit is contained in:
Dave Borowitz 2018-11-02 15:06:25 -07:00
parent 314edaa07b
commit d4fdc9323d
10 changed files with 416 additions and 17 deletions

View File

@ -4959,6 +4959,38 @@ executions are `Wed 10:30`, `Fri 10:30`. etc.
Assuming that the server is started on `Mon 07:00` then this yields the
first run on Tuesday at 06:00 and a repetition interval of 1 day.
[[All-Projects-project.config]]
== File `etc/All-Projects/project.config`
The optional file `'$site_path'/etc/All-Projects/project.config` provides
defaults for configuration read from
link:config-project-config.html[`project.config`] in the
`All-Projects` repo. Unlike `gerrit.config`, this file contains project-type
configuration rather than server-type configuration.
Most administrators will not need this file, and should instead make commits to
`All-Projects` to modify global config. However, a separate file can be useful
when managing multiple Gerrit servers, since pushing changes to defaults using
Puppet or a similar tool can be easier than scripting git updates to
`All-Projects`.
The contents of the file are loaded each time the `All-Projects` project is
reloaded. Updating the file requires either evicting the project cache or
restarting the server.
Caveats:
* The path from which the file is read corresponds to the name of the repo,
which is link:#gerrit.allProjects[configurable].
* Although the file lives in a directory that shares a name with a repository,
this directory is not a Git repository.
* Only the file `project.config` is read from this directory to provide
defaults; any other files in this directory, such as `rules.pl`, are ignored.
(This behavior may change in the future.)
* Group names listed in the access config in this file are resolved to UUIDs
using the `groups` file in the repository, not in the config directory. As a
result, setting ACLs in this file is not recommended.
[[secure.config]]
== File `etc/secure.config`

View File

@ -15,8 +15,10 @@
package com.google.gerrit.pgm.init.api;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.project.GroupList;
import com.google.gerrit.server.project.ProjectConfig;
@ -27,16 +29,21 @@ import org.eclipse.jgit.lib.CommitBuilder;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.RepositoryCache;
import org.eclipse.jgit.lib.StoredConfig;
public class AllProjectsConfig extends VersionedMetaDataOnInit {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
@Nullable private final StoredConfig baseConfig;
private Config cfg;
private GroupList groupList;
@Inject
AllProjectsConfig(AllProjectsNameOnInitProvider allProjects, SitePaths site, InitFlags flags) {
super(flags, site, allProjects.get(), RefNames.REFS_CONFIG);
this.baseConfig =
ProjectConfig.Factory.getBaseConfig(
site, new AllProjectsName(allProjects.get()), new Project.NameKey(allProjects.get()));
}
public Config getConfig() {
@ -55,8 +62,11 @@ public class AllProjectsConfig extends VersionedMetaDataOnInit {
@Override
protected void onLoad() throws IOException, ConfigInvalidException {
if (baseConfig != null) {
baseConfig.load();
}
groupList = readGroupList();
cfg = readConfig(ProjectConfig.PROJECT_CONFIG);
cfg = readConfig(ProjectConfig.PROJECT_CONFIG, baseConfig);
}
private GroupList readGroupList() throws IOException {

View File

@ -462,7 +462,12 @@ public abstract class VersionedMetaData {
}
protected Config readConfig(String fileName) throws IOException, ConfigInvalidException {
Config rc = new Config();
return readConfig(fileName, null);
}
protected Config readConfig(String fileName, Config baseConfig)
throws IOException, ConfigInvalidException {
Config rc = new Config(baseConfig);
String text = readUTF8(fileName);
if (!text.isEmpty()) {
try {

View File

@ -52,13 +52,16 @@ import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.server.account.GroupBackend;
import com.google.gerrit.server.account.ProjectWatches.NotifyType;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.ConfigUtil;
import com.google.gerrit.server.config.PluginConfig;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.git.BranchOrderSection;
import com.google.gerrit.server.git.NotifyConfig;
import com.google.gerrit.server.git.ValidationError;
import com.google.gerrit.server.git.meta.MetaDataUpdate;
import com.google.gerrit.server.git.meta.VersionedMetaData;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
import java.util.ArrayList;
@ -83,8 +86,11 @@ import org.eclipse.jgit.lib.CommitBuilder;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.util.FS;
public class ProjectConfig extends VersionedMetaData implements ValidationError.Sink {
public static final String COMMENTLINK = "commentlink";
@ -173,8 +179,28 @@ public class ProjectConfig extends VersionedMetaData implements ValidationError.
// ProjectCache, so this would retain lots more memory.
@Singleton
public static class Factory {
@Nullable
public static StoredConfig getBaseConfig(
SitePaths sitePaths, AllProjectsName allProjects, Project.NameKey projectName) {
return projectName.equals(allProjects)
// Delay loading till onLoad method.
? new FileBasedConfig(
sitePaths.etc_dir.resolve(allProjects.get()).resolve(PROJECT_CONFIG).toFile(),
FS.DETECTED)
: null;
}
private final SitePaths sitePaths;
private final AllProjectsName allProjects;
@Inject
Factory(SitePaths sitePaths, AllProjectsName allProjects) {
this.sitePaths = sitePaths;
this.allProjects = allProjects;
}
public ProjectConfig create(Project.NameKey projectName) {
return new ProjectConfig(projectName);
return new ProjectConfig(projectName, getBaseConfig(sitePaths, allProjects, projectName));
}
public ProjectConfig read(MetaDataUpdate update) throws IOException, ConfigInvalidException {
@ -191,6 +217,8 @@ public class ProjectConfig extends VersionedMetaData implements ValidationError.
}
}
private final StoredConfig baseConfig;
private Project project;
private AccountsSection accountsSection;
private GroupList groupList;
@ -253,8 +281,9 @@ public class ProjectConfig extends VersionedMetaData implements ValidationError.
commentLinkSections.add(commentLink);
}
private ProjectConfig(Project.NameKey projectName) {
private ProjectConfig(Project.NameKey projectName, @Nullable StoredConfig baseConfig) {
this.projectName = projectName;
this.baseConfig = baseConfig;
}
public void load(Repository repo) throws IOException, ConfigInvalidException {
@ -516,11 +545,14 @@ public class ProjectConfig extends VersionedMetaData implements ValidationError.
@Override
protected void onLoad() throws IOException, ConfigInvalidException {
if (baseConfig != null) {
baseConfig.load();
}
readGroupList();
groupsByName = mapGroupReferences();
rulesId = getObjectId("rules.pl");
Config rc = readConfig(PROJECT_CONFIG);
Config rc = readConfig(PROJECT_CONFIG, baseConfig);
project = new Project(projectName);
Project p = project;

View File

@ -17,12 +17,17 @@ package com.google.gerrit.server.schema;
import static com.google.gerrit.server.project.ProjectConfig.ACCESS;
import static java.util.stream.Collectors.toList;
import com.google.common.annotations.VisibleForTesting;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.data.PermissionRule;
import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.git.meta.MetaDataUpdate;
import com.google.gerrit.server.git.meta.VersionedMetaData;
import com.google.gerrit.server.project.ProjectConfig;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
@ -31,22 +36,38 @@ import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.CommitBuilder;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.StoredConfig;
public class ProjectConfigSchemaUpdate extends VersionedMetaData {
public static class Factory {
private final SitePaths sitePaths;
private final AllProjectsName allProjectsName;
@Inject
Factory(SitePaths sitePaths, AllProjectsName allProjectsName) {
this.sitePaths = sitePaths;
this.allProjectsName = allProjectsName;
}
ProjectConfigSchemaUpdate read(MetaDataUpdate update)
throws IOException, ConfigInvalidException {
ProjectConfigSchemaUpdate r =
new ProjectConfigSchemaUpdate(
update,
ProjectConfig.Factory.getBaseConfig(sitePaths, allProjectsName, allProjectsName));
r.load(update);
return r;
}
}
private final MetaDataUpdate update;
@Nullable private final StoredConfig baseConfig;
private Config config;
private boolean updated;
public static ProjectConfigSchemaUpdate read(MetaDataUpdate update)
throws IOException, ConfigInvalidException {
ProjectConfigSchemaUpdate r = new ProjectConfigSchemaUpdate(update);
r.load(update);
return r;
}
private ProjectConfigSchemaUpdate(MetaDataUpdate update) {
private ProjectConfigSchemaUpdate(MetaDataUpdate update, @Nullable StoredConfig baseConfig) {
this.update = update;
this.baseConfig = baseConfig;
}
@Override
@ -56,7 +77,15 @@ public class ProjectConfigSchemaUpdate extends VersionedMetaData {
@Override
protected void onLoad() throws IOException, ConfigInvalidException {
config = readConfig(ProjectConfig.PROJECT_CONFIG);
if (baseConfig != null) {
baseConfig.load();
}
config = readConfig(ProjectConfig.PROJECT_CONFIG, baseConfig);
}
@VisibleForTesting
Config getConfig() {
return config;
}
public void removeForceFromPermission(String name) {

View File

@ -41,15 +41,18 @@ public class Schema_130 extends ReviewDbSchemaVersion {
private final GitRepositoryManager repoManager;
private final PersonIdent serverUser;
private final ProjectConfigSchemaUpdate.Factory projectConfigSchemaUpdateFactory;
@Inject
Schema_130(
Provider<Schema_129> prior,
GitRepositoryManager repoManager,
@GerritPersonIdent PersonIdent serverUser) {
@GerritPersonIdent PersonIdent serverUser,
ProjectConfigSchemaUpdate.Factory projectConfigSchemaUpdateFactory) {
super(prior);
this.repoManager = repoManager;
this.serverUser = serverUser;
this.projectConfigSchemaUpdateFactory = projectConfigSchemaUpdateFactory;
}
@Override
@ -60,7 +63,7 @@ public class Schema_130 extends ReviewDbSchemaVersion {
for (Project.NameKey projectName : repoList) {
try (Repository git = repoManager.openRepository(projectName);
MetaDataUpdate md = new MetaDataUpdate(GitReferenceUpdated.DISABLED, projectName, git)) {
ProjectConfigSchemaUpdate cfg = ProjectConfigSchemaUpdate.read(md);
ProjectConfigSchemaUpdate cfg = projectConfigSchemaUpdateFactory.read(md);
cfg.removeForceFromPermission("pushTag");
if (cfg.isUpdated()) {
repoUpgraded.add(projectName);

View File

@ -12,6 +12,7 @@ junit_tests(
"//java/com/google/gerrit/pgm/init/api",
"//java/com/google/gerrit/server",
"//java/com/google/gerrit/server/securestore/testing",
"//java/com/google/gerrit/testing:gerrit-test-util",
"//lib:guava",
"//lib:junit",
"//lib/easymock",

View File

@ -0,0 +1,117 @@
// Copyright (C) 2018 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.pgm.init.api;
import static com.google.common.truth.Truth.assertThat;
import static org.easymock.EasyMock.createStrictMock;
import static org.easymock.EasyMock.replay;
import com.google.common.collect.ImmutableList;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.securestore.testing.InMemorySecureStore;
import com.google.gerrit.testing.TempFileUtil;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.internal.storage.file.FileRepository;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.eclipse.jgit.util.FS;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class AllProjectsConfigTest {
private static final String ALL_PROJECTS = "All-The-Projects";
private SitePaths sitePaths;
private AllProjectsConfig allProjectsConfig;
private File allProjectsRepoFile;
@Before
public void setUp() throws Exception {
sitePaths = new SitePaths(TempFileUtil.createTempDirectory().toPath());
Files.createDirectories(sitePaths.etc_dir);
Path gitPath = sitePaths.resolve("git");
StoredConfig gerritConfig =
new FileBasedConfig(
sitePaths.resolve("etc").resolve("gerrit.config").toFile(), FS.DETECTED);
gerritConfig.load();
gerritConfig.setString("gerrit", null, "basePath", gitPath.toAbsolutePath().toString());
gerritConfig.setString("gerrit", null, "allProjects", ALL_PROJECTS);
gerritConfig.save();
Files.createDirectories(sitePaths.resolve("git"));
allProjectsRepoFile = gitPath.resolve("All-The-Projects.git").toFile();
try (Repository repo = new FileRepository(allProjectsRepoFile)) {
repo.create(true);
}
InMemorySecureStore secureStore = new InMemorySecureStore();
InitFlags flags = new InitFlags(sitePaths, secureStore, ImmutableList.of(), false);
ConsoleUI ui = createStrictMock(ConsoleUI.class);
replay(ui);
Section.Factory sections =
(name, subsection) -> new Section(flags, sitePaths, secureStore, ui, name, subsection);
allProjectsConfig =
new AllProjectsConfig(new AllProjectsNameOnInitProvider(sections), sitePaths, flags);
}
@After
public void tearDown() throws Exception {
TempFileUtil.cleanup();
}
@Test
public void noBaseConfig() throws Exception {
assertThat(getConfig().getString("foo", null, "bar")).isNull();
try (Repository repo = new FileRepository(allProjectsRepoFile)) {
TestRepository<?> tr = new TestRepository<>(repo);
tr.branch("refs/meta/config").commit().add("project.config", "[foo]\nbar = baz").create();
}
assertThat(getConfig().getString("foo", null, "bar")).isEqualTo("baz");
}
@Test
public void baseConfig() throws Exception {
assertThat(getConfig().getString("foo", null, "bar")).isNull();
Path baseConfigPath = sitePaths.etc_dir.resolve(ALL_PROJECTS).resolve("project.config");
Files.createDirectories(baseConfigPath.getParent());
Files.write(baseConfigPath, ImmutableList.of("[foo]", "bar = base"));
assertThat(getConfig().getString("foo", null, "bar")).isEqualTo("base");
try (Repository repo = new FileRepository(allProjectsRepoFile)) {
TestRepository<?> tr = new TestRepository<>(repo);
tr.branch("refs/meta/config").commit().add("project.config", "[foo]\nbar = baz").create();
}
assertThat(getConfig().getString("foo", null, "bar")).isEqualTo("baz");
}
private Config getConfig() throws IOException, ConfigInvalidException {
return allProjectsConfig.load().getConfig();
}
}

View File

@ -16,7 +16,9 @@ package com.google.gerrit.server.project;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static com.google.gerrit.reviewdb.client.BooleanProjectConfig.REQUIRE_CHANGE_ID;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.gerrit.common.data.AccessSection;
import com.google.gerrit.common.data.ContributorAgreement;
@ -24,16 +26,22 @@ import com.google.gerrit.common.data.GroupReference;
import com.google.gerrit.common.data.LabelType;
import com.google.gerrit.common.data.Permission;
import com.google.gerrit.common.data.PermissionRule;
import com.google.gerrit.extensions.client.InheritableBoolean;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.PluginConfig;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
import com.google.gerrit.server.git.ValidationError;
import com.google.gerrit.server.git.meta.MetaDataUpdate;
import com.google.gerrit.server.project.testing.Util;
import com.google.gerrit.testing.GerritBaseTests;
import com.google.gerrit.testing.TempFileUtil;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
@ -50,6 +58,7 @@ import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.util.RawParseUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@ -74,21 +83,31 @@ public class ProjectConfigTest extends GerritBaseTests {
+ !LabelType.DEF_COPY_ALL_SCORES_IF_NO_CHANGE
+ "\n";
private static final AllProjectsName ALL_PROJECTS = new AllProjectsName("All-The-Projects");
private final GroupReference developers =
new GroupReference(new AccountGroup.UUID("X"), "Developers");
private final GroupReference staff = new GroupReference(new AccountGroup.UUID("Y"), "Staff");
private SitePaths sitePaths;
private ProjectConfig.Factory factory;
private Repository db;
private TestRepository<?> tr;
@Before
public void setUp() throws Exception {
factory = new ProjectConfig.Factory();
sitePaths = new SitePaths(TempFileUtil.createTempDirectory().toPath());
Files.createDirectories(sitePaths.etc_dir);
factory = new ProjectConfig.Factory(sitePaths, ALL_PROJECTS);
db = new InMemoryRepository(new DfsRepositoryDescription("repo"));
tr = new TestRepository<>(db);
}
@After
public void tearDown() throws Exception {
TempFileUtil.cleanup();
}
@Test
public void readConfig() throws Exception {
RevCommit rev =
@ -593,6 +612,44 @@ public class ProjectConfigTest extends GerritBaseTests {
+ "commentlink.bugzilla must have either link or html"));
}
@Test
public void readAllProjectsBaseConfigFromSitePaths() throws Exception {
ProjectConfig cfg = factory.create(ALL_PROJECTS);
cfg.load(db);
assertThat(cfg.getProject().getBooleanConfig(REQUIRE_CHANGE_ID))
.isEqualTo(InheritableBoolean.INHERIT);
writeDefaultAllProjectsConfig("[receive]", "requireChangeId = false");
cfg.load(db);
assertThat(cfg.getProject().getBooleanConfig(REQUIRE_CHANGE_ID))
.isEqualTo(InheritableBoolean.FALSE);
}
@Test
public void readOtherProjectIgnoresAllProjectsBaseConfig() throws Exception {
ProjectConfig cfg = factory.create(new Project.NameKey("test"));
cfg.load(db);
assertThat(cfg.getProject().getBooleanConfig(REQUIRE_CHANGE_ID))
.isEqualTo(InheritableBoolean.INHERIT);
writeDefaultAllProjectsConfig("[receive]", "requireChangeId = false");
cfg.load(db);
// If we went through ProjectState, then this would return FALSE, since project.config for
// All-Projects would inherit from all_projects.config, and this project would inherit from
// All-Projects. But in ProjectConfig itself, there is no inheritance from All-Projects, so this
// continues to return the default.
assertThat(cfg.getProject().getBooleanConfig(REQUIRE_CHANGE_ID))
.isEqualTo(InheritableBoolean.INHERIT);
}
private Path writeDefaultAllProjectsConfig(String... lines) throws IOException {
Path dir = sitePaths.etc_dir.resolve(ALL_PROJECTS.get());
Files.createDirectories(dir);
return Files.write(dir.resolve("project.config"), ImmutableList.copyOf(lines));
}
private ProjectConfig read(RevCommit rev) throws IOException, ConfigInvalidException {
ProjectConfig cfg = factory.create(new Project.NameKey("test"));
cfg.load(db, rev);

View File

@ -0,0 +1,113 @@
// Copyright (C) 2018 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 static com.google.common.truth.Truth.assertThat;
import com.google.common.collect.ImmutableList;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
import com.google.gerrit.server.git.meta.MetaDataUpdate;
import com.google.gerrit.testing.TempFileUtil;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import org.eclipse.jgit.internal.storage.file.FileRepository;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.eclipse.jgit.util.FS;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class ProjectConfigSchemaUpdateTest {
private static final String ALL_PROJECTS = "All-The-Projects";
private SitePaths sitePaths;
private ProjectConfigSchemaUpdate.Factory factory;
private File allProjectsRepoFile;
@Before
public void setUp() throws Exception {
sitePaths = new SitePaths(TempFileUtil.createTempDirectory().toPath());
Files.createDirectories(sitePaths.etc_dir);
Path gitPath = sitePaths.resolve("git");
StoredConfig gerritConfig = new FileBasedConfig(sitePaths.gerrit_config.toFile(), FS.DETECTED);
gerritConfig.load();
gerritConfig.setString("gerrit", null, "basePath", gitPath.toAbsolutePath().toString());
gerritConfig.setString("gerrit", null, "allProjects", ALL_PROJECTS);
gerritConfig.save();
Files.createDirectories(sitePaths.resolve("git"));
allProjectsRepoFile = gitPath.resolve("All-The-Projects.git").toFile();
try (Repository repo = new FileRepository(allProjectsRepoFile)) {
repo.create(true);
}
factory = new ProjectConfigSchemaUpdate.Factory(sitePaths, new AllProjectsName(ALL_PROJECTS));
}
@After
public void tearDown() throws Exception {
TempFileUtil.cleanup();
}
@Test
public void noBaseConfig() throws Exception {
assertThat(getConfig().getString("foo", null, "bar")).isNull();
try (Repository repo = new FileRepository(allProjectsRepoFile)) {
TestRepository<?> tr = new TestRepository<>(repo);
tr.branch("refs/meta/config").commit().add("project.config", "[foo]\nbar = baz").create();
}
assertThat(getConfig().getString("foo", null, "bar")).isEqualTo("baz");
}
@Test
public void baseConfig() throws Exception {
assertThat(getConfig().getString("foo", null, "bar")).isNull();
Path baseConfigPath = sitePaths.etc_dir.resolve(ALL_PROJECTS).resolve("project.config");
Files.createDirectories(baseConfigPath.getParent());
Files.write(baseConfigPath, ImmutableList.of("[foo]", "bar = base"));
assertThat(getConfig().getString("foo", null, "bar")).isEqualTo("base");
try (Repository repo = new FileRepository(allProjectsRepoFile)) {
TestRepository<?> tr = new TestRepository<>(repo);
tr.branch("refs/meta/config").commit().add("project.config", "[foo]\nbar = baz").create();
}
assertThat(getConfig().getString("foo", null, "bar")).isEqualTo("baz");
}
private Config getConfig() throws Exception {
try (Repository repo = new FileRepository(allProjectsRepoFile)) {
return factory
.read(
new MetaDataUpdate(
GitReferenceUpdated.DISABLED, new Project.NameKey(ALL_PROJECTS), repo, null))
.getConfig();
}
}
}