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

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

commit 11ebc82c4a70c6393135348ed78feb9b2f8fc32c
Author: David Smiley <[email protected]>
AuthorDate: Thu Oct 29 15:22:39 2026 -0400

    SOLR-18432: SolrVersion tolerates prerelease qualifier (#5254)
    
    SolrVersion now tolerates a prerelease qualifier such as -SNAPSHOT. Package 
version constraints are matched ignoring the qualifier, the cluster 
version-compatibility warning no longer treats a prerelease as older than its 
release, and /api/node/system reports the correct Solr implementation version.
    
    Co-authored-by: Claude Sonnet 5.5 <[email protected]>
    Co-authored-by: Nick Shanin <[email protected]>
    (cherry picked from commit 852b427c1154ce9eec988b9adaeb212294442126)
---
 .../SOLR-18432-solrversion-prerelease.yml          |  7 +++
 .../apache/solr/client/api/util/SolrVersion.java   | 12 ++++-
 .../test/org/apache/solr/util/TestSolrVersion.java | 60 ++++++++++++++++++++++
 .../java/org/apache/solr/cloud/ZkController.java   |  2 +-
 .../solr/handler/admin/SystemInfoProvider.java     |  3 +-
 .../handler/admin/NodeSystemInfoProviderTest.java  |  2 +-
 6 files changed, 80 insertions(+), 6 deletions(-)

diff --git a/changelog/unreleased/SOLR-18432-solrversion-prerelease.yml 
b/changelog/unreleased/SOLR-18432-solrversion-prerelease.yml
new file mode 100644
index 00000000000..ee6404c23cd
--- /dev/null
+++ b/changelog/unreleased/SOLR-18432-solrversion-prerelease.yml
@@ -0,0 +1,7 @@
+title: SolrVersion now tolerates a prerelease qualifier such as -SNAPSHOT. 
Package version constraints are matched ignoring the qualifier, the cluster 
version-compatibility warning no longer treats a prerelease as older than its 
release, and /api/node/system reports the correct Solr implementation version.
+type: fixed
+authors:
+  - name: David Smiley
+links:
+  - name: SOLR-18432
+    url: https://issues.apache.org/jira/browse/SOLR-18432
diff --git a/solr/api/src/java/org/apache/solr/client/api/util/SolrVersion.java 
b/solr/api/src/java/org/apache/solr/client/api/util/SolrVersion.java
index 42629f8900a..d85f92da9bb 100644
--- a/solr/api/src/java/org/apache/solr/client/api/util/SolrVersion.java
+++ b/solr/api/src/java/org/apache/solr/client/api/util/SolrVersion.java
@@ -76,12 +76,20 @@ public final class SolrVersion implements 
Comparable<SolrVersion> {
 
   /**
    * Returns true if this version satisfies the provided <a 
href="https://devhints.io/semver";>SemVer
-   * Expression</a>
+   * Expression</a>. Any prerelease qualifier (e.g. "-SNAPSHOT") is ignored, 
unlike plain SemVer
+   * range semantics where a prerelease satisfies no range that doesn't name 
one.
    *
    * @param semVerExpression the expression to test
    */
   public boolean satisfies(String semVerExpression) {
-    return version.satisfies(semVerExpression);
+    return version.withClearedPreRelease().satisfies(semVerExpression);
+  }
+
+  /**
+   * Returns this version with any prerelease qualifier removed, e.g. 
"10.1.0-SNAPSHOT" to "10.1.0"
+   */
+  public SolrVersion withoutPrerelease() {
+    return new SolrVersion(version.withClearedPreRelease());
   }
 
   public int getMajorVersion() {
diff --git a/solr/api/src/test/org/apache/solr/util/TestSolrVersion.java 
b/solr/api/src/test/org/apache/solr/util/TestSolrVersion.java
index ff55514e4ab..cb2394468fe 100644
--- a/solr/api/src/test/org/apache/solr/util/TestSolrVersion.java
+++ b/solr/api/src/test/org/apache/solr/util/TestSolrVersion.java
@@ -59,4 +59,64 @@ public class TestSolrVersion extends SolrTestCase {
     assertFalse(SOLR_9_0_1.satisfies("8.x"));
     assertTrue(SOLR_9_0_1.satisfies("8 - 9"));
   }
+
+  public void testPrereleaseIgnoredBySatisfies() {
+    SolrVersion snapshot = SolrVersion.valueOf("10.1.0-SNAPSHOT");
+    assertTrue(snapshot.satisfies(">=9.0.0"));
+    assertTrue(snapshot.satisfies("10.x"));
+    assertTrue(snapshot.satisfies("~10.1"));
+    assertFalse(snapshot.satisfies("<10.1"));
+  }
+
+  public void testPrereleaseRangeBoundaries() {
+    SolrVersion release = SolrVersion.valueOf("10.1.0");
+    for (String versionString : new String[] {"10.1.0-SNAPSHOT", 
"10.1.0-rc.1+b123"}) {
+      SolrVersion version = SolrVersion.valueOf(versionString);
+      assertTrue(versionString, version.satisfies(">=10.1.0"));
+      assertTrue(versionString, version.satisfies("<=10.1.0"));
+      assertTrue(versionString, version.satisfies("10.1.0"));
+      assertFalse(versionString, version.satisfies("<10.1.0"));
+      assertFalse(versionString, version.satisfies(">10.1.0"));
+      assertTrue(versionString, version.compareTo(release) < 0);
+      assertNotEquals(release, version);
+    }
+  }
+
+  public void testWithoutPrerelease() {
+    SolrVersion snapshot = SolrVersion.valueOf("10.1.0-SNAPSHOT");
+    assertTrue(snapshot.lessThan(SolrVersion.valueOf("10.1.0")));
+    assertEquals(SolrVersion.valueOf("10.1.0"), snapshot.withoutPrerelease());
+  }
+
+  public void testWithoutPrereleasePreservesBuildMetadata() {
+    SolrVersion prerelease = SolrVersion.valueOf("10.1.0-rc.1+build.123");
+    SolrVersion normalized = prerelease.withoutPrerelease();
+    assertEquals("10.1.0+build.123", normalized.toString());
+    assertEquals("10.1.0-rc.1+build.123", prerelease.toString());
+    assertTrue(prerelease.lessThan(normalized));
+  }
+
+  public void testWithoutPrereleaseOnRelease() {
+    for (String versionString : new String[] {"10.1.2", "10.1.2+build.123"}) {
+      SolrVersion release = SolrVersion.valueOf(versionString);
+      SolrVersion normalized = release.withoutPrerelease();
+      assertEquals(versionString, normalized.toString());
+      assertEquals(versionString, normalized.withoutPrerelease().toString());
+    }
+  }
+
+  public void testWithoutPrereleaseOrdering() {
+    SolrVersion normalized = 
SolrVersion.valueOf("10.1.0-SNAPSHOT").withoutPrerelease();
+    for (String versionString : new String[] {"10.1.0", "10.1.0-alpha.1", 
"10.1.0-rc.1+b123"}) {
+      SolrVersion sameRelease = 
SolrVersion.valueOf(versionString).withoutPrerelease();
+      assertFalse(versionString, normalized.lessThan(sameRelease));
+      assertFalse(versionString, sameRelease.lessThan(normalized));
+    }
+    for (String versionString :
+        new String[] {"10.1.1-SNAPSHOT", "10.2.0-SNAPSHOT", 
"11.0.0-SNAPSHOT"}) {
+      SolrVersion higherRelease = 
SolrVersion.valueOf(versionString).withoutPrerelease();
+      assertTrue(versionString, normalized.lessThan(higherRelease));
+      assertFalse(versionString, higherRelease.lessThan(normalized));
+    }
+  }
 }
diff --git a/solr/core/src/java/org/apache/solr/cloud/ZkController.java 
b/solr/core/src/java/org/apache/solr/cloud/ZkController.java
index d34a25f9a9e..c2e24e142d4 100644
--- a/solr/core/src/java/org/apache/solr/cloud/ZkController.java
+++ b/solr/core/src/java/org/apache/solr/cloud/ZkController.java
@@ -642,7 +642,7 @@ public class ZkController implements Closeable {
       SolrVersion ourVersion = SolrVersion.LATEST;
       SolrVersion clusterVersion = lowestVersion.get();
 
-      if (ourVersion.lessThan(clusterVersion)) {
+      if 
(ourVersion.withoutPrerelease().lessThan(clusterVersion.withoutPrerelease())) {
         log.warn(
             "Our Solr version {} is older than cluster version {}", 
ourVersion, clusterVersion);
 
diff --git 
a/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoProvider.java 
b/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoProvider.java
index 3006fb624a4..737d963d91f 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoProvider.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoProvider.java
@@ -339,8 +339,7 @@ public class SystemInfoProvider {
     String implVersion = p.getImplementationVersion();
     // non-null mostly for testing
     info.solrSpecVersion = specVersion == null ? SolrVersion.LATEST_STRING : 
specVersion;
-    info.solrImplVersion =
-        implVersion == null ? SolrVersion.LATEST.getPrereleaseVersion() : 
implVersion;
+    info.solrImplVersion = implVersion == null ? SolrVersion.LATEST_STRING : 
implVersion;
 
     info.luceneSpecVersion = Version.LATEST.toString();
     info.luceneImplVersion = Version.getPackageImplementationVersion();
diff --git 
a/solr/core/src/test/org/apache/solr/handler/admin/NodeSystemInfoProviderTest.java
 
b/solr/core/src/test/org/apache/solr/handler/admin/NodeSystemInfoProviderTest.java
index 13b3ee4ce3e..5d2e29a5119 100644
--- 
a/solr/core/src/test/org/apache/solr/handler/admin/NodeSystemInfoProviderTest.java
+++ 
b/solr/core/src/test/org/apache/solr/handler/admin/NodeSystemInfoProviderTest.java
@@ -67,7 +67,7 @@ public class NodeSystemInfoProviderTest extends 
SolrTestCaseJ4 {
     
Assert.assertEquals(h.getCoreContainer().getCoreRootDirectory().toString(), 
info.coreRoot);
     Assert.assertNotNull(info.lucene);
     Assert.assertNotNull(info.lucene.solrImplVersion);
-    Assert.assertEquals(info.lucene.solrImplVersion, 
SolrVersion.LATEST.getPrereleaseVersion());
+    Assert.assertEquals(info.lucene.solrImplVersion, 
SolrVersion.LATEST_STRING);
     Assert.assertNotNull(info.lucene.solrSpecVersion);
     Assert.assertEquals(info.lucene.solrSpecVersion, 
SolrVersion.LATEST_STRING);
     Assert.assertNotNull(info.lucene.luceneImplVersion);

Reply via email to