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

JiriOndrusek pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-upgrade-recipes.git


The following commit(s) were added to refs/heads/main by this push:
     new 5812577  Add test to verify camel-latest-version property in pom.xml 
is aligned to recipes.
5812577 is described below

commit 58125771f57e59391bd776953347fe72c4a20a10
Author: Jiri Ondrusek <[email protected]>
AuthorDate: Tue May 12 13:08:59 2026 +0200

    Add test to verify camel-latest-version property in pom.xml is aligned to 
recipes.
---
 README.adoc                                        |   2 +
 camel-spring-boot-upgrade-recipes/pom.xml          |   7 +
 .../camel/upgrade/springboot/LatestRecipeTest.java | 103 +--------------
 .../camel/upgrade/LatestCamelVersionTest.java      |  57 ++++++++
 .../org/apache/camel/upgrade/RecipeVersion.java    | 145 +++++++++++++++++++++
 5 files changed, 216 insertions(+), 98 deletions(-)

diff --git a/README.adoc b/README.adoc
index 6244959..d87b3d7 100644
--- a/README.adoc
+++ b/README.adoc
@@ -70,6 +70,8 @@ This project is released as standard Apache Camel module.
         <rewrite-recipe-bom.version>3.24.0</rewrite-recipe-bom.version>
 ```
 
+NOTE: The `camel-latest-version` property is automatically verified by the 
test suite (`LatestCamelVersionTest`) to match the highest version recipe file. 
If you add a new version recipe (e.g., `4.21.yaml`), the test will fail until 
you update the property.
+
 Check that everything is alright and run:
 
 ```bash
diff --git a/camel-spring-boot-upgrade-recipes/pom.xml 
b/camel-spring-boot-upgrade-recipes/pom.xml
index 9118474..af3dddf 100644
--- a/camel-spring-boot-upgrade-recipes/pom.xml
+++ b/camel-spring-boot-upgrade-recipes/pom.xml
@@ -47,6 +47,13 @@
             <artifactId>camel-upgrade-recipes</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel.upgrade</groupId>
+            <artifactId>camel-upgrade-recipes</artifactId>
+            <version>${project.version}</version>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
         <dependency>
             <groupId>org.openrewrite</groupId>
             <artifactId>rewrite-java-21</artifactId>
diff --git 
a/camel-spring-boot-upgrade-recipes/src/test/java/org/apache/camel/upgrade/springboot/LatestRecipeTest.java
 
b/camel-spring-boot-upgrade-recipes/src/test/java/org/apache/camel/upgrade/springboot/LatestRecipeTest.java
index 59e92c0..319c729 100644
--- 
a/camel-spring-boot-upgrade-recipes/src/test/java/org/apache/camel/upgrade/springboot/LatestRecipeTest.java
+++ 
b/camel-spring-boot-upgrade-recipes/src/test/java/org/apache/camel/upgrade/springboot/LatestRecipeTest.java
@@ -16,14 +16,13 @@
  */
 package org.apache.camel.upgrade.springboot;
 
