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

jdaugherty pushed a commit to branch 7.0.x
in repository https://gitbox.apache.org/repos/asf/grails-core.git


The following commit(s) were added to refs/heads/7.0.x by this push:
     new 5552997e2e fix GrailsVersion detection logic
5552997e2e is described below

commit 5552997e2e5c068860e8e15197bae1e81aebf9c4
Author: James Daugherty <[email protected]>
AuthorDate: Sun Jun 1 08:30:25 2025 -0400

    fix GrailsVersion detection logic
---
 grails-wrapper/build.gradle                        | 13 +++-
 .../src/main/java/grails/init/GrailsVersion.java   | 77 ++++++++++++++--------
 .../groovy/grails/init/GrailsVersionSpec.groovy    | 57 ++++++++++++++++
 3 files changed, 117 insertions(+), 30 deletions(-)

diff --git a/grails-wrapper/build.gradle b/grails-wrapper/build.gradle
index 19502e612b..f8022561df 100644
--- a/grails-wrapper/build.gradle
+++ b/grails-wrapper/build.gradle
@@ -17,6 +17,7 @@
 
 plugins {
     id 'java'
+    id 'groovy'
     id 'distribution'
 }
 
@@ -36,11 +37,21 @@ ext {
     startMainClass = 'grails.init.Start'
 }
 
-// Intentionally no dependencies to prevent bloat
+dependencies {
+    // Intentionally no implementation dependencies to prevent bloat
+
+    testImplementation platform(project(':grails-bom'))
+    testImplementation 'org.apache.groovy:groovy'
+    testImplementation 'org.spockframework:spock-core'
+    testImplementation 'org.apache.groovy:groovy-test-junit5'
+    testImplementation 'org.junit.jupiter:junit-jupiter-api'
+    testImplementation 'org.junit.platform:junit-platform-runner'
+}
 
 apply {
     from rootProject.layout.projectDirectory.file('gradle/java-config.gradle')
     from 
rootProject.layout.projectDirectory.file('gradle/publish-config.gradle')
+    from rootProject.layout.projectDirectory.file('gradle/test-config.gradle')
 }
 
 // It's surprisingly hard to generate start scripts and *not* have them nested 
