Add skeleton healthcheck for pull replication tasks

Register a pull-replication healthcheck in the healthcheck plugin's
dynamic set.
This change is just the scaffolding for the pull-replication health
check, a dummy check which (for now) always returns PASSED.

Bug: Issue 312895374
Change-Id: I780cfe4f1930e17d6561a4c155828e72a57d8f4a
diff --git a/BUILD b/BUILD
index 53b55dc..5825e1d 100644
--- a/BUILD
+++ b/BUILD
@@ -17,6 +17,7 @@
     resources = glob(["src/main/resources/**/*"]),
     deps = [
         ":events-broker-neverlink",
+        ":healthcheck-neverlink",
         "//lib/commons:io",
         "//plugins/delete-project",
         "//plugins/replication",
@@ -36,8 +37,8 @@
         ":pull-replication__plugin",
         ":pull_replication_util",
         "//plugins/delete-project",
-        "//plugins/replication",
         "//plugins/events-broker",
+        "//plugins/replication",
     ],
 )
 
@@ -85,3 +86,9 @@
     neverlink = 1,
     exports = ["//plugins/events-broker"],
 )
+
+java_library(
+    name = "healthcheck-neverlink",
+    neverlink = 1,
+    exports = ["//plugins/healthcheck"],
+)
diff --git a/Jenkinsfile b/Jenkinsfile
index a4fff37..cd68ab8 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -1,3 +1,4 @@
 pluginPipeline(formatCheckId: 'gerritforge:pull-replication-format-3852e64366bb37d13b8baf8af9b15cfd38eb9227',
                buildCheckId: 'gerritforge:pull-replication-3852e64366bb37d13b8baf8af9b15cfd38eb9227',
+               extraPlugins: ['healthcheck'],
                extraModules: ['events-broker'])
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationModule.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationModule.java
index fdd2a0f..a058426 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationModule.java
@@ -18,6 +18,7 @@
 import static com.googlesource.gerrit.plugins.replication.pull.api.FetchApiCapability.CALL_FETCH_ACTION;
 
 import com.google.common.eventbus.EventBus;
+import com.google.common.flogger.FluentLogger;
 import com.google.gerrit.extensions.annotations.Exports;
 import com.google.gerrit.extensions.config.CapabilityDefinition;
 import com.google.gerrit.extensions.events.HeadUpdatedListener;
@@ -49,10 +50,12 @@
 import com.googlesource.gerrit.plugins.replication.pull.event.EventsBrokerConsumerModule;
 import com.googlesource.gerrit.plugins.replication.pull.event.StreamEventModule;
 import com.googlesource.gerrit.plugins.replication.pull.fetch.ApplyObject;
+import com.googlesource.gerrit.plugins.replication.pull.health.PullReplicationHealthCheckModule;
 import org.eclipse.jgit.lib.Config;
 
 class PullReplicationModule extends AbstractModule {
 
+  private static final FluentLogger flogger = FluentLogger.forEnclosingClass();
   private final MetricMaker pluginMetricMaker;
   private final ReplicationConfigModule configModule;
 
@@ -137,5 +140,17 @@
     EventTypes.register(FetchRefReplicatedEvent.TYPE, FetchRefReplicatedEvent.class);
     EventTypes.register(FetchRefReplicationDoneEvent.TYPE, FetchRefReplicationDoneEvent.class);
     EventTypes.register(FetchReplicationScheduledEvent.TYPE, FetchReplicationScheduledEvent.class);
+
+    try {
+      install(new PullReplicationHealthCheckModule());
+    } catch (NoClassDefFoundError e) {
+      if (e.getMessage()
+          .contains("com/googlesource/gerrit/plugins/healthcheck/check/HealthCheck")) {
+        flogger.atInfo().log(
+            "Skipping registration of pull replication health checks; healthcheck plugin API not loaded");
+      } else {
+        throw e;
+      }
+    }
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/health/PullReplicationHealthCheckModule.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/health/PullReplicationHealthCheckModule.java
new file mode 100644
index 0000000..c607357
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/health/PullReplicationHealthCheckModule.java
@@ -0,0 +1,27 @@
+// 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.replication.pull.health;
+
+import com.google.gerrit.extensions.registration.DynamicSet;
+import com.google.inject.AbstractModule;
+import com.googlesource.gerrit.plugins.healthcheck.check.HealthCheck;
+
+public class PullReplicationHealthCheckModule extends AbstractModule {
+
+  @Override
+  protected void configure() {
+    DynamicSet.bind(binder(), HealthCheck.class).to(PullReplicationTasksHealthCheck.class);
+  }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/health/PullReplicationTasksHealthCheck.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/health/PullReplicationTasksHealthCheck.java
new file mode 100644
index 0000000..ea6fdb5
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/health/PullReplicationTasksHealthCheck.java
@@ -0,0 +1,41 @@
+// 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.replication.pull.health;
+
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.gerrit.extensions.annotations.PluginName;
+import com.google.gerrit.metrics.MetricMaker;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.googlesource.gerrit.plugins.healthcheck.HealthCheckConfig;
+import com.googlesource.gerrit.plugins.healthcheck.check.AbstractHealthCheck;
+
+@Singleton
+public class PullReplicationTasksHealthCheck extends AbstractHealthCheck {
+
+  @Inject
+  public PullReplicationTasksHealthCheck(
+      ListeningExecutorService executor,
+      HealthCheckConfig config,
+      @PluginName String name,
+      MetricMaker metricMaker) {
+    super(executor, config, name + "-tasks", metricMaker);
+  }
+
+  @Override
+  protected Result doCheck() throws Exception {
+    return Result.PASSED;
+  }
+}