+import org.apache.camel.upgrade.RecipeVersion;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
-import java.util.List;
-import java.util.stream.Stream;
 
 
 /**
@@ -47,18 +46,10 @@ class LatestRecipeTest {
     @Test
     void latestRecipeReferencesHighestVersion() throws Exception {
         // Get versions from camel-upgrade-recipes dependency - this is the 
source of truth
-        List<Version> versions = getVersionsFromCoreRecipes();
-
-        if (versions.isEmpty()) {
-            Path coreCamelRecipes = 
Paths.get("../camel-upgrade-recipes/src/main/resources/META-INF/rewrite")
-                    .toAbsolutePath();
-            Assertions.fail(String.format("No core Camel version recipe files 
found (pattern: X.Y.yaml). " +
-                    "Searched in: %s. Ensure multi-module structure is 
intact.", coreCamelRecipes));
-        }
-
-        Version latestVersion = versions.stream()
-                .max(Version::compareTo)
-                .orElseThrow(() -> new IllegalStateException("No maximum 
version found despite non-empty list"));
+        // Navigate to the sibling camel-upgrade-recipes module using relative 
path
+        Path coreCamelRecipes = 
Paths.get("../camel-upgrade-recipes/src/main/resources/META-INF/rewrite");
+        RecipeVersion latestVersion = 
RecipeVersion.getHighestVersionFromRecipeDirectory(coreCamelRecipes,
+                "core Camel recipes (ensure multi-module structure is 
intact)");
 
         // Read latest.yaml directly
         Path latestYamlPath = 
Paths.get("src/main/resources/META-INF/rewrite/latest.yaml").toAbsolutePath();
@@ -96,88 +87,4 @@ class LatestRecipeTest {
                                 "(it's included transitively via Spring Boot 
recipe): %s",
                         latestVersion.toDottedString(), 
latestCoreCamelRecipeName));
     }
-
-    /**
-     * Get version objects from YAML files in the camel-upgrade-recipes 
dependency.
-     * Returns only version files matching the pattern X.Y.yaml (e.g., 
4.20.yaml).
-     *
-     * @return List of Version objects found in the dependency
-     */
-    private List<Version> getVersionsFromCoreRecipes() throws Exception {
-        // Navigate to the sibling camel-upgrade-recipes module using relative 
path
-        Path coreCamelRecipes = 
Paths.get("../camel-upgrade-recipes/src/main/resources/META-INF/rewrite");
-
-        if (!Files.exists(coreCamelRecipes)) {
-            return List.of();
-        }
-
-        try (Stream<Path> paths = Files.walk(coreCamelRecipes)) {
-            return paths.filter(Files::isRegularFile)
-                    .map(Path::getFileName)
-                    .map(Path::toString)
-                    .filter(name -> name.endsWith(".yaml") && 
Character.isDigit(name.charAt(0)))
-                    .map(name -> name.substring(0, name.lastIndexOf('.')))
-                    .filter(version -> version.matches("^\\d+\\.\\d+$"))
-                    .map(Version::parse)
-                    .toList();
-        }
-    }
-
-    /**
-     * Semantic version holder for comparing X.Y version strings.
-     */
-    private static class Version implements Comparable<Version> {
-        final int major;
-        final int minor;
-
-        Version(int major, int minor) {
-            this.major = major;
-            this.minor = minor;
-        }
-
-        /**
-         * Parse a version string in X.Y format.
-         *
-         * @param version version string (e.g., "4.20")
-         * @return parsed Version object
-         * @throws IllegalArgumentException if format is invalid
-         */
-        static Version parse(String version) {
-            String[] parts = version.split("\\.");
-            if (parts.length != 2) {
-                throw new IllegalArgumentException("Version must be in format 
X.Y, got: " + version);
-            }
-            try {
-                return new Version(Integer.parseInt(parts[0]), 
Integer.parseInt(parts[1]));
-            } catch (NumberFormatException e) {
-                throw new IllegalArgumentException("Invalid version format: " 
+ version, e);
-            }
-        }
-
-        @Override
-        public int compareTo(Version other) {
-            int majorCompare = Integer.compare(this.major, other.major);
-            if (majorCompare != 0) {
-                return majorCompare;
-            }
-            return Integer.compare(this.minor, other.minor);
-        }
-
-        /**
-         * Returns version without dot (e.g., "420" for version 4.20).
-         * Used for recipe package names.
-         */
-        @Override
-        public String toString() {
-            return String.format("%d%d", major, minor);
-        }
-
-        /**
-         * Returns version with dot (e.g., "4.20").
-         * Used for user-facing messages.
-         */
-        String toDottedString() {
-            return String.format("%d.%d", major, minor);
-        }
-    }
 }
diff --git 
a/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/LatestCamelVersionTest.java
 
