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>