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 b36b25e Add LatestRecipeTest to veriflylatest.yaml being up-to-date
b36b25e is described below
commit b36b25e9ba8b7d507fb890d6a6adddc349afc0c6
Author: Jiri Ondrusek <[email protected]>
AuthorDate: Tue May 12 09:56:20 2026 +0200
Add LatestRecipeTest to veriflylatest.yaml being up-to-date
---
.../camel/upgrade/springboot/LatestRecipeTest.java | 183 +++++++++++++++++++++
1 file changed, 183 insertions(+)
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
new file mode 100644
index 0000000..59e92c0
--- /dev/null
+++
b/camel-spring-boot-upgrade-recipes/src/test/java/org/apache/camel/upgrade/springboot/LatestRecipeTest.java
@@ -0,0 +1,183 @@
+/*
+ * 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.springboot;
+
+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;
+
+
+/**
+ * Test to ensure the latest.yaml recipe references the highest version recipe
+ * from the camel-upgrade-recipes dependency.
+ *
+ * The test uses the camel-upgrade-recipes dependency as the source of truth,
+ * finds the highest version there, and verifies that latest.yaml references
+ * the Spring Boot migration recipe for that version (but NOT the core Camel
+ * migration recipe, which is included transitively via the version-specific
+ * recipe chain).
+ *
+ * This prevents forgetting to update latest.yaml when a new version is added
+ * to the dependency.
+ *
+ * Note: This test requires running from the camel-spring-boot-upgrade-recipes
+ * module directory with the full multi-module checkout structure intact.
+ */
+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"));
+
+ // Read latest.yaml directly
+ Path latestYamlPath =
Paths.get("src/main/resources/META-INF/rewrite/latest.yaml").toAbsolutePath();
+ if (!Files.exists(latestYamlPath)) {
+ Assertions.fail("latest.yaml not found at: " + latestYamlPath);
+ }
+ String latestYamlContent = Files.readString(latestYamlPath);
+
+ // Build recipe names using version string without dot (e.g., "4.20"
-> "420")
+ String versionWithoutDot = String.format("%d%d", latestVersion.major,
latestVersion.minor);
+
+ // Expected Spring Boot recipe name:
org.apache.camel.upgrade.camelXY.CamelSpringBootMigrationRecipe
+ String latestSpringBootRecipeName = String.format(
+
"org.apache.camel.upgrade.camel%s.CamelSpringBootMigrationRecipe",
+ versionWithoutDot);
+
+ // Verify Spring Boot recipe is present in recipeList section
+ if (!latestYamlContent.contains("recipeList:")) {
+ Assertions.fail("latest.yaml does not contain 'recipeList:'
section");
+ }
+ String recipeListSection =
latestYamlContent.substring(latestYamlContent.indexOf("recipeList:"));
+
+
Assertions.assertTrue(recipeListSection.contains(latestSpringBootRecipeName),
+ String.format("Expected Spring Boot recipe for version %s not
found in recipeList: %s",
+ latestVersion.toDottedString(),
latestSpringBootRecipeName));
+
+ // Expected core Camel recipe name from dependency:
org.apache.camel.upgrade.camelXY.CamelMigrationRecipe
+ String latestCoreCamelRecipeName = String.format(
+ "org.apache.camel.upgrade.camel%s.CamelMigrationRecipe",
+ versionWithoutDot);
+
+ // Verify core Camel recipe is NOT directly present (it's included
transitively)
+
Assertions.assertFalse(recipeListSection.contains(latestCoreCamelRecipeName),
+ String.format("Core Camel recipe for version %s should NOT be
directly present in latest.yaml " +
+ "(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);
+ }
+ }
+}