Use replication plugin API to update and access its config Instead of directly modifying the replication plugin configuration files in the `$site_path/etc` directory use new API. This guarantee that the configuration will be stored and read in a correct format and location. Bug: Issue 325000746 Change-Id: I9bde7e1148d932fb6861f51edb3521449ec20bef
diff --git a/github-plugin/BUILD b/github-plugin/BUILD index 589f7c6..3ff3d06 100644 --- a/github-plugin/BUILD +++ b/github-plugin/BUILD
@@ -30,6 +30,7 @@ resources = glob(["src/main/resources/**/*"]), deps = [ ":github-plugin-lib", + ":replication-api", "//plugins/github/github-oauth:github-oauth-lib", "@axis-jaxrpc//jar", "@axis//jar", @@ -76,7 +77,9 @@ ":github-plugin__plugin", "//javatests/com/google/gerrit/util/http/testutil", "//plugins/github/github-oauth:github-oauth-lib", + "//plugins/replication:replication-api", "@commons-io//jar", + "@github-api//jar", ], ) @@ -93,3 +96,9 @@ neverlink = True, exports = ["@lombok//jar"], ) + +java_library( + name = "replication-api", + neverlink = True, + exports = ["//plugins/replication:replication-api"], +)
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GuiceModule.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GuiceModule.java index 9bff585..991ba5a 100644 --- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GuiceModule.java +++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GuiceModule.java
@@ -18,18 +18,13 @@ import com.google.gerrit.extensions.restapi.RestApiModule; import com.google.gerrit.extensions.webui.TopMenu; import com.google.gerrit.server.account.GroupBackend; -import com.google.gerrit.server.config.SitePaths; import com.google.gerrit.server.events.EventListener; import com.google.gerrit.server.project.ProjectResource; import com.google.gson.Gson; import com.google.inject.AbstractModule; -import com.google.inject.Inject; import com.google.inject.Scopes; import com.google.inject.TypeLiteral; import com.google.inject.assistedinject.FactoryModuleBuilder; -import com.googlesource.gerrit.plugins.github.git.FanoutReplicationConfig; -import com.googlesource.gerrit.plugins.github.git.FileBasedReplicationConfig; -import com.googlesource.gerrit.plugins.github.git.ReplicationConfig; import com.googlesource.gerrit.plugins.github.group.GitHubGroupBackend; import com.googlesource.gerrit.plugins.github.group.GitHubGroupMembership; import com.googlesource.gerrit.plugins.github.group.GitHubGroupsCache; @@ -42,17 +37,9 @@ import com.googlesource.gerrit.plugins.github.replication.ReplicationStatusFlatFile; import com.googlesource.gerrit.plugins.github.replication.ReplicationStatusListener; import com.googlesource.gerrit.plugins.github.replication.ReplicationStatusStore; -import java.nio.file.Files; public class GuiceModule extends AbstractModule { - private final SitePaths site; - - @Inject - public GuiceModule(SitePaths site) { - this.site = site; - } - @Override protected void configure() { bind(new TypeLiteral<UserScopedProvider<GitHubLogin>>() {}) @@ -75,12 +62,6 @@ } }); - if (Files.exists(site.etc_dir.resolve("replication"))) { - bind(ReplicationConfig.class).to(FanoutReplicationConfig.class).in(Scopes.SINGLETON); - } else { - bind(ReplicationConfig.class).to(FileBasedReplicationConfig.class).in(Scopes.SINGLETON); - } - bind(ReplicationStatusStore.class).to(ReplicationStatusFlatFile.class).in(Scopes.SINGLETON); bind(Gson.class).toProvider(GerritGsonProvider.class); }
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 deleted file mode 100644 index 4a3bc4b..0000000 --- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/FanoutReplicationConfig.java +++ /dev/null
@@ -1,72 +0,0 @@ -// Copyright (C) 2020 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.git; - -import com.google.gerrit.server.config.SitePaths; -import com.google.inject.Inject; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import org.eclipse.jgit.errors.ConfigInvalidException; -import org.eclipse.jgit.storage.file.FileBasedConfig; -import org.eclipse.jgit.util.FS; - -public class FanoutReplicationConfig implements ReplicationConfig { - private final SitePaths site; - private final FileBasedConfig secureConf; - - @Inject - public FanoutReplicationConfig(final SitePaths site) { - this.site = site; - this.secureConf = new FileBasedConfig(site.secure_config.toFile(), FS.DETECTED); - } - - @Override - public void addSecureCredentials(String authUsername, String authToken) - throws IOException, ConfigInvalidException { - secureConf.load(); - secureConf.setString("remote", authUsername, "username", authUsername); - secureConf.setString("remote", authUsername, "password", authToken); - secureConf.save(); - } - - @Override - public void addReplicationRemote(String githubUsername, String url, String projectName) - throws IOException, ConfigInvalidException { - - FileBasedConfig replicationConf = - new FileBasedConfig( - new File(site.etc_dir.toFile(), String.format("replication/%s.config", githubUsername)), - FS.DETECTED); - - replicationConf.load(); - 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); - - 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/FileBasedReplicationConfig.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/FileBasedReplicationConfig.java deleted file mode 100644 index 842bde3..0000000 --- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/FileBasedReplicationConfig.java +++ /dev/null
@@ -1,60 +0,0 @@ -// Copyright (C) 2013 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.git; - -import com.google.gerrit.server.config.SitePaths; -import com.google.inject.Inject; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import org.eclipse.jgit.errors.ConfigInvalidException; -import org.eclipse.jgit.storage.file.FileBasedConfig; -import org.eclipse.jgit.util.FS; - -public class FileBasedReplicationConfig implements ReplicationConfig { - private final FileBasedConfig secureConf; - private final FileBasedConfig replicationConf; - - @Inject - public FileBasedReplicationConfig(final SitePaths site) { - replicationConf = - new FileBasedConfig(new File(site.etc_dir.toFile(), "replication.config"), FS.DETECTED); - secureConf = new FileBasedConfig(site.secure_config.toFile(), FS.DETECTED); - } - - @Override - public synchronized void addSecureCredentials(String authUsername, String authToken) - throws IOException, ConfigInvalidException { - secureConf.load(); - secureConf.setString("remote", authUsername, "username", authUsername); - secureConf.setString("remote", authUsername, "password", authToken); - secureConf.save(); - } - - @Override - public synchronized void addReplicationRemote(String username, String url, String projectName) - throws IOException, ConfigInvalidException { - replicationConf.load(); - replicationConf.setString("remote", username, "url", url); - List<String> projects = - new ArrayList<>( - Arrays.asList(replicationConf.getStringList("remote", username, "projects"))); - projects.add(projectName); - replicationConf.setStringList("remote", username, "projects", projects); - replicationConf.setString("remote", username, "push", "refs/*:refs/*"); - replicationConf.save(); - } -}
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/ReplicateProjectStep.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/ReplicateProjectStep.java index 5109cd2..4e75d31 100644 --- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/ReplicateProjectStep.java +++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/ReplicateProjectStep.java
@@ -13,22 +13,21 @@ // limitations under the License. package com.googlesource.gerrit.plugins.github.git; +import com.google.gerrit.extensions.registration.DynamicItem; import com.google.inject.Inject; import com.google.inject.assistedinject.Assisted; import com.googlesource.gerrit.plugins.github.GitHubURL; -import com.googlesource.gerrit.plugins.github.oauth.GitHubLogin; -import com.googlesource.gerrit.plugins.github.oauth.ScopedProvider; +import com.googlesource.gerrit.plugins.replication.api.ReplicationRemotesApi; import java.io.IOException; +import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.ProgressMonitor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ReplicateProjectStep extends ImportStep { private static final Logger LOG = LoggerFactory.getLogger(ReplicateProjectStep.class); - private final ReplicationConfig replicationConfig; - private final String authUsername; - private final String authToken; - private final String gitHubUrl; + private final DynamicItem<ReplicationRemotesApi> replicationRemotesUpdaterItem; + private final ReplicationRemoteConfigBuilder remoteConfigBuilder; public interface Factory { ReplicateProjectStep create( @@ -37,20 +36,17 @@ @Inject public ReplicateProjectStep( - final ReplicationConfig replicationConfig, + final DynamicItem<ReplicationRemotesApi> replicationRemotesUpdaterItem, final GitHubRepository.Factory gitHubRepoFactory, - final ScopedProvider<GitHubLogin> ghLoginProvider, + ReplicationRemoteConfigBuilder remoteConfigBuilder, @GitHubURL String gitHubUrl, @Assisted("organisation") String organisation, @Assisted("name") String repository) throws IOException { super(gitHubUrl, organisation, repository, gitHubRepoFactory); + this.remoteConfigBuilder = remoteConfigBuilder; LOG.debug("Gerrit ReplicateProject " + organisation + "/" + repository); - this.replicationConfig = replicationConfig; - GitHubLogin ghLogin = ghLoginProvider.get(); - this.authUsername = ghLogin.getMyself().getLogin(); - this.authToken = ghLogin.getAccessToken(); - this.gitHubUrl = gitHubUrl; + this.replicationRemotesUpdaterItem = replicationRemotesUpdaterItem; } @Override @@ -58,11 +54,15 @@ progress.beginTask("Setting up Gerrit replication", 2); String repositoryName = getOrganisation() + "/" + getRepositoryName(); + Config remoteConfig = remoteConfigBuilder.build(repositoryName); progress.update(1); - replicationConfig.addSecureCredentials(authUsername, authToken); + + ReplicationRemotesApi updater = replicationRemotesUpdaterItem.get(); + if (updater != null) { + updater.update(remoteConfig); + } progress.update(1); - replicationConfig.addReplicationRemote( - authUsername, gitHubUrl + "/${name}.git", repositoryName); + progress.endTask(); }
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/ReplicationConfig.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/ReplicationConfig.java deleted file mode 100644 index 8b7712a..0000000 --- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/ReplicationConfig.java +++ /dev/null
@@ -1,27 +0,0 @@ -// Copyright (C) 2013 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.git; - -import java.io.IOException; -import org.eclipse.jgit.errors.ConfigInvalidException; - -public interface ReplicationConfig { - - void addSecureCredentials(String authUsername, String authToken) - throws IOException, ConfigInvalidException; - - void addReplicationRemote(String username, String url, String projectName) - throws IOException, ConfigInvalidException; -}
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/ReplicationRemoteConfigBuilder.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/ReplicationRemoteConfigBuilder.java new file mode 100644 index 0000000..bef109c --- /dev/null +++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/ReplicationRemoteConfigBuilder.java
@@ -0,0 +1,72 @@ +// Copyright (C) 2024 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.git; + +import com.google.gerrit.extensions.registration.DynamicItem; +import com.google.inject.Inject; +import com.googlesource.gerrit.plugins.github.GitHubURL; +import com.googlesource.gerrit.plugins.github.oauth.GitHubLogin; +import com.googlesource.gerrit.plugins.github.oauth.ScopedProvider; +import com.googlesource.gerrit.plugins.replication.api.ReplicationRemotesApi; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import org.eclipse.jgit.lib.Config; + +class ReplicationRemoteConfigBuilder { + private final String gitHubUrl; + private final String username; + private final String authToken; + private final DynamicItem<ReplicationRemotesApi> replicationConfigItem; + + @Inject + ReplicationRemoteConfigBuilder( + DynamicItem<ReplicationRemotesApi> replicationRemotesItem, + ScopedProvider<GitHubLogin> ghLoginProvider, + @GitHubURL String gitHubUrl) + throws IOException { + this.gitHubUrl = gitHubUrl; + this.replicationConfigItem = replicationRemotesItem; + GitHubLogin ghLogin = ghLoginProvider.get(); + this.username = ghLogin.getMyself().getLogin(); + this.authToken = ghLogin.getAccessToken(); + } + + Config build(String repositoryName) { + Config remoteConfig = new Config(); + + remoteConfig.setString("remote", username, "username", username); + remoteConfig.setString("remote", username, "password", authToken); + + remoteConfig.setString("remote", username, "url", gitHubUrl + "/${name}.git"); + + String[] existingProjects = getProjects(); + List<String> projects = new ArrayList<>(List.of(existingProjects)); + projects.add(repositoryName); + + remoteConfig.setStringList("remote", username, "projects", projects); + remoteConfig.setString("remote", username, "push", "refs/*:refs/*"); + + return remoteConfig; + } + + private String[] getProjects() { + ReplicationRemotesApi config = replicationConfigItem.get(); + if (config != null) { + return config.get(username).getStringList("remote", username, "projects"); + } + + return new String[0]; + } +}
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 810632a..6d24b3e 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
@@ -18,22 +18,17 @@ import com.google.common.collect.Lists; import com.google.gerrit.server.PluginUser; import com.google.gerrit.server.account.GroupBackend; -import com.google.gerrit.server.config.SitePaths; import com.google.inject.Inject; -import java.io.IOException; +import com.googlesource.gerrit.plugins.replication.api.ReplicationConfig; import java.net.URISyntaxException; -import java.nio.file.Files; -import java.nio.file.Path; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Set; import org.eclipse.jgit.errors.ConfigInvalidException; -import org.eclipse.jgit.storage.file.FileBasedConfig; +import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.transport.RefSpec; import org.eclipse.jgit.transport.RemoteConfig; import org.eclipse.jgit.transport.URIish; -import org.eclipse.jgit.util.FS; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -60,15 +55,15 @@ @Inject GitHubDestinations( - final SitePaths site, + final ReplicationConfig replicationConfig, final RemoteSiteUser.Factory ruf, final GroupBackend gb, final PluginUser pu) - throws ConfigInvalidException, IOException { + throws ConfigInvalidException { pluginUser = pu; replicationUserFactory = ruf; groupBackend = gb; - configs = getDestinations(site.etc_dir.resolve("replication.config")); + configs = getDestinations(replicationConfig.getConfig()); organisations = getOrganisations(configs); } @@ -83,22 +78,7 @@ return result; } - private List<Destination> getDestinations(Path cfgPath) - throws ConfigInvalidException, IOException { - if (!Files.exists(cfgPath) || Files.size(cfgPath) == 0) { - return Collections.emptyList(); - } - - FileBasedConfig cfg = new FileBasedConfig(cfgPath.toFile(), FS.DETECTED); - try { - cfg.load(); - } catch (ConfigInvalidException e) { - throw new ConfigInvalidException( - String.format("Config file %s is invalid: %s", cfg.getFile(), e.getMessage()), e); - } catch (IOException e) { - throw new IOException(String.format("Cannot read %s: %s", cfg.getFile(), e.getMessage()), e); - } - + private List<Destination> getDestinations(Config cfg) throws ConfigInvalidException { ImmutableList.Builder<Destination> dest = ImmutableList.builder(); for (RemoteConfig c : allRemotes(cfg)) { if (c.getURIs().isEmpty()) { @@ -108,9 +88,7 @@ for (URIish u : c.getURIs()) { if (u.getPath() == null || !u.getPath().contains("${name}")) { throw new ConfigInvalidException( - String.format( - "remote.%s.url \"%s\" lacks ${name} placeholder in %s", - c.getName(), u, cfg.getFile())); + String.format("remote.%s.url \"%s\" lacks ${name} placeholder", c.getName(), u)); } } @@ -131,7 +109,7 @@ return dest.build(); } - private static List<RemoteConfig> allRemotes(FileBasedConfig cfg) throws ConfigInvalidException { + private static List<RemoteConfig> allRemotes(Config cfg) throws ConfigInvalidException { Set<String> names = cfg.getSubsections("remote"); List<RemoteConfig> result = Lists.newArrayListWithCapacity(names.size()); for (String name : names) { @@ -140,8 +118,7 @@ result.add(new RemoteConfig(cfg, name)); } } catch (URISyntaxException e) { - throw new ConfigInvalidException( - String.format("remote %s has invalid URL in %s", name, cfg.getFile())); + throw new ConfigInvalidException(String.format("remote %s has invalid URL", name)); } } return result;
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 deleted file mode 100644 index 3613c41..0000000 --- a/github-plugin/src/test/java/com/googlesource/gerrit/plugins/github/FanoutReplicationConfigTest.java +++ /dev/null
@@ -1,99 +0,0 @@ -// 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/git/ReplicationRemoteConfigBuilderTest.java b/github-plugin/src/test/java/com/googlesource/gerrit/plugins/github/git/ReplicationRemoteConfigBuilderTest.java new file mode 100644 index 0000000..c6023e0 --- /dev/null +++ b/github-plugin/src/test/java/com/googlesource/gerrit/plugins/github/git/ReplicationRemoteConfigBuilderTest.java
@@ -0,0 +1,86 @@ +// Copyright (C) 2024 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.git; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.google.gerrit.extensions.registration.DynamicItem; +import com.googlesource.gerrit.plugins.github.oauth.GitHubLogin; +import com.googlesource.gerrit.plugins.github.oauth.ScopedProvider; +import com.googlesource.gerrit.plugins.replication.api.ReplicationRemotesApi; +import org.eclipse.jgit.lib.Config; +import org.junit.Test; +import org.kohsuke.github.GHMyself; + +public class ReplicationRemoteConfigBuilderTest { + private final String repoName = "test-repo"; + private final String username = "test-user"; + private final String password = "myHighlySecretPassword"; + private final String gitHubUrl = "htpps://github.com"; + + @Test + public void shouldBuildConfig() throws Exception { + ReplicationRemoteConfigBuilder builder = newReplicationRemoteConfigBuilder(); + Config actual = builder.build(repoName); + + assertThat(actual.getString("remote", username, "username")).isEqualTo(username); + assertThat(actual.getString("remote", username, "password")).isEqualTo(password); + assertThat(actual.getString("remote", username, "url")).isEqualTo(gitHubUrl + "/${name}.git"); + assertThat(actual.getStringList("remote", username, "projects")) + .isEqualTo(new String[] {repoName}); + assertThat(actual.getString("remote", username, "push")).isEqualTo("refs/*:refs/*"); + } + + @Test + public void shouldAppendProjectToConfig() throws Exception { + String prevProject = "imported-project"; + Config currentConfig = new Config(); + currentConfig.setString("remote", username, "projects", prevProject); + + ReplicationRemoteConfigBuilder builder = newReplicationRemoteConfigBuilder(currentConfig); + Config actual = builder.build(repoName); + + assertThat(actual.getString("remote", username, "username")).isEqualTo(username); + assertThat(actual.getString("remote", username, "password")).isEqualTo(password); + assertThat(actual.getString("remote", username, "url")).isEqualTo(gitHubUrl + "/${name}.git"); + assertThat(actual.getStringList("remote", username, "projects")) + .isEqualTo(new String[] {prevProject, repoName}); + assertThat(actual.getString("remote", username, "push")).isEqualTo("refs/*:refs/*"); + } + + private ReplicationRemoteConfigBuilder newReplicationRemoteConfigBuilder() throws Exception { + return newReplicationRemoteConfigBuilder(new Config()); + } + + private ReplicationRemoteConfigBuilder newReplicationRemoteConfigBuilder(Config currentConfig) + throws Exception { + GitHubLogin gitHubLoginMock = mock(GitHubLogin.class); + GHMyself ghMyselfMock = mock(GHMyself.class); + ScopedProvider<GitHubLogin> scopedProviderMock = mock(ScopedProvider.class); + ReplicationRemotesApi replicationRemotesApi = mock(ReplicationRemotesApi.class); + DynamicItem<ReplicationRemotesApi> replicationRemotesItem = mock(DynamicItem.class); + + when(ghMyselfMock.getLogin()).thenReturn(username); + when(gitHubLoginMock.getMyself()).thenReturn(ghMyselfMock); + when(gitHubLoginMock.getAccessToken()).thenReturn(password); + when(scopedProviderMock.get()).thenReturn(gitHubLoginMock); + when(replicationRemotesApi.get(username)).thenReturn(currentConfig); + when(replicationRemotesItem.get()).thenReturn(replicationRemotesApi); + + return new ReplicationRemoteConfigBuilder( + replicationRemotesItem, scopedProviderMock, gitHubUrl); + } +}