into a bin / lib directory
diff --git a/grails-wrapper/src/main/java/grails/init/GrailsVersion.java 
b/grails-wrapper/src/main/java/grails/init/GrailsVersion.java
index 1acf1d40b8..2c21e9616d 100644
--- a/grails-wrapper/src/main/java/grails/init/GrailsVersion.java
+++ b/grails-wrapper/src/main/java/grails/init/GrailsVersion.java
@@ -24,19 +24,18 @@ import java.util.regex.Pattern;
  * Assists in parsing grails versions and sorting them by priority
  */
 public class GrailsVersion implements Comparable<GrailsVersion> {
-    private static final Pattern VERSION_PATTERN = 
Pattern.compile("^(\\d+)[.](\\d+)[.](.*)$");
+    private static final Pattern VERSION_PATTERN = 
Pattern.compile("^(\\d+)[.](\\d+)[.](\\d+)-?(.*)$");
 
-    private static final Pattern RELEASE = Pattern.compile("^(\\d+)$");
     private static final Pattern RC = Pattern.compile("^RC(\\d+)$");
     private static final Pattern MILESTONE = Pattern.compile("^M(\\d+)$");
-    private static final Pattern SNAPSHOT = 
Pattern.compile("^(\\d+)-SNAPSHOT$");
+    private static final Pattern SNAPSHOT = Pattern.compile("^SNAPSHOT$");
 
     public final String version;
-    public final String major;
-    public final String minor;
-    public final String patch;
+    public final int major;
+    public final int minor;
+    public final int patch;
     public final GrailsReleaseType releaseType;
-    public final int patchNumber;
+    public final Integer candidate;
 
     /**
      * @param version the grails version number
@@ -46,32 +45,38 @@ public class GrailsVersion implements 
Comparable<GrailsVersion> {
 
         Matcher matcher = VERSION_PATTERN.matcher(version);
         if (!matcher.matches()) {
-            throw new IllegalArgumentException("Invalid version format: " + 
version);
+            throw new IllegalArgumentException("Invalid Grails Version format: 
" + version);
         }
 
-        if (matcher.groupCount() != 3) {
-            throw new IllegalArgumentException("Invalid version format: " + 
version);
+        if (matcher.groupCount() != 4) {
+            throw new IllegalArgumentException("Invalid Grails Version format: 
" + version);
         }
 
-        major = matcher.group(1);
-        minor = matcher.group(2);
-        patch = matcher.group(3);
+        major = Integer.parseInt(matcher.group(1));
+        minor = Integer.parseInt(matcher.group(2));
+        patch = Integer.parseInt(matcher.group(3));
+
+        String candidateString = matcher.group(4);
 
         Matcher m;
-        if ((m = RELEASE.matcher(patch)).matches()) {
+        if(candidateString.isEmpty()) {
             releaseType = GrailsReleaseType.RELEASE;
-            patchNumber = Integer.parseInt(m.group(1));
-        } else if ((m = RC.matcher(patch)).matches()) {
+            candidate = null;
+        }
+        else if((m = RC.matcher(candidateString)).matches()) {
             releaseType = GrailsReleaseType.RC;
-            patchNumber = Integer.parseInt(m.group(1));
-        } else if ((m = MILESTONE.matcher(patch)).matches()) {
+            candidate = Integer.parseInt(m.group(1));
+        }
+        else if((m = MILESTONE.matcher(candidateString)).matches()) {
             releaseType = GrailsReleaseType.MILESTONE;
-            patchNumber = Integer.parseInt(m.group(1));
-        } else if ((m = SNAPSHOT.matcher(patch)).matches()) {
+            candidate = Integer.parseInt(m.group(1));
+        }
+        else if((m = SNAPSHOT.matcher(candidateString)).matches()) {
             releaseType = GrailsReleaseType.SNAPSHOT;
-            patchNumber = Integer.parseInt(m.group(1));
-        } else {
-            throw new IllegalArgumentException("Unrecognized patch version: " 
+ patch);
+            candidate = null;
+        }
+        else {
+            throw new IllegalArgumentException("Invalid Candidate Version: " + 
candidateString);
         }
     }
 
@@ -79,7 +84,12 @@ public class GrailsVersion implements 
Comparable<GrailsVersion> {
     public boolean equals(Object o) {
         if (o == null || getClass() != o.getClass()) return false;
         GrailsVersion that = (GrailsVersion) o;
-        return Objects.equals(major, that.major) && Objects.equals(minor, 
that.minor) && Objects.equals(patch, that.patch);
+        return Objects.equals(releaseType, that.releaseType) &&
+                Objects.equals(major, that.major) &&
+                Objects.equals(minor, that.minor) &&
+                Objects.equals(patch, that.patch) &&
+                Objects.equals(candidate, that.candidate)
+                ;
     }
 
     @Override
@@ -97,21 +107,30 @@ public class GrailsVersion implements 
Comparable<GrailsVersion> {
             return 0;
         }
 
-        int majorCompare = this.major.compareTo(o.major);
+        if (releaseType != o.releaseType) {
+            return o.releaseType.ordinal() - releaseType.ordinal();
+        }
+
+        int majorCompare = Integer.compare(this.major, o.major);
         if (majorCompare != 0) {
             return majorCompare;
         }
 
-        int minorCompare = this.minor.compareTo(o.minor);
+        int minorCompare = Integer.compare(this.minor, o.minor);
         if (minorCompare != 0) {
             return minorCompare;
         }
 
-        if(releaseType != o.releaseType) {
-            return releaseType.ordinal() - o.releaseType.ordinal();
+        int patchCompare = Integer.compare(this.patch, o.patch);
+        if (patchCompare != 0) {
+            return patchCompare;
+        }
+
+        if (candidate == null) {
+            return 0;
         }
 
-        return Integer.compare(patchNumber, o.patchNumber);
+        return Integer.compare(this.candidate, o.candidate);
     }
 
     @Override
diff --git 
a/grails-wrapper/src/test/groovy/grails/init/GrailsVersionSpec.groovy 
b/grails-wrapper/src/test/groovy/grails/init/GrailsVersionSpec.groovy
new file mode 100644
index 0000000000..42b6b6d56b
--- /dev/null
+++ b/grails-wrapper/src/test/groovy/grails/init/GrailsVersionSpec.groovy
@@ -0,0 +1,57 @@
+package grails.init
+
+import spock.lang.Specification
+import spock.lang.Unroll
+
+class GrailsVersionSpec extends Specification {
+
+    @Unroll
+    def "grails version #version"(String version, String major, String minor, 
String patch, GrailsReleaseType releaseType, Integer candidate) {
+        when:
+        GrailsVersion grailsVersion = new GrailsVersion(version)
+
+        then:
+        noExceptionThrown()
+        grailsVersion.version == version
+        grailsVersion.major == major as int
+        grailsVersion.minor == minor as int
+        grailsVersion.patch == patch as int
+        grailsVersion.releaseType == releaseType
+        grailsVersion.candidate == candidate as Integer
+
+        where:
+        version          | major | minor | patch | releaseType                 
| candidate
+        '7.0.0'          | '7'   | '0'   | '0'   | GrailsReleaseType.RELEASE   
| null
+        '7.0.1'          | '7'   | '0'   | '1'   | GrailsReleaseType.RELEASE   
| null
+        '7.2.0'          | '7'   | '2'   | '0'   | GrailsReleaseType.RELEASE   
| null
+        '7.0.0-SNAPSHOT' | '7'   | '0'   | '0'   | GrailsReleaseType.SNAPSHOT  
| null
+        '7.0.0-RC1'      | '7'   | '0'   | '0'   | GrailsReleaseType.RC        
| 1
+        '7.0.0-M2'       | '7'   | '0'   | '0'   | GrailsReleaseType.MILESTONE 
| 2
+    }
+
+    def "comparison checks"() {
+        expect:
+        new GrailsVersion('7.0.0') < new GrailsVersion('7.0.1')
+        new GrailsVersion('7.0.1') > new GrailsVersion('7.0.0')
+        new GrailsVersion('7.0.0') < new GrailsVersion('7.1.0')
+        new GrailsVersion('8.0.0') > new GrailsVersion('7.0.0')
+        new GrailsVersion('7.0.0') > new GrailsVersion('7.0.0-SNAPSHOT')
+        new GrailsVersion('7.0.0') > new GrailsVersion('7.0.0-RC1')
+        new GrailsVersion('7.0.0') > new GrailsVersion('7.0.0-M1')
+        new GrailsVersion('7.0.0-RC1') > new GrailsVersion('7.0.0-M1')
+        new GrailsVersion('7.0.0-RC2') > new GrailsVersion('7.0.0-RC1')
+        new GrailsVersion('7.0.0-RC1') > new GrailsVersion('7.0.0-SNAPSHOT')
+        new GrailsVersion('7.0.0-M2') > new GrailsVersion('7.0.0-M1')
+        new GrailsVersion('7.0.0-M1') > new GrailsVersion('7.0.0-SNAPSHOT')
+    }
+
+    def "sorted"() {
+        expect:
+        [new GrailsVersion('7.0.0'), new GrailsVersion('7.0.0-RC1'), new 
GrailsVersion('7.0.0-M1'), new GrailsVersion('7.0.0-SNAPSHOT')].sort() == [
+            new GrailsVersion('7.0.0-SNAPSHOT'),
+            new GrailsVersion('7.0.0-M1'),
+            new GrailsVersion('7.0.0-RC1'),
+            new GrailsVersion('7.0.0')
+        ]
+    }
+}

Reply via email to