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 ff4f64120cd7 CAMEL-25718: camel-jbang - Document the commands of camel
test that come from Citrus (#28000)
ff4f64120cd7 is described below
commit ff4f64120cd7d34b2178c6a3a5268c60de22ebb5
Author: Claus Ibsen <[email protected]>
AuthorDate: Sat Oct 17 20:35:25 2026 +0200
CAMEL-25718: camel-jbang - Document the commands of camel test that come
from Citrus (#28000)
The test plugin registers commands of Citrus as they are (inspect, run, ps,
agent and its start, run and stop), and PrepareCamelJBangCommandsMojo only
documented a command whose class has a source in the module, so 7 of the 9
commands of camel test had no page. A command class that the source registering
it imports by name is now read from the classpath of the project: its @Command
(description, hidden) and its options, by reflection, as the options of a
library class (CAMEL-25717). T [...]
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
---
.../jbang-commands/camel-jbang-test-agent-run.adoc | 43 +++++++
.../camel-jbang-test-agent-start.adoc | 44 +++++++
...-test.adoc => camel-jbang-test-agent-stop.adoc} | 15 +--
...jbang-test.adoc => camel-jbang-test-agent.adoc} | 10 +-
...ang-test.adoc => camel-jbang-test-inspect.adoc} | 15 +--
...el-jbang-test.adoc => camel-jbang-test-ps.adoc} | 17 +--
.../pages/jbang-commands/camel-jbang-test-run.adoc | 41 +++++++
.../pages/jbang-commands/camel-jbang-test.adoc | 4 +
.../camel-jbang-plugin-commands-metadata.json | 2 +-
.../packaging/PrepareCamelJBangCommandsMojo.java | 89 ++++++++++++--
.../PrepareCamelJBangCommandsMojoTest.java | 130 ++++++++++++++++++---
11 files changed, 346 insertions(+), 64 deletions(-)
diff --git
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test-agent-run.adoc
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test-agent-run.adoc
new file mode 100644
index 000000000000..ede01d282bf7
--- /dev/null
+++
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test-agent-run.adoc
@@ -0,0 +1,43 @@
+
+// AUTO-GENERATED by camel-package-maven-plugin - DO NOT EDIT THIS FILE
+= camel test agent run
+
+Runs tests on the agent server
+
+NOTE: This command is provided by the `test` plugin. Install it with `camel
plugin add test`.
+
+
+== Usage
+
+[source,bash]
+----
+camel test agent run [options]
+----
+
+
+
+== Options
+
+[cols="2,5,1,2",options="header"]
+|===
+| Option | Description | Default | Type
+| `--async` | Should the test engine print verbose test summary information. |
| boolean
+| `--background` | When enabled the command is not blocking for the test
result response. | | boolean
+| `--dep` | Set of additional Maven dependencies that should be loaded with
the agent. | | String[]
+| `--engine` | Name of the test engine that is used ti run tests. One of
junit, junit-jupiter, junit4, testng, cucumber | | String
+| `--includes` | Includes test name pattern. | | String[]
+| `--modules` | Comma delimited list of additional Citrus modules that should
be loaded with the agent. | | String
+| `--packages` | Test package name to include in the test run. | | String[]
+| `--polling-interval` | Interval used to poll for test results. Only used in
asynchronous test execution mode. | 2000 | String
+| `--port` | Server port to connect to. | | String
+| `--property` | Default System property to set before the test run. | |
String[]
+| `--reset` | Should the test engine reset the suite state for each run. |
true | String
+| `--test-jar` | Path to a Java archive that holds tests to run. | | String
+| `--timeout` | Http request timeout. | 60000 | String
+| `--url` | Server endpoint URL to connect to. | | String
+| `--verbose` | Should the test engine print verbose test summary information.
| true | String
+| `--work-directory` | The working directory used by the file based test
engines to load file resources from. | | String
+| `-h,--help` | Display the help and sub-commands | | boolean
+|===
+
+
diff --git
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test-agent-start.adoc
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test-agent-start.adoc
new file mode 100644
index 000000000000..6e3a9a3bb86a
--- /dev/null
+++
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test-agent-start.adoc
@@ -0,0 +1,44 @@
+
+// AUTO-GENERATED by camel-package-maven-plugin - DO NOT EDIT THIS FILE
+= camel test agent start
+
+Starts the Citrus agent as a server
+
+NOTE: This command is provided by the `test` plugin. Install it with `camel
plugin add test`.
+
+
+== Usage
+
+[source,bash]
+----
+camel test agent start [options]
+----
+
+
+
+== Options
+
+[cols="2,5,1,2",options="header"]
+|===
+| Option | Description | Default | Type
+| `--config-class` | Configuration class name. | | String
+| `--dep` | Set of additional Maven dependencies that should be loaded with
the agent. | | String[]
+| `--engine` | Name of the test engine that is used ti run tests. One of
junit, junit-jupiter, junit4, testng, cucumber | | String
+| `--includes` | Includes test name pattern. | | String[]
+| `--inspect-code` | When enabled the source code gets analyzed for required
modules and dependencies that are added to the classpath. | true | String
+| `--modules` | Comma delimited list of additional Citrus modules that should
be loaded with the agent. | | String
+| `--offline` | When enabled there will be no attempts to resolve Maven
artifacts via internet connection. | | String
+| `--packages` | Test package name to include in the test run. | | String[]
+| `--port` | Server port. | | String
+| `--property` | Default System property to set before the test run. | |
String[]
+| `--reset` | Should the test engine reset the suite state for each run. |
true | String
+| `--skip-tests` | Should the server skip the test run at startup. | | String
+| `--system-exit` | Should the server exit based on success or failure of the
test run. | | String
+| `--test-jar` | Path to a Java archive that holds tests to run. | | String
+| `--time-to-live` | If this time is set the server automatically terminates
after the given time. | | String
+| `--verbose` | Should the test engine print verbose test summary information.
| true | String
+| `--work-directory` | The working directory used by the file based test
engines to load file resources from. | | String
+| `-h,--help` | Display the help and sub-commands | | boolean
+|===
+
+
diff --git
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test.adoc
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test-agent-stop.adoc
similarity index 60%
copy from
docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test.adoc
copy to
docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test-agent-stop.adoc
index 13a7c0844597..b0db61a3798b 100644
--- a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test.adoc
+++
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test-agent-stop.adoc
@@ -1,8 +1,8 @@
// AUTO-GENERATED by camel-package-maven-plugin - DO NOT EDIT THIS FILE
-= camel test
+= camel test agent stop
-Manage tests for Camel applications
+Stop the Citrus agent service
NOTE: This command is provided by the `test` plugin. Install it with `camel
plugin add test`.
@@ -11,19 +11,10 @@ NOTE: This command is provided by the `test` plugin.
Install it with `camel plug
[source,bash]
----
-camel test [options]
+camel test agent stop [options]
----
-== Subcommands
-
-[cols="2,5",options="header"]
-|===
-| Subcommand | Description
-| xref:jbang-commands/camel-jbang-test-init.adoc[init] | Creates a new Citrus
test
-|===
-
-
== Options
diff --git
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test.adoc
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test-agent.adoc
similarity index 56%
copy from
docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test.adoc
copy to
docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test-agent.adoc
index 13a7c0844597..ffc5c5a0874e 100644
--- a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test.adoc
+++
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test-agent.adoc
@@ -1,8 +1,8 @@
// AUTO-GENERATED by camel-package-maven-plugin - DO NOT EDIT THIS FILE
-= camel test
+= camel test agent
-Manage tests for Camel applications
+Manage Citrus agents
NOTE: This command is provided by the `test` plugin. Install it with `camel
plugin add test`.
@@ -11,7 +11,7 @@ NOTE: This command is provided by the `test` plugin. Install
it with `camel plug
[source,bash]
----
-camel test [options]
+camel test agent [options]
----
@@ -20,7 +20,9 @@ camel test [options]
[cols="2,5",options="header"]
|===
| Subcommand | Description
-| xref:jbang-commands/camel-jbang-test-init.adoc[init] | Creates a new Citrus
test
+| xref:jbang-commands/camel-jbang-test-agent-run.adoc[run] | Runs tests on the
agent server
+| xref:jbang-commands/camel-jbang-test-agent-start.adoc[start] | Starts the
Citrus agent as a server
+| xref:jbang-commands/camel-jbang-test-agent-stop.adoc[stop] | Stop the Citrus
agent service
|===
diff --git
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test.adoc
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test-inspect.adoc
similarity index 60%
copy from
docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test.adoc
copy to
docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test-inspect.adoc
index 13a7c0844597..68529de396be 100644
--- a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test.adoc
+++
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test-inspect.adoc
@@ -1,8 +1,8 @@
// AUTO-GENERATED by camel-package-maven-plugin - DO NOT EDIT THIS FILE
-= camel test
+= camel test inspect
-Manage tests for Camel applications
+Inspect a Citrus test and its source code in order to provide detailed
information such as used endpoints as well as required modules and dependencies.
NOTE: This command is provided by the `test` plugin. Install it with `camel
plugin add test`.
@@ -11,19 +11,10 @@ NOTE: This command is provided by the `test` plugin.
Install it with `camel plug
[source,bash]
----
-camel test [options]
+camel test inspect [options]
----
-== Subcommands
-
-[cols="2,5",options="header"]
-|===
-| Subcommand | Description
-| xref:jbang-commands/camel-jbang-test-init.adoc[init] | Creates a new Citrus
test
-|===
-
-
== Options
diff --git
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test.adoc
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test-ps.adoc
similarity index 60%
copy from
docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test.adoc
copy to
docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test-ps.adoc
index 13a7c0844597..3f62893c0cd3 100644
--- a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test.adoc
+++
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test-ps.adoc
@@ -1,8 +1,8 @@
// AUTO-GENERATED by camel-package-maven-plugin - DO NOT EDIT THIS FILE
-= camel test
+= camel test ps
-Manage tests for Camel applications
+List running Citrus tests
NOTE: This command is provided by the `test` plugin. Install it with `camel
plugin add test`.
@@ -11,25 +11,18 @@ NOTE: This command is provided by the `test` plugin.
Install it with `camel plug
[source,bash]
----
-camel test [options]
+camel test ps [options]
----
-== Subcommands
-
-[cols="2,5",options="header"]
-|===
-| Subcommand | Description
-| xref:jbang-commands/camel-jbang-test-init.adoc[init] | Creates a new Citrus
test
-|===
-
-
== Options
[cols="2,5,1,2",options="header"]
|===
| Option | Description | Default | Type
+| `--pid` | List only pid in the output | | boolean
+| `--sort` | Sort by pid, name or age | pid | String
| `-h,--help` | Display the help and sub-commands | | boolean
|===
diff --git
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test-run.adoc
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test-run.adoc
new file mode 100644
index 000000000000..9151e00295a3
--- /dev/null
+++
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test-run.adoc
@@ -0,0 +1,41 @@
+
+// AUTO-GENERATED by camel-package-maven-plugin - DO NOT EDIT THIS FILE
+= camel test run
+
+Run as local Citrus test
+
+NOTE: This command is provided by the `test` plugin. Install it with `camel
plugin add test`.
+
+
+== Usage
+
+[source,bash]
+----
+camel test run [options]
+----
+
+
+
+== Options
+
+[cols="2,5,1,2",options="header"]
+|===
+| Option | Description | Default | Type
+| `--dep,--dependency` | Comma delimited list of additional Maven GAV
dependencies that must be loaded to run the test. | | List
+| `--engine` | Name of the test engine that is used to run tests. One of
junit, junit-jupiter, junit4, testng, cucumber | | String
+| `--includes` | Includes test name pattern. | | List
+| `--inspect-code` | When enabled the source code gets analyzed for required
modules and dependencies that are added to the classpath. | true | boolean
+| `--logging` | Can be used to turn off logging | true | boolean
+| `--logging-color` | Use colored logging | true | boolean
+| `--logging-level` | Logging level | info | String
+| `--modules` | Comma delimited list of additional Citrus modules that must be
loaded to run the test. | | String
+| `--offline` | When enabled there will be no attempts to resolve Maven
artifacts via internet connection. | false | boolean
+| `--property,--properties` | Default System property to set before the test
run. | | List
+| `--repository,--repositories` | Set of Maven repositories that should be
used to resolve dependencies. | | List
+| `--reset` | Should the test engine reset the suite state for this run. |
true | String
+| `--verbose` | Should the test engine print verbose test summary information.
| true | String
+| `--work-directory` | The working directory used by the file based test
engines to load file resources from. | | String
+| `-h,--help` | Display the help and sub-commands | | boolean
+|===
+
+
diff --git
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test.adoc
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test.adoc
index 13a7c0844597..e7afbee9facd 100644
--- a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test.adoc
+++ b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-test.adoc
@@ -20,7 +20,11 @@ camel test [options]
[cols="2,5",options="header"]
|===
| Subcommand | Description
+| xref:jbang-commands/camel-jbang-test-agent.adoc[agent] | Manage Citrus agents
| xref:jbang-commands/camel-jbang-test-init.adoc[init] | Creates a new Citrus
test
+| xref:jbang-commands/camel-jbang-test-inspect.adoc[inspect] | Inspect a
Citrus test and its source code in order to provide detailed information such
as used endpoints as well as required modules and dependencies.
+| xref:jbang-commands/camel-jbang-test-ps.adoc[ps] | List running Citrus tests
+| xref:jbang-commands/camel-jbang-test-run.adoc[run] | Run as local Citrus test
|===
diff --git
a/dsl/camel-jbang/camel-jbang-plugin-test/src/generated/resources/META-INF/camel-jbang-plugin-commands-metadata.json
b/dsl/camel-jbang/camel-jbang-plugin-test/src/generated/resources/META-INF/camel-jbang-plugin-commands-metadata.json
index 173749a94911..c48595f91fc2 100644
---
a/dsl/camel-jbang/camel-jbang-plugin-test/src/generated/resources/META-INF/camel-jbang-plugin-commands-metadata.json
+++
b/dsl/camel-jbang/camel-jbang-plugin-test/src/generated/resources/META-INF/camel-jbang-plugin-commands-metadata.json
@@ -1,5 +1,5 @@
{
"commands": [
- { "name": "test", "fullName": "test", "description": "Manage tests for
Camel applications", "sourceClass":
"org.apache.camel.dsl.jbang.core.commands.test.TestCommand", "plugin": "test",
"options": [ { "names": "-h,--help", "description": "Display the help and
sub-commands", "javaType": "boolean", "type": "boolean" } ], "subcommands": [ {
"name": "init", "fullName": "test init", "description": "Creates a new Citrus
test", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.test.T [...]
+ { "name": "test", "fullName": "test", "description": "Manage tests for
Camel applications", "sourceClass":
"org.apache.camel.dsl.jbang.core.commands.test.TestCommand", "plugin": "test",
"options": [ { "names": "-h,--help", "description": "Display the help and
sub-commands", "javaType": "boolean", "type": "boolean" } ], "subcommands": [ {
"name": "agent", "fullName": "test agent", "description": "Manage Citrus
agents", "sourceClass": "org.citrusframework.jbang.cli.commands.Agent", "pl
[...]
]
}
diff --git
a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCamelJBangCommandsMojo.java
b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCamelJBangCommandsMojo.java
index 9e46cd905846..5d9759622d82 100644
---
a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCamelJBangCommandsMojo.java
+++
b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCamelJBangCommandsMojo.java
@@ -51,6 +51,7 @@ import org.jboss.forge.roaster.model.JavaType;
import org.jboss.forge.roaster.model.source.AnnotationSource;
import org.jboss.forge.roaster.model.source.FieldSource;
import org.jboss.forge.roaster.model.source.Import;
+import org.jboss.forge.roaster.model.source.Importer;
import org.jboss.forge.roaster.model.source.JavaClassSource;
import org.jboss.forge.roaster.model.source.JavaSource;
@@ -200,6 +201,7 @@ public class PrepareCamelJBangCommandsMojo extends
AbstractGeneratorMojo {
throws IOException {
List<String> lines = Files.readAllLines(mainFile.toPath());
+ JavaSource<?> registering = parseSource(mainFile);
// Find the start of the commandLine builder chain
int startLine = -1;
@@ -226,7 +228,7 @@ public class PrepareCamelJBangCommandsMojo extends
AbstractGeneratorMojo {
break;
}
- processSubcommandLine(lines.get(i), parentStack,
commandsByClassName, model, null);
+ processSubcommandLine(lines.get(i), parentStack,
commandsByClassName, model, null, registering);
}
}
@@ -244,6 +246,7 @@ public class PrepareCamelJBangCommandsMojo extends
AbstractGeneratorMojo {
String plugin = nameMatcher.group(1);
List<String> lines = Files.readAllLines(pluginFile.toPath());
+ JavaSource<?> registering = parseSource(pluginFile);
for (String line : lines) {
Matcher matcher = PLUGIN_ROOT_PATTERN.matcher(line.trim());
if (!matcher.find()) {
@@ -255,7 +258,7 @@ public class PrepareCamelJBangCommandsMojo extends
AbstractGeneratorMojo {
Matcher newMatcher = NEW_COMMAND_PATTERN.matcher(target);
if (newMatcher.find()) {
// a command without subcommands:
commandLine.addSubcommand("name", new Command(main))
- CommandInfo info =
commandsByClassName.get(newMatcher.group(1));
+ CommandInfo info = commandInfo(newMatcher.group(1),
commandsByClassName, registering);
if (info != null && !info.hidden) {
JBangCommand cmd = createCommand(info, cmdName, "");
cmd.setPlugin(plugin);
@@ -273,7 +276,7 @@ public class PrepareCamelJBangCommandsMojo extends
AbstractGeneratorMojo {
if (!declMatcher.find()) {
continue;
}
- CommandInfo info =
commandsByClassName.get(declMatcher.group(1));
+ CommandInfo info = commandInfo(declMatcher.group(1),
commandsByClassName, registering);
if (info == null || info.hidden) {
break;
}
@@ -285,7 +288,7 @@ public class PrepareCamelJBangCommandsMojo extends
AbstractGeneratorMojo {
Stack<ParentInfo> parentStack = new Stack<>();
parentStack.push(new ParentInfo(root, -1));
for (int j = i + 1; j < lines.size(); j++) {
- processSubcommandLine(lines.get(j), parentStack,
commandsByClassName, model, plugin);
+ processSubcommandLine(lines.get(j), parentStack,
commandsByClassName, model, plugin, registering);
if (lines.get(j).trim().endsWith(";")) {
break;
}
@@ -297,7 +300,7 @@ public class PrepareCamelJBangCommandsMojo extends
AbstractGeneratorMojo {
private void processSubcommandLine(
String line, Stack<ParentInfo> parentStack, Map<String,
CommandInfo> commandsByClassName,
- JBangCommandModel model, String plugin) {
+ JBangCommandModel model, String plugin, JavaSource<?> registering)
{
String trimmedLine = line.trim();
Matcher matcher = SUBCOMMAND_PATTERN.matcher(trimmedLine);
@@ -340,7 +343,7 @@ public class PrepareCamelJBangCommandsMojo extends
AbstractGeneratorMojo {
// - Ends with 3 parens ())) = leaf command (closes CommandLine +
addSubcommand)
boolean hasSubcommands = closingParens == 2;
- CommandInfo info = commandsByClassName.get(className);
+ CommandInfo info = commandInfo(className, commandsByClassName,
registering);
boolean parentSkipped = !parentStack.isEmpty() &&
parentStack.peek().command == null;
if (info == null || info.hidden || parentSkipped) {
if (info == null) {
@@ -375,6 +378,71 @@ public class PrepareCamelJBangCommandsMojo extends
AbstractGeneratorMojo {
}
}
+ /**
+ * The source that registers the commands, for the imports of their
classes, or null when it cannot be parsed.
+ */
+ private JavaSource<?> parseSource(File file) {
+ try {
+ return Roaster.parse(file) instanceof JavaSource<?> source ?
source : null;
+ } catch (Exception e) {
+ getLog().debug("Could not parse: " + file + " - " +
e.getMessage());
+ return null;
+ }
+ }
+
+ /**
+ * The command of a class: from its source when it is one of the command
classes, or else from its class on the
+ * classpath of the project when the source that registers it imports it
by name, such as a command of a library
+ * that a plugin adds as it is (camel test run is the Run of Citrus).
+ */
+ private CommandInfo commandInfo(
+ String className, Map<String, CommandInfo> commandsByClassName,
JavaSource<?> registering) {
+ CommandInfo info = commandsByClassName.get(className);
+ if (info == null && registering != null) {
+ String imported = importedByName(registering, className);
+ if (imported != null) {
+ info = parseCommandFromClass(imported);
+ }
+ }
+ return info;
+ }
+
+ /**
+ * Parses a command from the picocli annotations of its class on the
classpath of the project, read by reflection,
+ * as picocli is not a dependency of this plugin.
+ */
+ @SuppressWarnings("unchecked")
+ private CommandInfo parseCommandFromClass(String className) {
+ try {
+ ClassLoader loader = getProjectClassLoader();
+ Class<?> clazz = loader.loadClass(className);
+ Annotation command
+ = clazz.getAnnotation((Class<? extends Annotation>)
loader.loadClass("picocli.CommandLine$Command"));
+ if (command == null) {
+ return null;
+ }
+ CommandInfo info = new CommandInfo();
+ info.className = clazz.getSimpleName();
+ info.qualifiedName = clazz.getName();
+ info.name = (String) attribute(command, "name");
+ String description = String.join(" ", (String[])
attribute(command, "description"));
+ // without the hint to the help, as for a command of the sources
+ if (description.contains("(use")) {
+ description = description.substring(0,
description.indexOf("(use")).trim();
+ }
+ info.description = description.isEmpty() ? null : description;
+ info.hidden = (Boolean) attribute(command, "hidden");
+ info.deprecated = clazz.isAnnotationPresent(Deprecated.class);
+ info.options = new ArrayList<>();
+ parseOptionsFromClass(className, info.options);
+ return info;
+ } catch (Exception | LinkageError e) {
+ // the command is then missing from the documentation
+ getLog().warn("Could not read the command of class: " + className
+ " - " + e.getMessage());
+ return null;
+ }
+ }
+
private File findPluginFile(File dir) throws IOException {
try (Stream<Path> paths = Files.walk(dir.toPath())) {
return paths.filter(p -> p.toString().endsWith(".java"))
@@ -559,10 +627,10 @@ public class PrepareCamelJBangCommandsMojo extends
AbstractGeneratorMojo {
}
/**
- * The qualified name of the type with the simple name that the class
imports by name, or null when it does not.
+ * The qualified name of the type with the simple name that the source
imports by name, or null when it does not.
*/
- private static String importedByName(JavaClassSource clazz, String
simpleName) {
- for (Import imported : clazz.getImports()) {
+ private static String importedByName(Importer<?> source, String
simpleName) {
+ for (Import imported : source.getImports()) {
if (!imported.isWildcard() && !imported.isStatic() &&
imported.getSimpleName().equals(simpleName)) {
return imported.getQualifiedName();
}
@@ -585,7 +653,8 @@ public class PrepareCamelJBangCommandsMojo extends
AbstractGeneratorMojo {
= (Class<? extends Annotation>)
loader.loadClass("picocli.CommandLine$Mixin");
parseOptionsFromClass(loader.loadClass(className), optionType,
mixinType, options);
} catch (Exception | LinkageError e) {
- getLog().debug("Could not read the options of class: " + className
+ " - " + e.getMessage());
+ // the options are then missing from the documentation
+ getLog().warn("Could not read the options of class: " + className
+ " - " + e.getMessage());
}
}
diff --git
a/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/PrepareCamelJBangCommandsMojoTest.java
b/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/PrepareCamelJBangCommandsMojoTest.java
index 553683627b87..e6a31707b6c5 100644
---
a/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/PrepareCamelJBangCommandsMojoTest.java
+++
b/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/PrepareCamelJBangCommandsMojoTest.java
@@ -61,6 +61,17 @@ class PrepareCamelJBangCommandsMojoTest {
}
""";
+ // the command test of the plugin
+ private static final String TEST_COMMAND = """
+ package org.apache.camel.dsl.jbang.core.commands.test;
+
+ import picocli.CommandLine.Command;
+
+ @Command(name = "test", description = "Manage tests")
+ public class TestCommand {
+ }
+ """;
+
@TempDir
Path tempDir;
@@ -270,6 +281,56 @@ class PrepareCamelJBangCommandsMojoTest {
assertThat(init.getOptions()).extracting(JBangCommandOption::getNames).containsExactly("--directory",
"-h,--help");
}
+ /**
+ * CAMEL-25718: the commands of a library that a plugin adds as they are
(as camel test run is the Run of Citrus)
+ * are documented from their classes on the classpath of the project, with
their subcommands.
+ */
+ @Test
+ void testPluginCommandsOfALibraryAreDocumented() throws Exception {
+ compileLibrary();
+ Path plugin = tempDir.resolve("plugin/commands");
+ write(plugin.resolve("test/TestPlugin.java"), """
+ package org.apache.camel.dsl.jbang.core.commands.test;
+
+ import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+ import org.apache.camel.dsl.jbang.core.common.CamelJBangPlugin;
+ import org.apache.camel.dsl.jbang.core.common.Plugin;
+ import org.example.cli.Agent;
+ import org.example.cli.AgentStart;
+ import org.example.cli.Run;
+ import picocli.CommandLine;
+
+ @CamelJBangPlugin(name = "camel-jbang-plugin-test",
firstVersion = "4.14.0")
+ public class TestPlugin implements Plugin {
+
+ @Override
+ public void customize(CommandLine commandLine,
CamelJBangMain main) {
+ var cmd = new CommandLine(new TestCommand(main))
+ .addSubcommand("run", new CommandLine(new
Run(main)))
+ .addSubcommand("agent", new CommandLine(new
Agent(main))
+ .addSubcommand("start", new
CommandLine(new AgentStart(main))));
+
+ commandLine.addSubcommand("test", cmd);
+ }
+ }
+ """);
+ write(plugin.resolve("test/TestCommand.java"), TEST_COMMAND);
+
+ JBangCommand test = generatePlugin(plugin, null);
+
+
assertThat(test.getSubcommands()).extracting(JBangCommand::getFullName).containsExactly("test
agent", "test run");
+ JBangCommand agent = test.getSubcommands().get(0);
+ // without the hint to the help of the subcommands
+ assertThat(agent.getDescription()).isEqualTo("Manage agents");
+
assertThat(agent.getSubcommands()).extracting(JBangCommand::getFullName).containsExactly("test
agent start");
+
assertThat(agent.getSubcommands().get(0).getOptions()).extracting(JBangCommandOption::getNames)
+ .containsExactly("--port", "-h,--help");
+ JBangCommand run = test.getSubcommands().get(1);
+ assertThat(run.getDescription()).isEqualTo("Run as local test");
+ assertThat(run.getSourceClass()).isEqualTo("org.example.cli.Run");
+
assertThat(run.getOptions()).extracting(JBangCommandOption::getNames).containsExactly("--engine",
"-h,--help");
+ }
+
/**
* A parent class of the same package is found when the class has a static
import on demand, for which Roaster
* resolves the parent class as a nested class of the imported one (as
camel export, whose ExportBaseCommand has
@@ -361,15 +422,7 @@ class PrepareCamelJBangCommandsMojoTest {
}
}
""");
- write(plugin.resolve("test/TestCommand.java"), """
- package org.apache.camel.dsl.jbang.core.commands.test;
-
- import picocli.CommandLine.Command;
-
- @Command(name = "test", description = "Manage tests")
- public class TestCommand {
- }
- """);
+ write(plugin.resolve("test/TestCommand.java"), TEST_COMMAND);
write(plugin.resolve("test/TestInit.java"), """
package org.apache.camel.dsl.jbang.core.commands.test;
@@ -381,9 +434,19 @@ class PrepareCamelJBangCommandsMojoTest {
}
""");
+ JBangCommand test = generatePlugin(plugin, core);
+
assertThat(test.getSubcommands()).extracting(JBangCommand::getFullName).containsExactly("test
init");
+ return test.getSubcommands().get(0);
+ }
+
+ /**
+ * Generates the metadata of the plugin with the commands in the given
directory (and the commands of
+ * camel-jbang-core in the other one, when given). Returns the root
command of the plugin.
+ */
+ private JBangCommand generatePlugin(Path plugin, Path core) throws
Exception {
PrepareCamelJBangCommandsMojo mojo = new
PrepareCamelJBangCommandsMojo(null, null);
mojo.commandsDir = plugin.toFile();
- mojo.coreCommandsDir = core.toFile();
+ mojo.coreCommandsDir = core != null ? core.toFile() : null;
mojo.outFolder = tempDir.resolve("generated-resources").toFile();
mojo.project =
projectWithOutputDir(tempDir.resolve("classes").toFile());
@@ -391,9 +454,7 @@ class PrepareCamelJBangCommandsMojoTest {
String json = Files.readString(
tempDir.resolve("generated-resources").resolve(PrepareCamelJBangCommandsMojo.PLUGIN_METADATA_FILE));
- JBangCommand test =
JsonMapper.generateJBangCommandModel(json).getCommands().get(0);
-
assertThat(test.getSubcommands()).extracting(JBangCommand::getFullName).containsExactly("test
init");
- return test.getSubcommands().get(0);
+ return JsonMapper.generateJBangCommandModel(json).getCommands().get(0);
}
/**
@@ -432,6 +493,16 @@ class PrepareCamelJBangCommandsMojoTest {
@Target(ElementType.FIELD)
public @interface Mixin {
}
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(ElementType.TYPE)
+ public @interface Command {
+ String name() default "<main class>";
+
+ String[] description() default {};
+
+ boolean hidden() default false;
+ }
}
""");
write(sources.resolve("org/example/cli/LibraryCommand.java"), """
@@ -457,6 +528,39 @@ class PrepareCamelJBangCommandsMojoTest {
String directory;
}
""");
+ write(sources.resolve("org/example/cli/Run.java"), """
+ package org.example.cli;
+
+ import picocli.CommandLine;
+
+ @CommandLine.Command(name = "run", description = "Run as local
test")
+ public class Run extends LibraryCommand {
+
+ @CommandLine.Option(names = "--engine", description = "The
test engine")
+ String engine;
+ }
+ """);
+ write(sources.resolve("org/example/cli/Agent.java"), """
+ package org.example.cli;
+
+ import picocli.CommandLine;
+
+ @CommandLine.Command(name = "agent", description = "Manage
agents (use agent --help to see sub commands)")
+ public class Agent extends LibraryCommand {
+ }
+ """);
+ write(sources.resolve("org/example/cli/AgentStart.java"), """
+ package org.example.cli;
+
+ import picocli.CommandLine;
+
+ @CommandLine.Command(name = "start", description = "Starts the
agent as a server")
+ public class AgentStart extends LibraryCommand {
+
+ @CommandLine.Option(names = "--port", description = "The
port of the agent", defaultValue = "4567")
+ int port;
+ }
+ """);
Path classes = tempDir.resolve("classes");
Files.createDirectories(classes);
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();