Merge branch 'stable-3.8' into stable-3.9
* stable-3.8:
GitHubOAuthConfigTest: Reformat the code using google-java-format
Build github plugin against the v3.8.0-rc5 Gerrit API
PullRequestCreateChange: Remove unused import
Set plugin version to 3.4.7
Fire git ref update events for all imported refs
PluginVelocityRuntimeProvider: Fix warning flagged by error prone
Fix default scopes resolution
Change-Id: Ifd589f9099f27ad59790e44f4cbca3f39327a767
diff --git a/README.md b/README.md
index 5a95019..c497a89 100644
--- a/README.md
+++ b/README.md
@@ -78,13 +78,13 @@
Gerrit 3.3 is distributed for Java 11 only. However, the source code is compatible
with Java 8 assuming you build it from the source repository by yourself.
-The GitHub plugin can be built for Java 8 by using the `javaVersion=1.8` Maven
+The GitHub plugin can be built for Java 17 by using the `javaVersion=1.17` Maven
parameter.
Example:
git clone https://gerrit.googlesource.com/plugins/github
cd github
- mvn -DjavaVersion=1.8 install
+ mvn -DjavaVersion=17 install
### singleusergroup plugin
@@ -136,9 +136,10 @@
* GitHub Integration
* GitHub URL: [https://github.com]: <confirm>
-* Use GitHub for Gerrit login? [Y/n] Y
+* GitHub API URL: [https://api.github.com]: <confirm>
* ClientId []: <provided client id from previous step>
* ClientSecret []: <provided client secret from previous step>
+* Gerrit OAuth implementation [http/?]: <http or oauth>
### Receiving Pull Request events to automatically import
@@ -195,4 +196,4 @@
refs/for/foo, refs/meta/bar
```
-More information on Gerrit magic refs can be found [here](https://gerrit-review.googlesource.com/Documentation/intro-user.html#upload-change)
\ No newline at end of file
+More information on Gerrit magic refs can be found [here](https://gerrit-review.googlesource.com/Documentation/intro-user.html#upload-change)
diff --git a/github-oauth/pom.xml b/github-oauth/pom.xml
index 75b9c09..d027b61 100644
--- a/github-oauth/pom.xml
+++ b/github-oauth/pom.xml
@@ -21,7 +21,7 @@
<parent>
<groupId>com.googlesource.gerrit.plugins.github</groupId>
<artifactId>github-parent</artifactId>
- <version>3.8.0</version>
+ <version>3.9.0-rc5</version>
</parent>
<artifactId>github-oauth</artifactId>
<name>Gerrit Code Review - GitHub OAuth login</name>
@@ -71,35 +71,35 @@
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
- <version>3.0.1</version>
+ <version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
- <version>4.1.0</version>
+ <version>6.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
- <version>20.0</version>
+ <version>32.1.2-jre</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.kohsuke</groupId>
<artifactId>github-api</artifactId>
- <version>1.116</version>
+ <version>1.316</version>
</dependency>
<dependency>
<groupId>com.infradna.tool</groupId>
<artifactId>bridge-method-injector</artifactId>
- <version>1.18</version>
+ <version>1.29</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
- <version>4.4</version>
+ <version>4.5.2</version>
<scope>provided</scope>
</dependency>
<dependency>
diff --git a/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/CanonicalWebUrls.java b/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/CanonicalWebUrls.java
new file mode 100644
index 0000000..faca0f9
--- /dev/null
+++ b/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/CanonicalWebUrls.java
@@ -0,0 +1,54 @@
+// 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.oauth;
+
+import static com.googlesource.gerrit.plugins.github.oauth.GitHubOAuthConfig.GERRIT_OAUTH_FINAL;
+import static com.googlesource.gerrit.plugins.github.oauth.GitHubOAuthConfig.GITHUB_PLUGIN_OAUTH_SCOPE;
+
+import com.google.common.base.CharMatcher;
+import com.google.common.base.MoreObjects;
+import com.google.gerrit.httpd.HttpCanonicalWebUrlProvider;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+@Singleton
+public class CanonicalWebUrls {
+ private final GitHubOAuthConfig oauthConf;
+ private final HttpCanonicalWebUrlProvider canonicalWebUrlProvider;
+
+ static String trimTrailingSlash(String url) {
+ return CharMatcher.is('/').trimTrailingFrom(url);
+ }
+
+ @Inject
+ CanonicalWebUrls(
+ GitHubOAuthConfig oauthConf, HttpCanonicalWebUrlProvider canonicalWebUrlProvider) {
+ this.oauthConf = oauthConf;
+ this.canonicalWebUrlProvider = canonicalWebUrlProvider;
+ }
+
+ public String getScopeSelectionUrl() {
+ return getCannonicalWebUrl()
+ + MoreObjects.firstNonNull(oauthConf.scopeSelectionUrl, GITHUB_PLUGIN_OAUTH_SCOPE);
+ }
+
+ String getOAuthFinalRedirectUrl() {
+ return getCannonicalWebUrl() + GERRIT_OAUTH_FINAL;
+ }
+
+ private String getCannonicalWebUrl() {
+ return trimTrailingSlash(canonicalWebUrlProvider.get());
+ }
+}
diff --git a/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/GitHubLogin.java b/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/GitHubLogin.java
index ece944d..02889a1 100644
--- a/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/GitHubLogin.java
+++ b/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/GitHubLogin.java
@@ -38,7 +38,9 @@
import org.kohsuke.github.GHMyself;
import org.kohsuke.github.GitHub;
import org.kohsuke.github.GitHubBuilder;
-import org.kohsuke.github.HttpConnector;
+import org.kohsuke.github.HttpException;
+import org.kohsuke.github.connector.GitHubConnector;
+import org.kohsuke.github.internal.GitHubConnectorHttpConnectorAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -63,7 +65,9 @@
private SortedSet<Scope> loginScopes;
private final GitHubOAuthConfig config;
- private final HttpConnector httpConnector;
+ private final CanonicalWebUrls canonicalWebUrls;
+ private final VirtualDomainConfig virtualDomainConfig;
+ private final GitHubConnector gitHubConnector;
public GHMyself getMyself() throws IOException {
if (isLoggedIn()) {
@@ -72,17 +76,35 @@
return null;
}
- public Set<String> getMyOrganisationsLogins() throws IOException {
+ public Set<String> getMyOrganisationsLogins(String username) throws IOException {
if (isLoggedIn()) {
- return getHub().getMyOrganizations().keySet();
+ try {
+ return getHub().getMyOrganizations().keySet();
+ } catch (HttpException httpException) {
+ if (!httpException.getMessage().contains("You need at least")) {
+ throw httpException;
+ }
+ log.info(
+ "Cannot access organizations for user '{}': falling back to list of public"
+ + " organisations",
+ username);
+
+ return getHub().getUserPublicOrganizations(username).keySet();
+ }
}
return Collections.emptySet();
}
@Inject
- public GitHubLogin(GitHubOAuthConfig config, GitHubHttpConnector httpConnector) {
+ public GitHubLogin(
+ GitHubOAuthConfig config,
+ CanonicalWebUrls canonicalWebUrls,
+ VirtualDomainConfig virutalDomainConfig,
+ GitHubHttpConnector httpConnector) {
this.config = config;
- this.httpConnector = httpConnector;
+ this.canonicalWebUrls = canonicalWebUrls;
+ this.virtualDomainConfig = virutalDomainConfig;
+ this.gitHubConnector = GitHubConnectorHttpConnectorAdapter.adapt(httpConnector);
}
public boolean isLoggedIn() {
@@ -107,12 +129,13 @@
response.sendRedirect(OAuthProtocol.getTargetUrl(request));
}
} else {
- Set<ScopeKey> configuredScopesProfiles = config.scopes.keySet();
+ Set<ScopeKey> configuredScopesProfiles = virtualDomainConfig.getScopes(request).keySet();
String scopeRequested = getScopesKey(request, response);
if (Strings.isNullOrEmpty(scopeRequested) && configuredScopesProfiles.size() > 1) {
- response.sendRedirect(config.getScopeSelectionUrl(request));
+ response.sendRedirect(canonicalWebUrls.getScopeSelectionUrl());
} else {
- this.loginScopes = getScopes(MoreObjects.firstNonNull(scopeRequested, "scopes"), scopes);
+ this.loginScopes =
+ getScopes(request, MoreObjects.firstNonNull(scopeRequested, "scopes"), scopes);
log.debug("Login-PHASE1 " + this);
state = oauth.loginPhase1(request, response, loginScopes);
}
@@ -141,7 +164,7 @@
return new GitHubBuilder()
.withEndpoint(config.gitHubApiUrl)
.withOAuthToken(token.accessToken)
- .withConnector(httpConnector)
+ .withConnector(gitHubConnector)
.build();
}
@@ -178,15 +201,15 @@
return null;
}
- private SortedSet<Scope> getScopes(String baseScopeKey, Scope... scopes) {
- HashSet<Scope> fullScopes = new HashSet<>(scopesForKey(baseScopeKey));
+ private SortedSet<Scope> getScopes(HttpServletRequest req, String baseScopeKey, Scope... scopes) {
+ HashSet<Scope> fullScopes = new HashSet<>(scopesForKey(req, baseScopeKey));
fullScopes.addAll(Arrays.asList(scopes));
return new TreeSet<>(fullScopes);
}
- private List<Scope> scopesForKey(String baseScopeKey) {
- return config.scopes.entrySet().stream()
+ private List<Scope> scopesForKey(HttpServletRequest req, String baseScopeKey) {
+ return virtualDomainConfig.getScopes(req).entrySet().stream()
.filter(entry -> entry.getKey().name.equals(baseScopeKey))
.map(entry -> entry.getValue())
.findFirst()
diff --git a/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/GitHubOAuthConfig.java b/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/GitHubOAuthConfig.java
index 19eebf2..300a945 100644
--- a/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/GitHubOAuthConfig.java
+++ b/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/GitHubOAuthConfig.java
@@ -13,14 +13,14 @@
// limitations under the License.
package com.googlesource.gerrit.plugins.github.oauth;
+import static com.googlesource.gerrit.plugins.github.oauth.CanonicalWebUrls.trimTrailingSlash;
import static com.googlesource.gerrit.plugins.github.oauth.GitHubOAuthConfig.KeyConfig.PASSWORD_DEVICE_CONFIG_LABEL;
-import com.google.common.base.CharMatcher;
import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableSortedMap;
import com.google.gerrit.extensions.client.AuthType;
-import com.google.gerrit.httpd.CanonicalWebUrl;
import com.google.gerrit.server.config.ConfigUtil;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.inject.Inject;
@@ -35,17 +35,16 @@
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import java.util.SortedMap;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
-import javax.servlet.http.HttpServletRequest;
import lombok.Getter;
import org.eclipse.jgit.lib.Config;
@Singleton
public class GitHubOAuthConfig {
private final Config config;
- private final CanonicalWebUrl canonicalWebUrl;
public static final String CONF_SECTION = "github";
public static final String CONF_KEY_SECTION = "github-key";
@@ -67,10 +66,11 @@
public final String httpHeader;
public final String gitHubOAuthUrl;
public final String gitHubOAuthAccessTokenUrl;
+ public final String scopeSelectionUrl;
public final boolean enabled;
- @Getter public final Map<ScopeKey, List<OAuthProtocol.Scope>> scopes;
- @Getter public final List<ScopeKey> sortedScopesKeys;
+ @Getter public final SortedMap<ScopeKey, List<OAuthProtocol.Scope>> scopes;
+ @Getter public final Map<String, SortedMap<ScopeKey, List<OAuthProtocol.Scope>>> virtualScopes;
public final int fileUpdateMaxRetryCount;
public final int fileUpdateMaxRetryIntervalMsec;
@@ -83,9 +83,8 @@
private final Optional<String> cookieDomain;
@Inject
- protected GitHubOAuthConfig(@GerritServerConfig Config config, CanonicalWebUrl canonicalWebUrl) {
+ protected GitHubOAuthConfig(@GerritServerConfig Config config) {
this.config = config;
- this.canonicalWebUrl = canonicalWebUrl;
httpHeader =
Preconditions.checkNotNull(
@@ -106,6 +105,7 @@
Preconditions.checkNotNull(
config.getString(CONF_SECTION, null, "clientSecret"),
"GitHub `clientSecret` must be provided");
+ scopeSelectionUrl = config.getString(CONF_SECTION, null, "scopeSelectionUrl");
oauthHttpHeader = config.getString("auth", null, "httpExternalIdHeader");
gitHubOAuthUrl = gitHubUrl + GITHUB_OAUTH_AUTHORIZE;
@@ -115,10 +115,7 @@
enabled = config.getString("auth", null, "type").equalsIgnoreCase(AuthType.HTTP.toString());
cookieDomain = Optional.ofNullable(config.getString("auth", null, "cookieDomain"));
scopes = getScopes(config);
- sortedScopesKeys =
- scopes.keySet().stream()
- .sorted(Comparator.comparing(ScopeKey::getSequence))
- .collect(Collectors.toList());
+ virtualScopes = getVirtualScopes(config);
fileUpdateMaxRetryCount = config.getInt(CONF_SECTION, "fileUpdateMaxRetryCount", 3);
fileUpdateMaxRetryIntervalMsec =
@@ -152,36 +149,29 @@
currentKeyConfig = currentKeyConfigs.get(0);
}
- public String getOAuthFinalRedirectUrl(HttpServletRequest req) {
- return req == null
- ? GERRIT_OAUTH_FINAL
- : trimTrailingSlash(canonicalWebUrl.get(req)) + GERRIT_OAUTH_FINAL;
+ private SortedMap<ScopeKey, List<Scope>> getScopes(Config config) {
+ return getScopesInSection(config, null);
}
- public String getScopeSelectionUrl(HttpServletRequest req) {
- String canonicalUrl = req == null ? "" : trimTrailingSlash(canonicalWebUrl.get(req));
- return canonicalUrl
- + MoreObjects.firstNonNull(
- config.getString(CONF_SECTION, null, "scopeSelectionUrl"), GITHUB_PLUGIN_OAUTH_SCOPE);
+ private Map<String, SortedMap<ScopeKey, List<Scope>>> getVirtualScopes(Config config) {
+ return config.getSubsections(CONF_SECTION).stream()
+ .collect(Collectors.toMap(k -> k, v -> getScopesInSection(config, v)));
}
- private Map<ScopeKey, List<Scope>> getScopes(Config config) {
- return config.getNames(CONF_SECTION, true).stream()
+ private SortedMap<ScopeKey, List<Scope>> getScopesInSection(Config config, String subsection) {
+ return config.getNames(CONF_SECTION, subsection, true).stream()
.filter(k -> k.startsWith("scopes"))
.filter(k -> !k.endsWith("Description"))
.filter(k -> !k.endsWith("Sequence"))
.collect(
- Collectors.toMap(
+ ImmutableSortedMap.toImmutableSortedMap(
+ Comparator.comparing(ScopeKey::getSequence),
k ->
new ScopeKey(
k,
- config.getString(CONF_SECTION, null, k + "Description"),
- config.getInt(CONF_SECTION, k + "Sequence", 0)),
- v -> parseScopesString(config.getString(CONF_SECTION, null, v))));
- }
-
- private String trimTrailingSlash(String url) {
- return CharMatcher.is('/').trimTrailingFrom(url);
+ config.getString(CONF_SECTION, subsection, k + "Description"),
+ config.getInt(CONF_SECTION, subsection, k + "Sequence", 0)),
+ v -> parseScopesString(config.getString(CONF_SECTION, subsection, v))));
}
private List<Scope> parseScopesString(String scopesString) {
diff --git a/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/IdentifiedUserGitHubLoginProvider.java b/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/IdentifiedUserGitHubLoginProvider.java
index 5449347..63414b2 100644
--- a/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/IdentifiedUserGitHubLoginProvider.java
+++ b/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/IdentifiedUserGitHubLoginProvider.java
@@ -36,23 +36,20 @@
ExternalId.SCHEME_EXTERNAL + ":" + OAuthWebFilter.GITHUB_EXT_ID;
private final Provider<IdentifiedUser> userProvider;
- private final GitHubOAuthConfig config;
private final AccountCache accountCache;
- private final GitHubHttpConnector httpConnector;
private final OAuthTokenCipher oAuthTokenCipher;
+ private final Provider<GitHubLogin> gitHubLoginProvider;
@Inject
public IdentifiedUserGitHubLoginProvider(
+ Provider<GitHubLogin> gitHubLoginaprovider,
Provider<IdentifiedUser> identifiedUserProvider,
- GitHubOAuthConfig config,
- GitHubHttpConnector httpConnector,
AccountCache accountCache,
OAuthTokenCipher oAuthTokenCipher) {
this.userProvider = identifiedUserProvider;
- this.config = config;
this.accountCache = accountCache;
- this.httpConnector = httpConnector;
this.oAuthTokenCipher = oAuthTokenCipher;
+ this.gitHubLoginProvider = gitHubLoginaprovider;
}
@Override
@@ -67,7 +64,7 @@
try {
AccessToken accessToken = newAccessTokenFromUser(username);
if (accessToken != null) {
- GitHubLogin login = new GitHubLogin(config, httpConnector);
+ GitHubLogin login = gitHubLoginProvider.get();
login.login(accessToken);
return login;
}
diff --git a/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/OAuthProtocol.java b/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/OAuthProtocol.java
index b93837b..035f1ce 100644
--- a/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/OAuthProtocol.java
+++ b/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/OAuthProtocol.java
@@ -155,6 +155,7 @@
private static SecureRandom randomState = newRandomGenerator();
private final GitHubOAuthConfig config;
+ private final CanonicalWebUrls canonicalWebUrls;
private final Gson gson;
private final Provider<HttpClient> httpProvider;
@@ -231,6 +232,7 @@
@Inject
public OAuthProtocol(
GitHubOAuthConfig config,
+ CanonicalWebUrls canonicalWebUrls,
PooledHttpClientProvider httpClientProvider,
/*
* We need to explicitly tell Guice which Provider<> we need as this class
@@ -239,6 +241,7 @@
*/
GsonProvider gsonProvider) {
this.config = config;
+ this.canonicalWebUrls = canonicalWebUrls;
this.httpProvider = httpClientProvider;
this.gson = gsonProvider.get();
}
@@ -256,7 +259,7 @@
+ "?client_id="
+ config.gitHubClientId
+ getURLEncodedParameter("&scope=", scopesString)
- + getURLEncodedParameter("&redirect_uri=", config.getOAuthFinalRedirectUrl(req))
+ + getURLEncodedParameter("&redirect_uri=", canonicalWebUrls.getOAuthFinalRedirectUrl())
+ getURLEncodedParameter("&state=", state);
}
diff --git a/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/OAuthWebFilter.java b/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/OAuthWebFilter.java
index 0bca570..20b80bd 100644
--- a/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/OAuthWebFilter.java
+++ b/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/OAuthWebFilter.java
@@ -131,7 +131,7 @@
String user = myself.getLogin();
updateSecureConfigWithRetry(
- ghLogin.getHub().getMyOrganizations().keySet(), user, ghLogin.getToken().accessToken);
+ ghLogin.getMyOrganisationsLogins(user), user, ghLogin.getToken().accessToken);
}
}
diff --git a/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/VirtualDomainConfig.java b/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/VirtualDomainConfig.java
new file mode 100644
index 0000000..a6b2b17
--- /dev/null
+++ b/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/VirtualDomainConfig.java
@@ -0,0 +1,38 @@
+// 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.oauth;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import java.util.List;
+import java.util.Optional;
+import java.util.SortedMap;
+import javax.servlet.http.HttpServletRequest;
+
+@Singleton
+public class VirtualDomainConfig {
+ private final GitHubOAuthConfig oauthConfig;
+
+ @Inject
+ VirtualDomainConfig(GitHubOAuthConfig oauthConfig) {
+ this.oauthConfig = oauthConfig;
+ }
+
+ public SortedMap<ScopeKey, List<OAuthProtocol.Scope>> getScopes(HttpServletRequest req) {
+ String serverName = req.getServerName();
+ return Optional.ofNullable(oauthConfig.virtualScopes.get(serverName))
+ .orElse(oauthConfig.scopes);
+ }
+}
diff --git a/github-oauth/src/test/java/com/googlesource/gerrit/plugins/github/oauth/GitHubOAuthConfigTest.java b/github-oauth/src/test/java/com/googlesource/gerrit/plugins/github/oauth/GitHubOAuthConfigTest.java
index 6e18170..7a11427 100644
--- a/github-oauth/src/test/java/com/googlesource/gerrit/plugins/github/oauth/GitHubOAuthConfigTest.java
+++ b/github-oauth/src/test/java/com/googlesource/gerrit/plugins/github/oauth/GitHubOAuthConfigTest.java
@@ -22,20 +22,20 @@
import static com.googlesource.gerrit.plugins.github.oauth.GitHubOAuthConfig.KeyConfig.SECRET_KEY_CONFIG_LABEL;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
import com.google.gerrit.extensions.client.AuthType;
-import com.google.gerrit.httpd.CanonicalWebUrl;
-import com.google.inject.AbstractModule;
-import com.google.inject.Guice;
-import com.google.inject.util.Providers;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
import java.util.Optional;
+import java.util.SortedMap;
import org.eclipse.jgit.lib.Config;
import org.junit.Before;
import org.junit.Test;
public class GitHubOAuthConfigTest {
- CanonicalWebUrl canonicalWebUrl;
Config config;
private static final String testPasswordDevice = "/dev/zero";
@@ -46,18 +46,6 @@
config.setString(CONF_SECTION, null, "clientId", "theClientId");
config.setString("auth", null, "httpHeader", "GITHUB_USER");
config.setString("auth", null, "type", AuthType.HTTP.toString());
-
- canonicalWebUrl =
- Guice.createInjector(
- new AbstractModule() {
- @Override
- protected void configure() {
- bind(String.class)
- .annotatedWith(com.google.gerrit.server.config.CanonicalWebUrl.class)
- .toProvider(Providers.of(null));
- }
- })
- .getInstance(CanonicalWebUrl.class);
}
@Test
@@ -180,8 +168,46 @@
assertEquals(Optional.of(myDomain), githubOAuthConfig().getCookieDomain());
}
+ @Test
+ public void shouldReturnOverridesForSpecificHostName() {
+ setupEncryptionConfig();
+ String vhost = "v.host.com";
+ String scope1Name = "scopesRepo";
+ String scope1Description = "repo scope description";
+ String scope2Name = "scopesVHost";
+ String scope2Description = "scope description";
+
+ // virtual host scopes
+ config.setString(CONF_SECTION, vhost, scope2Name, "USER_EMAIL");
+ config.setInt(CONF_SECTION, vhost, scope2Name + "Sequence", 1);
+ config.setString(CONF_SECTION, vhost, scope2Name + "Description", scope2Description);
+ config.setString(CONF_SECTION, vhost, scope1Name, "REPO");
+ config.setInt(CONF_SECTION, vhost, scope1Name + "Sequence", 0);
+ config.setString(CONF_SECTION, vhost, scope1Name + "Description", scope1Description);
+
+ Map<String, SortedMap<ScopeKey, List<OAuthProtocol.Scope>>> virtualScopes =
+ githubOAuthConfig().getVirtualScopes();
+
+ assertTrue(virtualScopes.containsKey(vhost));
+
+ SortedMap<ScopeKey, List<OAuthProtocol.Scope>> vhostConfig = virtualScopes.get(vhost);
+ List<Map.Entry<ScopeKey, List<OAuthProtocol.Scope>>> entries =
+ new ArrayList<>(vhostConfig.entrySet());
+ Map.Entry<ScopeKey, List<OAuthProtocol.Scope>> firstEntry = entries.get(0);
+ Map.Entry<ScopeKey, List<OAuthProtocol.Scope>> secondEntry = entries.get(1);
+
+ assertEquals(firstEntry.getKey().name, scope1Name);
+ assertEquals(firstEntry.getKey().description, scope1Description);
+ assertEquals(firstEntry.getKey().sequence, 0);
+ assertEquals(List.of(OAuthProtocol.Scope.REPO), firstEntry.getValue());
+ assertEquals(secondEntry.getKey().name, scope2Name);
+ assertEquals(secondEntry.getKey().description, scope2Description);
+ assertEquals(secondEntry.getKey().sequence, 1);
+ assertEquals(List.of(OAuthProtocol.Scope.USER_EMAIL), secondEntry.getValue());
+ }
+
private GitHubOAuthConfig githubOAuthConfig() {
- return new GitHubOAuthConfig(config, canonicalWebUrl);
+ return new GitHubOAuthConfig(config);
}
private void setupEncryptionConfig() {
diff --git a/github-oauth/src/test/java/com/googlesource/gerrit/plugins/github/oauth/OAuthTokenCipherTest.java b/github-oauth/src/test/java/com/googlesource/gerrit/plugins/github/oauth/OAuthTokenCipherTest.java
index 3e31d6b..f3dfb71 100644
--- a/github-oauth/src/test/java/com/googlesource/gerrit/plugins/github/oauth/OAuthTokenCipherTest.java
+++ b/github-oauth/src/test/java/com/googlesource/gerrit/plugins/github/oauth/OAuthTokenCipherTest.java
@@ -26,10 +26,6 @@
import static org.junit.Assert.assertThrows;
import com.google.gerrit.extensions.client.AuthType;
-import com.google.gerrit.httpd.CanonicalWebUrl;
-import com.google.inject.AbstractModule;
-import com.google.inject.Guice;
-import com.google.inject.util.Providers;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
@@ -43,7 +39,6 @@
public class OAuthTokenCipherTest {
- CanonicalWebUrl canonicalWebUrl;
Config config;
@ClassRule public static TemporaryFolder temporaryFolder = new TemporaryFolder();
@@ -63,18 +58,6 @@
CONF_KEY_SECTION, VERSION1_KEY_ID, PASSWORD_DEVICE_CONFIG_LABEL, testPasswordDevice);
config.setString(
CONF_KEY_SECTION, VERSION2_KEY_ID, PASSWORD_DEVICE_CONFIG_LABEL, testPasswordDevice);
-
- canonicalWebUrl =
- Guice.createInjector(
- new AbstractModule() {
- @Override
- protected void configure() {
- bind(String.class)
- .annotatedWith(com.google.gerrit.server.config.CanonicalWebUrl.class)
- .toProvider(Providers.of(null));
- }
- })
- .getInstance(CanonicalWebUrl.class);
}
@Test
@@ -193,7 +176,7 @@
}
private OAuthTokenCipher objectUnderTest(Config testConfig) throws IOException {
- return new OAuthTokenCipher(new GitHubOAuthConfig(testConfig, canonicalWebUrl));
+ return new OAuthTokenCipher(new GitHubOAuthConfig(testConfig));
}
private static Config createCommonConfig() {
diff --git a/github-plugin/.gitignore b/github-plugin/.gitignore
index 80d6257..1080f67 100644
--- a/github-plugin/.gitignore
+++ b/github-plugin/.gitignore
@@ -3,3 +3,6 @@
/.project
/.settings/org.maven.ide.eclipse.prefs
/.settings/org.eclipse.m2e.core.prefs
+/node_modules
+yarn-error.log
+/.rollup.cache
diff --git a/github-plugin/package.json b/github-plugin/package.json
new file mode 100644
index 0000000..209cc44
--- /dev/null
+++ b/github-plugin/package.json
@@ -0,0 +1,20 @@
+{
+ "name": "github-oauth-ui",
+ "description": "UI for the Gerrit GitHub OAuth plugin",
+ "browser": true,
+ "dependencies": {
+ "@gerritcodereview/typescript-api": "^3.8.0",
+ "@lit/ts-transformers": "^1.1.3",
+ "@polymer/polymer": "^3.5.1",
+ "@rollup/plugin-node-resolve": "^15.2.1",
+ "@rollup/plugin-terser": "^0.4.3",
+ "lit": "^2.8.0",
+ "rollup": "^3.29.4",
+ "typescript": "^4.9.5"
+ },
+ "license": "Apache-2.0",
+ "private": true,
+ "scripts": {
+ "build": "tsc && rollup -c"
+ }
+}
diff --git a/github-plugin/pom.xml b/github-plugin/pom.xml
index b77cd4e..1eec4f3 100644
--- a/github-plugin/pom.xml
+++ b/github-plugin/pom.xml
@@ -20,7 +20,7 @@
<parent>
<artifactId>github-parent</artifactId>
<groupId>com.googlesource.gerrit.plugins.github</groupId>
- <version>3.8.0</version>
+ <version>3.9.0-rc5</version>
</parent>
<artifactId>github-plugin</artifactId>
@@ -87,6 +87,57 @@
<goals>
<goal>shade</goal>
</goals>
+ <configuration>
+ <filters>
+ <filter>
+ <!-- is a signed jar hence the singature has to be removed during shading -->
+ <artifact>org.eclipse.mylyn.github:org.eclipse.egit.github.core</artifact>
+ <excludes>
+ <exclude>META-INF/*.SF</exclude>
+ <exclude>META-INF/*.DSA</exclude>
+ <exclude>META-INF/*.RSA</exclude>
+ </excludes>
+ </filter>
+ </filters>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>com.github.eirslett</groupId>
+ <artifactId>frontend-maven-plugin</artifactId>
+ <version>1.14.0</version>
+ <configuration>
+ <installDirectory>target</installDirectory>
+ </configuration>
+ <executions>
+ <execution>
+ <id>install node and yarn</id>
+ <goals>
+ <goal>install-node-and-yarn</goal>
+ </goals>
+ <configuration>
+ <nodeVersion>v17.9.1</nodeVersion>
+ <yarnVersion>v1.22.19</yarnVersion>
+ </configuration>
+ </execution>
+ <execution>
+ <id>yarn install</id>
+ <goals>
+ <goal>yarn</goal>
+ </goals>
+ <configuration>
+ <arguments>install</arguments>
+ </configuration>
+ </execution>
+ <execution>
+ <id>yarn build</id>
+ <goals>
+ <goal>yarn</goal>
+ </goals>
+ <configuration>
+ <arguments>build</arguments>
+ </configuration>
</execution>
</executions>
</plugin>
@@ -101,6 +152,12 @@
<scope>provided</scope>
</dependency>
<dependency>
+ <groupId>com.google.gerrit</groupId>
+ <artifactId>gerrit-acceptance-framework</artifactId>
+ <version>${Gerrit-ApiVersion}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
<groupId>${project.groupId}</groupId>
<artifactId>github-oauth</artifactId>
<version>${project.version}</version>
@@ -108,7 +165,7 @@
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
- <version>3.0.1</version>
+ <version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
@@ -124,33 +181,33 @@
<dependency>
<groupId>org.eclipse.mylyn.github</groupId>
<artifactId>org.eclipse.egit.github.core</artifactId>
- <version>1.3.1</version>
+ <version>6.1.0.202203080745-r</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
- <version>2.8.6</version>
+ <version>2.10.1</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
- <version>4.4</version>
+ <version>4.5.2</version>
<scope>provided</scope>
</dependency>
<dependency>
- <groupId>javax.mail</groupId>
- <artifactId>mail</artifactId>
- <version>1.4.5-rc1</version>
+ <groupId>com.sun.mail</groupId>
+ <artifactId>javax.mail</artifactId>
+ <version>1.6.2</version>
</dependency>
<dependency>
- <groupId>org.apache.commons</groupId>
+ <groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
- <version>1.3.2</version>
+ <version>2.14.0</version>
</dependency>
<dependency>
<groupId>commons-discovery</groupId>
<artifactId>commons-discovery</artifactId>
- <version>20040218.194635</version>
+ <version>0.5</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
diff --git a/github-plugin/rollup.config.mjs b/github-plugin/rollup.config.mjs
new file mode 100644
index 0000000..03d92be
--- /dev/null
+++ b/github-plugin/rollup.config.mjs
@@ -0,0 +1,17 @@
+import terser from '@rollup/plugin-terser';
+import { nodeResolve } from '@rollup/plugin-node-resolve';
+
+export default {
+ input: 'target/web/src/main/ts/main.js',
+ treeshake: false,
+ output: {
+ format: 'iife',
+ compact: true,
+ file: 'target/classes/static/github-plugin.js',
+ },
+ context: 'window',
+ plugins: [
+ terser(),
+ nodeResolve(),
+ ],
+}
\ No newline at end of file
diff --git a/github-plugin/src/main/java/com/google/gerrit/server/account/AccountImporter.java b/github-plugin/src/main/java/com/google/gerrit/server/account/AccountImporter.java
index e826880..1c0fe3b 100644
--- a/github-plugin/src/main/java/com/google/gerrit/server/account/AccountImporter.java
+++ b/github-plugin/src/main/java/com/google/gerrit/server/account/AccountImporter.java
@@ -15,10 +15,10 @@
import com.google.common.base.MoreObjects;
import com.google.gerrit.entities.Account;
+import com.google.gerrit.server.Sequences;
import com.google.gerrit.server.ServerInitiated;
import com.google.gerrit.server.account.externalids.ExternalId;
import com.google.gerrit.server.account.externalids.ExternalIdFactory;
-import com.google.gerrit.server.notedb.Sequences;
import com.google.inject.Inject;
import com.google.inject.Provider;
import java.io.IOException;
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 a22126d..2bacafd 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
@@ -17,7 +17,6 @@
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.AllProjectsName;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.SitePaths;
@@ -75,10 +74,9 @@
public GitHubConfig(
@GerritServerConfig Config config,
final SitePaths site,
- Provider<AllProjectsName> allProjectsNameProvider,
- CanonicalWebUrl canonicalWebUrl)
+ Provider<AllProjectsName> allProjectsNameProvider)
throws MalformedURLException {
- super(config, canonicalWebUrl);
+ super(config);
parseWizardFlow(config.getStringList(CONF_SECTION, null, CONF_WIZARD_FLOW), DEFAULT_SERVER);
// Virtual host specific sections
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GitHubTopMenu.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GitHubTopMenu.java
index 5ff5363..d345556 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GitHubTopMenu.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GitHubTopMenu.java
@@ -47,7 +47,7 @@
new MenuEntry(
"GitHub",
Arrays.asList(
- getItem("Scope", ghConfig.getScopeSelectionUrl(null)),
+ getItem("Scope", baseUrl + "/static/scope.html"),
getItem("Profile", baseUrl + "/static/account.html"),
getItem("Repositories", baseUrl + "/static/repositories.html"),
getItem("Pull Requests", baseUrl + "/static/pullrequests.html"))));
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GuiceHttpModule.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GuiceHttpModule.java
index f75030d..ef24191 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GuiceHttpModule.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GuiceHttpModule.java
@@ -15,10 +15,16 @@
import com.google.gerrit.extensions.annotations.Exports;
import com.google.gerrit.extensions.auth.oauth.OAuthServiceProvider;
+import com.google.gerrit.extensions.registration.DynamicSet;
+import com.google.gerrit.extensions.webui.JavaScriptPlugin;
+import com.google.gerrit.extensions.webui.WebUiPlugin;
+import com.google.gerrit.httpd.AllRequestFilter;
+import com.google.inject.Scopes;
import com.google.inject.TypeLiteral;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import com.google.inject.name.Names;
import com.google.inject.servlet.ServletModule;
+import com.googlesource.gerrit.plugins.github.filters.GitHubGroupCacheRefreshFilter;
import com.googlesource.gerrit.plugins.github.filters.GitHubOAuthFilter;
import com.googlesource.gerrit.plugins.github.git.CreateProjectStep;
import com.googlesource.gerrit.plugins.github.git.GitCloneStep;
@@ -90,6 +96,9 @@
.annotatedWith(Exports.named("github"))
.to(GitHubOAuthServiceProvider.class);
+ DynamicSet.bind(binder(), WebUiPlugin.class)
+ .toInstance(new JavaScriptPlugin("github-plugin.js"));
+
serve("*.css", "*.js", "*.png", "*.jpg", "*.woff", "*.gif", "*.ttf")
.with(VelocityStaticServlet.class);
serve("*.gh").with(VelocityControllerServlet.class);
@@ -97,5 +106,9 @@
serve("/static/*").with(VelocityViewServlet.class);
filterRegex("(?!/webhook).*").through(GitHubOAuthFilter.class);
+
+ DynamicSet.bind(binder(), AllRequestFilter.class)
+ .to(GitHubGroupCacheRefreshFilter.class)
+ .in(Scopes.SINGLETON);
}
}
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/filters/GitHubGroupCacheRefreshFilter.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/filters/GitHubGroupCacheRefreshFilter.java
new file mode 100644
index 0000000..eb34962
--- /dev/null
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/filters/GitHubGroupCacheRefreshFilter.java
@@ -0,0 +1,78 @@
+// 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.filters;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.httpd.AllRequestFilter;
+import com.googlesource.gerrit.plugins.github.group.GitHubGroupsCache;
+import java.io.IOException;
+import java.util.Optional;
+import javax.inject.Inject;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+public class GitHubGroupCacheRefreshFilter extends AllRequestFilter {
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+ private static final String LOGIN_URL = "/login";
+ private static final String LOGIN_QUERY_FINAL = "final=true";
+ private static final String ACCOUNT_COOKIE = "GerritAccount";
+ private static final String INVALIDATE_CACHED_GROUPS = "RefreshGroups";
+
+ private final GitHubGroupsCache ghGroupsCache;
+
+ @Inject
+ @VisibleForTesting
+ public GitHubGroupCacheRefreshFilter(GitHubGroupsCache ghGroupsCache) {
+ this.ghGroupsCache = ghGroupsCache;
+ }
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {}
+
+ @Override
+ public void doFilter(
+ ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
+ throws IOException, ServletException {
+ filterChain.doFilter(servletRequest, servletResponse);
+
+ HttpServletRequest req = (HttpServletRequest) servletRequest;
+ if (req.getRequestURI().endsWith(LOGIN_URL) && req.getQueryString().equals(LOGIN_QUERY_FINAL)) {
+ HttpServletResponse resp = (HttpServletResponse) servletResponse;
+ String cookieResponse = resp.getHeader("Set-Cookie");
+ if (cookieResponse != null && cookieResponse.contains(ACCOUNT_COOKIE)) {
+ req.getSession().setAttribute(INVALIDATE_CACHED_GROUPS, Boolean.TRUE);
+ }
+ } else if (hasSessionFlagForInvalidatingCachedUserGroups(req)) {
+ ghGroupsCache.invalidateCurrentUserGroups();
+ req.getSession().removeAttribute(INVALIDATE_CACHED_GROUPS);
+ }
+ }
+
+ private static boolean hasSessionFlagForInvalidatingCachedUserGroups(HttpServletRequest req) {
+ return Optional.ofNullable(req.getSession(false))
+ .flatMap(session -> Optional.ofNullable(session.getAttribute(INVALIDATE_CACHED_GROUPS)))
+ .filter(refresh -> (Boolean) refresh)
+ .isPresent();
+ }
+
+ @Override
+ public void destroy() {}
+}
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/BatchImporter.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/BatchImporter.java
index f26188d..d359526 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/BatchImporter.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/BatchImporter.java
@@ -44,7 +44,7 @@
}
public synchronized void schedule(int idx, GitJob pullRequestImportJob) {
- jobs.put(new Integer(idx), pullRequestImportJob);
+ jobs.put(Integer.valueOf(idx), pullRequestImportJob);
executor.exec(pullRequestImportJob);
}
}
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/FanoutReplicationConfig.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/FanoutReplicationConfig.java
index 412c2ff..4a3bc4b 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/FanoutReplicationConfig.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/FanoutReplicationConfig.java
@@ -54,12 +54,19 @@
FS.DETECTED);
replicationConf.load();
- replicationConf.setString("remote", null, "url", url);
+ String currentUrl = replicationConf.getString("remote", null, "url");
+ if (currentUrl == null) {
+ replicationConf.setString("remote", null, "url", url);
+ }
List<String> projects =
new ArrayList<>(Arrays.asList(replicationConf.getStringList("remote", null, "projects")));
projects.add(projectName);
replicationConf.setStringList("remote", null, "projects", projects);
- replicationConf.setString("remote", null, "push", "refs/*:refs/*");
+
+ String currentPushRefs = replicationConf.getString("remote", null, "push");
+ if (currentPushRefs == null) {
+ replicationConf.setString("remote", null, "push", "refs/*:refs/*");
+ }
replicationConf.save();
}
}
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/GitCloneStep.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/GitCloneStep.java
index 12e5101..9d09f51 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/GitCloneStep.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/GitCloneStep.java
@@ -13,6 +13,8 @@
// limitations under the License.
package com.googlesource.gerrit.plugins.github.git;
+import static java.util.stream.Collectors.toList;
+
import com.google.gerrit.entities.Project;
import com.google.gerrit.extensions.api.GerritApi;
import com.google.gerrit.extensions.api.changes.NotifyHandling;
@@ -34,6 +36,7 @@
import com.googlesource.gerrit.plugins.github.GitHubConfig;
import java.io.File;
import java.io.IOException;
+import java.util.stream.Stream;
import org.apache.commons.io.FileUtils;
import org.eclipse.jgit.api.FetchCommand;
import org.eclipse.jgit.api.Git;
@@ -50,11 +53,8 @@
private static final Logger LOG = LoggerFactory.getLogger(GitImporter.class);
private final GitHubConfig config;
- private final File gitDir;
private final GerritApi gerritApi;
private final OneOffRequestContext context;
- private final String organisation;
- private final String repository;
private final File destinationDirectory;
private final DynamicSet<ProjectDeletedListener> deletedListeners;
private final ProjectCache projectCache;
@@ -85,14 +85,11 @@
super(config.gitHubUrl, organisation, repository, gitHubRepoFactory);
LOG.debug("GitHub Clone " + organisation + "/" + repository);
this.config = config;
- this.gitDir = config.gitDir.toFile();
this.gerritApi = gerritApi;
this.context = context;
- this.organisation = organisation;
- this.repository = repository;
this.projectName = organisation + "/" + repository;
- this.destinationDirectory = prepareTargetGitDirectory(gitDir, this.projectName);
+ this.destinationDirectory = prepareTargetGitDirectory(config.gitDir.toFile(), this.projectName);
this.deletedListeners = deletedListeners;
this.projectCache = projectCache;
this.repoManager = repoManager;
@@ -113,7 +110,9 @@
try (ManualRequestContext requestContext = context.openAs(config.importAccountId)) {
ProjectInput pi = new ProjectInput();
pi.name = projectName;
- pi.parent = config.getBaseProject(getRepository().isPrivate());
+ GitHubRepository ghRepository = getRepository();
+ pi.parent = config.getBaseProject(ghRepository.isPrivate());
+ pi.branches = Stream.ofNullable(ghRepository.getDefaultBranch()).collect(toList());
gerritApi.projects().create(pi).get();
} catch (ResourceConflictException e) {
throw new GitDestinationAlreadyExistsException(projectName);
@@ -128,7 +127,8 @@
Project.NameKey key = Project.nameKey(projectName);
String sourceUri = getSourceUri();
try (Git git = Git.open(destinationDirectory)) {
- FetchCommand fetch = git.fetch().setRefSpecs("refs/*:refs/*").setRemote(sourceUri);
+ FetchCommand fetch =
+ git.fetch().setRefSpecs("^refs/changes/*", "refs/*:refs/*").setRemote(sourceUri);
fetch.setCredentialsProvider(getRepository().getCredentialsProvider());
if (progress != null) {
fetch.setProgressMonitor(progress);
@@ -146,10 +146,6 @@
}
}
- private boolean isNotEmpty(File destDirectory) {
- return destDirectory.listFiles().length > 0;
- }
-
@Override
public boolean rollback() {
File gitDirectory = destinationDirectory;
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/MagicRefFoundException.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/MagicRefFoundException.java
index 263ee9d..42b7e36 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/MagicRefFoundException.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/MagicRefFoundException.java
@@ -15,6 +15,8 @@
public class MagicRefFoundException extends GitException {
+ private static final long serialVersionUID = 1L;
+
public MagicRefFoundException(String message) {
super(message);
}
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/ProtectedBranchFoundException.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/ProtectedBranchFoundException.java
index 221152f..c156150 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/ProtectedBranchFoundException.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/ProtectedBranchFoundException.java
@@ -16,6 +16,8 @@
public class ProtectedBranchFoundException extends Exception {
+ private static final long serialVersionUID = 1L;
+
public ProtectedBranchFoundException(String msg) {
super(msg);
}
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/PullRequestCreateChange.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/PullRequestCreateChange.java
index f2a7f06..810acd8 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/PullRequestCreateChange.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/PullRequestCreateChange.java
@@ -27,10 +27,10 @@
import com.google.gerrit.server.ChangeUtil;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.IdentifiedUser.GenericFactory;
+import com.google.gerrit.server.Sequences;
import com.google.gerrit.server.change.ChangeInserter;
import com.google.gerrit.server.change.PatchSetInserter;
import com.google.gerrit.server.notedb.ChangeNotes;
-import com.google.gerrit.server.notedb.Sequences;
import com.google.gerrit.server.project.InvalidChangeOperationException;
import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gerrit.server.query.change.ChangeData;
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/PullRequestImportJob.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/PullRequestImportJob.java
index 52d7b34..da16dc2 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/PullRequestImportJob.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/PullRequestImportJob.java
@@ -191,7 +191,7 @@
pullRequestOwner,
revCommit,
getChangeMessage(pr),
- String.format(TOPIC_FORMAT, new Integer(pr.getNumber())));
+ String.format(TOPIC_FORMAT, Integer.valueOf(pr.getNumber())));
if (changeId != null) {
prChanges.add(changeId);
}
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/group/CurrentUsernameProvider.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/group/CurrentUsernameProvider.java
new file mode 100644
index 0000000..028aa6b
--- /dev/null
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/group/CurrentUsernameProvider.java
@@ -0,0 +1,41 @@
+// 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.group;
+
+import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.IdentifiedUser;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import java.util.Optional;
+
+public class CurrentUsernameProvider implements Provider<String> {
+ public static final String CURRENT_USERNAME = "CurrentUsername";
+
+ private final Provider<CurrentUser> userProvider;
+
+ @Inject
+ CurrentUsernameProvider(Provider<CurrentUser> userProvider) {
+ this.userProvider = userProvider;
+ }
+
+ @Override
+ public String get() {
+ return Optional.ofNullable(userProvider.get())
+ .filter(CurrentUser::isIdentifiedUser)
+ .map(CurrentUser::asIdentifiedUser)
+ .flatMap(IdentifiedUser::getUserName)
+ .orElse(null);
+ }
+}
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/group/GitHubGroupsCache.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/group/GitHubGroupsCache.java
index 3504f2c..8f9c776 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/group/GitHubGroupsCache.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/group/GitHubGroupsCache.java
@@ -14,19 +14,21 @@
package com.googlesource.gerrit.plugins.github.group;
+import static com.googlesource.gerrit.plugins.github.group.CurrentUsernameProvider.CURRENT_USERNAME;
import static java.time.temporal.ChronoUnit.MINUTES;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableSet;
import com.google.gerrit.entities.AccountGroup.UUID;
-import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.cache.CacheModule;
import com.google.inject.Inject;
import com.google.inject.Module;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
+import com.google.inject.name.Names;
import com.googlesource.gerrit.plugins.github.groups.OrganizationStructure;
import com.googlesource.gerrit.plugins.github.oauth.GitHubLogin;
import com.googlesource.gerrit.plugins.github.oauth.UserScopedProvider;
@@ -95,7 +97,7 @@
private void loadOrganisations(
String username, OrganizationStructure orgsTeams, GitHubLogin ghLogin) throws IOException {
logger.debug("Getting list of public organisations for user '{}'", username);
- Set<String> organisations = ghLogin.getMyOrganisationsLogins();
+ Set<String> organisations = ghLogin.getMyOrganisationsLogins(username);
for (String org : organisations) {
orgsTeams.put(org, EVERYONE_TEAM_NAME);
}
@@ -106,6 +108,9 @@
return new CacheModule() {
@Override
protected void configure() {
+ bind(String.class)
+ .annotatedWith(Names.named(CurrentUsernameProvider.CURRENT_USERNAME))
+ .toProvider(CurrentUsernameProvider.class);
persist(ORGS_CACHE_NAME, String.class, OrganizationStructure.class)
.expireAfterWrite(Duration.of(GROUPS_CACHE_TTL_MINS, MINUTES))
.loader(OrganisationLoader.class);
@@ -115,14 +120,15 @@
}
private final LoadingCache<String, OrganizationStructure> orgTeamsByUsername;
- private final Provider<IdentifiedUser> userProvider;
+ private final Provider<String> usernameProvider;
@Inject
- GitHubGroupsCache(
+ @VisibleForTesting
+ public GitHubGroupsCache(
@Named(ORGS_CACHE_NAME) LoadingCache<String, OrganizationStructure> byUsername,
- Provider<IdentifiedUser> userProvider) {
+ @Named(CURRENT_USERNAME) Provider<String> usernameProvider) {
this.orgTeamsByUsername = byUsername;
- this.userProvider = userProvider;
+ this.usernameProvider = usernameProvider;
}
Set<String> getOrganizationsForUser(String username) {
@@ -135,7 +141,7 @@
}
Set<String> getOrganizationsForCurrentUser() throws ExecutionException {
- return orgTeamsByUsername.get(userProvider.get().getUserName().get()).keySet();
+ return orgTeamsByUsername.get(usernameProvider.get()).keySet();
}
Set<String> getTeamsForUser(String organizationName, String username) {
@@ -156,7 +162,7 @@
}
Set<String> getTeamsForCurrentUser(String organizationName) {
- return getTeamsForUser(organizationName, userProvider.get().getUserName().get());
+ return getTeamsForUser(organizationName, usernameProvider.get());
}
public Set<UUID> getGroupsForUser(String username) {
@@ -170,4 +176,8 @@
}
return groupsBuilder.build();
}
+
+ public void invalidateCurrentUserGroups() {
+ orgTeamsByUsername.invalidate(usernameProvider.get());
+ }
}
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/notification/PullRequestHandler.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/notification/PullRequestHandler.java
index 540b98a..361ccc2 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/notification/PullRequestHandler.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/notification/PullRequestHandler.java
@@ -46,7 +46,7 @@
String action = payload.getAction();
if (action.equals("opened") || action.equals("synchronize")) {
GHRepository repository = payload.getRepository();
- Integer prNumber = new Integer(payload.getNumber());
+ Integer prNumber = Integer.valueOf(payload.getNumber());
PullRequestImporter prImporter = prImportProvider.get();
String organization = repository.getOwnerName();
String name = repository.getName();
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/replication/GitHubDestinations.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/replication/GitHubDestinations.java
index af644fe..810632a 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/replication/GitHubDestinations.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/replication/GitHubDestinations.java
@@ -20,7 +20,6 @@
import com.google.gerrit.server.account.GroupBackend;
import com.google.gerrit.server.config.SitePaths;
import com.google.inject.Inject;
-import com.google.inject.Injector;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
@@ -52,24 +51,20 @@
return null;
}
- private final Injector injector;
private final List<Destination> configs;
private final RemoteSiteUser.Factory replicationUserFactory;
private final PluginUser pluginUser;
private final GroupBackend groupBackend;
- boolean replicateAllOnPluginStart;
private final List<String> organisations;
@Inject
GitHubDestinations(
- final Injector i,
final SitePaths site,
final RemoteSiteUser.Factory ruf,
final GroupBackend gb,
final PluginUser pu)
throws ConfigInvalidException, IOException {
- injector = i;
pluginUser = pu;
replicationUserFactory = ruf;
groupBackend = gb;
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/velocity/PluginVelocityRuntimeProvider.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/velocity/PluginVelocityRuntimeProvider.java
index 144e77a..735ac4d 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/velocity/PluginVelocityRuntimeProvider.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/velocity/PluginVelocityRuntimeProvider.java
@@ -30,12 +30,12 @@
@Singleton
public class PluginVelocityRuntimeProvider implements Provider<RuntimeInstance> {
- private static final String VELOCITY_FILE_RESOURCE_LOADER_PATH = "file.resource.loader.path";
- private static final String VELOCITY_FILE_RESOURCE_LOADER_CLASS = "file.resource.loader.class";
- private static final String VELOCITY_CLASS_RESOURCE_LOADER_CLASS = "class.resource.loader.class";
- private static final String VELOCITY_JAR_RESOURCE_LOADER_CLASS = "jar.resource.loader.class";
- private static final String VELOCITY_JAR_RESOURCE_LOADER_PATH = "jar.resource.loader.path";
- private static final String VELOCITY_RESOURCE_LOADER = "resource.loader";
+ private static final String VELOCITY_FILE_RESOURCE_LOADER_PATH = "resource.loader.file.path";
+ private static final String VELOCITY_FILE_RESOURCE_LOADER_CLASS = "resource.loader.jar.path";
+ private static final String VELOCITY_CLASS_RESOURCE_LOADER_CLASS = "resource.loader.class.class";
+ private static final String VELOCITY_JAR_RESOURCE_LOADER_CLASS = "resource.loader.jar.class";
+ private static final String VELOCITY_JAR_RESOURCE_LOADER_PATH = "resource.loader.jar.path";
+ private static final String VELOCITY_RESOURCE_LOADER = "resource.loaders";
private final SitePaths site;
private String pluginName;
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/velocity/VelocityViewServlet.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/velocity/VelocityViewServlet.java
index 85197dd..5e4498f 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/velocity/VelocityViewServlet.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/velocity/VelocityViewServlet.java
@@ -13,15 +13,20 @@
// limitations under the License.
package com.googlesource.gerrit.plugins.github.velocity;
+import static com.googlesource.gerrit.plugins.github.oauth.GitHubOAuthConfig.GITHUB_PLUGIN_OAUTH_SCOPE;
+
import com.google.common.base.MoreObjects;
import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.config.AuthConfig;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
import com.googlesource.gerrit.plugins.github.GitHubConfig;
+import com.googlesource.gerrit.plugins.github.oauth.CanonicalWebUrls;
import com.googlesource.gerrit.plugins.github.oauth.GitHubLogin;
import com.googlesource.gerrit.plugins.github.oauth.ScopedProvider;
+import com.googlesource.gerrit.plugins.github.oauth.VirtualDomainConfig;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Map.Entry;
@@ -49,6 +54,9 @@
private final ScopedProvider<GitHubLogin> loginProvider;
private final Provider<CurrentUser> userProvider;
private final GitHubConfig config;
+ private final VirtualDomainConfig virtualDomainConfig;
+ private final CanonicalWebUrls canonicalWebUrls;
+ private final AuthConfig authConfig;
@Inject
public VelocityViewServlet(
@@ -56,13 +64,19 @@
Provider<PluginVelocityModel> modelProvider,
ScopedProvider<GitHubLogin> loginProvider,
Provider<CurrentUser> userProvider,
- GitHubConfig config) {
+ GitHubConfig config,
+ VirtualDomainConfig virutalDomainConfig,
+ CanonicalWebUrls canonicalWebUrls,
+ AuthConfig authConfig) {
this.velocityRuntime = velocityRuntime;
this.modelProvider = modelProvider;
this.loginProvider = loginProvider;
this.userProvider = userProvider;
this.config = config;
+ this.virtualDomainConfig = virutalDomainConfig;
+ this.canonicalWebUrls = canonicalWebUrls;
+ this.authConfig = authConfig;
}
@Override
@@ -71,6 +85,12 @@
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
+ if (!(req.getRequestURI().equals(GITHUB_PLUGIN_OAUTH_SCOPE)
+ || userProvider.get().isIdentifiedUser())) {
+ resp.sendRedirect(authConfig.getLoginUrl());
+ return;
+ }
+
String pathInfo =
STATIC_PREFIX
+ MoreObjects.firstNonNull((String) req.getAttribute("destUrl"), req.getPathInfo());
@@ -96,6 +116,8 @@
GitHubLogin gitHubLogin = loginProvider.get(request);
model.put("myself", gitHubLogin.getMyself());
model.put("config", config);
+ model.put("scopeSelectionUrl", canonicalWebUrls.getScopeSelectionUrl());
+ model.put("scopes", virtualDomainConfig.getScopes(request));
CurrentUser user = userProvider.get();
if (user.isIdentifiedUser()) {
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/wizard/AccountController.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/wizard/AccountController.java
index fc578af..0bb7e3e 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/wizard/AccountController.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/wizard/AccountController.java
@@ -25,7 +25,6 @@
import com.google.gerrit.extensions.restapi.RawInput;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.ServerInitiated;
-import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.account.AccountManager;
import com.google.gerrit.server.account.AccountResource;
import com.google.gerrit.server.account.AccountsUpdate;
@@ -65,7 +64,6 @@
private final AddSshKey restAddSshKey;
private final GetSshKeys restGetSshKeys;
private final AccountManager accountManager;
- private final AccountCache accountCache;
private final PutPreferred putPreferred;
private final PutName putName;
private final Provider<AccountsUpdate> accountsUpdateProvider;
@@ -79,7 +77,6 @@
final AddSshKey restAddSshKey,
final GetSshKeys restGetSshKeys,
final AccountManager accountManager,
- final AccountCache accountCache,
final PutPreferred putPreferred,
final PutName putName,
@ServerInitiated final Provider<AccountsUpdate> accountsUpdateProvider,
@@ -90,7 +87,6 @@
this.restAddSshKey = restAddSshKey;
this.restGetSshKeys = restGetSshKeys;
this.accountManager = accountManager;
- this.accountCache = accountCache;
this.putPreferred = putPreferred;
this.putName = putName;
this.accountsUpdateProvider = accountsUpdateProvider;
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/wizard/PullRequestListController.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/wizard/PullRequestListController.java
index e47f161..b7fc801 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/wizard/PullRequestListController.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/wizard/PullRequestListController.java
@@ -101,7 +101,7 @@
JsonArray prArray = new JsonArray();
for (GHPullRequest pr : repoEntry.getValue()) {
JsonObject prObj = new JsonObject();
- prObj.add("id", new JsonPrimitive(new Integer(pr.getNumber())));
+ prObj.add("id", new JsonPrimitive(Integer.valueOf(pr.getNumber())));
prObj.add("title", new JsonPrimitive(Strings.nullToEmpty(pr.getTitle())));
prObj.add("body", new JsonPrimitive(Strings.nullToEmpty(pr.getBody())));
prObj.add(
@@ -137,7 +137,7 @@
if (githubRepo.isPresent()) {
numPullRequests =
collectPullRequestsFromGitHubRepository(
- numPullRequests, allPullRequests, gitRepo, ghRepoName, githubRepo);
+ numPullRequests, allPullRequests, gitRepo, ghRepoName, githubRepo.get());
}
}
}
@@ -149,13 +149,14 @@
Map<String, List<GHPullRequest>> allPullRequests,
Repository gitRepo,
String ghRepoName,
- Optional<GHRepository> githubRepo)
+ GHRepository githubRepo)
throws IncorrectObjectTypeException, IOException {
List<GHPullRequest> repoPullRequests = Lists.newArrayList();
int count = numPullRequests;
if (count < config.pullRequestListLimit) {
- for (GHPullRequest ghPullRequest : githubRepo.get().listPullRequests(GHIssueState.OPEN)) {
+ for (GHPullRequest ghPullRequest :
+ githubRepo.queryPullRequests().state(GHIssueState.OPEN).list()) {
if (isAnyCommitOfPullRequestToBeImported(gitRepo, ghPullRequest)) {
repoPullRequests.add(ghPullRequest);
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/wizard/RepositoriesListController.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/wizard/RepositoriesListController.java
index 2cf6170..01a3d25 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/wizard/RepositoriesListController.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/wizard/RepositoriesListController.java
@@ -72,7 +72,7 @@
repository.add("organisation", new JsonPrimitive(organisation));
repository.add(
"description", new JsonPrimitive(Strings.nullToEmpty(ghRepository.getDescription())));
- repository.add("private", new JsonPrimitive(new Boolean(ghRepository.isPrivate())));
+ repository.add("private", new JsonPrimitive(Boolean.valueOf(ghRepository.isPrivate())));
jsonRepos.add(repository);
numRepos++;
}
diff --git a/github-plugin/src/main/resources/Documentation/config.md b/github-plugin/src/main/resources/Documentation/config.md
index c9eebc5..4adcd41 100644
--- a/github-plugin/src/main/resources/Documentation/config.md
+++ b/github-plugin/src/main/resources/Documentation/config.md
@@ -77,6 +77,10 @@
Default is empty read-only access to public
information (includes public user profile info, public repository info, and gists).
+github.<domain>.scopes
+: Use only in conjunction with the `virtualhost` plugin to provide different GitHub scopes
+ selections for each virtual domain. It works the same way as `github.scopes`.
+
github.httpConnectionTimeout
: Maximum time to wait for GitHub API to answer to a new HTTP connection attempt.
Values should use common common unit unit suffixes to express their setting:
diff --git a/github-plugin/src/main/resources/static/repositories.html b/github-plugin/src/main/resources/static/repositories.html
index 9db7e3f..5a3df08 100644
--- a/github-plugin/src/main/resources/static/repositories.html
+++ b/github-plugin/src/main/resources/static/repositories.html
@@ -53,7 +53,7 @@
</select>
<input type="text" id="filter" class="filter" name="filter" placeholder="Filter by name" />
</li>
- <li class="info"><p>Not seeing your organizations or repositories? <a href="$config.getScopeSelectionUrl(null)">Login with a different GitHub Scope</a> and try again.</p></li>
+ <li class="info"><p>Not seeing your organizations or repositories? <a href="$scopeSelectionUrl">Login with a different GitHub Scope</a> and try again.</p></li>
</ul>
<div class="loading">
<p>Loading list of GitHub repositories ...</p>
diff --git a/github-plugin/src/main/resources/static/scope.html b/github-plugin/src/main/resources/static/scope.html
index 113b5b5..ebc2580 100644
--- a/github-plugin/src/main/resources/static/scope.html
+++ b/github-plugin/src/main/resources/static/scope.html
@@ -6,6 +6,14 @@
#include ("static/styles.html")
#include ("static/scripts.html")
</head>
+ <script type="text/javascript">
+ function submitOAuth() {
+ const submitButton =$("button[type='submit']");
+ submitButton.attr("disabled", true);
+ submitButton.find("span").text("Waiting for GitHub API response...");
+ document.forms[0].submit();
+ }
+ </script>
<body>
<!-- div.header start -->
<div class="header">
@@ -19,7 +27,7 @@
<button type="button" onclick="window.location='/'" id="cancel">
<span class="button"><span>Cancel</span></span>
</button>
- <button type="submit" onclick="document.forms[0].submit()">
+ <button type="submit" onclick="submitOAuth()">
<span class="button green"><span>Login ></span></span>
</button>
</div>
@@ -36,7 +44,7 @@
<form class="signupform" method="get" action="/login">
<h5>Which level of GitHub access do you need?</h5>
<ul class="scopes">
- #foreach ( $scope in $config.sortedScopesKeys )
+ #foreach ( $scope in $scopes.keySet() )
<li>
#set ( $scopeName = $scope.name.substring(6) )
#set ( $scopeDescription = $scope.description )
@@ -52,7 +60,7 @@
#end
<p class="scopeDescription">$scopeDescription</p>
<p class="scopePermissions">Allow to:
- #set ( $scopeItems = $config.scopes.get($scope) )
+ #set ( $scopeItems = $scopes.get($scope) )
#foreach ( $scopeItem in $scopeItems )
$scopeItem.description
#if ( $foreach.count < $scopeItems.size())
diff --git a/github-plugin/src/main/ts/gr-github-oauth-progress.ts b/github-plugin/src/main/ts/gr-github-oauth-progress.ts
new file mode 100644
index 0000000..3b53d47
--- /dev/null
+++ b/github-plugin/src/main/ts/gr-github-oauth-progress.ts
@@ -0,0 +1,72 @@
+import { PluginApi } from '@gerritcodereview/typescript-api/plugin';
+import { AuthInfo } from '@gerritcodereview/typescript-api/rest-api';
+import { CSSResult, LitElement, css, html } from "lit";
+import { customElement, property, query, state } from 'lit/decorators.js';
+
+@customElement('gr-github-oauth-progress')
+export class GrGitHubOAuthProgress extends LitElement {
+ @query('#gitHubOAuthProgress')
+ gitHubOAuthProgress?: HTMLDialogElement;
+
+ @property() plugin!: PluginApi;
+
+ @state() authInfo?: AuthInfo
+
+ @state() loggedIn?: boolean
+
+ override connectedCallback() {
+ super.connectedCallback();
+ const restApi = this.plugin.restApi();
+ if (!this.authInfo) {
+ restApi.getConfig().then(config => this.authInfo = config?.auth);
+ }
+ restApi.getLoggedIn().then(loggedIn => this.loggedIn = loggedIn);
+ }
+
+ static override get styles() {
+ return [
+ window.Gerrit.styles.spinner as CSSResult,
+ window.Gerrit.styles.font as CSSResult,
+ window.Gerrit.styles.modal as CSSResult,
+ css`
+ .loginButton {
+ --gr-button-text-color: var(--header-text-color);
+ color: var(--header-text-color);
+ padding: var(--spacing-m) var(--spacing-l);
+ }
+ .loadingContainer {
+ display: flex;
+ gap: var(--spacing-s);
+ align-items: baseline;
+ padding: var(--spacing-xxl);
+ }
+ .loadingSpin {
+ vertical-align: top;
+ position: relative;
+ top: 3px;
+ }
+ `];
+ }
+
+ override render() {
+ if (!this.authInfo || this.loggedIn !== false) {
+ return
+ }
+
+ return html`
+ <a class="loginButton" href=${this.authInfo.login_url} @click=${this.showModal}>
+ ${this.authInfo.login_text}
+ </a>
+ <dialog id="gitHubOAuthProgress">
+ <div class="loadingContainer">
+ <span class="loadingSpin"></span>
+ <span class="loadingText">Waiting for GitHub API response ...</span>
+ </div>
+ </dialog>
+ `
+ }
+
+ private showModal() {
+ setTimeout(() => this.gitHubOAuthProgress?.showModal(), 550);
+ }
+}
diff --git a/github-plugin/src/main/ts/main.ts b/github-plugin/src/main/ts/main.ts
new file mode 100644
index 0000000..2a465ca
--- /dev/null
+++ b/github-plugin/src/main/ts/main.ts
@@ -0,0 +1,9 @@
+import '@gerritcodereview/typescript-api/gerrit';
+import './gr-github-oauth-progress';
+
+window.Gerrit.install(plugin => {
+ plugin.registerCustomComponent(
+ 'auth-link',
+ 'gr-github-oauth-progress',
+ { replace: true });
+});
diff --git a/github-plugin/src/test/java/com/googlesource/gerrit/plugins/github/FakeHttpSession.java b/github-plugin/src/test/java/com/googlesource/gerrit/plugins/github/FakeHttpSession.java
new file mode 100644
index 0000000..6a820e7
--- /dev/null
+++ b/github-plugin/src/test/java/com/googlesource/gerrit/plugins/github/FakeHttpSession.java
@@ -0,0 +1,112 @@
+// 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 java.util.Enumeration;
+import java.util.HashMap;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpSessionContext;
+
+public class FakeHttpSession implements HttpSession {
+ private final HashMap<String, Object> attributes;
+
+ public FakeHttpSession() {
+ this.attributes = new HashMap<>();
+ }
+
+ @Override
+ public long getCreationTime() {
+ return 0;
+ }
+
+ @Override
+ public String getId() {
+ return null;
+ }
+
+ @Override
+ public long getLastAccessedTime() {
+ return 0;
+ }
+
+ @Override
+ public ServletContext getServletContext() {
+ return null;
+ }
+
+ @Override
+ public void setMaxInactiveInterval(int i) {}
+
+ @Override
+ public int getMaxInactiveInterval() {
+ return 0;
+ }
+
+ @Override
+ public HttpSessionContext getSessionContext() {
+ return null;
+ }
+
+ @Override
+ public Object getAttribute(String s) {
+ return attributes.get(s);
+ }
+
+ @Override
+ public Object getValue(String s) {
+ return getAttribute(s);
+ }
+
+ @Override
+ public Enumeration<String> getAttributeNames() {
+ return java.util.Collections.enumeration(attributes.keySet());
+ }
+
+ @Override
+ public String[] getValueNames() {
+ return attributes.keySet().toArray(new String[0]);
+ }
+
+ @Override
+ public void setAttribute(String s, Object o) {
+ attributes.put(s, o);
+ }
+
+ @Override
+ public void putValue(String s, Object o) {
+ setAttribute(s, o);
+ }
+
+ @Override
+ public void removeAttribute(String s) {
+ attributes.remove(s);
+ }
+
+ @Override
+ public void removeValue(String s) {
+ removeAttribute(s);
+ }
+
+ @Override
+ public void invalidate() {
+ attributes.clear();
+ }
+
+ @Override
+ public boolean isNew() {
+ return false;
+ }
+}
diff --git a/github-plugin/src/test/java/com/googlesource/gerrit/plugins/github/FanoutReplicationConfigTest.java b/github-plugin/src/test/java/com/googlesource/gerrit/plugins/github/FanoutReplicationConfigTest.java
new file mode 100644
index 0000000..3613c41
--- /dev/null
+++ b/github-plugin/src/test/java/com/googlesource/gerrit/plugins/github/FanoutReplicationConfigTest.java
@@ -0,0 +1,99 @@
+// 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.SitePaths;
+import com.googlesource.gerrit.plugins.github.git.FanoutReplicationConfig;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import org.apache.commons.io.FileUtils;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.FS;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class FanoutReplicationConfigTest {
+
+ private static final String CUSTOM_KEY = "mykey";
+ private static final String CUSTOM_VALUE = "myvalue";
+ private static final String REMOTE_ENDPOINT = "my-remote-endpoint";
+ private static final String TEST_REMOTE_URL = "http://github.com/myurl";
+ private static final String TEST_PROJECT_NAME = "myprojectname";
+ private Path tempDir;
+ private SitePaths sitePaths;
+
+ @Before
+ public void setup() throws Exception {
+ tempDir = Files.createTempDirectory(getClass().getSimpleName());
+ sitePaths = new SitePaths(tempDir);
+ Files.createDirectories(sitePaths.etc_dir);
+ }
+
+ @After
+ public void teardown() throws Exception {
+ FileUtils.deleteDirectory(tempDir.toFile());
+ }
+
+ @Test
+ public void shoudKeepAdHocSettingsInFanoutReplicationConfig() throws Exception {
+ FileBasedConfig currConfig = getReplicationConfig();
+ currConfig.setString("remote", null, CUSTOM_KEY, CUSTOM_VALUE);
+ currConfig.save();
+
+ String url = "http://github.com/myurl";
+ FanoutReplicationConfig fanoutReplicationConfig = new FanoutReplicationConfig(sitePaths);
+ fanoutReplicationConfig.addReplicationRemote(REMOTE_ENDPOINT, url, "myproject");
+
+ currConfig.load();
+ assertThat(currConfig.getString("remote", null, CUSTOM_KEY)).isEqualTo(CUSTOM_VALUE);
+ }
+
+ @Test
+ public void shoudKeepCustomUrlInFanoutReplicationConfig() throws Exception {
+ FileBasedConfig currConfig = getReplicationConfig();
+ String customUrl = "http://my-custom-url";
+ currConfig.setString("remote", null, "url", customUrl);
+ currConfig.save();
+
+ new FanoutReplicationConfig(sitePaths)
+ .addReplicationRemote(REMOTE_ENDPOINT, TEST_REMOTE_URL, TEST_PROJECT_NAME);
+
+ currConfig.load();
+ assertThat(currConfig.getString("remote", null, "url")).isEqualTo(customUrl);
+ }
+
+ @Test
+ public void shoudKeepCustomPushRefSpecInFanoutReplicationConfig() throws Exception {
+ FileBasedConfig currConfig = getReplicationConfig();
+ String customPushRefSpec = "+refs/heads/myheads/*:refs/heads/myheads/*";
+ currConfig.setString("remote", null, "push", customPushRefSpec);
+ currConfig.save();
+
+ new FanoutReplicationConfig(sitePaths)
+ .addReplicationRemote(REMOTE_ENDPOINT, TEST_REMOTE_URL, TEST_PROJECT_NAME);
+
+ currConfig.load();
+ assertThat(currConfig.getString("remote", null, "push")).isEqualTo(customPushRefSpec);
+ }
+
+ private FileBasedConfig getReplicationConfig() {
+ return new FileBasedConfig(
+ sitePaths.etc_dir.resolve("replication").resolve(REMOTE_ENDPOINT + ".config").toFile(),
+ FS.DETECTED);
+ }
+}
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
index 56f7b90..b7dfc60 100644
--- 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
@@ -117,6 +117,6 @@
+ "clientId = myclientid\n"
+ "clientSecret = mysecret\n"
+ configText);
- return new GitHubConfig(gerritConfig, site, ALL_PROJECTS_NAME_PROVIDER, null);
+ return new GitHubConfig(gerritConfig, site, ALL_PROJECTS_NAME_PROVIDER);
}
}
diff --git a/github-plugin/src/test/java/com/googlesource/gerrit/plugins/github/GitHubGroupCacheRefreshFilterTest.java b/github-plugin/src/test/java/com/googlesource/gerrit/plugins/github/GitHubGroupCacheRefreshFilterTest.java
new file mode 100644
index 0000000..5c1707f
--- /dev/null
+++ b/github-plugin/src/test/java/com/googlesource/gerrit/plugins/github/GitHubGroupCacheRefreshFilterTest.java
@@ -0,0 +1,125 @@
+// 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.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.gerrit.util.http.testutil.FakeHttpServletRequest;
+import com.google.gerrit.util.http.testutil.FakeHttpServletResponse;
+import com.googlesource.gerrit.plugins.github.filters.GitHubGroupCacheRefreshFilter;
+import com.googlesource.gerrit.plugins.github.group.GitHubGroupsCache;
+import com.googlesource.gerrit.plugins.github.groups.OrganizationStructure;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.junit.Before;
+import org.junit.Test;
+
+public class GitHubGroupCacheRefreshFilterTest {
+ private static final FilterChain NOOP_FILTER_CHAIN_TEST = (req, res) -> {};
+ private static final String GITHUB_USERNAME_TEST = "somegithubuser";
+ private static final OrganizationStructure GITHUB_USER_ORGANIZATION = new OrganizationStructure();
+ private static final String TEST_SERVER = "test-server";
+ private static final int TEST_PORT = 80;
+
+ private LoadingCache<String, OrganizationStructure> groupsByUsernameCache;
+ private GitHubGroupCacheRefreshFilter filter;
+ private FakeGroupCacheLoader groupsCacheLoader;
+ private int initialLoadCount;
+
+ private static class FakeGroupCacheLoader extends CacheLoader<String, OrganizationStructure> {
+ private final String username;
+ private final OrganizationStructure organizationStructure;
+ private int loadCount;
+
+ FakeGroupCacheLoader(String username, OrganizationStructure organizationStructure) {
+ this.username = username;
+ this.organizationStructure = organizationStructure;
+ }
+
+ @Override
+ public OrganizationStructure load(String u) throws Exception {
+ if (u.equals(username)) {
+ loadCount++;
+ return organizationStructure;
+ } else {
+ return null;
+ }
+ }
+
+ public int getLoadCount() {
+ return loadCount;
+ }
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ groupsCacheLoader = new FakeGroupCacheLoader(GITHUB_USERNAME_TEST, GITHUB_USER_ORGANIZATION);
+ groupsByUsernameCache = CacheBuilder.newBuilder().build(groupsCacheLoader);
+ filter =
+ new GitHubGroupCacheRefreshFilter(
+ new GitHubGroupsCache(groupsByUsernameCache, () -> GITHUB_USERNAME_TEST));
+ // Trigger the initial load of the groups cache
+ assertThat(groupsByUsernameCache.get(GITHUB_USERNAME_TEST)).isEqualTo(GITHUB_USER_ORGANIZATION);
+ initialLoadCount = groupsCacheLoader.getLoadCount();
+ }
+
+ @Test
+ public void shouldReloadGroupsUponSuccessfulLogin() throws Exception {
+ FakeHttpServletRequest finalLoginRequest = newFinalLoginRequest();
+ filter.doFilter(finalLoginRequest, newFinalLoginRedirectWithCookie(), NOOP_FILTER_CHAIN_TEST);
+ filter.doFilter(
+ newHomepageRequest(finalLoginRequest.getSession()),
+ new FakeHttpServletResponse(),
+ NOOP_FILTER_CHAIN_TEST);
+
+ assertThat(groupsByUsernameCache.get(GITHUB_USERNAME_TEST)).isEqualTo(GITHUB_USER_ORGANIZATION);
+ assertThat(groupsCacheLoader.getLoadCount()).isEqualTo(initialLoadCount + 1);
+ }
+
+ @Test
+ public void shouldNotReloadGroupsOnRegularRequests() throws Exception {
+ FakeHttpServletRequest regularRequest = new FakeHttpServletRequest();
+ filter.doFilter(regularRequest, new FakeHttpServletResponse(), NOOP_FILTER_CHAIN_TEST);
+ filter.doFilter(
+ newHomepageRequest(null), new FakeHttpServletResponse(), NOOP_FILTER_CHAIN_TEST);
+
+ assertThat(groupsByUsernameCache.get(GITHUB_USERNAME_TEST)).isEqualTo(GITHUB_USER_ORGANIZATION);
+ assertThat(groupsCacheLoader.getLoadCount()).isEqualTo(initialLoadCount);
+ }
+
+ private ServletRequest newHomepageRequest(HttpSession session) {
+ return new FakeHttpServletRequest(TEST_SERVER, TEST_PORT, "", "/", null, session);
+ }
+
+ private static HttpServletResponse newFinalLoginRedirectWithCookie() {
+ HttpServletResponse res = new FakeHttpServletResponse();
+ res.setHeader("Set-Cookie", "GerritAccount=foo");
+ return res;
+ }
+
+ private static FakeHttpServletRequest newFinalLoginRequest() {
+ FakeHttpServletRequest req =
+ new FakeHttpServletRequest(
+ TEST_SERVER, TEST_PORT, "", "", () -> new FakeHttpSession(), null);
+ req.setQueryString("final=true");
+ req.setPathInfo("/login");
+ return req;
+ }
+}
diff --git a/github-plugin/tsconfig-plugins-base.json b/github-plugin/tsconfig-plugins-base.json
new file mode 100644
index 0000000..a19ebbf
--- /dev/null
+++ b/github-plugin/tsconfig-plugins-base.json
@@ -0,0 +1,50 @@
+/* TODO: this file should be included in @gerritcodereview/typescript-api */
+{
+ "compilerOptions": {
+ /* Basic Options */
+ "target": "es2019", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
+ "module": "es2015", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
+ "inlineSourceMap": true, /* Generates corresponding '.map' file. */
+ "rootDir": ".", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
+ "removeComments": false, /* Emit comments to output */
+
+ /* Strict Type-Checking Options */
+ "strict": true, /* Enable all strict type-checking options. */
+ "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
+ "strictNullChecks": true, /* Enable strict null checks. */
+ "strictFunctionTypes": true, /* Enable strict checking of function types. */
+ "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
+ "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
+ "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
+
+ /* Additional Checks */
+ "noUnusedLocals": true, /* Report errors on unused locals. */
+ "noUnusedParameters": true, /* Report errors on unused parameters. */
+ "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
+ "noImplicitOverride": true,
+ "noFallthroughCasesInSwitch": true,/* Report errors for fallthrough cases in switch statement. */
+
+ "skipLibCheck": true, /* Do not check node_modules */
+
+ /* Module Resolution Options */
+ "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
+ "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
+ "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
+
+ /* Advanced Options */
+ "forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */
+ "incremental": true,
+ "experimentalDecorators": true,
+
+ "allowUmdGlobalAccess": true,
+
+ "typeRoots": [
+ /* typeRoots for Bazel */
+ "../external/ui_dev_npm/node_modules/@types",
+ "../external/plugins_npm/node_modules/@types",
+ /* typeRoots for IDE */
+ "../polygerrit-ui/node_modules/@types",
+ "../plugins/node_modules/@types"
+ ]
+ },
+}
diff --git a/github-plugin/tsconfig.json b/github-plugin/tsconfig.json
new file mode 100644
index 0000000..f08de5a
--- /dev/null
+++ b/github-plugin/tsconfig.json
@@ -0,0 +1,10 @@
+{
+ /* TODO: should be change to ./node_modules/@gerritcodereview/typescript-api/tsconfig-plugins-base.json' when NPM paclage is fixed */
+ "extends": "./tsconfig-plugins-base.json",
+ "compilerOptions": {
+ "rootDir": ".",
+ "experimentalDecorators": true,
+ "skipLibCheck": true,
+ "outDir": "./target/web"
+ },
+}
\ No newline at end of file
diff --git a/github-plugin/yarn.lock b/github-plugin/yarn.lock
new file mode 100644
index 0000000..51435d5
--- /dev/null
+++ b/github-plugin/yarn.lock
@@ -0,0 +1,316 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@gerritcodereview/typescript-api@^3.8.0":
+ version "3.8.0"
+ resolved "https://registry.yarnpkg.com/@gerritcodereview/typescript-api/-/typescript-api-3.8.0.tgz#2e418b814d7451c40365b2dc4f88e9965ece0769"
+ integrity sha512-wUkIWUx99Rj1vxRYQISxyzN0nplqu7t5sRDyJ8R3yNNkvALQAMC6Whj63qzCsZsymVFzC5up3y+ZVxaeh7b+xA==
+
+"@jridgewell/gen-mapping@^0.3.0":
+ version "0.3.3"
+ resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098"
+ integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==
+ dependencies:
+ "@jridgewell/set-array" "^1.0.1"
+ "@jridgewell/sourcemap-codec" "^1.4.10"
+ "@jridgewell/trace-mapping" "^0.3.9"
+
+"@jridgewell/resolve-uri@^3.1.0":
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721"
+ integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==
+
+"@jridgewell/set-array@^1.0.1":
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
+ integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
+
+"@jridgewell/source-map@^0.3.3":
+ version "0.3.5"
+ resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.5.tgz#a3bb4d5c6825aab0d281268f47f6ad5853431e91"
+ integrity sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==
+ dependencies:
+ "@jridgewell/gen-mapping" "^0.3.0"
+ "@jridgewell/trace-mapping" "^0.3.9"
+
+"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14":
+ version "1.4.15"
+ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
+ integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
+
+"@jridgewell/trace-mapping@^0.3.9":
+ version "0.3.19"
+ resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz#f8a3249862f91be48d3127c3cfe992f79b4b8811"
+ integrity sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==
+ dependencies:
+ "@jridgewell/resolve-uri" "^3.1.0"
+ "@jridgewell/sourcemap-codec" "^1.4.14"
+
+"@lit-labs/ssr-dom-shim@^1.0.0", "@lit-labs/ssr-dom-shim@^1.1.0":
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.1.1.tgz#64df34e2f12e68e78ac57e571d25ec07fa460ca9"
+ integrity sha512-kXOeFbfCm4fFf2A3WwVEeQj55tMZa8c8/f9AKHMobQMkzNUfUj+antR3fRPaZJawsa1aZiP/Da3ndpZrwEe4rQ==
+
+"@lit/reactive-element@^1.3.0", "@lit/reactive-element@^1.6.0":
+ version "1.6.3"
+ resolved "https://registry.yarnpkg.com/@lit/reactive-element/-/reactive-element-1.6.3.tgz#25b4eece2592132845d303e091bad9b04cdcfe03"
+ integrity sha512-QuTgnG52Poic7uM1AN5yJ09QMe0O28e10XzSvWDz02TJiiKee4stsiownEIadWm8nYzyDAyT+gKzUoZmiWQtsQ==
+ dependencies:
+ "@lit-labs/ssr-dom-shim" "^1.0.0"
+
+"@lit/ts-transformers@^1.1.3":
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/@lit/ts-transformers/-/ts-transformers-1.1.3.tgz#0d6c99c9a619dc762f896bd403546a7e396942be"
+ integrity sha512-I3Pp2J9SS09h3SiMxOQ87vVPZA74qZfYR1rD5by8F6VXYYwmN8DEe52tpi/u4Na2wE/XmkFgAg/vsVWz0fqvuw==
+ dependencies:
+ ts-clone-node "^1.0.0"
+ typescript "~4.7.4"
+
+"@polymer/polymer@^3.5.1":
+ version "3.5.1"
+ resolved "https://registry.yarnpkg.com/@polymer/polymer/-/polymer-3.5.1.tgz#4b5234e43b8876441022bcb91313ab3c4a29f0c8"
+ integrity sha512-JlAHuy+1qIC6hL1ojEUfIVD58fzTpJAoCxFwV5yr0mYTXV1H8bz5zy0+rC963Cgr9iNXQ4T9ncSjC2fkF9BQfw==
+ dependencies:
+ "@webcomponents/shadycss" "^1.9.1"
+
+"@rollup/plugin-node-resolve@^15.2.1":
+ version "15.2.1"
+ resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.1.tgz#a15b14fb7969229e26a30feff2816d39eff503f0"
+ integrity sha512-nsbUg588+GDSu8/NS8T4UAshO6xeaOfINNuXeVHcKV02LJtoRaM1SiOacClw4kws1SFiNhdLGxlbMY9ga/zs/w==
+ dependencies:
+ "@rollup/pluginutils" "^5.0.1"
+ "@types/resolve" "1.20.2"
+ deepmerge "^4.2.2"
+ is-builtin-module "^3.2.1"
+ is-module "^1.0.0"
+ resolve "^1.22.1"
+
+"@rollup/plugin-terser@^0.4.3":
+ version "0.4.3"
+ resolved "https://registry.yarnpkg.com/@rollup/plugin-terser/-/plugin-terser-0.4.3.tgz#c2bde2fe3a85e45fa68a454d48f4e73e57f98b30"
+ integrity sha512-EF0oejTMtkyhrkwCdg0HJ0IpkcaVg1MMSf2olHb2Jp+1mnLM04OhjpJWGma4HobiDTF0WCyViWuvadyE9ch2XA==
+ dependencies:
+ serialize-javascript "^6.0.1"
+ smob "^1.0.0"
+ terser "^5.17.4"
+
+"@rollup/pluginutils@^5.0.1":
+ version "5.0.4"
+ resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.0.4.tgz#74f808f9053d33bafec0cc98e7b835c9667d32ba"
+ integrity sha512-0KJnIoRI8A+a1dqOYLxH8vBf8bphDmty5QvIm2hqm7oFCFYKCAZWWd2hXgMibaPsNDhI0AtpYfQZJG47pt/k4g==
+ dependencies:
+ "@types/estree" "^1.0.0"
+ estree-walker "^2.0.2"
+ picomatch "^2.3.1"
+
+"@types/estree@^1.0.0":
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.2.tgz#ff02bc3dc8317cd668dfec247b750ba1f1d62453"
+ integrity sha512-VeiPZ9MMwXjO32/Xu7+OwflfmeoRwkE/qzndw42gGtgJwZopBnzy2gD//NN1+go1mADzkDcqf/KnFRSjTJ8xJA==
+
+"@types/resolve@1.20.2":
+ version "1.20.2"
+ resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.2.tgz#97d26e00cd4a0423b4af620abecf3e6f442b7975"
+ integrity sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==
+
+"@types/trusted-types@^2.0.2":
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.4.tgz#2b38784cd16957d3782e8e2b31c03bc1d13b4d65"
+ integrity sha512-IDaobHimLQhjwsQ/NMwRVfa/yL7L/wriQPMhw1ZJall0KX6E1oxk29XMDeilW5qTIg5aoiqf5Udy8U/51aNoQQ==
+
+"@webcomponents/shadycss@^1.9.1":
+ version "1.11.2"
+ resolved "https://registry.yarnpkg.com/@webcomponents/shadycss/-/shadycss-1.11.2.tgz#7539b0ad29598aa2eafee8b341059e20ac9e1006"
+ integrity sha512-vRq+GniJAYSBmTRnhCYPAPq6THYqovJ/gzGThWbgEZUQaBccndGTi1hdiUP15HzEco0I6t4RCtXyX0rsSmwgPw==
+
+acorn@^8.8.2:
+ version "8.10.0"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5"
+ integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==
+
+buffer-from@^1.0.0:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
+ integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
+
+builtin-modules@^3.3.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6"
+ integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==
+
+commander@^2.20.0:
+ version "2.20.3"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
+ integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
+
+compatfactory@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/compatfactory/-/compatfactory-1.0.1.tgz#a5940f1d734b86c02bb818a67a412d4c306ccaf4"
+ integrity sha512-hR9u0HSZTKDNNchPtMHg6myeNx0XO+av7UZIJPsi4rPALJBHi/W5Mbwi19hC/xm6y3JkYpxVYjTqnSGsU5X/iw==
+ dependencies:
+ helpertypes "^0.0.18"
+
+deepmerge@^4.2.2:
+ version "4.3.1"
+ resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a"
+ integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==
+
+estree-walker@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac"
+ integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==
+
+fsevents@~2.3.2:
+ version "2.3.3"
+ resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
+ integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
+
+has@^1.0.3:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/has/-/has-1.0.4.tgz#2eb2860e000011dae4f1406a86fe80e530fb2ec6"
+ integrity sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==
+
+helpertypes@^0.0.18:
+ version "0.0.18"
+ resolved "https://registry.yarnpkg.com/helpertypes/-/helpertypes-0.0.18.tgz#fd2bf5d3351cc7d80f7876732361d3adba63e5b4"
+ integrity sha512-XRhfbSEmR+poXUC5/8AbmYNJb2riOT6qPzjGJZr0S9YedHiaY+/tzPYzWMUclYMEdCYo/1l8PDYrQFCj02v97w==
+
+is-builtin-module@^3.2.1:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-3.2.1.tgz#f03271717d8654cfcaf07ab0463faa3571581169"
+ integrity sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==
+ dependencies:
+ builtin-modules "^3.3.0"
+
+is-core-module@^2.13.0:
+ version "2.13.0"
+ resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.0.tgz#bb52aa6e2cbd49a30c2ba68c42bf3435ba6072db"
+ integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==
+ dependencies:
+ has "^1.0.3"
+
+is-module@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591"
+ integrity sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==
+
+lit-element@^3.3.0:
+ version "3.3.3"
+ resolved "https://registry.yarnpkg.com/lit-element/-/lit-element-3.3.3.tgz#10bc19702b96ef5416cf7a70177255bfb17b3209"
+ integrity sha512-XbeRxmTHubXENkV4h8RIPyr8lXc+Ff28rkcQzw3G6up2xg5E8Zu1IgOWIwBLEQsu3cOVFqdYwiVi0hv0SlpqUA==
+ dependencies:
+ "@lit-labs/ssr-dom-shim" "^1.1.0"
+ "@lit/reactive-element" "^1.3.0"
+ lit-html "^2.8.0"
+
+lit-html@^2.8.0:
+ version "2.8.0"
+ resolved "https://registry.yarnpkg.com/lit-html/-/lit-html-2.8.0.tgz#96456a4bb4ee717b9a7d2f94562a16509d39bffa"
+ integrity sha512-o9t+MQM3P4y7M7yNzqAyjp7z+mQGa4NS4CxiyLqFPyFWyc4O+nodLrkrxSaCTrla6M5YOLaT3RpbbqjszB5g3Q==
+ dependencies:
+ "@types/trusted-types" "^2.0.2"
+
+lit@^2.8.0:
+ version "2.8.0"
+ resolved "https://registry.yarnpkg.com/lit/-/lit-2.8.0.tgz#4d838ae03059bf9cafa06e5c61d8acc0081e974e"
+ integrity sha512-4Sc3OFX9QHOJaHbmTMk28SYgVxLN3ePDjg7hofEft2zWlehFL3LiAuapWc4U/kYwMYJSh2hTCPZ6/LIC7ii0MA==
+ dependencies:
+ "@lit/reactive-element" "^1.6.0"
+ lit-element "^3.3.0"
+ lit-html "^2.8.0"
+
+path-parse@^1.0.7:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
+ integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
+
+picomatch@^2.3.1:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
+ integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
+
+randombytes@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
+ integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==
+ dependencies:
+ safe-buffer "^5.1.0"
+
+resolve@^1.22.1:
+ version "1.22.6"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.6.tgz#dd209739eca3aef739c626fea1b4f3c506195362"
+ integrity sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==
+ dependencies:
+ is-core-module "^2.13.0"
+ path-parse "^1.0.7"
+ supports-preserve-symlinks-flag "^1.0.0"
+
+rollup@^3.29.4:
+ version "3.29.4"
+ resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.29.4.tgz#4d70c0f9834146df8705bfb69a9a19c9e1109981"
+ integrity sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==
+ optionalDependencies:
+ fsevents "~2.3.2"
+
+safe-buffer@^5.1.0:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
+ integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
+
+serialize-javascript@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.1.tgz#b206efb27c3da0b0ab6b52f48d170b7996458e5c"
+ integrity sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==
+ dependencies:
+ randombytes "^2.1.0"
+
+smob@^1.0.0:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/smob/-/smob-1.4.1.tgz#66270e7df6a7527664816c5b577a23f17ba6f5b5"
+ integrity sha512-9LK+E7Hv5R9u4g4C3p+jjLstaLe11MDsL21UpYaCNmapvMkYhqCV4A/f/3gyH8QjMyh6l68q9xC85vihY9ahMQ==
+
+source-map-support@~0.5.20:
+ version "0.5.21"
+ resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
+ integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
+ dependencies:
+ buffer-from "^1.0.0"
+ source-map "^0.6.0"
+
+source-map@^0.6.0:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
+ integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
+
+supports-preserve-symlinks-flag@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
+ integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
+
+terser@^5.17.4:
+ version "5.21.0"
+ resolved "https://registry.yarnpkg.com/terser/-/terser-5.21.0.tgz#d2b27e92b5e56650bc83b6defa00a110f0b124b2"
+ integrity sha512-WtnFKrxu9kaoXuiZFSGrcAvvBqAdmKx0SFNmVNYdJamMu9yyN3I/QF0FbH4QcqJQ+y1CJnzxGIKH0cSj+FGYRw==
+ dependencies:
+ "@jridgewell/source-map" "^0.3.3"
+ acorn "^8.8.2"
+ commander "^2.20.0"
+ source-map-support "~0.5.20"
+
+ts-clone-node@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/ts-clone-node/-/ts-clone-node-1.0.0.tgz#aaffa5478cf303471cec9c3c8169e117a0f87614"
+ integrity sha512-/cDYbr2HAXxFNeTT41c/xs/2bhLJjqnYheHsmA3AoHSt+n4JA4t0FL9Lk5O8kWnJ6jeB3kPcUoXIFtwERNzv6Q==
+ dependencies:
+ compatfactory "^1.0.1"
+
+typescript@^4.9.5:
+ version "4.9.5"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a"
+ integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==
+
+typescript@~4.7.4:
+ version "4.7.4"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235"
+ integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==
diff --git a/pom.xml b/pom.xml
index 5d6b07e..d0f54d8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -18,12 +18,12 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.googlesource.gerrit.plugins.github</groupId>
<artifactId>github-parent</artifactId>
- <version>3.8.0</version>
+ <version>3.9.0-rc5</version>
<name>Gerrit Code Review - GitHub integration</name>
<url>http://www.gerritforge.com</url>
<packaging>pom</packaging>
<properties>
- <javaVersion>11</javaVersion>
+ <javaVersion>17</javaVersion>
</properties>
<licenses>
<license>
@@ -255,7 +255,7 @@
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
- <version>3.0.0</version>
+ <version>3.0.5</version>
</plugin>
</plugins>
</reporting>
@@ -292,13 +292,13 @@
<dependency>
<groupId>com.ryanharter.auto.value</groupId>
<artifactId>auto-value-gson</artifactId>
- <version>1.3.0</version>
+ <version>1.3.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
- <version>1.18.22</version>
+ <version>1.18.30</version>
<scope>provided</scope>
</dependency>
</dependencies>
@@ -313,7 +313,7 @@
<dependency>
<groupId>com.google.truth</groupId>
<artifactId>truth</artifactId>
- <version>1.1.4</version>
+ <version>1.1.5</version>
<scope>test</scope>
</dependency>
</dependencies>