b/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/LatestCamelVersionTest.java
new file mode 100644
index 0000000..c1ab188
--- /dev/null
+++ 
b/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/LatestCamelVersionTest.java
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+package org.apache.camel.upgrade;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/**
+ * Test to ensure the camel-latest-version property in pom.xml is kept aligned
+ * with the highest version recipe file.
+ *
+ * This test prevents forgetting to update the camel-latest-version property
+ * when a new version recipe is added.
+ */
+class LatestCamelVersionTest {
+
+    @Test
+    void camelLatestVersionPropertyMatchesHighestRecipe() throws Exception {
+        // Find the highest version from recipe YAML files
+        Path recipesPath = Paths.get("src/main/resources/META-INF/rewrite");
+        RecipeVersion highestVersion = 
RecipeVersion.getHighestVersionFromRecipeDirectory(recipesPath, "recipe 
directory");
+
+        // Read camel-latest-version from versions.properties
+        String camelLatestVersion = CamelTestUtil.getCamelLatestVersion();
+
+        if (camelLatestVersion == null || camelLatestVersion.trim().isEmpty()) 
{
+            Assertions.fail("camel.latest.version not found in 
versions.properties. " +
+                    "Ensure the project has been built (mvn 
process-resources).");
+        }
+
+        // Parse the version from the property (e.g., "4.20.0")
+        RecipeVersion propertyVersion = 
RecipeVersion.parseFromFullVersion(camelLatestVersion);
+
+        // Compare major.minor versions
+        Assertions.assertEquals(highestVersion, propertyVersion,
+                String.format("camel-latest-version property (%s) does not 
match the highest recipe version (%s). " +
+                                "Please update the <camel-latest-version> 
property in pom.xml to %s.0",
+                        camelLatestVersion, highestVersion.toDottedString(), 
highestVersion.toDottedString()));
+    }
+}
diff --git 
a/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/RecipeVersion.java
 
b/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/RecipeVersion.java
new file mode 100644
index 0000000..6ea3b1a
--- /dev/null
+++ 
b/camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/RecipeVersion.java
@@ -0,0 +1,145 @@
+/*
+ * 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.
+ */
+package org.apache.camel.upgrade;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.stream.Stream;
+
+/**
+ * Semantic version holder for comparing X.Y version strings used in recipe 
files.
+ * This is a test utility class shared across recipe verification tests.
+ */
+public class RecipeVersion implements Comparable<RecipeVersion> {
+    public final int major;
+    public final int minor;
+
+    public RecipeVersion(int major, int minor) {
+        this.major = major;
+        this.minor = minor;
+    }
+
+    /**
+     * Parse a version string in X.Y format (e.g., "4.20").
+     *
+     * @param version version string
+     * @return parsed RecipeVersion object
+     * @throws IllegalArgumentException if format is invalid
+     */
+    public static RecipeVersion parse(String version) {
+        String[] parts = version.split("\\.");
+        if (parts.length != 2) {
+            throw new IllegalArgumentException("Version must be in format X.Y, 
got: " + version);
+        }
+        try {
+            return new RecipeVersion(Integer.parseInt(parts[0]), 
Integer.parseInt(parts[1]));
+        } catch (NumberFormatException e) {
+            throw new IllegalArgumentException("Invalid version format: " + 
version, e);
+        }
+    }
+
+    /**
+     * Parse a version string in X.Y.Z or X.Y format (e.g., "4.20.0" or 
"4.20") and return X.Y.
+     *
+     * @param fullVersion version string in X.Y.Z or X.Y format
+     * @return parsed RecipeVersion object with major.minor
+     * @throws IllegalArgumentException if format is invalid
+     */
+    public static RecipeVersion parseFromFullVersion(String fullVersion) {
+        String[] parts = fullVersion.split("\\.");
+        if (parts.length < 2) {
+            throw new IllegalArgumentException("Version must be in format 
X.Y.Z or X.Y, got: " + fullVersion);
+        }
+        try {
+            return new RecipeVersion(Integer.parseInt(parts[0]), 
Integer.parseInt(parts[1]));
+        } catch (NumberFormatException e) {
+            throw new IllegalArgumentException("Invalid version format: " + 
fullVersion, e);
+        }
+    }
+
+    @Override
+    public int compareTo(RecipeVersion other) {
+        int majorCompare = Integer.compare(this.major, other.major);
+        if (majorCompare != 0) {
+            return majorCompare;
+        }
+        return Integer.compare(this.minor, other.minor);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (obj == null || getClass() != obj.getClass()) return false;
+        RecipeVersion version = (RecipeVersion) obj;
+        return major == version.major && minor == version.minor;
+    }
+
+    @Override
+    public int hashCode() {
+        return 31 * major + minor;
+    }
+
+    /**
+     * Returns version without dot (e.g., "420" for version 4.20).
+     * Used for recipe package names.
+     */
+    @Override
+    public String toString() {
+        return String.format("%d%d", major, minor);
+    }
+
+    /**
+     * Returns version with dot (e.g., "4.20").
+     * Used for user-facing messages.
+     */
+    public String toDottedString() {
+        return String.format("%d.%d", major, minor);
+    }
+
+    /**
+     * Finds the highest version from recipe YAML files in the specified 
directory.
+     * Scans the directory for files matching the pattern X.Y.yaml (e.g., 
4.20.yaml)
+     * and returns the highest version found.
+     *
+     * @param recipesPath the directory to scan for recipe files
+     * @param pathDescription description of the path for error messages 
(e.g., "core recipes", "Spring Boot recipes")
+     * @return the highest RecipeVersion found
+     * @throws Exception if an I/O error occurs during directory traversal
+     * @throws IllegalStateException if no version files are found in the 
directory
+     */
+    public static RecipeVersion getHighestVersionFromRecipeDirectory(Path 
recipesPath, String pathDescription) throws Exception {
+        if (!Files.exists(recipesPath)) {
+            throw new IllegalStateException(
+                String.format("Recipe directory not found for %s: %s",
+                    pathDescription, recipesPath.toAbsolutePath()));
+        }
+
+        try (Stream<Path> paths = Files.walk(recipesPath)) {
+            return paths.filter(Files::isRegularFile)
+                    .map(Path::getFileName)
+                    .map(Path::toString)
+                    .filter(name -> name.endsWith(".yaml") && 
Character.isDigit(name.charAt(0)))
+                    .map(name -> name.substring(0, name.lastIndexOf('.')))
+                    .filter(version -> version.matches("^\\d+\\.\\d+$"))
+                    .map(RecipeVersion::parse)
+                    .max(RecipeVersion::compareTo)
+                    .orElseThrow(() -> new IllegalStateException(
+                        String.format("No version recipe files found (pattern: 
X.Y.yaml) in %s. Searched in: %s",
+                            pathDescription, recipesPath.toAbsolutePath())));
+        }
+    }
+}

Reply via email to