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:
parent
314edaa07b
commit
d4fdc9323d
@ -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`
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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",
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user