This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new feb1e3ed47a7 yaml dsl validator maven plugin (#21403)
feb1e3ed47a7 is described below
commit feb1e3ed47a7bfed733d4dd56142ae0d82285a20
Author: Claus Ibsen <[email protected]>
AuthorDate: Wed Feb 11 14:07:08 2026 +0100
yaml dsl validator maven plugin (#21403)
* CAMEL-22931: Maven Plugin for YAML DSL validator
---
bom/camel-bom/pom.xml | 5 +
docs/components/modules/others/nav.adoc | 1 +
.../camel-yaml-dsl-validator-maven-plugin.adoc | 1 +
docs/pom.xml | 3 +
docs/user-manual/modules/ROOT/nav.adoc | 11 +-
.../camel-yaml-dsl-validator-maven-plugin.adoc | 119 +++++++++
.../maven/dsl/yaml/GenerateYamlSchemaMojo.java | 5 +-
.../camel-yaml-dsl-validator-maven-plugin/pom.xml | 117 +++++++++
.../camel-yaml-dsl-validator-maven-plugin.adoc | 119 +++++++++
.../camel/dsl/yaml/validator/ValidateMojo.java | 291 +++++++++++++++++++++
.../camel-yaml-dsl-validator/pom.xml | 80 ++++++
.../camel/dsl/yaml/validator/YamlValidator.java | 82 ++++++
.../dsl/yaml/validator/YamlValidatorTest.java | 48 ++++
.../src/test/resources/bad.yaml | 26 ++
.../src/test/resources/foo.yaml | 26 ++
.../src/test/resources/log4j2.properties | 31 +++
dsl/camel-yaml-dsl/pom.xml | 2 +
parent/pom.xml | 5 +
18 files changed, 966 insertions(+), 6 deletions(-)
diff --git a/bom/camel-bom/pom.xml b/bom/camel-bom/pom.xml
index 13bb1c80c79c..dda32ab0f532 100644
--- a/bom/camel-bom/pom.xml
+++ b/bom/camel-bom/pom.xml
@@ -2567,6 +2567,11 @@
<artifactId>camel-yaml-dsl-deserializers</artifactId>
<version>4.18.0-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-yaml-dsl-validator</artifactId>
+ <version>4.18.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-yaml-io</artifactId>
diff --git a/docs/components/modules/others/nav.adoc
b/docs/components/modules/others/nav.adoc
index 5ccb0459539f..138e6ddf9ef3 100644
--- a/docs/components/modules/others/nav.adoc
+++ b/docs/components/modules/others/nav.adoc
@@ -5,6 +5,7 @@
** xref:attachments.adoc[Attachments]
*** xref:aws-xray.adoc[AWS XRay]
*** xref:azure-schema-registry.adoc[Azure Schema Registry]
+** xref:camel-yaml-dsl-validator-maven-plugin.adoc[Camel YAML DSL Validator
Maven Plugin]
** xref:cli-connector.adoc[CLI Connector]
** xref:cli-debug.adoc[CLI Debug]
** xref:cloudevents.adoc[Cloudevents]
diff --git
a/docs/components/modules/others/pages/camel-yaml-dsl-validator-maven-plugin.adoc
b/docs/components/modules/others/pages/camel-yaml-dsl-validator-maven-plugin.adoc
new file mode 120000
index 000000000000..1ab0b4936762
--- /dev/null
+++
b/docs/components/modules/others/pages/camel-yaml-dsl-validator-maven-plugin.adoc
@@ -0,0 +1 @@
+../../../../../dsl/camel-yaml-dsl/camel-yaml-dsl-validator-maven-plugin/src/main/docs/camel-yaml-dsl-validator-maven-plugin.adoc
\ No newline at end of file
diff --git a/docs/pom.xml b/docs/pom.xml
index 55b34dcc8b91..c50fc522a7d4 100644
--- a/docs/pom.xml
+++ b/docs/pom.xml
@@ -123,6 +123,9 @@
<resource>
<directory>../catalog/camel-report-maven-plugin/src/main/docs</directory>
</resource>
+ <resource>
+
<directory>../dsl/camel-yaml-dsl/camel-yaml-dsl-validator-maven-plugin/src/main/docs</directory>
+ </resource>
</resources>
</configuration>
</execution>
diff --git a/docs/user-manual/modules/ROOT/nav.adoc
b/docs/user-manual/modules/ROOT/nav.adoc
index eb09a11eadaa..62a471a755e0 100644
--- a/docs/user-manual/modules/ROOT/nav.adoc
+++ b/docs/user-manual/modules/ROOT/nav.adoc
@@ -8,13 +8,14 @@
** xref:camel-jbang.adoc[Camel JBang]
*** xref:jbang-commands/camel-jbang-commands.adoc[Camel JBang Command
Reference]
*** xref:camel-jbang-launcher.adoc[Camel JBang Launcher]
-*** xref:camel-jbang-kubernetes.adoc[Camel JBang Kubernetes plugin]
-*** xref:camel-jbang-test.adoc[Camel JBang Testing plugin]
+*** xref:camel-jbang-kubernetes.adoc[Camel JBang Kubernetes Plugin]
+*** xref:camel-jbang-test.adoc[Camel JBang Testing Plugin]
*** xref:camel-jbang-mcp.adoc[Camel MCP Server]
** xref:camel-maven-plugin.adoc[Camel Maven Plugin]
-** xref:camel-component-maven-plugin.adoc[Camel Component Maven Plugin]
-** xref:camel-report-maven-plugin.adoc[Camel Maven Report Plugin]
-** xref:camel-maven-archetypes.adoc[Camel Maven Archetypes]
+*** xref:camel-component-maven-plugin.adoc[Camel Component Maven Plugin]
+*** xref:camel-report-maven-plugin.adoc[Camel Maven Report Plugin]
+*** xref:camel-yaml-dsl-validator-maven-plugin.adoc[Camel Maven YAML DSL
Validator Plugin]
+*** xref:camel-maven-archetypes.adoc[Camel Maven Archetypes]
** xref:configuring-route-startup-ordering-and-autostartup.adoc[Configuring
route startup ordering and autostartup]
** xref:component-dsl.adoc[Component DSL]
** xref:Endpoint-dsl.adoc[Endpoint DSL]
diff --git
a/docs/user-manual/modules/ROOT/pages/camel-yaml-dsl-validator-maven-plugin.adoc
b/docs/user-manual/modules/ROOT/pages/camel-yaml-dsl-validator-maven-plugin.adoc
new file mode 100644
index 000000000000..99678fafadfd
--- /dev/null
+++
b/docs/user-manual/modules/ROOT/pages/camel-yaml-dsl-validator-maven-plugin.adoc
@@ -0,0 +1,119 @@
+= Camel YAML DSL Validator Maven Plugin
+
+The Camel YAML DSL Validator Maven Plugin supports the following goals
+
+ - camel-yaml-dsl-validator:validate - To validate YAML routes are correct
according to spec
+
+== camel-yaml-dsl-validator:validate
+
+For validating the YAML routes for syntax errors according to the spec.
+
+Then you can run the `validate` goal from the command line or from within your
Java editor such as IDEA or Eclipse.
+
+[source,bash]
+----
+mvn camel-yaml-dsl-validator:validate
+----
+
+You can also enable the plugin to run automatically as part of the build to
catch these errors.
+
+[source,xml]
+----
+<plugin>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-yaml-dsl-validate-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>process-classes</phase>
+ <goals>
+ <goal>validate</goal>
+ </goals>
+ </execution>
+ </executions>
+</plugin>
+----
+
+The phase determines when the plugin runs. In the sample above the phase is
`process-classes` which runs after
+the compilation of the main source code.
+
+The maven plugin can also be configured to validate the test source code,
which means that the phase should be
+changed accordingly to `process-test-classes` as shown below:
+
+[source,xml]
+----
+<plugin>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-yaml-dsl-validate-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <configuration>
+ <includeTest>true</includeTest>
+ </configuration>
+ <phase>process-test-classes</phase>
+ <goals>
+ <goal>validate</goal>
+ </goals>
+ </execution>
+ </executions>
+</plugin>
+----
+
+=== Running the goal on any Maven project
+
+You can also run the validate goal on any Maven project without having to add
the plugin to the `pom.xml` file.
+Doing so requires to specify the plugin using its fully qualified name. For
example to run the goal on
+the `main-yaml` from Apache Camel you can run
+
+[source,bash]
+----
+$cd main-yaml
+$mvn org.apache.camel:camel-yaml-dsl-validator-maven-plugin:4.18.0:validate
+----
+
+Which for example outputs (with a forced error)
+[source,text]
+----
+[INFO] --- camel-yaml-dsl-validator:4.18.0:validate (default-cli) @
camel-example-main-yaml ---
+[INFO] Found
[/Users/davsclaus/workspace/camel-examples/main-yaml/src/main/resources/routes/my-route.camel.yaml]
YAML files ...
+[INFO] Validating 1 YAML files ...
+[WARNING]
+
+Validation error detected in 1 files
+
+ File: my-route.camel.yaml
+ /0/route/from: property 'step' is not defined in the schema and
the schema does not allow additional properties
+ /0/route/from: required property 'steps' not found
+----
+
+=== Options
+
+The maven plugin *validate* goal supports the following options which can be
configured from the command line (use `-D` syntax), or defined in the `pom.xml`
file in the `<configuration>` tag.
+
+|===
+| Parameter | Default Value | Description
+| skip | false | Skip the validation execution.
+| failOnError | false | Whether to fail if invalid Camel endpoints was found.
By default the plugin logs the errors at WARN level.
+| includeTest | false | Whether to include test source code.
+| includes | | To filter the names of YAML files to only include files
matching any of the given list of patterns (wildcard and regular expression).
Multiple values can be separated by comma.
+| excludes | | To filter the names of YAML files to exclude files matching any
of the given list of patterns (wildcard and regular expression). Multiple
values can be separated by comma.
+| onlyCamelYamlExt | false | Whether to only accept files with xxx.camel.yaml
as file name. By default, all .yaml files are accepted.
+|===
+
+For example to excludes a specific file:
+
+[source,bash]
+----
+$mvn camel-yaml-dsl-validator:validate -Dcamel.excludes=cheese.yaml
+----
+
+Notice that you must prefix the `-D` command argument with `camel.`, eg
`camel.excludes` as the option name.
+
+=== Validating include test
+
+If you have a Maven project then you can run the plugin to validate the
endpoints in the unit test source code as well.
+You can pass in the options using `-D` style as shown:
+
+----
+$cd myproject
+$mvn org.apache.camel:camel-yaml-dsl-validator:4.18.0:validate
-Dcamel.includeTest=true
+----
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl-maven-plugin/src/main/java/org/apache/camel/maven/dsl/yaml/GenerateYamlSchemaMojo.java
b/dsl/camel-yaml-dsl/camel-yaml-dsl-maven-plugin/src/main/java/org/apache/camel/maven/dsl/yaml/GenerateYamlSchemaMojo.java
index 5f1389eb43f3..46c3f031f91a 100644
---
a/dsl/camel-yaml-dsl/camel-yaml-dsl-maven-plugin/src/main/java/org/apache/camel/maven/dsl/yaml/GenerateYamlSchemaMojo.java
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl-maven-plugin/src/main/java/org/apache/camel/maven/dsl/yaml/GenerateYamlSchemaMojo.java
@@ -66,6 +66,9 @@ import org.jboss.jandex.DotName;
threadSafe = true,
requiresProject = false)
public class GenerateYamlSchemaMojo extends GenerateYamlSupportMojo {
+
+ private static final String DRAFT =
"http://json-schema.org/draft-04/schema#";
+
@Parameter(required = true)
private File outputFile;
@Parameter(defaultValue = "true")
@@ -84,7 +87,7 @@ public class GenerateYamlSchemaMojo extends
GenerateYamlSupportMojo {
final ObjectNode root = mapper.createObjectNode();
- root.put("$schema", "http://json-schema.org/draft-04/schema#");
+ root.put("$schema", DRAFT);
root.put("type", "array");
items = root.putObject("items");
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator-maven-plugin/pom.xml
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator-maven-plugin/pom.xml
new file mode 100644
index 000000000000..09a91b578249
--- /dev/null
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator-maven-plugin/pom.xml
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-yaml-dsl-parent</artifactId>
+ <version>4.18.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>camel-yaml-dsl-validator-maven-plugin</artifactId>
+ <packaging>maven-plugin</packaging>
+
+ <name>Camel :: YAML DSL :: Validator :: Maven Plugins</name>
+ <description>Maven plugin to validate YAML DSL</description>
+
+ <properties>
+ <firstVersion>4.18.0</firstVersion>
+ <camel-prepare-component>false</camel-prepare-component>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-yaml-dsl-validator</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-plugin-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-compat</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.plugin-tools</groupId>
+ <artifactId>maven-plugin-annotations</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-settings-builder</artifactId>
+ <version>${maven-version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-builder-support</artifactId>
+ <version>${maven-version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-model-builder</artifactId>
+ <version>${maven-version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-resolver-provider</artifactId>
+ <version>${maven-version}</version>
+ <scope>provided</scope>
+ </dependency>
+
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-plugin-plugin</artifactId>
+ <configuration>
+ <goalPrefix>camel-yaml-dsl-validator</goalPrefix>
+ <mojoDependencies>
+ <dep>org.codehaus.mojo:exec-maven-plugin</dep>
+ <dep>org.apache.maven:maven-plugin-api</dep>
+ </mojoDependencies>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.eclipse.sisu</groupId>
+ <artifactId>sisu-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>generate-index</id>
+ <goals>
+ <goal>main-index</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator-maven-plugin/src/main/docs/camel-yaml-dsl-validator-maven-plugin.adoc
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator-maven-plugin/src/main/docs/camel-yaml-dsl-validator-maven-plugin.adoc
new file mode 100644
index 000000000000..99678fafadfd
--- /dev/null
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator-maven-plugin/src/main/docs/camel-yaml-dsl-validator-maven-plugin.adoc
@@ -0,0 +1,119 @@
+= Camel YAML DSL Validator Maven Plugin
+
+The Camel YAML DSL Validator Maven Plugin supports the following goals
+
+ - camel-yaml-dsl-validator:validate - To validate YAML routes are correct
according to spec
+
+== camel-yaml-dsl-validator:validate
+
+For validating the YAML routes for syntax errors according to the spec.
+
+Then you can run the `validate` goal from the command line or from within your
Java editor such as IDEA or Eclipse.
+
+[source,bash]
+----
+mvn camel-yaml-dsl-validator:validate
+----
+
+You can also enable the plugin to run automatically as part of the build to
catch these errors.
+
+[source,xml]
+----
+<plugin>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-yaml-dsl-validate-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>process-classes</phase>
+ <goals>
+ <goal>validate</goal>
+ </goals>
+ </execution>
+ </executions>
+</plugin>
+----
+
+The phase determines when the plugin runs. In the sample above the phase is
`process-classes` which runs after
+the compilation of the main source code.
+
+The maven plugin can also be configured to validate the test source code,
which means that the phase should be
+changed accordingly to `process-test-classes` as shown below:
+
+[source,xml]
+----
+<plugin>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-yaml-dsl-validate-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <configuration>
+ <includeTest>true</includeTest>
+ </configuration>
+ <phase>process-test-classes</phase>
+ <goals>
+ <goal>validate</goal>
+ </goals>
+ </execution>
+ </executions>
+</plugin>
+----
+
+=== Running the goal on any Maven project
+
+You can also run the validate goal on any Maven project without having to add
the plugin to the `pom.xml` file.
+Doing so requires to specify the plugin using its fully qualified name. For
example to run the goal on
+the `main-yaml` from Apache Camel you can run
+
+[source,bash]
+----
+$cd main-yaml
+$mvn org.apache.camel:camel-yaml-dsl-validator-maven-plugin:4.18.0:validate
+----
+
+Which for example outputs (with a forced error)
+[source,text]
+----
+[INFO] --- camel-yaml-dsl-validator:4.18.0:validate (default-cli) @
camel-example-main-yaml ---
+[INFO] Found
[/Users/davsclaus/workspace/camel-examples/main-yaml/src/main/resources/routes/my-route.camel.yaml]
YAML files ...
+[INFO] Validating 1 YAML files ...
+[WARNING]
+
+Validation error detected in 1 files
+
+ File: my-route.camel.yaml
+ /0/route/from: property 'step' is not defined in the schema and
the schema does not allow additional properties
+ /0/route/from: required property 'steps' not found
+----
+
+=== Options
+
+The maven plugin *validate* goal supports the following options which can be
configured from the command line (use `-D` syntax), or defined in the `pom.xml`
file in the `<configuration>` tag.
+
+|===
+| Parameter | Default Value | Description
+| skip | false | Skip the validation execution.
+| failOnError | false | Whether to fail if invalid Camel endpoints was found.
By default the plugin logs the errors at WARN level.
+| includeTest | false | Whether to include test source code.
+| includes | | To filter the names of YAML files to only include files
matching any of the given list of patterns (wildcard and regular expression).
Multiple values can be separated by comma.
+| excludes | | To filter the names of YAML files to exclude files matching any
of the given list of patterns (wildcard and regular expression). Multiple
values can be separated by comma.
+| onlyCamelYamlExt | false | Whether to only accept files with xxx.camel.yaml
as file name. By default, all .yaml files are accepted.
+|===
+
+For example to excludes a specific file:
+
+[source,bash]
+----
+$mvn camel-yaml-dsl-validator:validate -Dcamel.excludes=cheese.yaml
+----
+
+Notice that you must prefix the `-D` command argument with `camel.`, eg
`camel.excludes` as the option name.
+
+=== Validating include test
+
+If you have a Maven project then you can run the plugin to validate the
endpoints in the unit test source code as well.
+You can pass in the options using `-D` style as shown:
+
+----
+$cd myproject
+$mvn org.apache.camel:camel-yaml-dsl-validator:4.18.0:validate
-Dcamel.includeTest=true
+----
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator-maven-plugin/src/main/java/org/apache/camel/dsl/yaml/validator/ValidateMojo.java
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator-maven-plugin/src/main/java/org/apache/camel/dsl/yaml/validator/ValidateMojo.java
new file mode 100644
index 000000000000..bea0fe93e0bb
--- /dev/null
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator-maven-plugin/src/main/java/org/apache/camel/dsl/yaml/validator/ValidateMojo.java
@@ -0,0 +1,291 @@
+/*
+ * 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.dsl.yaml.validator;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+import javax.inject.Inject;
+
+import com.networknt.schema.ValidationMessage;
+import org.apache.camel.support.PatternHelper;
+import org.apache.camel.util.FileUtil;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.model.Resource;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.project.MavenProject;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+
+@Mojo(name = "validate", threadSafe = true)
+public class ValidateMojo extends AbstractMojo {
+
+ private final YamlValidator validator = new YamlValidator();
+
+ private static final String IGNORE_FILE = "application.yml";
+
+ /**
+ * The maven project.
+ */
+ @Parameter(property = "project", required = true, readonly = true)
+ protected MavenProject project;
+
+ @Parameter(defaultValue = "${session}", readonly = true, required = true)
+ private MavenSession session;
+
+ /**
+ * Skip the validation execution.
+ */
+ @Parameter(property = "camel.skipValidation", defaultValue = "false")
+ private boolean skip;
+
+ /**
+ * Whether to fail if validation reported errors. By default, the plugin
logs the errors at WARN level
+ */
+ @Parameter(property = "camel.failOnError", defaultValue = "false")
+ private boolean failOnError;
+
+ @Parameter(defaultValue = "${project.build.directory}")
+ private String projectBuildDir;
+
+ /**
+ * Whether to only accept files with xxx.camel.yaml as file name. By
default, all .yaml files are accepted.
+ */
+ @Parameter(property = "camel.onlyCamelYamlExt")
+ private boolean onlyCamelYamlExt;
+
+ /**
+ * Whether to include test source code
+ */
+ @Parameter(property = "camel.includeTest", defaultValue = "false")
+ private boolean includeTest;
+
+ /**
+ * To filter the names of YAML files to only include files matching any of
the given list of patterns (wildcard and
+ * regular expression). Multiple values can be separated by comma.
+ */
+ @Parameter(property = "camel.includes")
+ private String includes;
+
+ /**
+ * To filter the names of YAML files to exclude files matching any of the
given pattern in the list (wildcard and
+ * regular expression). Multiple values can be separated by comma.
+ */
+ @Parameter(property = "camel.excludes")
+ private String excludes;
+
+ /**
+ * yamlFiles in memory cache, useful for multi modules maven projects
+ */
+ private static final Set<File> yamlFiles = new LinkedHashSet<>();
+
+ private final RepositorySystem repositorySystem;
+
+ @Parameter(defaultValue = "${repositorySystemSession}", readonly = true)
+ private RepositorySystemSession repositorySystemSession;
+
+ @Inject
+ public ValidateMojo(RepositorySystem repositorySystem) {
+ this.repositorySystem = repositorySystem;
+ }
+
+ @Override
+ public void execute() throws MojoExecutionException {
+ if (skip) {
+ getLog().info("skipping YAML DSL validation as per configuration");
+ return;
+ }
+
+ // find all XML routes
+ String ext = onlyCamelYamlExt ? ".camel.yaml" : ".yaml";
+ findYamlRouters(yamlFiles, includeTest, ext, project);
+ getLog().debug("Found " + yamlFiles.size() + " YAML files ...");
+
+ Map<File, List<ValidationMessage>> reports = new LinkedHashMap<>();
+ List<File> matched = new ArrayList<>();
+ for (File file : yamlFiles) {
+ if (matchFile(file)) {
+ matched.add(file);
+ }
+ }
+ if (!matched.isEmpty()) {
+ getLog().info("Validating " + matched.size() + " YAML files ...");
+ try {
+ validator.init();
+ for (File file : matched) {
+ var report = validateYamlRoute(file);
+ reports.put(file, report);
+ }
+ } catch (Exception e) {
+ throw new MojoExecutionException(e);
+ }
+ }
+
+ validateResults(reports);
+ }
+
+ private void validateResults(Map<File, List<ValidationMessage>> reports)
throws MojoExecutionException {
+ int count = errorCounts(reports);
+ if (count == 0) {
+ getLog().info("Validation success");
+ return;
+ }
+ StringBuilder sb = new StringBuilder();
+ sb.append("Validation error detected in ").append(count).append("
files\n\n");
+
+ for (var e : reports.entrySet()) {
+ String name = e.getKey().getName();
+ var report = e.getValue();
+
+ sb.append("\tFile: ").append(name).append("\n");
+ for (var r : report) {
+ sb.append("\t\t").append(r.toString()).append("\n");
+ }
+ sb.append("\n");
+ }
+ getLog().warn("\n\n" + sb + "\n\n");
+
+ if (failOnError) {
+ throw new MojoExecutionException(sb.toString());
+ }
+ }
+
+ private int errorCounts(Map<File, List<ValidationMessage>> reports) {
+ int count = 0;
+ for (List<ValidationMessage> list : reports.values()) {
+ if (!list.isEmpty()) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ private List<ValidationMessage> validateYamlRoute(File file) throws
Exception {
+ getLog().debug("Validating YAML DSL in file: " + file);
+ return validator.validate(file);
+ }
+
+ private boolean matchFile(File file) {
+ String no = FileUtil.onlyName(file.getName());
+ if (IGNORE_FILE.equals(no)) {
+ return false;
+ }
+ return matchRouteFile(file, excludes, includes, project);
+ }
+
+ public static boolean matchRouteFile(File file, String excludes, String
includes, MavenProject project) {
+ if (excludes == null && includes == null) {
+ return true;
+ } else if (excludes != null && fileListMatchesPattern(excludes, file,
project)) {
+ return false;
+ } else {
+ return includes != null ? fileListMatchesPattern(includes, file,
project) : true;
+ }
+ }
+
+ public static boolean fileListMatchesPattern(String fileList, File file,
MavenProject project) {
+ for (String fileName : fileList.split(",")) {
+ fileName = fileName.trim();
+ String fqn = stripRootPath(asRelativeFile(file.getAbsolutePath(),
project), project);
+ boolean match = PatternHelper.matchPattern(fqn, fileName) ||
PatternHelper.matchPattern(file.getName(), fileName);
+ if (match) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static String stripRootPath(String name, MavenProject project) {
+ for (String dir : project.getCompileSourceRoots()) {
+ dir = asRelativeFile(dir, project);
+ if (name.startsWith(dir)) {
+ return name.substring(dir.length() + 1);
+ }
+ }
+
+ for (String dir : project.getTestCompileSourceRoots()) {
+ dir = asRelativeFile(dir, project);
+ if (name.startsWith(dir)) {
+ return name.substring(dir.length() + 1);
+ }
+ }
+
+ for (Resource resource : project.getResources()) {
+ String dir = asRelativeFile(resource.getDirectory(), project);
+ if (name.startsWith(dir)) {
+ return name.substring(dir.length() + 1);
+ }
+ }
+
+ for (Resource resource : project.getTestResources()) {
+ String dir = asRelativeFile(resource.getDirectory(), project);
+ if (name.startsWith(dir)) {
+ return name.substring(dir.length() + 1);
+ }
+ }
+
+ return name;
+ }
+
+ private static String asRelativeFile(String name, MavenProject project) {
+ String answer = name;
+ String base = project.getBasedir().getAbsolutePath();
+ if (name.startsWith(base)) {
+ answer = name.substring(base.length());
+ if (answer.startsWith(File.separator)) {
+ answer = answer.substring(1);
+ }
+ }
+
+ return answer;
+ }
+
+ private static void findYamlRouters(Set<File> yamlFiles, boolean
includeTest, String ext, MavenProject project) {
+ for (Resource dir : project.getResources()) {
+ finYamlFiles(new File(dir.getDirectory()), ext, yamlFiles);
+ }
+ if (includeTest) {
+ for (Resource dir : project.getTestResources()) {
+ finYamlFiles(new File(dir.getDirectory()), ext, yamlFiles);
+ }
+ }
+ }
+
+ private static void finYamlFiles(File dir, String ext, Set<File>
yamlFiles) {
+ File[] files = dir.isDirectory() ? dir.listFiles() : null;
+ if (files != null) {
+ for (File file : files) {
+ String name = file.getName().toLowerCase(Locale.ROOT);
+ if (name.endsWith(ext)) {
+ yamlFiles.add(file);
+ } else if (file.isDirectory()) {
+ finYamlFiles(file, ext, yamlFiles);
+ }
+ }
+ }
+ }
+
+}
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/pom.xml
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/pom.xml
new file mode 100644
index 000000000000..d508387a7358
--- /dev/null
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/pom.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-yaml-dsl-parent</artifactId>
+ <version>4.18.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>camel-yaml-dsl-validator</artifactId>
+ <packaging>jar</packaging>
+ <name>Camel :: YAML DSL :: Validator</name>
+ <description>Camel DSL with YAML Validator</description>
+
+ <properties>
+ <firstVersion>4.18.0</firstVersion>
+ <camel-prepare-component>false</camel-prepare-component>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-yaml-dsl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.networknt</groupId>
+ <artifactId>json-schema-validator</artifactId>
+ <version>${networknt-json-schema-validator-version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.assertj</groupId>
+ <artifactId>assertj-core</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-core</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-slf4j2-impl</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-jcl</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+
+</project>
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/YamlValidator.java
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/YamlValidator.java
new file mode 100644
index 000000000000..c28edeef540b
--- /dev/null
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/YamlValidator.java
@@ -0,0 +1,82 @@
+/*
+ * 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.dsl.yaml.validator;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
+import com.networknt.schema.JsonMetaSchema;
+import com.networknt.schema.JsonSchema;
+import com.networknt.schema.JsonSchemaFactory;
+import com.networknt.schema.NonValidationKeyword;
+import com.networknt.schema.SchemaValidatorsConfig;
+import com.networknt.schema.SpecVersionDetector;
+import com.networknt.schema.ValidationMessage;
+
+public class YamlValidator {
+
+ private static final String DRAFT =
"http://json-schema.org/draft-04/schema#";
+
+ // TODO: yaml-dsl-parser to see if its validate camel
+
+ private ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
+ private JsonNode model;
+ private JsonSchemaFactory factory;
+ private SchemaValidatorsConfig config;
+ private JsonSchema schema;
+
+ private String jsonSchema = "/schema/camelYamlDsl.json";
+
+ public String getJsonSchema() {
+ return jsonSchema;
+ }
+
+ /**
+ * The schema to use for validating
+ */
+ public void setJsonSchema(String jsonSchema) {
+ this.jsonSchema = jsonSchema;
+ }
+
+ public List<ValidationMessage> validate(File file) throws Exception {
+ if (schema == null) {
+ init();
+ }
+ try (InputStream is = new FileInputStream(file)) {
+ var target = mapper.readTree(is);
+ return new ArrayList<>(schema.validate(target));
+ }
+ }
+
+ public void init() throws Exception {
+ model =
mapper.readTree(YamlValidator.class.getResourceAsStream(jsonSchema));
+ factory =
JsonSchemaFactory.getInstance(SpecVersionDetector.detect(model));
+ config =
SchemaValidatorsConfig.builder().locale(Locale.ENGLISH).build();
+ // include deprecated as an unknown keyword so the validator does not
WARN log about this
+ JsonMetaSchema jms = factory.getMetaSchema(DRAFT, null);
+ jms.getKeywords().put("deprecated", new
NonValidationKeyword("deprecated"));
+ schema = factory.getSchema(model, config);
+ }
+
+}
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/YamlValidatorTest.java
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/YamlValidatorTest.java
new file mode 100644
index 000000000000..d53e7a107dc3
--- /dev/null
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/YamlValidatorTest.java
@@ -0,0 +1,48 @@
+/*
+ * 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.dsl.yaml.validator;
+
+import java.io.File;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+public class YamlValidatorTest {
+
+ private static YamlValidator validator;
+
+ @BeforeAll
+ public static void setup() throws Exception {
+ validator = new YamlValidator();
+ validator.init();
+ }
+
+ @Test
+ public void testValidateOk() throws Exception {
+ Assertions.assertTrue(validator.validate(new
File("src/test/resources/foo.yaml")).isEmpty());
+ }
+
+ @Test
+ public void testValidateBad() throws Exception {
+ var report = validator.validate(new
File("src/test/resources/bad.yaml"));
+ Assertions.assertFalse(report.isEmpty());
+ Assertions.assertEquals(1, report.size());
+
Assertions.assertTrue(report.get(0).getMessage().contains("setCheese"));
+ System.out.println(report);
+ }
+}
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/resources/bad.yaml
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/resources/bad.yaml
new file mode 100644
index 000000000000..5e660e31edd0
--- /dev/null
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/resources/bad.yaml
@@ -0,0 +1,26 @@
+#
+# 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.
+#
+
+- route:
+ from:
+ uri: timer:yaml
+ parameters:
+ period: "1000"
+ steps:
+ - setCheese:
+ simple: Hello Camel from ${routeId}
+ - log: ${body}
\ No newline at end of file
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/resources/foo.yaml
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/resources/foo.yaml
new file mode 100644
index 000000000000..d239b6ba3fc1
--- /dev/null
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/resources/foo.yaml
@@ -0,0 +1,26 @@
+#
+# 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.
+#
+
+- route:
+ from:
+ uri: timer:yaml
+ parameters:
+ period: "1000"
+ steps:
+ - setBody:
+ simple: Hello Camel from ${routeId}
+ - log: ${body}
\ No newline at end of file
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/resources/log4j2.properties
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/resources/log4j2.properties
new file mode 100644
index 000000000000..492c47dd3f71
--- /dev/null
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/resources/log4j2.properties
@@ -0,0 +1,31 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+
+appender.file.type = File
+appender.file.name = file
+appender.file.fileName = target/camel-yaml-dsl-validator-test.log
+appender.file.layout.type = PatternLayout
+appender.file.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
+
+appender.out.type = Console
+appender.out.name = out
+appender.out.layout.type = PatternLayout
+appender.out.layout.pattern = [%30.30t] %-30.30c{1} %-5p %m%n
+
+rootLogger.level = INFO
+rootLogger.appenderRef.file.ref = file
+#rootLogger.appenderRef.out.ref = out
\ No newline at end of file
diff --git a/dsl/camel-yaml-dsl/pom.xml b/dsl/camel-yaml-dsl/pom.xml
index f449b5f0d6c2..5becaa137159 100644
--- a/dsl/camel-yaml-dsl/pom.xml
+++ b/dsl/camel-yaml-dsl/pom.xml
@@ -37,6 +37,8 @@
<module>camel-yaml-dsl-common</module>
<module>camel-yaml-dsl-deserializers</module>
<module>camel-yaml-dsl</module>
+ <module>camel-yaml-dsl-validator</module>
+ <module>camel-yaml-dsl-validator-maven-plugin</module>
</modules>
</project>
\ No newline at end of file
diff --git a/parent/pom.xml b/parent/pom.xml
index fe4a4e0a0c79..b09d582d9c73 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -3081,6 +3081,11 @@
<artifactId>camel-yaml-dsl-deserializers</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-yaml-dsl-validator</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jbang-core</artifactId>