Allow to configure a code owners backend We want to support multiple syntaxes for code owner config files. Each syntax is implemented in a seperate CodeOwnersBackend. This change adds a global plugin configuration that allows administrators to configure which CodeOwnersBackend should be used. Signed-off-by: Edwin Kempin <ekempin@google.com> Change-Id: Ifa68b9a094035da019dd07822d49e247568af530
diff --git a/java/com/google/gerrit/plugins/codeowners/CodeOwnersPluginConfiguration.java b/java/com/google/gerrit/plugins/codeowners/CodeOwnersPluginConfiguration.java new file mode 100644 index 0000000..b11e2d5 --- /dev/null +++ b/java/com/google/gerrit/plugins/codeowners/CodeOwnersPluginConfiguration.java
@@ -0,0 +1,77 @@ +// Copyright (C) 2020 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.plugins.codeowners; + +import com.google.gerrit.extensions.annotations.PluginName; +import com.google.gerrit.extensions.registration.DynamicMap; +import com.google.gerrit.plugins.codeowners.backend.CodeOwnersBackend; +import com.google.gerrit.plugins.codeowners.backend.findowners.FindOwnersBackend; +import com.google.gerrit.server.config.PluginConfigFactory; +import com.google.inject.Inject; +import com.google.inject.Singleton; +import java.util.Optional; + +/** + * The configuration of the code-owners plugin. + * + * <p>The configuration of the code-owners plugin is stored globally in the {@code gerrit.config} + * file in the {@code plugin.code-owners} subsection. + */ +@Singleton +public class CodeOwnersPluginConfiguration { + private static final String KEY_BACKEND = "backend"; + + private final String pluginName; + private final DynamicMap<CodeOwnersBackend> codeOwnersBackends; + + /** The name of the configured code owners backend. */ + private final String backendName; + + @Inject + CodeOwnersPluginConfiguration( + @PluginName String pluginName, + PluginConfigFactory pluginConfigFactory, + DynamicMap<CodeOwnersBackend> codeOwnersBackends) { + this.pluginName = pluginName; + this.codeOwnersBackends = codeOwnersBackends; + + this.backendName = + pluginConfigFactory + .getFromGerritConfig(pluginName) + .getString(KEY_BACKEND, FindOwnersBackend.ID); + } + + /** + * Returns the configured {@link CodeOwnersBackend}. + * + * @return the {@link CodeOwnersBackend} that should be used + */ + public CodeOwnersBackend getBackend() { + return lookupBackend(backendName) + .orElseThrow( + () -> + new IllegalStateException( + String.format( + "Code owner backend '%s' that is configured in gerrit.config" + + " (parameter plugin.%s.%s) not found", + backendName, pluginName, KEY_BACKEND))); + } + + private Optional<CodeOwnersBackend> lookupBackend(String backendName) { + // We must use "gerrit" as plugin name since DynamicMapProvider#get() hard-codes "gerrit" as + // plugin name. + return Optional.ofNullable(codeOwnersBackends.get("gerrit", backendName)); + } +}
diff --git a/java/com/google/gerrit/plugins/codeowners/Module.java b/java/com/google/gerrit/plugins/codeowners/Module.java index d87a514..cf82ccd 100644 --- a/java/com/google/gerrit/plugins/codeowners/Module.java +++ b/java/com/google/gerrit/plugins/codeowners/Module.java
@@ -15,11 +15,12 @@ package com.google.gerrit.plugins.codeowners; import com.google.gerrit.extensions.config.FactoryModule; +import com.google.gerrit.plugins.codeowners.backend.BackendModule; /** Guice module that registers the extensions of the code-owners plugin. */ public class Module extends FactoryModule { @Override protected void configure() { - // TODO register extensions + install(new BackendModule()); } }
diff --git a/java/com/google/gerrit/plugins/codeowners/backend/BackendModule.java b/java/com/google/gerrit/plugins/codeowners/backend/BackendModule.java new file mode 100644 index 0000000..83fd3be --- /dev/null +++ b/java/com/google/gerrit/plugins/codeowners/backend/BackendModule.java
@@ -0,0 +1,31 @@ +// Copyright (C) 2020 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.plugins.codeowners.backend; + +import com.google.gerrit.extensions.annotations.Exports; +import com.google.gerrit.extensions.config.FactoryModule; +import com.google.gerrit.extensions.registration.DynamicMap; +import com.google.gerrit.plugins.codeowners.backend.findowners.FindOwnersBackend; + +/** Guice module to bind code owner backends. */ +public class BackendModule extends FactoryModule { + @Override + protected void configure() { + DynamicMap.mapOf(binder(), CodeOwnersBackend.class); + bind(CodeOwnersBackend.class) + .annotatedWith(Exports.named(FindOwnersBackend.ID)) + .to(FindOwnersBackend.class); + } +}
diff --git a/java/com/google/gerrit/plugins/codeowners/backend/findowners/FindOwnersBackend.java b/java/com/google/gerrit/plugins/codeowners/backend/findowners/FindOwnersBackend.java index 125fa3d..6532a0f 100644 --- a/java/com/google/gerrit/plugins/codeowners/backend/findowners/FindOwnersBackend.java +++ b/java/com/google/gerrit/plugins/codeowners/backend/findowners/FindOwnersBackend.java
@@ -36,6 +36,9 @@ @Singleton public class FindOwnersBackend implements CodeOwnersBackend { + /** The ID of this code owner backend. */ + public static final String ID = "find-owners"; + private final CodeOwnerConfigFile.Factory codeOwnerConfigFileFactory; private final GitRepositoryManager repoManager; private final PersonIdent serverIdent;
diff --git a/javatests/com/google/gerrit/plugins/codeowners/BUILD b/javatests/com/google/gerrit/plugins/codeowners/BUILD new file mode 100644 index 0000000..c12ec57 --- /dev/null +++ b/javatests/com/google/gerrit/plugins/codeowners/BUILD
@@ -0,0 +1,11 @@ +load("//javatests/com/google/gerrit/acceptance:tests.bzl", "acceptance_tests") +acceptance_tests( + srcs = glob(["*Test.java"]), + group = "codeowners", + deps = [ + "//plugins/code-owners:code-owners__plugin", + "//plugins/code-owners/java/com/google/gerrit/plugins/codeowners/acceptance", + "//plugins/code-owners/java/com/google/gerrit/plugins/codeowners/testing", + ], +) +
diff --git a/javatests/com/google/gerrit/plugins/codeowners/CodeOwnersPluginConfigurationTest.java b/javatests/com/google/gerrit/plugins/codeowners/CodeOwnersPluginConfigurationTest.java new file mode 100644 index 0000000..72f1072 --- /dev/null +++ b/javatests/com/google/gerrit/plugins/codeowners/CodeOwnersPluginConfigurationTest.java
@@ -0,0 +1,99 @@ +// Copyright (C) 2020 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.plugins.codeowners; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.gerrit.testing.GerritJUnit.assertThrows; + +import com.google.gerrit.acceptance.config.GerritConfig; +import com.google.gerrit.common.Nullable; +import com.google.gerrit.extensions.registration.DynamicMap; +import com.google.gerrit.extensions.registration.PrivateInternals_DynamicMapImpl; +import com.google.gerrit.extensions.registration.RegistrationHandle; +import com.google.gerrit.plugins.codeowners.acceptance.AbstractCodeOwnersTest; +import com.google.gerrit.plugins.codeowners.backend.CodeOwnerConfig; +import com.google.gerrit.plugins.codeowners.backend.CodeOwnerConfigUpdate; +import com.google.gerrit.plugins.codeowners.backend.CodeOwnersBackend; +import com.google.gerrit.plugins.codeowners.backend.findowners.FindOwnersBackend; +import com.google.gerrit.server.IdentifiedUser; +import com.google.inject.Key; +import com.google.inject.util.Providers; +import java.util.Optional; +import org.junit.Before; +import org.junit.Test; + +/** Tests for {@link CodeOwnersPluginConfiguration}. */ +public class CodeOwnersPluginConfigurationTest extends AbstractCodeOwnersTest { + private CodeOwnersPluginConfiguration codeOwnersPluginConfiguration; + private DynamicMap<CodeOwnersBackend> codeOwnersBackends; + + @Before + public void setUpCodeOwnersPlugin() throws Exception { + codeOwnersPluginConfiguration = + plugin.getSysInjector().getInstance(CodeOwnersPluginConfiguration.class); + codeOwnersBackends = + plugin.getSysInjector().getInstance(new Key<DynamicMap<CodeOwnersBackend>>() {}); + } + + @Test + public void getDefaultBackendWhenNoBackendIsConfigured() throws Exception { + assertThat(codeOwnersPluginConfiguration.getBackend()).isInstanceOf(FindOwnersBackend.class); + } + + @Test + @GerritConfig(name = "plugin.code-owners.backend", value = TestCodeOwnersBackend.ID) + public void getConfiguredBackend() throws Exception { + try (AutoCloseable registration = registerTestBackend()) { + assertThat(codeOwnersPluginConfiguration.getBackend()) + .isInstanceOf(TestCodeOwnersBackend.class); + } + } + + @Test + @GerritConfig(name = "plugin.code-owners.backend", value = "non-existing-backend") + public void cannotGetBackendIfNonExistingBackendIsConfigured() throws Exception { + IllegalStateException exception = + assertThrows(IllegalStateException.class, () -> codeOwnersPluginConfiguration.getBackend()); + assertThat(exception) + .hasMessageThat() + .isEqualTo( + "Code owner backend 'non-existing-backend' that is configured in gerrit.config" + + " (parameter plugin.code-owners.backend) not found"); + } + + private AutoCloseable registerTestBackend() { + RegistrationHandle registrationHandle = + ((PrivateInternals_DynamicMapImpl<CodeOwnersBackend>) codeOwnersBackends) + .put("gerrit", TestCodeOwnersBackend.ID, Providers.of(new TestCodeOwnersBackend())); + return () -> registrationHandle.remove(); + } + + private static class TestCodeOwnersBackend implements CodeOwnersBackend { + static final String ID = "test-backend"; + + @Override + public Optional<CodeOwnerConfig> getCodeOwnerConfig(CodeOwnerConfig.Key codeOwnerConfigKey) { + throw new UnsupportedOperationException("not implemented"); + } + + @Override + public Optional<CodeOwnerConfig> upsertCodeOwnerConfig( + CodeOwnerConfig.Key codeOwnerConfigKey, + CodeOwnerConfigUpdate codeOwnerConfigUpdate, + @Nullable IdentifiedUser currentUser) { + throw new UnsupportedOperationException("not implemented"); + } + } +}
diff --git a/resources/Documentation/config.md b/resources/Documentation/config.md new file mode 100644 index 0000000..0ff10d6 --- /dev/null +++ b/resources/Documentation/config.md
@@ -0,0 +1,20 @@ +# @PLUGIN@ - Configuration + +The configuration of the @PLUGIN@ plugin is stored in the `gerrit.config` file +in the `plugin.@PLUGIN@` subsection. + +# <a id="globalConfiguration">Global configuration in gerrit.config</a> + +<a id="pluginCodeOwnersBackend">plugin.@PLUGIN@.backend</a> +: The code owners backend that should be used. + + The following code owner backends are supported: + + * `find-owners`: Code owners backend that supports the syntax of the + [find-owners](https://gerrit-review.googlesource.com/admin/repos/plugins/find-owners) + plugin. + + By default `find-owners`. + +Part of [Gerrit Code Review](../../../Documentation/index.html) +