Merge branch 'stable-3.8'
* stable-3.8:
Add support for virtual host based wizard flow
Change-Id: I260557af0d3bd4ee35d3373ae010f6026f72ed07
diff --git a/github-plugin/pom.xml b/github-plugin/pom.xml
index cc410e6..b77cd4e 100644
--- a/github-plugin/pom.xml
+++ b/github-plugin/pom.xml
@@ -157,5 +157,13 @@
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.truth</groupId>
+ <artifactId>truth</artifactId>
+ </dependency>
</dependencies>
</project>
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GitHubConfig.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GitHubConfig.java
index 010660e..a22126d 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GitHubConfig.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GitHubConfig.java
@@ -14,25 +14,25 @@
package com.googlesource.gerrit.plugins.github;
import com.google.common.base.MoreObjects;
-import com.google.common.collect.Maps;
+import com.google.common.collect.HashBasedTable;
+import com.google.common.collect.Table;
import com.google.gerrit.entities.Account;
import com.google.gerrit.httpd.CanonicalWebUrl;
-import com.google.gerrit.server.config.AllProjectsNameProvider;
+import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.SitePaths;
import com.google.inject.Inject;
+import com.google.inject.Provider;
import com.google.inject.Singleton;
import com.googlesource.gerrit.plugins.github.oauth.GitHubOAuthConfig;
import java.net.MalformedURLException;
import java.nio.file.Path;
-import java.util.HashMap;
import org.eclipse.jgit.lib.Config;
@Singleton
public class GitHubConfig extends GitHubOAuthConfig {
private static final String CONF_WIZARD_FLOW = "wizardFlow";
- private HashMap<String, NextPage> wizardFromTo = Maps.newHashMap();
private static final String FROM_TO_SEPARATOR = "=>";
private static final String FROM_TO_REDIRECT_SEPARATOR = "R>";
private static final String CONF_JOB_POOL_LIMIT = "jobPoolLimit";
@@ -45,6 +45,7 @@
private static final String CONF_WEBHOOK_SECRET = "webhookSecret";
private static final String CONF_WEBHOOK_USER = "webhookUser";
private static final String CONF_IMPORT_ACCOUNT_ID = "importAccountId";
+ private static final String DEFAULT_SERVER = "default";
public final Path gitDir;
public final int jobPoolLimit;
@@ -58,6 +59,7 @@
public final String webhookSecret;
public final String webhookUser;
public final Account.Id importAccountId;
+ private final Table<String, String, NextPage> wizardFromTo = HashBasedTable.create();
public static class NextPage {
public final String uri;
@@ -73,19 +75,15 @@
public GitHubConfig(
@GerritServerConfig Config config,
final SitePaths site,
- AllProjectsNameProvider allProjectsNameProvider,
+ Provider<AllProjectsName> allProjectsNameProvider,
CanonicalWebUrl canonicalWebUrl)
throws MalformedURLException {
super(config, canonicalWebUrl);
- String[] wizardFlows = config.getStringList(CONF_SECTION, null, CONF_WIZARD_FLOW);
- for (String fromTo : wizardFlows) {
- boolean redirect = fromTo.indexOf(FROM_TO_REDIRECT_SEPARATOR) > 0;
- int sepPos = getSepPos(fromTo, redirect);
- String fromPage = fromTo.substring(0, sepPos).trim();
- NextPage toPage =
- new NextPage(
- fromTo.substring(sepPos + getSeparator(redirect).length() + 1).trim(), redirect);
- wizardFromTo.put(fromPage, toPage);
+ parseWizardFlow(config.getStringList(CONF_SECTION, null, CONF_WIZARD_FLOW), DEFAULT_SERVER);
+
+ // Virtual host specific sections
+ for (String server : config.getSubsections(CONF_SECTION)) {
+ parseWizardFlow(config.getStringList(CONF_SECTION, server, CONF_WIZARD_FLOW), server);
}
jobPoolLimit = config.getInt(CONF_SECTION, CONF_JOB_POOL_LIMIT, 5);
@@ -107,12 +105,24 @@
importAccountId = Account.id(config.getInt(CONF_SECTION, CONF_IMPORT_ACCOUNT_ID, 1000000));
}
- private String getSeparator(boolean redirect) {
+ private void parseWizardFlow(String[] wizardFlows, String server) {
+ for (String fromTo : wizardFlows) {
+ boolean redirect = fromTo.indexOf(FROM_TO_REDIRECT_SEPARATOR) > 0;
+ int sepPos = getSepPos(fromTo, redirect);
+ String fromPage = fromTo.substring(0, sepPos).trim();
+ NextPage toPage =
+ new NextPage(
+ fromTo.substring(sepPos + getSeparator(redirect).length() + 1).trim(), redirect);
+ wizardFromTo.put(server, fromPage, toPage);
+ }
+ }
+
+ private static String getSeparator(boolean redirect) {
String separator = redirect ? FROM_TO_REDIRECT_SEPARATOR : FROM_TO_SEPARATOR;
return separator;
}
- private int getSepPos(String fromTo, boolean redirect) {
+ private static int getSepPos(String fromTo, boolean redirect) {
int sepPos = fromTo.indexOf(getSeparator(redirect));
if (sepPos < 0) {
throw new InvalidGitHubConfigException(fromTo);
@@ -120,8 +130,11 @@
return sepPos;
}
- public NextPage getNextPage(String sourcePage) {
- return wizardFromTo.get(sourcePage);
+ public NextPage getNextPage(String serverName, String sourcePage) {
+ if (!wizardFromTo.containsRow(serverName)) {
+ return wizardFromTo.get(DEFAULT_SERVER, sourcePage);
+ }
+ return wizardFromTo.get(serverName, sourcePage);
}
public String getBaseProject(boolean isPrivateProject) {
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/wizard/VelocityControllerServlet.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/wizard/VelocityControllerServlet.java
index 845399e..224fbb5 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/wizard/VelocityControllerServlet.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/wizard/VelocityControllerServlet.java
@@ -125,7 +125,7 @@
if (queryStringStart > 0) {
sourcePage = sourcePage.substring(0, queryStringStart);
}
- NextPage nextPage = githubConfig.getNextPage(sourcePage);
+ NextPage nextPage = githubConfig.getNextPage(req.getServerName(), sourcePage);
if (nextPage != null) {
if (nextPage.redirect) {
resp.sendRedirect(nextPageURL(sourcePath, nextPage));
diff --git a/github-plugin/src/main/resources/Documentation/config.md b/github-plugin/src/main/resources/Documentation/config.md
index e2ea0a3..c9eebc5 100644
--- a/github-plugin/src/main/resources/Documentation/config.md
+++ b/github-plugin/src/main/resources/Documentation/config.md
@@ -95,6 +95,40 @@
* h, hr, hour, hours
Default value: 30 seconds
+github.wizardFlow
+: Define the transition from one page to another during the initial
+ user setup wizard flow. The format of the value is the following:
+ `page => next page` or `page R> next page` for redirections.
+
+ The example below shows an initial wizard that guides through
+ the import of repositories, pull-requests and then redirects
+ to the Gerrit projects admin page.
+
+ **Example:**
+ ```
+ wizardFlow = account.gh => repositories.html
+ wizardFlow = repositories-next.gh => pullrequests.html
+ wizardFlow = pullrequests-next.gh R> / #/admin/projects/
+ ```
+
+github.<domain>.wizardFlow
+: Allow to customise the GitHub wizard flow for the domain `<domain>`.
+ This setting is useful for multi-site setups where the GitHub
+ import Wizard can be different between sites.
+
+ The example below shows an initial wizard that guides through
+ the import of repositories for all sites, but redirects to
+ the Eclipse ECA sign page for the `eclipse.gerrithub.io` site.
+
+ **Example:**
+ ```
+ [github]
+ wizardFlow = account.gh => repositories.html
+
+ [github "eclipse.gerrithub.io"]
+ wizardFlow = account.gh R> eclipse-eca.html
+ ```
+
Key Configuration
-------------
diff --git a/github-plugin/src/test/java/com/googlesource/gerrit/plugins/github/GitHubConfigTest.java b/github-plugin/src/test/java/com/googlesource/gerrit/plugins/github/GitHubConfigTest.java
new file mode 100644
index 0000000..56f7b90
--- /dev/null
+++ b/github-plugin/src/test/java/com/googlesource/gerrit/plugins/github/GitHubConfigTest.java
@@ -0,0 +1,122 @@
+// Copyright (C) 2023 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.googlesource.gerrit.plugins.github;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.gerrit.server.config.AllProjectsName;
+import com.google.gerrit.server.config.SitePaths;
+import com.google.inject.Provider;
+import com.google.inject.util.Providers;
+import java.nio.file.Path;
+import org.eclipse.jgit.lib.Config;
+import org.junit.Before;
+import org.junit.Test;
+
+public class GitHubConfigTest {
+ private static final Provider<AllProjectsName> ALL_PROJECTS_NAME_PROVIDER =
+ Providers.of(new AllProjectsName("All-Projects"));
+ public static final String TEST_DOMAIN = "anydomain.com";
+ public static final String SOURCE_PAGE = "sourcePage";
+ public static final String NEXT_PAGE = "nextPage";
+ public static final String CUSTOM_NEXT_PAGE = "customNextPage";
+ private SitePaths site;
+
+ @Before
+ public void setup() throws Exception {
+ site = new SitePaths(Path.of("/tmp"));
+ }
+
+ @Test
+ public void getNextPageDefault() throws Exception {
+ GitHubConfig.NextPage nextPage =
+ newGitHubConfig("wizardFlow = " + SOURCE_PAGE + " => " + NEXT_PAGE)
+ .getNextPage(TEST_DOMAIN, SOURCE_PAGE);
+
+ assertThat(nextPage.redirect).isFalse();
+ assertThat(nextPage.uri).isEqualTo(NEXT_PAGE);
+ }
+
+ @Test
+ public void getNextPageRedirectDefault() throws Exception {
+ GitHubConfig.NextPage nextPage =
+ newGitHubConfig("wizardFlow = " + SOURCE_PAGE + " R> " + NEXT_PAGE)
+ .getNextPage(TEST_DOMAIN, SOURCE_PAGE);
+
+ assertThat(nextPage.redirect).isTrue();
+ assertThat(nextPage.uri).isEqualTo(NEXT_PAGE);
+ }
+
+ @Test
+ public void getNextPageByDomain() throws Exception {
+ GitHubConfig.NextPage nextPage =
+ newGitHubConfig(
+ "wizardFlow = "
+ + SOURCE_PAGE
+ + " => "
+ + NEXT_PAGE
+ + "\n"
+ + "[github \""
+ + TEST_DOMAIN
+ + "\"]\n"
+ + "wizardFlow = "
+ + SOURCE_PAGE
+ + " => "
+ + CUSTOM_NEXT_PAGE)
+ .getNextPage(TEST_DOMAIN, SOURCE_PAGE);
+
+ assertThat(nextPage.redirect).isFalse();
+ assertThat(nextPage.uri).isEqualTo(CUSTOM_NEXT_PAGE);
+ }
+
+ @Test
+ public void getNextPageRedirectByDomain() throws Exception {
+ GitHubConfig.NextPage nextPage =
+ newGitHubConfig(
+ "wizardFlow = "
+ + SOURCE_PAGE
+ + " R> "
+ + CUSTOM_NEXT_PAGE
+ + "\n"
+ + "[github \""
+ + TEST_DOMAIN
+ + "\"]\n"
+ + "wizardFlow = \""
+ + SOURCE_PAGE
+ + "\" R> "
+ + CUSTOM_NEXT_PAGE)
+ .getNextPage(TEST_DOMAIN, SOURCE_PAGE);
+
+ assertThat(nextPage.redirect).isTrue();
+ assertThat(nextPage.uri).isEqualTo(CUSTOM_NEXT_PAGE);
+ }
+
+ private GitHubConfig newGitHubConfig(String configText) throws Exception {
+ Config gerritConfig = new Config();
+ gerritConfig.fromText(
+ "[auth]\n"
+ + "httpHeader = GITHUB\n"
+ + "type = HTTP\n"
+ + "[gerrit]\n"
+ + "basePath = /tmp\n"
+ + "[github-key \"default\"]\n"
+ + "current = true\n"
+ + "passwordDevice = /dev/zero\n"
+ + "[github]\n"
+ + "clientId = myclientid\n"
+ + "clientSecret = mysecret\n"
+ + configText);
+ return new GitHubConfig(gerritConfig, site, ALL_PROJECTS_NAME_PROVIDER, null);
+ }
+}
diff --git a/pom.xml b/pom.xml
index 326ce5c..5d6b07e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -310,6 +310,12 @@
<version>4.13.2</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>com.google.truth</groupId>
+ <artifactId>truth</artifactId>
+ <version>1.1.4</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</dependencyManagement>
</project>