Use per-project settings for Zuul v3 support In Zuul v3, the whole API is split by the tenant name; there is no possibility to request status of a change without knowing the tenant name. This patch adapts Tricium's code for per-project setting retrieval. The top-level global variable in site-path/etc/gerrit.config is no longer used. Given that this is a fresh plugin, I think it's safe to make that change now without any extra compatibility code. The value can be set just as easily in All-Project's refs/meta/config. It was also necessary to remove that extra JSON Content-Type header. Without that, Firefox would complain about Access-Control-Allow-Headers not allowing the `content-type`. It seems that there's no need to send these headers in the first place. The curret version is able to show the status dashboard for the ucurrent job in both Zuul v2 and Zuul v3. In v2, links point to individual job's logs. For v3, they go to a not-that-useful page with job description. That will be fixed later. I also plan to expand this a bit for Zuul v3 because it supports querying build results even after all jobs have concluded. I hope to offer a nice and simple but persistent indication of job results so that one could configure PolyGerrit to hide bot's comments by default, only relying on the zuul-status' output as a result matrix. That's future work, though. Change-Id: I93b4d6fcd7c312ddc543bff42522c82be77d7a76
diff --git a/src/main/java/com/googlesource/gerrit/plugins/zuulstatus/GetConfig.java b/src/main/java/com/googlesource/gerrit/plugins/zuulstatus/GetConfig.java index dae676d..1622755 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/zuulstatus/GetConfig.java +++ b/src/main/java/com/googlesource/gerrit/plugins/zuulstatus/GetConfig.java
@@ -16,28 +16,38 @@ import com.google.gerrit.extensions.annotations.PluginName; import com.google.gerrit.extensions.restapi.RestReadView; -import com.google.gerrit.server.config.ConfigResource; import com.google.gerrit.server.config.PluginConfig; import com.google.gerrit.server.config.PluginConfigFactory; +import com.google.gerrit.server.project.NoSuchProjectException; +import com.google.gerrit.server.project.ProjectResource; import com.google.inject.Inject; +import com.google.inject.Singleton; -public class GetConfig implements RestReadView<ConfigResource> { +@Singleton +public class GetConfig implements RestReadView<ProjectResource> { - private final PluginConfig cfg; + private final PluginConfigFactory config; + private final String pluginName; @Inject public GetConfig(PluginConfigFactory cfgFactory, @PluginName String pluginName) { - this.cfg = cfgFactory.getFromGerritConfig(pluginName); + this.config = cfgFactory; + this.pluginName = pluginName; } @Override - public ConfigInfo apply(ConfigResource resource) { + public ConfigInfo apply(ProjectResource project) throws NoSuchProjectException { + PluginConfig cfg = config.getFromProjectConfigWithInheritance( + project.getNameKey(), pluginName); + ConfigInfo info = new ConfigInfo(); - info.zuulUrl = cfg.getString("zuulUrl", null); + info.zuulUrl = cfg.getString("url", null); + info.zuulTenant = cfg.getString("tenant", null); return info; } public static class ConfigInfo { String zuulUrl; + String zuulTenant; } }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/zuulstatus/Module.java b/src/main/java/com/googlesource/gerrit/plugins/zuulstatus/Module.java index e2e3d91..59dcff6 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/zuulstatus/Module.java +++ b/src/main/java/com/googlesource/gerrit/plugins/zuulstatus/Module.java
@@ -14,26 +14,30 @@ package com.googlesource.gerrit.plugins.zuulstatus; -import static com.google.gerrit.server.config.ConfigResource.CONFIG_KIND; +import static com.google.gerrit.server.project.ProjectResource.PROJECT_KIND; +import com.google.gerrit.extensions.annotations.Exports; import com.google.gerrit.extensions.registration.DynamicSet; import com.google.gerrit.extensions.restapi.RestApiModule; import com.google.gerrit.extensions.webui.JavaScriptPlugin; import com.google.gerrit.extensions.webui.WebUiPlugin; -import com.google.inject.AbstractModule; +import com.google.gerrit.server.config.ProjectConfigEntry; -public class Module extends AbstractModule { +public class Module extends RestApiModule { @Override protected void configure() { - install( - new RestApiModule() { - @Override - protected void configure() { - get(CONFIG_KIND, "config").to(GetConfig.class); - } - }); - DynamicSet.bind(binder(), WebUiPlugin.class) .toInstance(new JavaScriptPlugin("zuul-status.html")); + + get(PROJECT_KIND, "config").to(GetConfig.class); + + // TODO: these annotations only apply to GWT UIs... + bind(ProjectConfigEntry.class) + .annotatedWith(Exports.named("url")) + .toInstance(new ProjectConfigEntry("Top-level Zuul URL", null)); + + bind(ProjectConfigEntry.class) + .annotatedWith(Exports.named("tenant")) + .toInstance(new ProjectConfigEntry("Zuul v3 tenant name -- leave empty on Zuul v2", null)); } }
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md index 3dacbe1..2babffe 100644 --- a/src/main/resources/Documentation/config.md +++ b/src/main/resources/Documentation/config.md
@@ -1,15 +1,39 @@ Configuration ============= -The configuration of the @PLUGIN@ plugin is done in the `gerrit.config` -file. +The configuration of the @PLUGIN@ plugin is done via the `project.config` +stored in each project's `refs/meta/config` branch. Configuration is subject to +inheritance from parent projects as per usual rules. + +Zuul v2: +-------- + +Specify path including the API subdirectory: ``` [plugin "@PLUGIN@"] -zuulUrl = https://example.org/zuul/status/change/ +url = https://example.org/zuul-v2/status/change/ +``` + +Zuul v3: +-------- + +Zuul v3 added support for multi-tenancy. The `url` contains just the root path +of the Zuul web application. Use the `tenant` to set the tenant name: + +``` +[plugin "@PLUGIN@"] +url = https://zuul.example.org/ +tenant = public ``` <a id="show-zuul-url"> -`plugin.@PLUGIN@.zuulUrl` -: Url to zuul api. +`plugin.@PLUGIN@.url` +: URL to Zuul's root (for Zuul v3), or an URL to Zuul v2's API. +By default not set. + +<a id="show-zuul-tenant"> +`plugin.@PLUGIN@.tenant` +: Tenant name to be used within Zuul. +Leave this unset on Zuul v2. Set this to a valid tenant name if using Zuul v3. By default not set.
diff --git a/src/main/resources/static/zuul-status-view.js b/src/main/resources/static/zuul-status-view.js index de873ae..b10dec7 100644 --- a/src/main/resources/static/zuul-status-view.js +++ b/src/main/resources/static/zuul-status-view.js
@@ -62,6 +62,10 @@ is: 'zuul-status-view', properties: { zuulUrl: String, + zuulTenant: { + type: String, + value: null, + }, plugin: Object, change: Object, revision: { @@ -118,12 +122,19 @@ this.set('zuulDisable', false); } - const config = await this.getConfig(); + const project = this.change.project; + const plugin = this.plugin.getPluginName(); + const config = await this.getConfig(project, plugin); if (config && config.zuul_url) { this.zuulUrl = config.zuul_url; + if (config.zuul_tenant) { + this.zuulTenant = config.zuul_tenant; + console.info(`zuul-status: Zuul v3 at ${this.zuulUrl}, tenant ${this.zuulTenant}`); + } else { + console.info(`zuul-status: Zuul v2 at ${this.zuulUrl}`); + } } else { - console.info("No config found for plugin zuul-status at endpoint " + - "/config/server/info"); + console.info("No config found for plugin zuul-status"); } if (this.zuulUrl) { await this._update(); @@ -136,8 +147,10 @@ * @return {Promise} Resolves to the fetched config object, * or rejects if the response is non-OK. */ - async getConfig() { - return await this.plugin.restApi().get('/config/server/config'); + async getConfig(project, plugin) { + return await this.plugin.restApi().get( + `/projects/${encodeURIComponent(project)}` + + `/${encodeURIComponent(plugin)}~config`); }, /** @@ -191,10 +204,10 @@ * @return {Promise} Resolves to a fetch Response object. */ async _getReponse(change, revision) { - const url = `${this.zuulUrl}${change._number},${revision._number}` + const url = this.zuulTenant === null ? + `${this.zuulUrl}${change._number},${revision._number}` : + `${this.zuulUrl}/api/tenant/${this.zuulTenant}/status/change/${change._number},${revision._number}`; const options = {method: 'GET'}; - options.headers = new Headers(); - options.headers.set('Content-Type', 'application/json'); return await fetch(url, options); },