Allow to filter out refs from the fetch-replication deltas Other plugins, e.g. the global-refdb, may want to influence the behaviour of the pull-replication plugin and prevent refs from being replicated. Introduce the refs filtering interface defined already in the replication plugin with I99a7cb4fb2 but applied to the refs deltas to fetch. Bug: Issue 15637 Change-Id: I19d58638181fa4bab204aba30b2cda73241f7ed0
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/FetchOne.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/FetchOne.java index 24da012..c028d84 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/FetchOne.java +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/FetchOne.java
@@ -22,6 +22,7 @@ import com.google.common.collect.ListMultimap; import com.google.common.collect.Sets; import com.google.gerrit.entities.Project; +import com.google.gerrit.extensions.registration.DynamicItem; import com.google.gerrit.metrics.Timer1; import com.google.gerrit.server.git.GitRepositoryManager; import com.google.gerrit.server.git.PerThreadRequestScope; @@ -100,6 +101,7 @@ private final AtomicBoolean canceledWhileRunning; private final FetchFactory fetchFactory; private final Optional<PullReplicationApiRequestMetrics> apiRequestMetrics; + private DynamicItem<ReplicationFetchFilter> replicationFetchFilter; @Inject FetchOne( @@ -133,6 +135,12 @@ this.apiRequestMetrics = apiRequestMetrics; } + @Inject(optional = true) + public void setReplicationFetchFilter( + DynamicItem<ReplicationFetchFilter> replicationFetchFilter) { + this.replicationFetchFilter = replicationFetchFilter; + } + @Override public void cancel() { repLog.info("[{}] Replication task from {} was canceled", taskIdHex, getURI()); @@ -438,13 +446,20 @@ return configRefSpecs; } - return delta.stream() + return runRefsFilter(delta).stream() .map(ref -> refToFetchRefSpec(ref, configRefSpecs)) .filter(Optional::isPresent) .map(Optional::get) .collect(Collectors.toList()); } + private Set<String> runRefsFilter(Set<String> refs) { + return Optional.ofNullable(replicationFetchFilter) + .flatMap(filter -> Optional.ofNullable(filter.get())) + .map(f -> f.filter(this.projectName.get(), refs)) + .orElse(refs); + } + private Optional<RefSpec> refToFetchRefSpec(String ref, List<RefSpec> configRefSpecs) { for (RefSpec refSpec : configRefSpecs) { if (refSpec.matchSource(ref)) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/ReplicationExtensionPointModule.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/ReplicationExtensionPointModule.java new file mode 100644 index 0000000..7b35668 --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/ReplicationExtensionPointModule.java
@@ -0,0 +1,32 @@ +// 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.replication.pull; + +import com.google.gerrit.extensions.registration.DynamicItem; +import com.google.inject.AbstractModule; + +/** + * Gerrit libModule for applying a fetch-filter for pull replications. + * + * <p>It should be used only when an actual filter is defined, otherwise the default plugin + * behaviour will be fetching refs without any filtering. + */ +public class ReplicationExtensionPointModule extends AbstractModule { + + @Override + protected void configure() { + DynamicItem.itemOf(binder(), ReplicationFetchFilter.class); + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/ReplicationFetchFilter.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/ReplicationFetchFilter.java new file mode 100644 index 0000000..dfe6fbd --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/ReplicationFetchFilter.java
@@ -0,0 +1,29 @@ +// 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.replication.pull; + +import com.google.gerrit.extensions.annotations.ExtensionPoint; +import java.util.Set; + +/** + * Filter that is invoked before a set of remote refs are fetched from a remote instance. + * + * <p>It can be used to filter out unwanted fetches. + */ +@ExtensionPoint +public interface ReplicationFetchFilter { + + public Set<String> filter(String projectName, Set<String> fetchRefs); +}
diff --git a/src/main/resources/Documentation/extension-point.md b/src/main/resources/Documentation/extension-point.md new file mode 100644 index 0000000..33127c5 --- /dev/null +++ b/src/main/resources/Documentation/extension-point.md
@@ -0,0 +1,47 @@ +@PLUGIN@ extension points +============== + +The @PLUGIN@ plugin exposes an extension point to allow influencing its +behaviour from another plugin or a script. +Extension points are available only when the plugin extension points module +is loaded as [libModule](/config-gerrit.html#gerrit.installModule) and +implemented by another plugin which depends on this as `provided` +dependency. + +### Install extension libModule + +The @PLUGIN@ plugin's extension points are defined in the +`c.g.g.p.r.p.ReplicationExtensionPointModule` that needs to be configured +as libModule. + +Create a symbolic link from `$GERRIT_SITE/plugins/@PLUGIN@.jar` into +`$GERRIT_SITE/lib` and then add the @PLUGIN@ extension module to the +`gerrit.config`. + +Example: + +``` +[gerrit] + installModule = com.googlesource.gerrit.plugins.replication.pull.ReplicationExtensionPointModule +``` + +> **NOTE**: Use and configuration of the @PLUGIN@ plugin as library module +requires a Gerrit server restart and does not support hot plugin install or +upgrade. + + +### Extension points + +* `com.googlesource.gerrit.plugins.replication.pull.ReplicationFetchFilter` + + Filter out the refs fetched from a remote instance. + Only one filter at a time is supported. Filter implementation needs to + bind a `DynamicItem`. + + Default: no filtering + + Example: + + ``` + DynamicItem.bind(binder(), ReplicationFetchFilter.class).to(ReplicationFetchFilterImpl.class); + ```