This is an automated email from the ASF dual-hosted git repository. christophd pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel.git
commit 5b491ec3dd69304513f70411629bc820131f58a6 Author: Christoph Deppisch <[email protected]> AuthorDate: Wed Nov 11 10:07:30 2026 +0100 CAMEL-26766: Address review feedback - Keep --plugin-config on subcommands only (add, get, delete, list); PluginCommand extends CamelCommand directly so the option is not inherited by the parent command where it had no effect - Handle InvalidPathException in env var and --plugin-config paths - Improve file vs directory detection: check Files.isDirectory first, then case-insensitive .json suffix with null-safe getFileName - Revert constant rename PLUGIN_CONFIG_FILE back to PLUGIN_CONFIG - Extract package-private resolvePluginConfigPath(Path, String) for env var test coverage without touching the real environment - Add tests for env var path, directory, precedence, invalid path - Remove duplicate testCustomPluginConfigPathReset - Document CAMEL_CLI_PLUGIN_CONFIG env var and --plugin-config scope - Regenerate golden file and generated docs Co-Authored-By: Claude Opus 4.6 <[email protected]> --- .../modules/ROOT/pages/camel-jbang-projects.adoc | 27 +++++++++++ .../jbang-commands/camel-jbang-plugin-add.adoc | 2 +- .../jbang-commands/camel-jbang-plugin-delete.adoc | 2 +- .../jbang-commands/camel-jbang-plugin-get.adoc | 2 +- .../jbang-commands/camel-jbang-plugin-list.adoc | 2 +- .../pages/jbang-commands/camel-jbang-plugin.adoc | 1 - .../META-INF/camel-jbang-commands-metadata.json | 2 +- .../core/commands/plugin/PluginBaseCommand.java | 15 ++++++- .../jbang/core/commands/plugin/PluginCommand.java | 3 +- .../camel/dsl/jbang/core/common/PluginHelper.java | 28 ++++++++---- .../jbang/core/commands/plugin/PluginGetTest.java | 2 +- .../dsl/jbang/core/common/PluginHelperTest.java | 52 +++++++++++++++------- .../src/test/resources/golden/cli-help.txt | 30 +++++++++++-- 13 files changed, 129 insertions(+), 39 deletions(-) diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang-projects.adoc b/docs/user-manual/modules/ROOT/pages/camel-jbang-projects.adoc index 7994a3c3c4e7..305ff888f5e2 100644 --- a/docs/user-manual/modules/ROOT/pages/camel-jbang-projects.adoc +++ b/docs/user-manual/modules/ROOT/pages/camel-jbang-projects.adoc @@ -274,6 +274,33 @@ camel plugin get camel plugin delete <plugin-name> ---- +=== Custom plugin configuration + +By default, the CLI stores the plugin configuration in `~/.camel-jbang-plugins.json`. +To use a different location, pass the `--plugin-config` option to any `plugin` subcommand: + +[source,bash] +---- +camel plugin get --plugin-config /path/to/my-plugins.json +camel plugin add kubernetes --plugin-config /path/to/my-plugins.json +---- + +The path can point to a JSON file or to a directory (in which case the default filename `.camel-jbang-plugins.json` is resolved inside it). + +Alternatively, set the `CAMEL_CLI_PLUGIN_CONFIG` environment variable: + +[source,bash] +---- +export CAMEL_CLI_PLUGIN_CONFIG=/path/to/my-plugins.json +camel plugin get +---- + +The resolution order is: `--plugin-config` option > `CAMEL_CLI_PLUGIN_CONFIG` environment variable > default `~/.camel-jbang-plugins.json`. + +NOTE: The `--plugin-config` option only applies to the `plugin` subcommands (`add`, `get`, `delete`). +Running a plugin's own command (e.g. `camel kubernetes ...`) discovers plugins only through the environment variable or the default file. +So a plugin added with `camel plugin add --plugin-config X` is not seen unless `CAMEL_CLI_PLUGIN_CONFIG` is also set. + === Plugin versions The plugins of the Apache Camel project always use the version of the CLI. diff --git a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-plugin-add.adoc b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-plugin-add.adoc index c42db1eab9bd..687ee867303c 100644 --- a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-plugin-add.adoc +++ b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-plugin-add.adoc @@ -25,7 +25,7 @@ camel plugin add [options] | `--first-version` | First version of this plugin | | String | `--gav` | Maven group and artifact coordinates. | | String | `--groupId` | Maven groupId | org.apache.camel | String -| `--plugin-config` | Path to a custom plugin configuration file or directory | | String +| `--plugin-config` | Path to a custom plugin configuration file or directory. Only applies to the plugin subcommands; for plugin commands themselves (e.g. 'camel kubernetes'), set CAMEL_CLI_PLUGIN_CONFIG instead. | | String | `--repo,--repos` | Additional maven repositories to use for downloading the plugin (Use commas to separate multiple repositories) | | String | `--version` | Maven artifact version | | String | `-h,--help` | Display the help and sub-commands | | boolean diff --git a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-plugin-delete.adoc b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-plugin-delete.adoc index 631a979660a4..8d2b0957acf6 100644 --- a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-plugin-delete.adoc +++ b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-plugin-delete.adoc @@ -19,7 +19,7 @@ camel plugin delete [options] [cols="2,5,1,2",options="header"] |=== | Option | Description | Default | Type -| `--plugin-config` | Path to a custom plugin configuration file or directory | | String +| `--plugin-config` | Path to a custom plugin configuration file or directory. Only applies to the plugin subcommands; for plugin commands themselves (e.g. 'camel kubernetes'), set CAMEL_CLI_PLUGIN_CONFIG instead. | | String | `-h,--help` | Display the help and sub-commands | | boolean |=== diff --git a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-plugin-get.adoc b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-plugin-get.adoc index 2ca6dd356b3f..3e5eb3db4cc5 100644 --- a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-plugin-get.adoc +++ b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-plugin-get.adoc @@ -20,7 +20,7 @@ camel plugin get [options] |=== | Option | Description | Default | Type | `--json` | Output in JSON Format | | boolean -| `--plugin-config` | Path to a custom plugin configuration file or directory | | String +| `--plugin-config` | Path to a custom plugin configuration file or directory. Only applies to the plugin subcommands; for plugin commands themselves (e.g. 'camel kubernetes'), set CAMEL_CLI_PLUGIN_CONFIG instead. | | String | `--repos` | Display maven repository column | false | boolean | `-h,--help` | Display the help and sub-commands | | boolean |=== diff --git a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-plugin-list.adoc b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-plugin-list.adoc index 0474a8002df1..72f5b083a0b4 100644 --- a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-plugin-list.adoc +++ b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-plugin-list.adoc @@ -20,7 +20,7 @@ camel plugin list [options] |=== | Option | Description | Default | Type | `--json` | Output in JSON Format | | boolean -| `--plugin-config` | Path to a custom plugin configuration file or directory | | String +| `--plugin-config` | Path to a custom plugin configuration file or directory. Only applies to the plugin subcommands; for plugin commands themselves (e.g. 'camel kubernetes'), set CAMEL_CLI_PLUGIN_CONFIG instead. | | String | `--repos` | Display maven repository column | false | boolean | `-h,--help` | Display the help and sub-commands | | boolean |=== diff --git a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-plugin.adoc b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-plugin.adoc index 12414aa1d96c..1397ec4d03a6 100644 --- a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-plugin.adoc +++ b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-plugin.adoc @@ -31,7 +31,6 @@ camel plugin [options] [cols="2,5,1,2",options="header"] |=== | Option | Description | Default | Type -| `--plugin-config` | Path to a custom plugin configuration file or directory | | String | `-h,--help` | Display the help and sub-commands | | boolean |=== diff --git a/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json b/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json index 5a5d8790c89f..a4984581645d 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json +++ b/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json @@ -24,7 +24,7 @@ { "name": "log", "fullName": "log", "description": "Tail logs from running Camel integrations", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.action.CamelLogAction", "options": [ { "names": "--duration", "description": "How long to keep watching or following, in millis or as a duration such as 30s (default: until Enter is pressed)", "javaType": "long", "type": "integer" }, { "names": "--find", "description": "Find and highlight matching text (ignore case).", "javaType": "j [...] { "name": "nano", "fullName": "nano", "description": "Nano editor to edit file", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Nano", "options": [ { "names": "-h,--help", "description": "Display the help and sub-commands", "javaType": "boolean", "type": "boolean" } ] }, { "name": "overview", "fullName": "overview", "description": "High-level overview of the integrations in a project, optionally explained by AI\/LLM", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Overview", "options": [ { "names": "--ai", "description": "Ask an LLM to explain the project (an overview, the capabilities, labels and notes of routes that have none) and save it in camel-summary.md, marked as AI-assisted", "javaType": "boolean", "type": "boolean" }, { "names": " [...] - { "name": "plugin", "fullName": "plugin", "description": "Manage plugins that add sub-commands to this CLI", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.plugin.PluginCommand", "options": [ { "names": "--plugin-config", "description": "Path to a custom plugin configuration file or directory", "javaType": "java.lang.String", "type": "string" }, { "names": "-h,--help", "description": "Display the help and sub-commands", "javaType": "boolean", "type": "boolean" } ], "subcomm [...] + { "name": "plugin", "fullName": "plugin", "description": "Manage plugins that add sub-commands to this CLI", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.plugin.PluginCommand", "options": [ { "names": "-h,--help", "description": "Display the help and sub-commands", "javaType": "boolean", "type": "boolean" } ], "subcommands": [ { "name": "add", "fullName": "plugin add", "description": "Add new plugin", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.plugin.PluginA [...] { "name": "ps", "fullName": "ps", "description": "List running Camel integrations", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.process.ListProcess", "options": [ { "names": "--duration", "description": "How long to keep watching or following, in millis or as a duration such as 30s (default: until Enter is pressed)", "javaType": "long", "type": "integer" }, { "names": "--json", "description": "Output in JSON Format", "javaType": "boolean", "type": "boolean" }, { "names": [...] { "name": "restart", "fullName": "restart", "description": "Restarts running Camel integrations (stop + re-launch)", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.process.RestartProcess", "options": [ { "names": "--timeout", "description": "How long to wait for the integration to stop, and again to start, in millis or as a duration such as 30s", "defaultValue": "60000", "javaType": "long", "type": "integer" }, { "names": "-h,--help", "description": "Display the help and su [...] { "name": "run", "fullName": "run", "description": "Run as local Camel integration", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Run", "options": [ { "names": "--background", "description": "Run in the background", "defaultValue": "false", "javaType": "boolean", "type": "boolean" }, { "names": "--background-wait", "description": "How long to wait for the integration in the background to start, before returning, in millis or as a duration such as 2m (true waits 60 seconds [...] diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/plugin/PluginBaseCommand.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/plugin/PluginBaseCommand.java index 22a57a2b15ba..9f3112a3ad72 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/plugin/PluginBaseCommand.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/plugin/PluginBaseCommand.java @@ -32,7 +32,10 @@ import picocli.CommandLine; abstract class PluginBaseCommand extends CamelCommand { @CommandLine.Option(names = { "--plugin-config" }, - description = "Path to a custom plugin configuration file or directory") + description = "Path to a custom plugin configuration file or directory. " + + "Only applies to the plugin subcommands; " + + "for plugin commands themselves (e.g. 'camel kubernetes'), " + + "set CAMEL_CLI_PLUGIN_CONFIG instead.") String pluginConfig; protected PluginBaseCommand(CamelJBangMain main) { @@ -40,7 +43,15 @@ abstract class PluginBaseCommand extends CamelCommand { } private Path pluginConfigPath() { - return pluginConfig != null ? Path.of(pluginConfig) : null; + if (pluginConfig != null) { + try { + return Path.of(pluginConfig); + } catch (java.nio.file.InvalidPathException e) { + throw new IllegalStateException( + "Invalid path in --plugin-config option: " + pluginConfig, e); + } + } + return null; } JsonObject loadConfig() { diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/plugin/PluginCommand.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/plugin/PluginCommand.java index 1921dd380366..89bd3200746a 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/plugin/PluginCommand.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/plugin/PluginCommand.java @@ -16,12 +16,13 @@ */ package org.apache.camel.dsl.jbang.core.commands.plugin; +import org.apache.camel.dsl.jbang.core.commands.CamelCommand; import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain; import picocli.CommandLine; @CommandLine.Command(name = "plugin", description = "Manage plugins that add sub-commands to this CLI") -public class PluginCommand extends PluginBaseCommand { +public class PluginCommand extends CamelCommand { public PluginCommand(CamelJBangMain main) { super(main); diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/PluginHelper.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/PluginHelper.java index 959b0c2995e6..2824454fce8b 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/PluginHelper.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/PluginHelper.java @@ -68,7 +68,7 @@ import picocli.CommandLine; */ public final class PluginHelper { - public static final String PLUGIN_CONFIG_FILE = ".camel-jbang-plugins.json"; + public static final String PLUGIN_CONFIG = ".camel-jbang-plugins.json"; public static final String PLUGIN_CONFIG_ENV = "CAMEL_CLI_PLUGIN_CONFIG"; public static final String PLUGIN_SERVICE_DIR = "META-INF/services/org/apache/camel/camel-jbang-plugin/"; @@ -99,26 +99,38 @@ public final class PluginHelper { * <ol> * <li>A path set programmatically via method argument</li> * <li>The {@value #PLUGIN_CONFIG_ENV} environment variable</li> - * <li>The default {@value #PLUGIN_CONFIG_FILE} in the user home directory</li> + * <li>The default {@value #PLUGIN_CONFIG} in the user home directory</li> * </ol> */ public static Path getCustomPluginConfigPath(Path configPath) { + return resolvePluginConfigPath(configPath, System.getenv(PLUGIN_CONFIG_ENV)); + } + + static Path resolvePluginConfigPath(Path configPath, String envValue) { Path pluginConfigPath; if (configPath != null) { pluginConfigPath = configPath; } else { - String env = System.getenv(PLUGIN_CONFIG_ENV); - if (env != null && !env.isBlank()) { - pluginConfigPath = Path.of(env); + if (envValue != null && !envValue.isBlank()) { + try { + pluginConfigPath = Path.of(envValue); + } catch (java.nio.file.InvalidPathException e) { + throw new IllegalStateException( + "Invalid path in " + PLUGIN_CONFIG_ENV + " environment variable: " + envValue, e); + } } else { - return CommandLineHelper.getHomeDir().resolve(PLUGIN_CONFIG_FILE); + return CommandLineHelper.getHomeDir().resolve(PLUGIN_CONFIG); } } - if (pluginConfigPath.getFileName().toString().endsWith(".json")) { + if (Files.isDirectory(pluginConfigPath)) { + return pluginConfigPath.resolve(PLUGIN_CONFIG); + } + Path fileName = pluginConfigPath.getFileName(); + if (fileName != null && fileName.toString().toLowerCase().endsWith(".json")) { return pluginConfigPath; } - return pluginConfigPath.resolve(PLUGIN_CONFIG_FILE); + return pluginConfigPath.resolve(PLUGIN_CONFIG); } /** diff --git a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/plugin/PluginGetTest.java b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/plugin/PluginGetTest.java index 02dd47070b85..f4c119a2d0b8 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/plugin/PluginGetTest.java +++ b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/plugin/PluginGetTest.java @@ -100,7 +100,7 @@ class PluginGetTest extends CamelCommandBaseTestSupport { public void shouldUseCustomPluginConfigDirectory() throws Exception { Path configDir = customConfigDir.resolve("config-dir"); Files.createDirectories(configDir); - Path configFile = configDir.resolve(PluginHelper.PLUGIN_CONFIG_FILE); + Path configFile = configDir.resolve(PluginHelper.PLUGIN_CONFIG); String configContent = """ { "plugins": { diff --git a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/common/PluginHelperTest.java b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/common/PluginHelperTest.java index cd5bbafdce9c..9f6e1a3f1fd4 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/common/PluginHelperTest.java +++ b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/common/PluginHelperTest.java @@ -66,7 +66,7 @@ public class PluginHelperTest { @Test public void aPluginCommandIsOfACamelPluginOrOfTheConfiguration() throws Exception { - Path userConfig = CommandLineHelper.getHomeDir().resolve(PluginHelper.PLUGIN_CONFIG_FILE); + Path userConfig = CommandLineHelper.getHomeDir().resolve(PluginHelper.PLUGIN_CONFIG); Files.writeString(userConfig, """ { "plugins": { @@ -92,7 +92,7 @@ public class PluginHelperTest { @Test public void testFallbackToJsonConfig() throws Exception { // Create a user plugin config file in home directory - Path userConfig = CommandLineHelper.getHomeDir().resolve(PluginHelper.PLUGIN_CONFIG_FILE); + Path userConfig = CommandLineHelper.getHomeDir().resolve(PluginHelper.PLUGIN_CONFIG); String userConfigContent = """ { "plugins": { @@ -121,7 +121,7 @@ public class PluginHelperTest { @Test public void testGetActivePluginsFiltersByTarget() throws Exception { - Path userConfig = CommandLineHelper.getHomeDir().resolve(PluginHelper.PLUGIN_CONFIG_FILE); + Path userConfig = CommandLineHelper.getHomeDir().resolve(PluginHelper.PLUGIN_CONFIG); String configContent = """ { "plugins": { @@ -151,7 +151,7 @@ public class PluginHelperTest { @Test public void testGetActivePluginsNoFilterLoadsAll() throws Exception { - Path userConfig = CommandLineHelper.getHomeDir().resolve(PluginHelper.PLUGIN_CONFIG_FILE); + Path userConfig = CommandLineHelper.getHomeDir().resolve(PluginHelper.PLUGIN_CONFIG); String configContent = """ { "plugins": { @@ -414,7 +414,7 @@ public class PluginHelperTest { @Test public void testDefaultPluginConfigPath() { - Path expected = CommandLineHelper.getHomeDir().resolve(PluginHelper.PLUGIN_CONFIG_FILE); + Path expected = CommandLineHelper.getHomeDir().resolve(PluginHelper.PLUGIN_CONFIG); assertEquals(expected, PluginHelper.getCustomPluginConfigPath()); } @@ -428,16 +428,7 @@ public class PluginHelperTest { public void testCustomPluginConfigPathAsDirectory() throws Exception { Path customDir = tempDir.resolve("custom-config-dir"); Files.createDirectories(customDir); - assertEquals(customDir.resolve(PluginHelper.PLUGIN_CONFIG_FILE), PluginHelper.getCustomPluginConfigPath(customDir)); - } - - @Test - public void testCustomPluginConfigPathReset() { - Path custom = tempDir.resolve("custom-plugins.json"); - assertEquals(custom, PluginHelper.getCustomPluginConfigPath(custom)); - - Path expected = CommandLineHelper.getHomeDir().resolve(PluginHelper.PLUGIN_CONFIG_FILE); - assertEquals(expected, PluginHelper.getCustomPluginConfigPath()); + assertEquals(customDir.resolve(PluginHelper.PLUGIN_CONFIG), PluginHelper.getCustomPluginConfigPath(customDir)); } @Test @@ -491,7 +482,7 @@ public class PluginHelperTest { @Test public void testCustomPathIsolatesFromDefaultConfig() throws Exception { - Path defaultConfig = CommandLineHelper.getHomeDir().resolve(PluginHelper.PLUGIN_CONFIG_FILE); + Path defaultConfig = CommandLineHelper.getHomeDir().resolve(PluginHelper.PLUGIN_CONFIG); String defaultContent = """ { "plugins": { @@ -526,12 +517,39 @@ public class PluginHelperTest { assertNull(plugins.getMap("default-plugin")); } + @Test + public void testEnvVarPluginConfigPath() { + Path result = PluginHelper.resolvePluginConfigPath(null, "/tmp/camel-test-plugins.json"); + assertEquals(Path.of("/tmp/camel-test-plugins.json"), result); + } + + @Test + public void testEnvVarPluginConfigPathAsDirectory() throws Exception { + Path customDir = tempDir.resolve("env-config-dir"); + Files.createDirectories(customDir); + Path result = PluginHelper.resolvePluginConfigPath(null, customDir.toString()); + assertEquals(customDir.resolve(PluginHelper.PLUGIN_CONFIG), result); + } + + @Test + public void testExplicitPathTakesPrecedenceOverEnvVar() { + Path explicit = tempDir.resolve("explicit-plugins.json"); + Path result = PluginHelper.resolvePluginConfigPath(explicit, "/tmp/env-plugins.json"); + assertEquals(explicit, result); + } + + @Test + public void testInvalidEnvVarPathThrowsIllegalState() { + assertThrows(IllegalStateException.class, + () -> PluginHelper.resolvePluginConfigPath(null, "\u0000invalid")); + } + private void writeConfig(JsonObject pluginEntry) throws Exception { JsonObject plugins = new JsonObject(); plugins.put(pluginEntry.getString("name"), pluginEntry); JsonObject config = new JsonObject(); config.put("plugins", plugins); - Path userConfig = CommandLineHelper.getHomeDir().resolve(PluginHelper.PLUGIN_CONFIG_FILE); + Path userConfig = CommandLineHelper.getHomeDir().resolve(PluginHelper.PLUGIN_CONFIG); Files.writeString(userConfig, config.toJson(), StandardOpenOption.CREATE); } diff --git a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/cli-help.txt b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/cli-help.txt index 9398ab867eb6..31dd30bd41b3 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/cli-help.txt +++ b/dsl/camel-jbang/camel-jbang-core/src/test/resources/golden/cli-help.txt @@ -5003,11 +5003,17 @@ Commands: Usage: camel plugin add [-h] [--artifactId=<artifactId>] [--command=<command>] [--description=<description>] [--first-version=<firstVersion>] [--gav=<gav>] - [--groupId=<groupId>] [--repo=<repositories>] - [--version=<version>] <name> + [--groupId=<groupId>] [--plugin-config=<pluginConfig>] + [--repo=<repositories>] [--version=<version>] <name> Add new plugin <name> The Camel plugin to add -h, --help Display the help and sub-commands + --plugin-config=<pluginConfig> + Path to a custom plugin configuration file or + directory. Only applies to the plugin + subcommands; for plugin commands themselves (e.g. + 'camel kubernetes'), set CAMEL_CLI_PLUGIN_CONFIG + instead. --command=<command> The command that the plugin uses --description=<description> A short description of the plugin @@ -5028,18 +5034,28 @@ Examples: camel plugin add --command=my-cmd --gav=com.foo:bar:1.0 == camel plugin delete --help -Usage: camel plugin delete [-h] <plugin> +Usage: camel plugin delete [-h] [--plugin-config=<pluginConfig>] <plugin> Removes a plugin <plugin> The Camel plugin to remove -h, --help Display the help and sub-commands + --plugin-config=<pluginConfig> + Path to a custom plugin configuration file or directory. Only + applies to the plugin subcommands; for plugin commands + themselves (e.g. 'camel kubernetes'), set + CAMEL_CLI_PLUGIN_CONFIG instead. Examples: camel plugin delete my-cmd == camel plugin get --help -Usage: camel plugin get [-h] [--json] [--repos] +Usage: camel plugin get [-h] [--json] [--repos] [--plugin-config=<pluginConfig>] Get installed plugins -h, --help Display the help and sub-commands + --plugin-config=<pluginConfig> + Path to a custom plugin configuration file or directory. Only + applies to the plugin subcommands; for plugin commands + themselves (e.g. 'camel kubernetes'), set + CAMEL_CLI_PLUGIN_CONFIG instead. --repos Display maven repository column --json Output in JSON Format @@ -5049,8 +5065,14 @@ Examples: == camel plugin list --help Usage: camel plugin list [-h] [--json] [--repos] + [--plugin-config=<pluginConfig>] List all available plugins -h, --help Display the help and sub-commands + --plugin-config=<pluginConfig> + Path to a custom plugin configuration file or directory. Only + applies to the plugin subcommands; for plugin commands + themselves (e.g. 'camel kubernetes'), set + CAMEL_CLI_PLUGIN_CONFIG instead. --repos Display maven repository column --json Output in JSON Format
