diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt index e13a9b9507..6362597669 100644 --- a/Documentation/config-gerrit.txt +++ b/Documentation/config-gerrit.txt @@ -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` diff --git a/java/com/google/gerrit/pgm/init/api/AllProjectsConfig.java b/java/com/google/gerrit/pgm/init/api/AllProjectsConfig.java index 9fd3f16e43..20e7ba24b4 100644 --- a/java/com/google/gerrit/pgm/init/api/AllProjectsConfig.java +++ b/java/com/google/gerrit/pgm/init/api/AllProjectsConfig.java @@ -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 { diff --git a/java/com/google/gerrit/server/git/meta/VersionedMetaData.java b/java/com/google/gerrit/server/git/meta/VersionedMetaData.java index 196267eba5..b33aa3c222 100644 --- a/java/com/google/gerrit/server/git/meta/VersionedMetaData.java +++ b/java/com/google/gerrit/server/git/meta/VersionedMetaData.java @@ -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 { diff --git a/java/com/google/gerrit/server/project/ProjectConfig.java b/java/com/google/gerrit/server/project/ProjectConfig.java index 74c0f3bebb..b16b0768c8 100644 --- a/java/com/google/gerrit/server/project/ProjectConfig.java +++ b/java/com/google/gerrit/server/project/ProjectConfig.java @@ -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; diff --git a/java/com/google/gerrit/server/schema/ProjectConfigSchemaUpdate.java b/java/com/google/gerrit/server/schema/ProjectConfigSchemaUpdate.java index c25b846ae1..483e36323d 100644 --- a/java/com/google/gerrit/server/schema/ProjectConfigSchemaUpdate.java +++ b/java/com/google/gerrit/server/schema/ProjectConfigSchemaUpdate.java @@ -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) { diff --git a/java/com/google/gerrit/server/schema/Schema_130.java b/java/com/google/gerrit/server/schema/Schema_130.java index 0c9d79d523..e550121a1e 100644 --- a/java/com/google/gerrit/server/schema/Schema_130.java +++ b/java/com/google/gerrit/server/schema/Schema_130.java @@ -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 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); diff --git a/javatests/com/google/gerrit/pgm/BUILD b/javatests/com/google/gerrit/pgm/BUILD index 01ebb0e40d..8e3b71da10 100644 --- a/javatests/com/google/gerrit/pgm/BUILD +++ b/javatests/com/google/gerrit/pgm/BUILD @@ -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", diff --git a/javatests/com/google/gerrit/pgm/init/api/AllProjectsConfigTest.java b/javatests/com/google/gerrit/pgm/init/api/AllProjectsConfigTest.java new file mode 100644 index 0000000000..68b4a8ee47 --- /dev/null +++ b/javatests/com/google/gerrit/pgm/init/api/AllProjectsConfigTest.java @@ -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(); + } +} diff --git a/javatests/com/google/gerrit/server/project/ProjectConfigTest.java b/javatests/com/google/gerrit/server/project/ProjectConfigTest.java index 764d49a921..a1e0566086 100644 --- a/javatests/com/google/gerrit/server/project/ProjectConfigTest.java +++ b/javatests/com/google/gerrit/server/project/ProjectConfigTest.java @@ -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); diff --git a/javatests/com/google/gerrit/server/schema/ProjectConfigSchemaUpdateTest.java b/javatests/com/google/gerrit/server/schema/ProjectConfigSchemaUpdateTest.java new file mode 100644 index 0000000000..de825e61fd --- /dev/null +++ b/javatests/com/google/gerrit/server/schema/ProjectConfigSchemaUpdateTest.java @@ -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(); + } + } +}