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)
+