Merge changes from topic 'plugin-api'
* changes:
ServerInfoIT: Use API to install plugin
Add implementation of PluginApi
PluginLoader: Ensure that $site/plugins folder exists
Plugins#ListRequest: Remove parameter from all() method
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/plugin/PluginIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/plugin/PluginIT.java
index cfc6318..58619ad 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/plugin/PluginIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/plugin/PluginIT.java
@@ -15,15 +15,89 @@
package com.google.gerrit.acceptance.api.plugin;
import static com.google.common.truth.Truth.assertThat;
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.util.stream.Collectors.toList;
+import com.google.common.collect.ImmutableList;
import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.GerritConfig;
import com.google.gerrit.acceptance.NoHttpd;
+import com.google.gerrit.common.RawInputUtil;
+import com.google.gerrit.extensions.api.plugins.PluginApi;
+import com.google.gerrit.extensions.api.plugins.Plugins.ListRequest;
+import com.google.gerrit.extensions.common.InstallPluginInput;
+import com.google.gerrit.extensions.common.PluginInfo;
+import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
+import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
+import com.google.gerrit.extensions.restapi.RestApiException;
+import java.util.List;
import org.junit.Test;
@NoHttpd
public class PluginIT extends AbstractDaemonTest {
+ private static final byte[] JS_PLUGIN_CONTENT =
+ "Gerrit.install(function(self){});\n".getBytes(UTF_8);
+ private static final List<String> PLUGINS =
+ ImmutableList.of("plugin-a", "plugin-b", "plugin-c", "plugin-d");
+
@Test
- public void noPlugins() throws Exception {
- assertThat(gApi.plugins().list().get()).isEmpty();
+ @GerritConfig(name = "plugins.allowRemoteAdmin", value = "true")
+ public void pluginManagement() throws Exception {
+ // No plugins are loaded
+ assertThat(list().get()).isEmpty();
+ assertThat(list().all().get()).isEmpty();
+
+ PluginApi test;
+ PluginInfo info;
+
+ // Install all the plugins
+ InstallPluginInput input = new InstallPluginInput();
+ input.raw = RawInputUtil.create(JS_PLUGIN_CONTENT);
+ for (String plugin : PLUGINS) {
+ test = gApi.plugins().install(plugin + ".js", input);
+ assertThat(test).isNotNull();
+ info = test.get();
+ assertThat(info.id).isEqualTo(plugin);
+ assertThat(info.disabled).isNull();
+ }
+ assertPlugins(list().get(), PLUGINS);
+
+ // Disable
+ test = gApi.plugins().name("plugin-a");
+ test.disable();
+ test = gApi.plugins().name("plugin-a");
+ info = test.get();
+ assertThat(info.disabled).isTrue();
+ assertPlugins(list().get(), PLUGINS.subList(1, PLUGINS.size()));
+ assertPlugins(list().all().get(), PLUGINS);
+
+ // Enable
+ test.enable();
+ test = gApi.plugins().name("plugin-a");
+ info = test.get();
+ assertThat(info.disabled).isNull();
+ assertPlugins(list().get(), PLUGINS);
+ }
+
+ @Test
+ public void installNotAllowed() throws Exception {
+ exception.expect(MethodNotAllowedException.class);
+ exception.expectMessage("remote installation is disabled");
+ gApi.plugins().install("test.js", new InstallPluginInput());
+ }
+
+ @Test
+ public void getNonExistingThrowsNotFound() throws Exception {
+ exception.expect(ResourceNotFoundException.class);
+ gApi.plugins().name("does-not-exist");
+ }
+
+ private ListRequest list() throws RestApiException {
+ return gApi.plugins().list();
+ }
+
+ private void assertPlugins(List<PluginInfo> actual, List<String> expected) {
+ List<String> _actual = actual.stream().map(p -> p.id).collect(toList());
+ assertThat(_actual).containsExactlyElementsIn(expected);
}
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/ServerInfoIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/ServerInfoIT.java
index 2a33140..365a0d8 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/ServerInfoIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/ServerInfoIT.java
@@ -20,22 +20,20 @@
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.GerritConfig;
import com.google.gerrit.acceptance.NoHttpd;
-import com.google.gerrit.acceptance.UseSsh;
+import com.google.gerrit.common.RawInputUtil;
import com.google.gerrit.extensions.client.AccountFieldName;
import com.google.gerrit.extensions.client.AuthType;
+import com.google.gerrit.extensions.common.InstallPluginInput;
import com.google.gerrit.extensions.common.ServerInfo;
import com.google.gerrit.server.config.AllProjectsNameProvider;
import com.google.gerrit.server.config.AllUsersNameProvider;
import com.google.gerrit.server.config.AnonymousCowardNameProvider;
-import com.google.gerrit.server.config.SitePaths;
-import com.google.inject.Inject;
-import java.nio.file.Files;
-import java.nio.file.Path;
import org.junit.Test;
@NoHttpd
public class ServerInfoIT extends AbstractDaemonTest {
- @Inject private SitePaths sitePaths;
+ private static final byte[] JS_PLUGIN_CONTENT =
+ "Gerrit.install(function(self){});\n".getBytes(UTF_8);
@Test
// auth
@@ -132,18 +130,16 @@
}
@Test
- @UseSsh
@GerritConfig(name = "plugins.allowRemoteAdmin", value = "true")
public void serverConfigWithPlugin() throws Exception {
- Path plugins = sitePaths.plugins_dir;
- Files.createDirectory(plugins);
- Path jsplugin = plugins.resolve("js-plugin-1.js");
- Files.write(jsplugin, "Gerrit.install(function(self){});\n".getBytes(UTF_8));
- adminSshSession.exec("gerrit plugin reload");
-
ServerInfo i = gApi.config().server().getInfo();
+ assertThat(i.plugin.jsResourcePaths).isEmpty();
- // plugin
+ InstallPluginInput input = new InstallPluginInput();
+ input.raw = RawInputUtil.create(JS_PLUGIN_CONTENT);
+ gApi.plugins().install("js-plugin-1.js", input);
+
+ i = gApi.config().server().getInfo();
assertThat(i.plugin.jsResourcePaths).hasSize(1);
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/plugins/PluginApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/plugins/PluginApi.java
new file mode 100644
index 0000000..b6d78a3
--- /dev/null
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/plugins/PluginApi.java
@@ -0,0 +1,55 @@
+// Copyright (C) 2017 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.extensions.api.plugins;
+
+import com.google.gerrit.extensions.common.PluginInfo;
+import com.google.gerrit.extensions.restapi.NotImplementedException;
+import com.google.gerrit.extensions.restapi.RestApiException;
+
+public interface PluginApi {
+ PluginInfo get() throws RestApiException;
+
+ void enable() throws RestApiException;
+
+ void disable() throws RestApiException;
+
+ void reload() throws RestApiException;
+
+ /**
+ * A default implementation which allows source compatibility when adding new methods to the
+ * interface.
+ */
+ class NotImplemented implements PluginApi {
+ @Override
+ public PluginInfo get() throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void enable() throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void disable() throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void reload() throws RestApiException {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/plugins/Plugins.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/plugins/Plugins.java
index 808a8252..a97073f 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/plugins/Plugins.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/plugins/Plugins.java
@@ -14,6 +14,7 @@
package com.google.gerrit.extensions.api.plugins;
+import com.google.gerrit.extensions.common.InstallPluginInput;
import com.google.gerrit.extensions.common.PluginInfo;
import com.google.gerrit.extensions.restapi.NotImplementedException;
import com.google.gerrit.extensions.restapi.RestApiException;
@@ -24,7 +25,11 @@
public interface Plugins {
- ListRequest list();
+ ListRequest list() throws RestApiException;
+
+ PluginApi name(String name) throws RestApiException;
+
+ PluginApi install(String name, InstallPluginInput input) throws RestApiException;
abstract class ListRequest {
private boolean all;
@@ -40,8 +45,8 @@
public abstract SortedMap<String, PluginInfo> getAsMap() throws RestApiException;
- public ListRequest all(boolean all) {
- this.all = all;
+ public ListRequest all() {
+ this.all = true;
return this;
}
@@ -59,5 +64,15 @@
public ListRequest list() {
throw new NotImplementedException();
}
+
+ @Override
+ public PluginApi name(String name) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public PluginApi install(String name, InstallPluginInput input) throws RestApiException {
+ throw new NotImplementedException();
+ }
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/plugins/PluginApiImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/plugins/PluginApiImpl.java
new file mode 100644
index 0000000..2fc2e50
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/plugins/PluginApiImpl.java
@@ -0,0 +1,72 @@
+// Copyright (C) 2017 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.api.plugins;
+
+import com.google.gerrit.extensions.api.plugins.PluginApi;
+import com.google.gerrit.extensions.common.PluginInfo;
+import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.server.plugins.DisablePlugin;
+import com.google.gerrit.server.plugins.EnablePlugin;
+import com.google.gerrit.server.plugins.GetStatus;
+import com.google.gerrit.server.plugins.PluginResource;
+import com.google.gerrit.server.plugins.ReloadPlugin;
+import com.google.inject.Inject;
+import com.google.inject.assistedinject.Assisted;
+
+public class PluginApiImpl implements PluginApi {
+ public interface Factory {
+ PluginApiImpl create(PluginResource resource);
+ }
+
+ private final GetStatus getStatus;
+ private final EnablePlugin enable;
+ private final DisablePlugin disable;
+ private final ReloadPlugin reload;
+ private final PluginResource resource;
+
+ @Inject
+ PluginApiImpl(
+ GetStatus getStatus,
+ EnablePlugin enable,
+ DisablePlugin disable,
+ ReloadPlugin reload,
+ @Assisted PluginResource resource) {
+ this.getStatus = getStatus;
+ this.enable = enable;
+ this.disable = disable;
+ this.reload = reload;
+ this.resource = resource;
+ }
+
+ @Override
+ public PluginInfo get() throws RestApiException {
+ return getStatus.apply(resource);
+ }
+
+ @Override
+ public void enable() throws RestApiException {
+ enable.apply(resource, new EnablePlugin.Input());
+ }
+
+ @Override
+ public void disable() throws RestApiException {
+ disable.apply(resource, new DisablePlugin.Input());
+ }
+
+ @Override
+ public void reload() throws RestApiException {
+ reload.apply(resource, new ReloadPlugin.Input());
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/plugins/PluginsImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/plugins/PluginsImpl.java
index 01ab6ba..994acbf 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/plugins/PluginsImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/plugins/PluginsImpl.java
@@ -14,22 +14,44 @@
package com.google.gerrit.server.api.plugins;
+import com.google.gerrit.extensions.api.plugins.PluginApi;
import com.google.gerrit.extensions.api.plugins.Plugins;
+import com.google.gerrit.extensions.common.InstallPluginInput;
import com.google.gerrit.extensions.common.PluginInfo;
+import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.extensions.restapi.TopLevelResource;
+import com.google.gerrit.server.plugins.InstallPlugin;
import com.google.gerrit.server.plugins.ListPlugins;
+import com.google.gerrit.server.plugins.PluginsCollection;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
+import java.io.IOException;
import java.util.SortedMap;
@Singleton
public class PluginsImpl implements Plugins {
+ private final PluginsCollection plugins;
private final Provider<ListPlugins> listProvider;
+ private final Provider<InstallPlugin> installProvider;
+ private final PluginApiImpl.Factory pluginApi;
@Inject
- PluginsImpl(Provider<ListPlugins> listProvider) {
+ PluginsImpl(
+ PluginsCollection plugins,
+ Provider<ListPlugins> listProvider,
+ Provider<InstallPlugin> installProvider,
+ PluginApiImpl.Factory pluginApi) {
+ this.plugins = plugins;
this.listProvider = listProvider;
+ this.installProvider = installProvider;
+ this.pluginApi = pluginApi;
+ }
+
+ @Override
+ public PluginApi name(String name) throws RestApiException {
+ return pluginApi.create(plugins.parse(name));
}
@Override
@@ -43,4 +65,15 @@
}
};
}
+
+ @Override
+ public PluginApi install(String name, InstallPluginInput input) throws RestApiException {
+ try {
+ Response<PluginInfo> created =
+ installProvider.get().setName(name).apply(TopLevelResource.INSTANCE, input);
+ return pluginApi.create(plugins.parse(created.value().id));
+ } catch (IOException e) {
+ throw new RestApiException("could not install plugin", e);
+ }
+ }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/DisablePlugin.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/DisablePlugin.java
index 8732e3e..a2da580 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/DisablePlugin.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/DisablePlugin.java
@@ -26,8 +26,8 @@
@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
@Singleton
-class DisablePlugin implements RestModifyView<PluginResource, Input> {
- static class Input {}
+public class DisablePlugin implements RestModifyView<PluginResource, Input> {
+ public static class Input {}
private final PluginLoader loader;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/EnablePlugin.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/EnablePlugin.java
index 41f9349..f29e36b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/EnablePlugin.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/EnablePlugin.java
@@ -29,8 +29,8 @@
@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
@Singleton
-class EnablePlugin implements RestModifyView<PluginResource, Input> {
- static class Input {}
+public class EnablePlugin implements RestModifyView<PluginResource, Input> {
+ public static class Input {}
private final PluginLoader loader;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/GetStatus.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/GetStatus.java
index 650f9fc..cbd864a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/GetStatus.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/GetStatus.java
@@ -19,7 +19,7 @@
import com.google.inject.Singleton;
@Singleton
-class GetStatus implements RestReadView<PluginResource> {
+public class GetStatus implements RestReadView<PluginResource> {
@Override
public PluginInfo apply(PluginResource resource) {
return ListPlugins.toPluginInfo(resource.getPlugin());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/InstallPlugin.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/InstallPlugin.java
index 61aed6a..531e9ac 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/InstallPlugin.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/InstallPlugin.java
@@ -33,7 +33,7 @@
import java.util.zip.ZipException;
@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
-class InstallPlugin implements RestModifyView<TopLevelResource, InstallPluginInput> {
+public class InstallPlugin implements RestModifyView<TopLevelResource, InstallPluginInput> {
private final PluginLoader loader;
private String name;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginLoader.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginLoader.java
index dd3dc93..fcc6801 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginLoader.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginLoader.java
@@ -309,7 +309,16 @@
@Override
public synchronized void start() {
removeStalePluginFiles();
- log.info("Loading plugins from " + pluginsDir.toAbsolutePath());
+ Path absolutePath = pluginsDir.toAbsolutePath();
+ if (!Files.exists(absolutePath)) {
+ log.info(absolutePath + " does not exist; creating");
+ try {
+ Files.createDirectories(absolutePath);
+ } catch (IOException e) {
+ log.error(String.format("Failed to create %s: %s", absolutePath, e.getMessage()));
+ }
+ }
+ log.info("Loading plugins from " + absolutePath);
srvInfoImpl.state = ServerInformation.State.STARTUP;
rescan();
srvInfoImpl.state = ServerInformation.State.RUNNING;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginRestApiModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginRestApiModule.java
index e61c517..5f97134 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginRestApiModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginRestApiModule.java
@@ -19,6 +19,7 @@
import com.google.gerrit.extensions.api.plugins.Plugins;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.RestApiModule;
+import com.google.gerrit.server.api.plugins.PluginApiImpl;
import com.google.gerrit.server.api.plugins.PluginsImpl;
public class PluginRestApiModule extends RestApiModule {
@@ -33,5 +34,6 @@
post(PLUGIN_KIND, "enable").to(EnablePlugin.class);
post(PLUGIN_KIND, "reload").to(ReloadPlugin.class);
bind(Plugins.class).to(PluginsImpl.class);
+ factory(PluginApiImpl.Factory.class);
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginsCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginsCollection.java
index 314415e..a1dc5c1 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginsCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginsCollection.java
@@ -55,7 +55,11 @@
@Override
public PluginResource parse(TopLevelResource parent, IdString id)
throws ResourceNotFoundException {
- Plugin p = loader.get(id.get());
+ return parse(id.get());
+ }
+
+ public PluginResource parse(String id) throws ResourceNotFoundException {
+ Plugin p = loader.get(id);
if (p == null) {
throw new ResourceNotFoundException(id);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ReloadPlugin.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ReloadPlugin.java
index 426d323..7b464bb 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ReloadPlugin.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ReloadPlugin.java
@@ -28,8 +28,8 @@
@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
@Singleton
-class ReloadPlugin implements RestModifyView<PluginResource, Input> {
- static class Input {}
+public class ReloadPlugin implements RestModifyView<PluginResource, Input> {
+ public static class Input {}
private final PluginLoader loader;