diff --git a/changelog/unreleased/SOLR-18432-solrversion-prerelease.yml b/changelog/unreleased/SOLR-18432-solrversion-prerelease.yml new file mode 100644 index 000000000000..ee6404c23cde --- /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 c0d5324e5aab..92b1c82e60cc 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 boolean lessThanOrEqualTo(SolrVersion other) { /** * Returns true if this version satisfies the provided SemVer - * Expression + * Expression. 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 ff55514e4ab2..cb2394468fef 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 void testSatisfies() { 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 0abc95cbd9b8..3daf99712afb 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 @@ private void checkClusterVersionCompatibility() throws InterruptedException, Kee 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 f9accfe106b0..52d279a3f6b4 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 @@ -338,8 +338,7 @@ public NodeSystemResponse.Lucene getLuceneInfo() { 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 13b3ee4ce3e4..5d2e29a51194 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 void testGetNodeSystemInfo() { 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);