This is an automated email from the ASF dual-hosted git repository.

janhoy pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr.git


The following commit(s) were added to refs/heads/main by this push:
     new 4ae645ef0e1 SOLR-18511: Port ClusterTool to picocli (#5038)
4ae645ef0e1 is described below

commit 4ae645ef0e1a5d0249eb859e98188341ec63f0bc
Author: Serhiy Bzhezytskyy <[email protected]>
AuthorDate: Thu Oct 8 18:31:17 2026 +0300

    SOLR-18511: Port ClusterTool to picocli (#5038)
    
    Co-authored-by: Jan Høydahl <[email protected]>
---
 .../SOLR-17697-picocli-experimental-cli.yml        |  2 +
 .../src/java/org/apache/solr/cli/ClusterTool.java  | 44 ++++++++++-
 .../core/src/java/org/apache/solr/cli/SolrCLI.java |  3 +-
 .../apache/solr/cli/ZkSubcommandsPicocliTest.java  | 14 ++++
 .../org/apache/solr/cli/ZkSubcommandsTest.java     | 20 ++++-
 .../modules/deployment-guide/deployment-nav.adoc   |  1 +
 .../modules/deployment-guide/pages/cli/index.adoc  |  1 +
 .../deployment-guide/pages/cli/solr-cluster.adoc   | 85 ++++++++++++++++++++++
 8 files changed, 164 insertions(+), 6 deletions(-)

diff --git a/changelog/unreleased/SOLR-17697-picocli-experimental-cli.yml 
b/changelog/unreleased/SOLR-17697-picocli-experimental-cli.yml
index 410b7c408a5..b554c9600fb 100644
--- a/changelog/unreleased/SOLR-17697-picocli-experimental-cli.yml
+++ b/changelog/unreleased/SOLR-17697-picocli-experimental-cli.yml
@@ -15,3 +15,5 @@ links:
     url: https://issues.apache.org/jira/browse/SOLR-18510
   - name: SOLR-18509
     url: https://issues.apache.org/jira/browse/SOLR-18509
+  - name: SOLR-18511
+    url: https://issues.apache.org/jira/browse/SOLR-18511
diff --git a/solr/core/src/java/org/apache/solr/cli/ClusterTool.java 
b/solr/core/src/java/org/apache/solr/cli/ClusterTool.java
index ce43eff54f1..baf98380fca 100644
--- a/solr/core/src/java/org/apache/solr/cli/ClusterTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/ClusterTool.java
@@ -32,9 +32,23 @@ import org.apache.solr.common.cloud.SolrZkClient;
  *
  * <p>Set cluster properties by directly manipulating ZooKeeper.
  */
+@SuppressWarnings("UnnecessarilyFullyQualified")
[email protected](
+    name = "cluster",
+    description = "Set cluster properties by directly manipulating ZooKeeper.",
+    footerHeading = "%nExamples:%n",
+    footer = {
+      "  # Set the urlScheme cluster property",
+      "  bin/solr cluster --property urlScheme --value https"
+    })
 public class ClusterTool extends ToolBase {
   // It is a shame this tool doesn't more closely mimic how the ConfigTool 
works.
 
+  /**
+   * @deprecated Only used by the commons-cli parser; the picocli path 
declares this as an annotated
+   *     field.
+   */
+  @Deprecated
   private static final Option PROPERTY_OPTION =
       Option.builder()
           .longOpt("property")
@@ -44,6 +58,11 @@ public class ClusterTool extends ToolBase {
           .desc("Name of the Cluster property to apply the action to, such as: 
'urlScheme'.")
           .get();
 
+  /**
+   * @deprecated Only used by the commons-cli parser; the picocli path 
declares this as an annotated
+   *     field.
+   */
+  @Deprecated
   private static final Option VALUE_OPTION =
       Option.builder()
           .longOpt("value")
@@ -55,6 +74,27 @@ public class ClusterTool extends ToolBase {
   /** Parameters for the cluster command, independent of the command line 
parser. */
   record ClusterParams(String propertyName, String propertyValue, String 
zkHost) {}
 
+  // --- picocli fields ---
+
+  @picocli.CommandLine.Option(
+      names = "--property",
+      required = true,
+      paramLabel = "PROPERTY",
+      description = "Name of the Cluster property to apply the action to, such 
as: 'urlScheme'.")
+  private String propertyOpt;
+
+  @picocli.CommandLine.Option(
+      names = "--value",
+      paramLabel = "VALUE",
+      description = "Set the property to this value.")
+  private String valueOpt;
+
+  @picocli.CommandLine.Mixin private ZkConnectionOptions zkOpts;
+
+  public ClusterTool() {
+    this(new DefaultToolRuntime());
+  }
+
   public ClusterTool(ToolRuntime runtime) {
     super(runtime);
   }
@@ -111,6 +151,8 @@ public class ClusterTool extends ToolBase {
 
   @Override
   public int callTool() throws Exception {
-    throw new UnsupportedOperationException("This tool does not yet support 
PicoCli");
+    ClusterParams params = new ClusterParams(propertyOpt, valueOpt, 
zkOpts.resolveZkHost());
+    setClusterProperty(params);
+    return 0;
   }
 }
diff --git a/solr/core/src/java/org/apache/solr/cli/SolrCLI.java 
b/solr/core/src/java/org/apache/solr/cli/SolrCLI.java
index 998414dd4dd..1e0e5e46a3a 100755
--- a/solr/core/src/java/org/apache/solr/cli/SolrCLI.java
+++ b/solr/core/src/java/org/apache/solr/cli/SolrCLI.java
@@ -82,7 +82,8 @@ import org.slf4j.LoggerFactory;
       CreateTool.class,
       DeleteTool.class,
       AssertTool.class,
-      ApiTool.class
+      ApiTool.class,
+      ClusterTool.class
     })
 public class SolrCLI implements CLIO, java.util.concurrent.Callable<Integer> {
 
diff --git 
a/solr/core/src/test/org/apache/solr/cli/ZkSubcommandsPicocliTest.java 
b/solr/core/src/test/org/apache/solr/cli/ZkSubcommandsPicocliTest.java
index 9b631013cd5..72279717ea9 100644
--- a/solr/core/src/test/org/apache/solr/cli/ZkSubcommandsPicocliTest.java
+++ b/solr/core/src/test/org/apache/solr/cli/ZkSubcommandsPicocliTest.java
@@ -17,6 +17,8 @@
 package org.apache.solr.cli;
 
 import java.util.Arrays;
+import org.apache.solr.common.cloud.ClusterProperties;
+import org.junit.Test;
 import picocli.CommandLine;
 
 /**
@@ -48,4 +50,16 @@ public class ZkSubcommandsPicocliTest extends 
ZkSubcommandsTest {
         .setDefaultValueProvider(new CliDefaultValueProvider())
         .execute(toolArgs);
   }
+
+  @Test
+  public void testSetClusterPropertyWithSolrConnection() throws Exception {
+    // picocli only: the picocli tool takes the shared connection options, 
commons-cli has -z alone
+    ClusterProperties properties = new ClusterProperties(zkClient);
+    String[] args =
+        new String[] {
+          "cluster", "--property", "urlScheme", "--value", "https", "-s", 
zkServer.getZkAddress()
+        };
+    assertEquals(0, runTool(args, ClusterTool.class));
+    assertEquals("https", properties.getClusterProperty("urlScheme", "none"));
+  }
 }
diff --git a/solr/core/src/test/org/apache/solr/cli/ZkSubcommandsTest.java 
b/solr/core/src/test/org/apache/solr/cli/ZkSubcommandsTest.java
index 4aebf94ee76..80d02217a89 100644
--- a/solr/core/src/test/org/apache/solr/cli/ZkSubcommandsTest.java
+++ b/solr/core/src/test/org/apache/solr/cli/ZkSubcommandsTest.java
@@ -59,7 +59,7 @@ public class ZkSubcommandsTest extends SolrTestCaseJ4 {
 
   protected ZkTestServer zkServer;
 
-  private SolrZkClient zkClient;
+  SolrZkClient zkClient;
 
   protected static final Path SOLR_HOME = SolrTestCaseJ4.TEST_HOME();
 
@@ -590,22 +590,34 @@ public class ZkSubcommandsTest extends SolrTestCaseJ4 {
 
   @Test
   public void testSetClusterProperty() throws Exception {
-    // ClusterTool is not a picocli ZK subcommand; always use the commons-cli 
path.
     ClusterProperties properties = new ClusterProperties(zkClient);
     // add property urlScheme=http
     String[] args =
         new String[] {
           "cluster", "--property", "urlScheme", "--value", "http", "-z", 
zkServer.getZkAddress()
         };
-    assertEquals(0, CLITestHelper.runTool(args, ClusterTool.class));
+    assertEquals(0, runTool(args, ClusterTool.class));
 
     assertEquals("http", properties.getClusterProperty("urlScheme", "none"));
 
     args = new String[] {"cluster", "--property", "urlScheme", "-z", 
zkServer.getZkAddress()};
-    assertEquals(0, CLITestHelper.runTool(args, ClusterTool.class));
+    assertEquals(0, runTool(args, ClusterTool.class));
     assertNull(properties.getClusterProperty("urlScheme", (String) null));
   }
 
+  @Test
+  public void testSetClusterPropertyUsesZkHostProperty() throws Exception {
+    ClusterProperties properties = new ClusterProperties(zkClient);
+    System.setProperty("zkHost", zkServer.getZkAddress());
+    try {
+      String[] args = new String[] {"cluster", "--property", "urlScheme", 
"--value", "https"};
+      assertEquals(0, runTool(args, ClusterTool.class));
+    } finally {
+      System.clearProperty("zkHost");
+    }
+    assertEquals("https", properties.getClusterProperty("urlScheme", "none"));
+  }
+
   @Test
   public void testUpdateAcls() throws Exception {
 
diff --git a/solr/solr-ref-guide/modules/deployment-guide/deployment-nav.adoc 
b/solr/solr-ref-guide/modules/deployment-guide/deployment-nav.adoc
index a5c2d787e0b..0d6de3d1693 100644
--- a/solr/solr-ref-guide/modules/deployment-guide/deployment-nav.adoc
+++ b/solr/solr-ref-guide/modules/deployment-guide/deployment-nav.adoc
@@ -23,6 +23,7 @@
 *** xref:cli/solr-api.adoc[api]
 *** xref:cli/solr-assert.adoc[assert]
 *** xref:cli/solr-auth.adoc[auth]
+*** xref:cli/solr-cluster.adoc[cluster]
 *** xref:cli/solr-create.adoc[create]
 *** xref:cli/solr-delete.adoc[delete]
 *** xref:cli/solr-start.adoc[start]
diff --git a/solr/solr-ref-guide/modules/deployment-guide/pages/cli/index.adoc 
b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/index.adoc
index ed3b6ccda34..cc5d9215739 100644
--- a/solr/solr-ref-guide/modules/deployment-guide/pages/cli/index.adoc
+++ b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/index.adoc
@@ -62,6 +62,7 @@ Any command not listed here is unavailable when the picocli 
implementation is en
 |xref:cli/solr-api.adoc[bin/solr api]
 |xref:cli/solr-assert.adoc[bin/solr assert]
 |xref:cli/solr-auth.adoc[bin/solr auth]
+|xref:cli/solr-cluster.adoc[bin/solr cluster]
 |xref:cli/solr-create.adoc[bin/solr create]
 |xref:cli/solr-delete.adoc[bin/solr delete]
 |xref:cli/solr-start.adoc[bin/solr start]
diff --git 
a/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-cluster.adoc 
b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-cluster.adoc
new file mode 100644
index 00000000000..cd4c7ee8792
--- /dev/null
+++ b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-cluster.adoc
@@ -0,0 +1,85 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+//
+// DO NOT EDIT -- this page is auto-generated from picocli annotations.
+// To update: modify the @Command/@Option annotations in the Java source, then 
run:
+//   ./gradlew :solr:solr-ref-guide:generateCliDocs
+
+= bin/solr cluster
+:page-toclevels: 2
+
+[WARNING]
+====
+This page documents the *experimental* picocli implementation of `bin/solr`, 
which is not enabled by default.
+For what `bin/solr` does by default, see 
xref:solr-control-script-reference.adoc[].
+See xref:cli/index.adoc[] to enable this implementation and for its known 
limitations.
+====
+
+// tag::picocli-generated-man-section-synopsis[]
+== Synopsis
+
+....
+bin/solr cluster [-hv] --property=PROPERTY [-s=<solrConnection>]
+                 [--solr-url=<solrUrl>] [-u=<credentials>] [--value=VALUE]
+                 [-z=<zkHost>]
+....
+
+// end::picocli-generated-man-section-synopsis[]
+
+// tag::picocli-generated-man-section-description[]
+== Description
+
+Set cluster properties by directly manipulating ZooKeeper.
+
+// end::picocli-generated-man-section-description[]
+
+// tag::picocli-generated-man-section-options[]
+== Options
+
+*-h*, *--help*::
+  Print this help message and exit.
+
+*--property*=_PROPERTY_::
+  *(required)* Name of the Cluster property to apply the action to, such as: 
'urlScheme'.
+
+*-s*, *--solr-connection*=_<solrConnection>_::
+  Zookeeper or HTTP(s) connection string; unnecessary if SOLR_CONNECTION is 
defined in solr.in.sh; otherwise, defaults to localhost:9983.
+
+*--solr-url*=_<solrUrl>_::
+  Base Solr URL, which can be used to determine the zk-host if --zk-host is 
not known
+
+*-u*, *--credentials*=_<credentials>_::
+  Credentials in the format username:password. Example: --credentials 
solr:SolrRocks
+
+*-v*, *--verbose*::
+  Enable verbose mode.
+
+*--value*=_VALUE_::
+  Set the property to this value.
+
+*-z*, *--zk-host*=_<zkHost>_::
+  Zookeeper connection string; unnecessary if ZK_HOST is defined in 
solr.in.sh; otherwise, defaults to localhost:9983.
+
+// end::picocli-generated-man-section-options[]
+
+// tag::picocli-generated-man-section-footer[]
+== Examples
+[%hardbreaks]
+  # Set the urlScheme cluster property
+  bin/solr cluster --property urlScheme --value https
+
+// end::picocli-generated-man-section-footer[]

Reply via email to