You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2026/07/10 21:09:24 UTC

(camel) branch main updated (2860757583a5 -> 9fdc6b4a0acc)

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

davsclaus pushed a change to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


    from 2860757583a5 CAMEL-23957: Synchronize MCP reconnect to protect shared endpoint tool state (#24587)
     new f59a19a4f141 chore: fix NPEs, sort bugs, and filter issues in CLI cmd/process commands
     new 8aa7bd17f2d9 chore: fix version list EOL filter, update command bugs, and Windows compatibility
     new 3af7b261cac5 chore: fix various bugs in CLI core commands, config, and infra
     new 304782512c46 chore: fix bugs in CLI edit, generate, test, and validate plugins
     new c581f266509e chore: fix bare validate and kubernetes commands printing nothing
     new 3df8b5412d07 chore: fix GitHubHelper handling of blob and raw.githubusercontent URLs
     new 9fdc6b4a0acc chore: do not log stacktrace for theme preference read failure

The 7 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../camel/dsl/jbang/core/commands/Debug.java       | 14 ++++---
 .../camel/dsl/jbang/core/commands/Doctor.java      |  2 +-
 .../camel/dsl/jbang/core/commands/Explain.java     |  3 +-
 .../camel/dsl/jbang/core/commands/Export.java      |  8 ++--
 .../dsl/jbang/core/commands/ExportBaseCommand.java | 14 ++++---
 .../camel/dsl/jbang/core/commands/Harden.java      |  3 +-
 .../apache/camel/dsl/jbang/core/commands/Init.java |  2 +-
 .../apache/camel/dsl/jbang/core/commands/Run.java  |  4 +-
 .../dsl/jbang/core/commands/SBOMGenerator.java     | 43 ++++++++++----------
 .../jbang/core/commands/TransformDataWeave.java    |  5 ++-
 .../dsl/jbang/core/commands/TransformRoute.java    |  1 +
 .../core/commands/action/ActionBaseCommand.java    |  1 +
 .../core/commands/action/CamelReceiveAction.java   | 10 ++---
 .../jbang/core/commands/action/CamelSourceTop.java |  4 ++
 .../core/commands/action/CamelStubAction.java      |  4 +-
 .../core/commands/action/CamelThreadDump.java      |  8 +++-
 .../core/commands/action/CamelTraceAction.java     |  6 +--
 .../jbang/core/commands/action/LoggerAction.java   |  2 +-
 .../commands/action/RouteControllerAction.java     |  4 ++
 .../dsl/jbang/core/commands/config/ConfigGet.java  |  4 +-
 .../dsl/jbang/core/commands/infra/InfraLog.java    |  2 +-
 .../core/commands/process/CamelContextStatus.java  |  3 +-
 .../core/commands/process/CamelContextTop.java     |  2 +-
 .../jbang/core/commands/process/CamelCount.java    |  3 +-
 .../commands/process/CamelRouteGroupStatus.java    | 12 ++++--
 .../core/commands/process/CamelRouteStatus.java    |  9 +++--
 .../dsl/jbang/core/commands/process/Hawtio.java    |  4 +-
 .../dsl/jbang/core/commands/process/Jolokia.java   |  1 +
 .../jbang/core/commands/process/ListMetric.java    |  9 +++--
 .../core/commands/update/CamelQuarkusUpdate.java   | 15 +++++--
 .../jbang/core/commands/update/CamelUpdate.java    |  4 +-
 .../dsl/jbang/core/commands/update/Update.java     |  9 ++---
 .../dsl/jbang/core/commands/update/UpdateList.java | 10 +++--
 .../dsl/jbang/core/commands/update/UpdateRun.java  |  4 +-
 .../jbang/core/commands/version/VersionList.java   |  7 ++--
 .../dsl/jbang/core/common/CommandLineHelper.java   |  1 +
 .../camel/dsl/jbang/core/common/ExampleHelper.java |  3 +-
 .../camel/dsl/jbang/core/common/GitHubHelper.java  | 46 ++++++++++++++++++++--
 .../core/commands/edit/CamelNanoLspEditor.java     |  7 ++--
 .../core/commands/generate/CodeRestGenerator.java  | 15 ++++++-
 .../commands/generate/CodeSchemaGenerator.java     | 21 +++++-----
 .../commands/kubernetes/KubernetesCommand.java     |  3 +-
 .../dsl/jbang/core/commands/test/TestInit.java     |  3 +-
 .../core/commands/test/TestPluginExporter.java     |  6 ++-
 .../camel/dsl/jbang/core/commands/tui/Theme.java   |  3 +-
 .../core/commands/validate/ValidateCommand.java    |  3 +-
 .../commands/validate/YamlNormalizeCommand.java    |  1 +
 .../commands/validate/YamlValidateCommand.java     |  6 +--
 48 files changed, 228 insertions(+), 126 deletions(-)


(camel) 04/07: chore: fix bugs in CLI edit, generate, test, and validate plugins

Posted by da...@apache.org.
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

commit 304782512c468f227652ce83f8ba25b39966cb9a
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Fri Jul 10 21:48:43 2026 +0200

    chore: fix bugs in CLI edit, generate, test, and validate plugins
    
    - Fix swapped start/end line variables and zero-length append in LSP
      text edit application
    - Remove duplicate connected-mode diagnostics computation
    - Fix dotted package path not converted to directory separators in
      REST code generator, add renameTo return value check
    - Add null check after OpenAPI parse and unknown --type handling
    - Fix test init directory comparison using wrong Path reference
    - Skip blank dependency entries in test plugin exporter
    - Fix regex group(0) vs group(1) in class name mangling
    - Delete stale dump files before normalize and transform runs
    - Fix YAML validate error count to sum actual errors, warn on
      non-YAML files
    - Fix schema generator --output default to write to stdout as
      documented, close classloader on error paths
    
    Co-Authored-By: Claude Opus 4.6 <no...@anthropic.com>
    Signed-off-by: Claus Ibsen <cl...@gmail.com>
---
 .../dsl/jbang/core/commands/TransformRoute.java     |  1 +
 .../core/commands/edit/CamelNanoLspEditor.java      |  7 +++----
 .../core/commands/generate/CodeRestGenerator.java   | 15 +++++++++++++--
 .../core/commands/generate/CodeSchemaGenerator.java | 21 ++++++++++++---------
 .../dsl/jbang/core/commands/test/TestInit.java      |  3 ++-
 .../core/commands/test/TestPluginExporter.java      |  6 +++++-
 .../commands/validate/YamlNormalizeCommand.java     |  1 +
 .../core/commands/validate/YamlValidateCommand.java |  6 +++---
 8 files changed, 40 insertions(+), 20 deletions(-)

diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/TransformRoute.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/TransformRoute.java
index 81d875d5de6e..7a74d4924b3e 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/TransformRoute.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/TransformRoute.java
@@ -105,6 +105,7 @@ public class TransformRoute extends CamelCommand {
         if (output == null || "clipboard".equals(output)) {
             dump = CommandLineHelper.CAMEL_JBANG_WORK_DIR + "/transform-output." + format;
         }
+        Files.deleteIfExists(Path.of(dump));
         final String target = dump;
 
         Run run = new Run(getMain()) {
diff --git a/dsl/camel-jbang/camel-jbang-plugin-edit/src/main/java/org/apache/camel/dsl/jbang/core/commands/edit/CamelNanoLspEditor.java b/dsl/camel-jbang/camel-jbang-plugin-edit/src/main/java/org/apache/camel/dsl/jbang/core/commands/edit/CamelNanoLspEditor.java
index c3a2cafef72d..fd7a3ac23fe8 100644
--- a/dsl/camel-jbang/camel-jbang-plugin-edit/src/main/java/org/apache/camel/dsl/jbang/core/commands/edit/CamelNanoLspEditor.java
+++ b/dsl/camel-jbang/camel-jbang-plugin-edit/src/main/java/org/apache/camel/dsl/jbang/core/commands/edit/CamelNanoLspEditor.java
@@ -145,9 +145,9 @@ public class CamelNanoLspEditor extends Nano {
             TextEdit left = textEdit.getLeft();
             Range range = left.getRange();
             Position start = range.getStart();
-            int endLine = start.getLine();
+            int startLine = start.getLine();
             Position end = range.getEnd();
-            int startLine = end.getLine();
+            int endLine = end.getLine();
             if (startLine == endLine) {
                 StringBuilder newLine = new StringBuilder();
                 String line = this.buffer.getLines().get(startLine);
@@ -168,7 +168,7 @@ public class CamelNanoLspEditor extends Nano {
                 StringBuilder newSecondLine = new StringBuilder();
                 String oldSecondLine = this.buffer.getLines().get(endLine);
                 newSecondLine.append(newText, oldFirstLine.length() - start.getCharacter(), end.getCharacter());
-                newSecondLine.append(oldSecondLine, end.getCharacter(), end.getCharacter());
+                newSecondLine.append(oldSecondLine.substring(end.getCharacter()));
                 this.buffer.getLines().set(endLine, newSecondLine.toString());
                 this.buffer.moveRight(left.getNewText().length());
             }
@@ -222,7 +222,6 @@ public class CamelNanoLspEditor extends Nano {
             diagnostics.addAll(configurationPropertiesDiagnosticService.converToLSPDiagnostics(configurationPropertiesErrors));
             diagnostics.addAll(camelKModelineDiagnosticService.compute(camelText, documentItem));
             diagnostics.addAll(connectedModeDiagnosticService.compute(camelText, documentItem));
-            diagnostics.addAll(connectedModeDiagnosticService.compute(camelText, documentItem));
             return diagnostics.stream()
                     .map(diag -> (Diagnostic) new DiagnosticWrapper(diag))
                     .toList();
diff --git a/dsl/camel-jbang/camel-jbang-plugin-generate/src/main/java/org/apache/camel/dsl/jbang/core/commands/generate/CodeRestGenerator.java b/dsl/camel-jbang/camel-jbang-plugin-generate/src/main/java/org/apache/camel/dsl/jbang/core/commands/generate/CodeRestGenerator.java
index 516f580f074b..a721be5cb527 100644
--- a/dsl/camel-jbang/camel-jbang-plugin-generate/src/main/java/org/apache/camel/dsl/jbang/core/commands/generate/CodeRestGenerator.java
+++ b/dsl/camel-jbang/camel-jbang-plugin-generate/src/main/java/org/apache/camel/dsl/jbang/core/commands/generate/CodeRestGenerator.java
@@ -113,6 +113,11 @@ public class CodeRestGenerator extends CamelCommand {
         OpenAPIV3Parser parser = new OpenAPIV3Parser();
         doc = parser.read(input);
 
+        if (doc == null) {
+            printer().println("Error: Failed to parse OpenAPI specification: " + input);
+            return 1;
+        }
+
         Configurator.setRootLevel(Level.OFF);
         try (CamelContext context = new DefaultCamelContext()) {
             String text = null;
@@ -124,6 +129,9 @@ public class CodeRestGenerator extends CamelCommand {
                 text = RestDslGenerator.toXml(doc)
                         .withDtoPackageName(generateDataObjects ? packageName : null)
                         .generate(context);
+            } else {
+                printer().println("Error: Unknown type: " + type + " (supported: yaml, xml)");
+                return 1;
             }
             if (text != null) {
                 if (output == null) {
@@ -163,7 +171,10 @@ public class CodeRestGenerator extends CamelCommand {
 
         final ClientOptInput clientOptInput = configurator.toClientOptInput();
         new DefaultGenerator().opts(clientOptInput).generate();
-        File generated = new File(Paths.get(output.getAbsolutePath(), code, packageName).toUri());
-        generated.renameTo(new File(packageName));
+        String packageDir = packageName.replace('.', File.separatorChar);
+        File generated = Paths.get(output.getAbsolutePath(), code, packageDir).toFile();
+        if (generated.exists() && !generated.renameTo(new File(packageDir))) {
+            printer().println("Error: Failed to move generated DTOs to " + packageDir);
+        }
     }
 }
diff --git a/dsl/camel-jbang/camel-jbang-plugin-generate/src/main/java/org/apache/camel/dsl/jbang/core/commands/generate/CodeSchemaGenerator.java b/dsl/camel-jbang/camel-jbang-plugin-generate/src/main/java/org/apache/camel/dsl/jbang/core/commands/generate/CodeSchemaGenerator.java
index 4d48d53a56c4..451781ece0a3 100644
--- a/dsl/camel-jbang/camel-jbang-plugin-generate/src/main/java/org/apache/camel/dsl/jbang/core/commands/generate/CodeSchemaGenerator.java
+++ b/dsl/camel-jbang/camel-jbang-plugin-generate/src/main/java/org/apache/camel/dsl/jbang/core/commands/generate/CodeSchemaGenerator.java
@@ -17,7 +17,6 @@
 package org.apache.camel.dsl.jbang.core.commands.generate;
 
 import java.io.File;
-import java.nio.file.Paths;
 import java.util.List;
 
 import com.fasterxml.jackson.databind.JsonNode;
@@ -35,6 +34,7 @@ import org.apache.camel.dsl.jbang.core.commands.MavenResolverMixin;
 import org.apache.camel.main.download.DependencyDownloaderClassLoader;
 import org.apache.camel.main.download.MavenDependencyDownloader;
 import org.apache.camel.tooling.maven.MavenArtifact;
+import org.apache.camel.util.IOHelper;
 import picocli.CommandLine;
 
 /**
@@ -212,6 +212,7 @@ public class CodeSchemaGenerator extends CamelCommand {
                             "Error: No artifacts found for component 'camel-" + camelComponent + "' version '" + version + "'");
                     printer().printErr("Please verify that the component name is correct and the version exists.");
                     printer().printErr("Available components can be found at: https://camel.apache.org/components/");
+                    IOHelper.close(cl);
                     return null;
                 }
 
@@ -221,6 +222,9 @@ public class CodeSchemaGenerator extends CamelCommand {
                 }
 
                 artifacts.forEach(artifact -> cl.addFile(artifact.getFile()));
+            } catch (Exception e) {
+                IOHelper.close(cl);
+                throw e;
             }
 
             return cl;
@@ -324,15 +328,14 @@ public class CodeSchemaGenerator extends CamelCommand {
      * @param schema The schema to output
      */
     private void outputSchema(JsonNode schema) throws Exception {
-        if (outputFile == null || outputFile.isEmpty()) {
-            outputFile = Paths.get(".") + File.separator + fullyQualifiedName + "-schema.json";
-        }
-
         ObjectMapper objectMapper = new ObjectMapper();
 
-        objectMapper.writerWithDefaultPrettyPrinter()
-                .writeValue(new File(outputFile), schema);
-
-        printer().println("Schema saved to: " + outputFile);
+        if (outputFile == null || outputFile.isEmpty()) {
+            printer().println(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(schema));
+        } else {
+            objectMapper.writerWithDefaultPrettyPrinter()
+                    .writeValue(new File(outputFile), schema);
+            printer().println("Schema saved to: " + outputFile);
+        }
     }
 }
diff --git a/dsl/camel-jbang/camel-jbang-plugin-test/src/main/java/org/apache/camel/dsl/jbang/core/commands/test/TestInit.java b/dsl/camel-jbang/camel-jbang-plugin-test/src/main/java/org/apache/camel/dsl/jbang/core/commands/test/TestInit.java
index 8d8eea6fd034..cadb45651a15 100644
--- a/dsl/camel-jbang/camel-jbang-plugin-test/src/main/java/org/apache/camel/dsl/jbang/core/commands/test/TestInit.java
+++ b/dsl/camel-jbang/camel-jbang-plugin-test/src/main/java/org/apache/camel/dsl/jbang/core/commands/test/TestInit.java
@@ -75,7 +75,8 @@ public class TestInit extends CitrusCommand {
 
         Path currentDir = Paths.get(".");
         Path workingDir;
-        if (directory.equals(currentDir.getFileName().toString())) {
+        String currentDirName = Paths.get("").toAbsolutePath().getFileName().toString();
+        if (directory.equals(currentDirName)) {
             // current directory is already the target subfolder
             workingDir = currentDir;
         } else if (currentDir.resolve(directory).toFile().exists()) {
diff --git a/dsl/camel-jbang/camel-jbang-plugin-test/src/main/java/org/apache/camel/dsl/jbang/core/commands/test/TestPluginExporter.java b/dsl/camel-jbang/camel-jbang-plugin-test/src/main/java/org/apache/camel/dsl/jbang/core/commands/test/TestPluginExporter.java
index c20a1a59bfeb..b3db94123827 100644
--- a/dsl/camel-jbang/camel-jbang-plugin-test/src/main/java/org/apache/camel/dsl/jbang/core/commands/test/TestPluginExporter.java
+++ b/dsl/camel-jbang/camel-jbang-plugin-test/src/main/java/org/apache/camel/dsl/jbang/core/commands/test/TestPluginExporter.java
@@ -25,6 +25,7 @@ import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.HashSet;
+import java.util.Locale;
 import java.util.Properties;
 import java.util.Set;
 import java.util.regex.Matcher;
@@ -98,6 +99,9 @@ public class TestPluginExporter implements PluginExporter {
                 // read runtime dependencies from jbang-.properties
                 String[] dependencies = props.getOrDefault("run.deps", "").toString().split(",");
                 for (String dependency : dependencies) {
+                    if (dependency.isBlank()) {
+                        continue;
+                    }
                     if (dependency.startsWith("org.citrusframework:")) {
                         // construct proper Citrus Maven GAV from just the artifact id
                         deps.add(asDependency(extractArtifactId(dependency)));
@@ -219,7 +223,7 @@ public class TestPluginExporter implements PluginExporter {
         int last = 0;
         while (matcher.find()) {
             sb.append(resourceName, last, matcher.start());
-            sb.append(matcher.group(0).toUpperCase());
+            sb.append(matcher.group(1).toUpperCase(Locale.ROOT));
             last = matcher.end();
         }
         sb.append(resourceName.substring(last));
diff --git a/dsl/camel-jbang/camel-jbang-plugin-validate/src/main/java/org/apache/camel/dsl/jbang/core/commands/validate/YamlNormalizeCommand.java b/dsl/camel-jbang/camel-jbang-plugin-validate/src/main/java/org/apache/camel/dsl/jbang/core/commands/validate/YamlNormalizeCommand.java
index 8e569c2eed00..38fb2a0c80e0 100644
--- a/dsl/camel-jbang/camel-jbang-plugin-validate/src/main/java/org/apache/camel/dsl/jbang/core/commands/validate/YamlNormalizeCommand.java
+++ b/dsl/camel-jbang/camel-jbang-plugin-validate/src/main/java/org/apache/camel/dsl/jbang/core/commands/validate/YamlNormalizeCommand.java
@@ -73,6 +73,7 @@ public class YamlNormalizeCommand extends CamelCommand {
         }
 
         String dump = CommandLineHelper.CAMEL_JBANG_WORK_DIR + "/normalize-output.yaml";
+        Files.deleteIfExists(Path.of(dump));
         final String target = dump;
 
         Run run = new Run(getMain()) {
diff --git a/dsl/camel-jbang/camel-jbang-plugin-validate/src/main/java/org/apache/camel/dsl/jbang/core/commands/validate/YamlValidateCommand.java b/dsl/camel-jbang/camel-jbang-plugin-validate/src/main/java/org/apache/camel/dsl/jbang/core/commands/validate/YamlValidateCommand.java
index ae89965d4fc9..f174a02053b5 100644
--- a/dsl/camel-jbang/camel-jbang-plugin-validate/src/main/java/org/apache/camel/dsl/jbang/core/commands/validate/YamlValidateCommand.java
+++ b/dsl/camel-jbang/camel-jbang-plugin-validate/src/main/java/org/apache/camel/dsl/jbang/core/commands/validate/YamlValidateCommand.java
@@ -60,6 +60,8 @@ public class YamlValidateCommand extends CamelCommand {
             if (matchFile(n)) {
                 var report = validator.validate(new File(n));
                 reports.put(n, report);
+            } else {
+                printer().println("WARN: Skipping non-YAML file: " + n);
             }
         }
 
@@ -105,9 +107,7 @@ public class YamlValidateCommand extends CamelCommand {
     private static int errorCounts(Map<String, List<Error>> reports) {
         int count = 0;
         for (List<Error> list : reports.values()) {
-            if (!list.isEmpty()) {
-                count++;
-            }
+            count += list.size();
         }
         return count;
     }


(camel) 06/07: chore: fix GitHubHelper handling of blob and raw.githubusercontent URLs

Posted by da...@apache.org.
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

commit 3df8b5412d072fbffe2ff77127d2eb434ab1b044
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Fri Jul 10 21:56:24 2026 +0200

    chore: fix GitHubHelper handling of blob and raw.githubusercontent URLs
    
    asGithubSingleUrl hardcoded substring(19) which only works for
    github.com URLs, not raw.githubusercontent.com (34 chars).
    doFetchGithubUrls only handled tree (directory) URLs; blob and raw
    URLs produced invalid URIs causing 'Failed to resolve sources'.
    
    Now handles all three URL types: tree URLs query the GitHub API for
    directory contents, blob and raw URLs resolve as single files.
    
    Co-Authored-By: Claude Opus 4.6 <no...@anthropic.com>
    Signed-off-by: Claus Ibsen <cl...@gmail.com>
---
 .../camel/dsl/jbang/core/common/GitHubHelper.java  | 46 ++++++++++++++++++++--
 1 file changed, 42 insertions(+), 4 deletions(-)

diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/GitHubHelper.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/GitHubHelper.java
index fe1f96ba6757..caf0b2ace047 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/GitHubHelper.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/GitHubHelper.java
@@ -35,9 +35,17 @@ public final class GitHubHelper {
     }
 
     public static String asGithubSingleUrl(String url) {
+        if (url.startsWith("https://raw.githubusercontent.com/")) {
+            // https://raw.githubusercontent.com/apache/camel/main/path/file.java
+            // -> github:apache:camel:main:path/file.java
+            url = url.substring(34);
+            url = url.replaceFirst("/", ":");
+            url = url.replaceFirst("/", ":");
+            url = url.replaceFirst("/", ":");
+            return "github:" + url;
+        }
         // strip https://github.com/
         url = url.substring(19);
-        // https://raw.githubusercontent.com/apache/camel-kamelets-examples/main/jbang/hello-java/Hey.java
         // https://github.com/apache/camel-kamelets-examples/blob/main/jbang/hello-java/Hey.java
         url = url.replaceFirst("/", ":");
         url = url.replaceFirst("/", ":");
@@ -61,7 +69,11 @@ public final class GitHubHelper {
             StringJoiner all)
             throws Exception {
 
-        // this is a directory, so we need to query github which files are there and filter them
+        // raw.githubusercontent.com URLs are single files, not directories
+        if (url.startsWith("https://raw.githubusercontent.com/")) {
+            addSingleFileUrl(url, routes, kamelets, properties, all);
+            return;
+        }
 
         // strip https://github.com/
         url = url.substring(19);
@@ -75,7 +87,14 @@ public final class GitHubHelper {
         String repo = parts[1];
         String action = parts[2];
         String branch = parts[3];
-        String path;
+
+        // blob URLs are single files, not directories
+        if ("blob".equals(action)) {
+            addSingleFileUrl("https://github.com/" + url, routes, kamelets, properties, all);
+            return;
+        }
+
+        // this is a directory, so we need to query github which files are there and filter them
         String wildcard = null;
         StringJoiner sj = new StringJoiner("/");
         for (int i = 4; i < parts.length; i++) {
@@ -88,7 +107,7 @@ public final class GitHubHelper {
             }
             sj.add(parts[i]);
         }
-        path = sj.toString();
+        String path = sj.toString();
 
         if ("tree".equals(action)) {
             url = "https://api.github.com/repos/" + org + "/" + repo + "/contents/" + path;
@@ -100,6 +119,25 @@ public final class GitHubHelper {
         resolveGithubAsRawFiles(url, wildcard, routes, kamelets, properties, all);
     }
 
+    private static void addSingleFileUrl(
+            String url, StringJoiner routes, StringJoiner kamelets, StringJoiner properties,
+            StringJoiner all) {
+        String ghUrl = asGithubSingleUrl(url);
+        String ext = FileUtil.onlyExt(url, false);
+        if (all != null) {
+            all.add(ghUrl);
+        } else if (kamelets != null && "kamelet.yaml".equalsIgnoreCase(ext)) {
+            kamelets.add(ghUrl);
+        } else if (properties != null && "properties".equalsIgnoreCase(ext)) {
+            properties.add(ghUrl);
+        } else if (routes != null) {
+            if ("java".equalsIgnoreCase(ext) || "xml".equalsIgnoreCase(ext)
+                    || "yaml".equalsIgnoreCase(ext) || "camel.yaml".equalsIgnoreCase(ext)) {
+                routes.add(ghUrl);
+            }
+        }
+    }
+
     private static void resolveGithubAsRawFiles(
             String url, String wildcard, StringJoiner routes, StringJoiner kamelets, StringJoiner properties, StringJoiner all)
             throws Exception {


(camel) 03/07: chore: fix various bugs in CLI core commands, config, and infra

Posted by da...@apache.org.
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

commit 3af7b261cac519a2c9f7aadf1d3ec6bbb48235c5
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Fri Jul 10 20:16:38 2026 +0200

    chore: fix various bugs in CLI core commands, config, and infra
    
    - Run: pass kameletsVersion instead of camelVersion for kamelets <= 4.16 (task 1)
    - Debug: fix mvnw lookup from filesystem root to project-relative path (task 3)
    - Debug: drain Maven output via inheritIO and raise timeout to 120s (task 2)
    - TransformDataWeave: null-check getParent() for bare output filename (task 4)
    - SBOMGenerator: split Windows mvn tokens, guard exitValue on timeout, drain output (task 5)
    - Init: use toAbsolutePath().normalize() instead of toRealPath() for dirs not yet created (task 6)
    - ExportBaseCommand: use split("=", 2) for property parsing to support = in values (task 7)
    - CommandLineHelper: return after IOException fallback to prevent overwriting (task 8)
    - Export: use Instant.now() for proper UTC timestamp in reproducible builds (task 10)
    - Doctor: fix disk space unit threshold mismatch between value and label (task 11)
    - ExportBaseCommand: restrict file:->classpath: rewrite to values starting with file: (task 12)
    - Run, ExampleHelper, Explain, Harden: use Locale.ROOT for toUpperCase() (task 13)
    - InfraLog: reuse serviceNameFromPidFile for hyphenated service names (task 41)
    - ConfigGet: return exit code 1 for missing key (task 43)
    - VersionList: return null instead of throwing UncheckedIOException when website unreachable (task 44)
    
    Co-Authored-By: Claude Opus 4.6 <no...@anthropic.com>
    Signed-off-by: Claus Ibsen <cl...@gmail.com>
---
 .../camel/dsl/jbang/core/commands/Debug.java       | 14 ++++---
 .../camel/dsl/jbang/core/commands/Doctor.java      |  2 +-
 .../camel/dsl/jbang/core/commands/Explain.java     |  3 +-
 .../camel/dsl/jbang/core/commands/Export.java      |  8 ++--
 .../dsl/jbang/core/commands/ExportBaseCommand.java | 14 ++++---
 .../camel/dsl/jbang/core/commands/Harden.java      |  3 +-
 .../apache/camel/dsl/jbang/core/commands/Init.java |  2 +-
 .../apache/camel/dsl/jbang/core/commands/Run.java  |  4 +-
 .../dsl/jbang/core/commands/SBOMGenerator.java     | 43 ++++++++++++----------
 .../jbang/core/commands/TransformDataWeave.java    |  5 ++-
 .../dsl/jbang/core/commands/config/ConfigGet.java  |  4 +-
 .../dsl/jbang/core/commands/infra/InfraLog.java    |  2 +-
 .../jbang/core/commands/version/VersionList.java   |  3 +-
 .../dsl/jbang/core/common/CommandLineHelper.java   |  1 +
 .../camel/dsl/jbang/core/common/ExampleHelper.java |  3 +-
 15 files changed, 62 insertions(+), 49 deletions(-)

diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Debug.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Debug.java
index 30245fd6cafe..e78ff44d89ce 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Debug.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Debug.java
@@ -379,9 +379,9 @@ public class Debug extends Run {
             printer().println("Preparing Camel Spring Boot for debugging ...");
 
             // use maven wrapper if present
-            String mvnw = "/mvnw";
+            String mvnw = "mvnw";
             if (FileUtil.isWindows()) {
-                mvnw = "/mvnw.cmd";
+                mvnw = "mvnw.cmd";
             }
             if (!new File(mvnw).exists()) {
                 mvnw = "mvn";
@@ -389,9 +389,10 @@ public class Debug extends Run {
             // use maven to build the JAR and then run the JAR after-wards
             ProcessBuilder pb = new ProcessBuilder();
             pb.command(mvnw, "-Dmaven.test.skip", "--file", "camel-jbang-debug-pom.xml", "package", "spring-boot:repackage");
+            pb.inheritIO();
             Process p = pb.start();
 
-            if (p.waitFor(30, TimeUnit.SECONDS)) {
+            if (p.waitFor(120, TimeUnit.SECONDS)) {
                 AtomicReference<Process> processRef = new AtomicReference<>();
                 Runtime.getRuntime().addShutdownHook(new Thread(() -> {
                     try {
@@ -503,9 +504,9 @@ public class Debug extends Run {
             printer().println("Preparing Camel Quarkus for debugging ...");
 
             // use maven wrapper if present
-            String mvnw = "/mvnw";
+            String mvnw = "mvnw";
             if (FileUtil.isWindows()) {
-                mvnw = "/mvnw.cmd";
+                mvnw = "mvnw.cmd";
             }
             if (!new File(mvnw).exists()) {
                 mvnw = "mvn";
@@ -513,9 +514,10 @@ public class Debug extends Run {
             // use maven to build the JAR and then run the JAR after-wards
             ProcessBuilder pb = new ProcessBuilder();
             pb.command(mvnw, "-Dmaven.test.skip", "--file", "camel-jbang-debug-pom.xml", "package", "quarkus:build");
+            pb.inheritIO();
             Process p = pb.start();
 
-            if (p.waitFor(30, TimeUnit.SECONDS)) {
+            if (p.waitFor(120, TimeUnit.SECONDS)) {
                 AtomicReference<Process> processRef = new AtomicReference<>();
                 Runtime.getRuntime().addShutdownHook(new Thread(() -> {
                     try {
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Doctor.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Doctor.java
index 42ced6711412..a4f7622ea5ef 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Doctor.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Doctor.java
@@ -157,7 +157,7 @@ public class Doctor extends CamelCommand {
         long mb = free / (1024 * 1024);
         long gb = mb / (1024);
         String status = mb > 500 ? "OK" : "LOW";
-        String unit = gb > 10 ? "GB" : "MB";
+        String unit = gb > 0 ? "GB" : "MB";
         printer().printf("  Disk Space:  %d %s free in temp dir (%s)%n", gb > 0 ? gb : mb, unit, status);
     }
 }
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Explain.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Explain.java
index f55d479dd842..836afd62f164 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Explain.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Explain.java
@@ -21,6 +21,7 @@ import java.nio.file.Path;
 import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Locale;
 import java.util.Optional;
 
 import org.apache.camel.catalog.CamelCatalog;
@@ -288,7 +289,7 @@ public class Explain extends CamelCommand {
         }
 
         prompt.append("File: ").append(fileName).append("\n");
-        prompt.append("Format: ").append(fileExtension.toUpperCase()).append("\n\n");
+        prompt.append("Format: ").append(fileExtension.toUpperCase(Locale.ROOT)).append("\n\n");
         prompt.append("Route definition:\n```").append(fileExtension).append("\n");
         prompt.append(routeContent).append("\n```\n\n");
         prompt.append("Please explain this Camel route:");
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Export.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Export.java
index 25532983bbb1..09912a00615e 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Export.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Export.java
@@ -21,8 +21,8 @@ import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
-import java.text.SimpleDateFormat;
-import java.util.Date;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Properties;
@@ -306,9 +306,7 @@ public class Export extends ExportBaseCommand {
 
     // Maven reproducible builds: https://maven.apache.org/guides/mini/guide-reproducible-builds.html
     protected String getBuildMavenProjectDate() {
-        // 2024-09-23T10:00:00Z
-        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
-        return sdf.format(new Date());
+        return Instant.now().truncatedTo(ChronoUnit.SECONDS).toString();
     }
 
     // Copy the dockerfile into the same Maven project root directory.
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportBaseCommand.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportBaseCommand.java
index ecec1bdadf2a..66393190a527 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportBaseCommand.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportBaseCommand.java
@@ -1031,7 +1031,9 @@ public abstract class ExportBaseCommand extends CamelCommand {
             }
 
             // files are now loaded in classpath
-            v = v.replaceAll("file:", "classpath:");
+            if (v.startsWith("file:")) {
+                v = "classpath:" + v.substring(5);
+            }
             if ("camel.main.routesIncludePattern".equals(k)) {
                 // camel.main.routesIncludePattern should remove all .java as we use move them to regular src/main/java
                 // camel.main.routesIncludePattern should remove all file: classpath: as we copy
@@ -1076,10 +1078,9 @@ public abstract class ExportBaseCommand extends CamelCommand {
         if (propertySources != null) {
             for (String[] props : Arrays.stream(propertySources).filter(Objects::nonNull).toList()) {
                 for (String s : props) {
-                    String[] kv = s.split("=");
-                    if (kv.length != 2) {
-                        // likely a user mistake, we warn the user
-                        printer().println("WARN: property '" + s + "'' has a bad format (should be 'key=value'), skipping.");
+                    String[] kv = s.split("=", 2);
+                    if (kv.length < 2) {
+                        printer().println("WARN: property '" + s + "' has a bad format (should be 'key=value'), skipping.");
                     } else {
                         result.put(kv[0], kv[1]);
                     }
@@ -1098,7 +1099,8 @@ public abstract class ExportBaseCommand extends CamelCommand {
         var answer = new Properties();
         buildProperties.stream()
                 .filter(item -> !item.isEmpty())
-                .map(item -> item.split("="))
+                .map(item -> item.split("=", 2))
+                .filter(toks -> toks.length == 2)
                 .forEach(toks -> answer.setProperty(toks[0], toks[1]));
         return answer;
     }
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Harden.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Harden.java
index e7f5a2fca0e6..0b130ad11e17 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Harden.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Harden.java
@@ -28,6 +28,7 @@ import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Optional;
 import java.util.function.BiFunction;
@@ -475,7 +476,7 @@ public class Harden extends CamelCommand {
         }
 
         prompt.append("File: ").append(fileName).append("\n");
-        prompt.append("Format: ").append(fileExtension.toUpperCase()).append("\n\n");
+        prompt.append("Format: ").append(fileExtension.toUpperCase(Locale.ROOT)).append("\n\n");
         prompt.append("Route definition:\n```").append(fileExtension).append("\n");
         prompt.append(routeContent).append("\n```\n\n");
         prompt.append("Please perform a security analysis of this Camel route and provide hardening recommendations:");
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Init.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Init.java
index 276926f26c15..65a5e5457b20 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Init.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Init.java
@@ -240,7 +240,7 @@ public class Init extends CamelCommand {
      */
     private String computeJavaPackageDeclaration(Path targetPath) throws IOException {
         String packageDeclaration = "";
-        String canonicalPath = targetPath.getParent().toRealPath().toString();
+        String canonicalPath = targetPath.getParent().toAbsolutePath().normalize().toString();
         String srcMainJavaPath = Paths.get("src", "main", "java").toString();
         int index = canonicalPath.indexOf(srcMainJavaPath);
         if (index != -1) {
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java
index d8ecbe8a8243..a28cb1515706 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java
@@ -417,7 +417,7 @@ public class Run extends CamelCommand {
                 return cat.equals(levelName) ? "" : cat;
             }).thenComparing(e -> e.getString("name")));
             printer().println();
-            String levelLabel = levelName.substring(0, 1).toUpperCase() + levelName.substring(1) + ":";
+            String levelLabel = levelName.substring(0, 1).toUpperCase(Locale.ROOT) + levelName.substring(1) + ":";
             printer().println(levelLabel);
             printer().println("=".repeat(levelLabel.length()));
             String currentCategory = null;
@@ -2051,7 +2051,7 @@ public class Run extends CamelCommand {
         }
         if (kameletsVersion != null) {
             if (camelVersion != null && VersionHelper.isLE(camelVersion, "4.16.0")) {
-                jbangArgs.add("-Dcamel-kamelets.version=" + camelVersion);
+                jbangArgs.add("-Dcamel-kamelets.version=" + kameletsVersion);
             } else {
                 cmds.add("--kamelets-version=" + kameletsVersion);
             }
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/SBOMGenerator.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/SBOMGenerator.java
index cde55103ae68..7db300a29f0b 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/SBOMGenerator.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/SBOMGenerator.java
@@ -19,6 +19,8 @@ package org.apache.camel.dsl.jbang.core.commands;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Properties;
 import java.util.concurrent.TimeUnit;
 
@@ -98,11 +100,11 @@ public class SBOMGenerator extends Export {
         Integer answer = doExport();
         if (answer == 0) {
             Path buildDir = Paths.get(EXPORT_DIR);
-            String mvnProgramCall;
+            List<String> mvnProgramCall;
             if (FileUtil.isWindows()) {
-                mvnProgramCall = "cmd /c mvn";
+                mvnProgramCall = List.of("cmd", "/c", "mvn");
             } else {
-                mvnProgramCall = "mvn";
+                mvnProgramCall = List.of("mvn");
             }
             boolean done;
             if (sbomFormat.equalsIgnoreCase(CYCLONEDX_FORMAT)) {
@@ -112,25 +114,25 @@ public class SBOMGenerator extends Export {
                 } else {
                     outputDirectoryParameter += "../../" + outputDirectory;
                 }
-                ProcessBuilder pb = new ProcessBuilder(
-                        mvnProgramCall,
-                        "org.cyclonedx:cyclonedx-maven-plugin:" + cyclonedxPluginVersion + ":makeAggregateBom",
-                        outputDirectoryParameter,
-                        "-DoutputName=" + outputName,
-                        "-DoutputFormat=" + sbomOutputFormat);
-
+                List<String> cmd = new ArrayList<>(mvnProgramCall);
+                cmd.add("org.cyclonedx:cyclonedx-maven-plugin:" + cyclonedxPluginVersion + ":makeAggregateBom");
+                cmd.add(outputDirectoryParameter);
+                cmd.add("-DoutputName=" + outputName);
+                cmd.add("-DoutputFormat=" + sbomOutputFormat);
+                ProcessBuilder pb = new ProcessBuilder(cmd);
                 pb.directory(buildDir.toFile());
+                pb.inheritIO();
 
                 Process p = pb.start();
                 done = p.waitFor(60, TimeUnit.SECONDS);
                 if (!done) {
+                    p.destroyForcibly();
                     answer = 1;
-                }
-                if (p.exitValue() != 0) {
+                } else if (p.exitValue() != 0) {
                     answer = p.exitValue();
                 }
             } else if (sbomFormat.equalsIgnoreCase(SPDX_FORMAT)) {
-                String outputDirectoryParameter = null;
+                String outputDirectoryParameter;
                 String outputFormat = null;
                 if (Paths.get(outputDirectory).isAbsolute()) {
                     outputDirectoryParameter = outputDirectory;
@@ -142,19 +144,20 @@ public class SBOMGenerator extends Export {
                 } else if (sbomOutputFormat.equalsIgnoreCase(SBOM_XML_FORMAT)) {
                     outputFormat = "RDF/XML";
                 }
-                ProcessBuilder pb = new ProcessBuilder(
-                        mvnProgramCall,
-                        "org.spdx:spdx-maven-plugin:" + spdxPluginVersion + ":createSPDX",
-                        "-DspdxFileName=" + Paths.get(outputDirectoryParameter, outputName + "." + sbomOutputFormat),
-                        "-DoutputFormat=" + outputFormat);
+                List<String> cmd = new ArrayList<>(mvnProgramCall);
+                cmd.add("org.spdx:spdx-maven-plugin:" + spdxPluginVersion + ":createSPDX");
+                cmd.add("-DspdxFileName=" + Paths.get(outputDirectoryParameter, outputName + "." + sbomOutputFormat));
+                cmd.add("-DoutputFormat=" + outputFormat);
+                ProcessBuilder pb = new ProcessBuilder(cmd);
                 pb.directory(buildDir.toFile());
+                pb.inheritIO();
 
                 Process p = pb.start();
                 done = p.waitFor(60, TimeUnit.SECONDS);
                 if (!done) {
+                    p.destroyForcibly();
                     answer = 1;
-                }
-                if (p.exitValue() != 0) {
+                } else if (p.exitValue() != 0) {
                     answer = p.exitValue();
                 }
             }
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/TransformDataWeave.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/TransformDataWeave.java
index 69dc286c0c88..bc3ff95df84d 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/TransformDataWeave.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/TransformDataWeave.java
@@ -121,7 +121,10 @@ public class TransformDataWeave extends CamelCommand {
 
             if (output != null) {
                 Path outputPath = resolveOutputPath(dwlFile, Path.of(output));
-                Files.createDirectories(outputPath.getParent());
+                Path parentDir = outputPath.getParent();
+                if (parentDir != null) {
+                    Files.createDirectories(parentDir);
+                }
                 Files.writeString(outputPath, dsContent);
                 printer().println("Converted: " + dwlFile + " -> " + outputPath);
             } else {
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/config/ConfigGet.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/config/ConfigGet.java
index 69fd0c074bbe..3b3e95bf04d1 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/config/ConfigGet.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/config/ConfigGet.java
@@ -43,15 +43,17 @@ public class ConfigGet extends CamelCommand {
 
     @Override
     public Integer doCall() throws Exception {
+        int[] exitCode = { 0 };
         CommandLineHelper.loadProperties(properties -> {
             Optional<Object> maybeProperty = Optional.ofNullable(properties.get(key));
             if (maybeProperty.isPresent()) {
                 printer().println(String.valueOf(maybeProperty.get()));
             } else {
                 printer().printErr(key + " key not found");
+                exitCode[0] = 1;
             }
         }, !global);
 
-        return 0;
+        return exitCode[0];
     }
 }
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/infra/InfraLog.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/infra/InfraLog.java
index 12025f67f09e..97a78992d32f 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/infra/InfraLog.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/infra/InfraLog.java
@@ -69,7 +69,7 @@ public class InfraLog extends InfraBaseCommand {
                         .toList();
 
                 for (Path logFile : logFiles) {
-                    String alias = logFile.getFileName().toString().split("-")[1];
+                    String alias = serviceNameFromPidFile(logFile.getFileName().toString());
                     createTailer(logFile.toFile(), alias, futures);
                 }
             } catch (IOException e) {
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/version/VersionList.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/version/VersionList.java
index b879aec3bf4b..63b5137c219a 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/version/VersionList.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/version/VersionList.java
@@ -19,7 +19,6 @@ package org.apache.camel.dsl.jbang.core.commands.version;
 import java.io.IOException;
 import java.io.LineNumberReader;
 import java.io.StringReader;
-import java.io.UncheckedIOException;
 import java.net.ProxySelector;
 import java.net.URI;
 import java.net.URISyntaxException;
@@ -599,7 +598,7 @@ public class VersionList extends CamelCommand {
                 }
             }
         } catch (IOException e) {
-            throw new UncheckedIOException("Could not get " + gitUrl, e);
+            return null;
         } catch (InterruptedException e) {
             Thread.currentThread().interrupt();
             throw new RuntimeException("Interrupted", e);
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/CommandLineHelper.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/CommandLineHelper.java
index 44440aba6077..5b2cb90dd9ba 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/CommandLineHelper.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/CommandLineHelper.java
@@ -129,6 +129,7 @@ public final class CommandLineHelper {
                 properties.load(reader);
             } catch (IOException e) {
                 commandLine.setDefaultValueProvider(new CamelUserConfigDefaultValueProvider(file));
+                return;
             }
 
             commandLine.setDefaultValueProvider(new CamelUserConfigDefaultValueProvider(properties));
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/ExampleHelper.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/ExampleHelper.java
index d1821c946c2f..e1ba0ed1d2f8 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/ExampleHelper.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/ExampleHelper.java
@@ -28,6 +28,7 @@ import java.time.Duration;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+import java.util.Locale;
 
 import org.apache.camel.util.IOHelper;
 import org.apache.camel.util.json.JsonArray;
@@ -133,7 +134,7 @@ public final class ExampleHelper {
             case "ai" -> "AI";
             case "eip" -> "EIP";
             case "rest" -> "REST";
-            default -> category.substring(0, 1).toUpperCase() + category.substring(1);
+            default -> category.substring(0, 1).toUpperCase(Locale.ROOT) + category.substring(1);
         };
     }
 


(camel) 01/07: chore: fix NPEs, sort bugs, and filter issues in CLI cmd/process commands

Posted by da...@apache.org.
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

commit f59a19a4f1412481b3f7d7e54868f18d14380b0a
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Fri Jul 10 20:01:27 2026 +0200

    chore: fix NPEs, sort bugs, and filter issues in CLI cmd/process commands
    
    - CamelRouteGroupStatus: null-check routeGroups array, fix sort group
      comparing name vs group, move limit after sorting
    - CamelRouteStatus: null-check stackTrace in error table, move limit
      after sorting so top-N works correctly
    - CamelContextTop: move rows.add after field population to avoid garbage rows
    - CamelContextStatus: null-safe reload error message via Objects.toString
    - CamelCount: assign row.uptime so --sort age works
    - ListMetric: add tags check to counters, gauges and distributions filters
    - Jolokia: print error message when no integration matches
    - Hawtio: skip disconnect when pid is 0
    - CamelTraceAction/CamelReceiveAction: fix t2 fallback assignment and use
      getOrDefault to avoid NPE on first use
    - LoggerAction: use name filter instead of wildcard in callList
    - CamelReceiveAction: default to all pids for status and fix filter
    - CamelStubAction: sort by queue name instead of integration name
    - RouteControllerAction/CamelSourceTop/CamelThreadDump: null-check arrays
      from empty JSON response
    - ActionBaseCommand: return null after interrupt instead of busy-spinning
    
    Co-Authored-By: Claude Opus 4.6 <no...@anthropic.com>
    Signed-off-by: Claus Ibsen <cl...@gmail.com>
---
 .../dsl/jbang/core/commands/action/ActionBaseCommand.java    |  1 +
 .../dsl/jbang/core/commands/action/CamelReceiveAction.java   | 10 +++++-----
 .../camel/dsl/jbang/core/commands/action/CamelSourceTop.java |  4 ++++
 .../dsl/jbang/core/commands/action/CamelStubAction.java      |  4 +++-
 .../dsl/jbang/core/commands/action/CamelThreadDump.java      |  8 ++++++--
 .../dsl/jbang/core/commands/action/CamelTraceAction.java     |  6 +++---
 .../camel/dsl/jbang/core/commands/action/LoggerAction.java   |  2 +-
 .../jbang/core/commands/action/RouteControllerAction.java    |  4 ++++
 .../dsl/jbang/core/commands/process/CamelContextStatus.java  |  3 ++-
 .../dsl/jbang/core/commands/process/CamelContextTop.java     |  2 +-
 .../camel/dsl/jbang/core/commands/process/CamelCount.java    |  3 ++-
 .../jbang/core/commands/process/CamelRouteGroupStatus.java   | 12 ++++++++----
 .../dsl/jbang/core/commands/process/CamelRouteStatus.java    |  9 +++++----
 .../apache/camel/dsl/jbang/core/commands/process/Hawtio.java |  4 +++-
 .../camel/dsl/jbang/core/commands/process/Jolokia.java       |  1 +
 .../camel/dsl/jbang/core/commands/process/ListMetric.java    |  9 ++++++---
 16 files changed, 55 insertions(+), 27 deletions(-)

diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/ActionBaseCommand.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/ActionBaseCommand.java
index ffa8a4915601..8e4025432245 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/ActionBaseCommand.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/ActionBaseCommand.java
@@ -63,6 +63,7 @@ abstract class ActionBaseCommand extends CamelCommand {
                 }
             } catch (InterruptedException e) {
                 Thread.currentThread().interrupt();
+                return null;
             } catch (Exception e) {
                 // ignore
             }
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelReceiveAction.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelReceiveAction.java
index 65e39b7d8f94..57d5c16708cc 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelReceiveAction.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelReceiveAction.java
@@ -420,10 +420,10 @@ public class CamelReceiveAction extends ActionBaseCommand {
         } else if (name != null) {
             pids = findPids(name);
         } else {
-            return 0;
+            pids = findPids("*");
         }
         ProcessHandle.allProcesses()
-                .filter(ph -> pid == 0 && pids.contains(ph.pid()))
+                .filter(ph -> pids.contains(ph.pid()))
                 .forEach(ph -> {
                     JsonObject root = loadStatus(ph.pid());
                     if (root != null) {
@@ -808,10 +808,10 @@ public class CamelReceiveAction extends ActionBaseCommand {
                 long t1 = r1.timestamp;
                 long t2 = r2.timestamp;
                 if (t1 == 0) {
-                    t1 = lastTimestamp.get(r1.name);
+                    t1 = lastTimestamp.getOrDefault(r1.name, 0L);
                 }
-                if (t1 == 0) {
-                    t1 = lastTimestamp.get(r2.name);
+                if (t2 == 0) {
+                    t2 = lastTimestamp.getOrDefault(r2.name, 0L);
                 }
                 if (t1 == 0 && t2 == 0) {
                     return 0;
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelSourceTop.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelSourceTop.java
index c5adb41a09cd..0cd102cd2344 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelSourceTop.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelSourceTop.java
@@ -86,6 +86,10 @@ public class CamelSourceTop extends ActionWatchCommand {
         JsonObject jo = waitForOutputFile(outputFile);
         if (jo != null) {
             JsonArray arr = (JsonArray) jo.get("processors");
+            if (arr == null) {
+                printer().printErr("Source top data not available from the running integration");
+                return 0;
+            }
             for (int i = 0; i < arr.size(); i++) {
                 JsonObject o = (JsonObject) arr.get(i);
                 Row row = new Row();
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelStubAction.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelStubAction.java
index 500873bd1202..a784e8317bb6 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelStubAction.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelStubAction.java
@@ -256,7 +256,9 @@ public class CamelStubAction extends ActionWatchCommand {
         }
         switch (s) {
             case "name":
-                return o1.name.compareToIgnoreCase(o2.name) * negate;
+                String q1 = o1.queue != null ? o1.queue : "";
+                String q2 = o2.queue != null ? o2.queue : "";
+                return q1.compareToIgnoreCase(q2) * negate;
             case "total":
                 return Integer.compare(o1.size, o2.size) * negate;
             default:
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelThreadDump.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelThreadDump.java
index 8843aa4c5579..207f2e65c07f 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelThreadDump.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelThreadDump.java
@@ -134,6 +134,10 @@ public class CamelThreadDump extends ActionWatchCommand {
         JsonObject jo = waitForOutputFile(outputFile);
         if (jo != null) {
             JsonArray arr = (JsonArray) jo.get("threads");
+            if (arr == null) {
+                printer().printErr("Thread dump data not available from the running integration");
+                return 0;
+            }
             for (int i = 0; i < arr.size(); i++) {
                 JsonObject jt = (JsonObject) arr.get(i);
 
@@ -177,8 +181,8 @@ public class CamelThreadDump extends ActionWatchCommand {
             clearScreen();
         }
         if (!rows.isEmpty()) {
-            int total = jo.getInteger("threadCount");
-            int peak = jo.getInteger("peakThreadCount");
+            int total = jo.getIntegerOrDefault("threadCount", 0);
+            int peak = jo.getIntegerOrDefault("peakThreadCount", 0);
             printer().printf("PID: %s\tThreads: %d\tPeak: %d\t\tDisplay: %d/%d%n", pid, total, peak, rows.size(), total);
 
             if (depth == 1) {
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelTraceAction.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelTraceAction.java
index e51f723eb5e2..0c90cc4573c3 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelTraceAction.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelTraceAction.java
@@ -660,10 +660,10 @@ public class CamelTraceAction extends ActionBaseCommand {
                 long t1 = r1.timestamp;
                 long t2 = r2.timestamp;
                 if (t1 == 0) {
-                    t1 = lastTimestamp.get(r1.name);
+                    t1 = lastTimestamp.getOrDefault(r1.name, 0L);
                 }
-                if (t1 == 0) {
-                    t1 = lastTimestamp.get(r2.name);
+                if (t2 == 0) {
+                    t2 = lastTimestamp.getOrDefault(r2.name, 0L);
                 }
                 if (t1 == 0 && t2 == 0) {
                     return 0;
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/LoggerAction.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/LoggerAction.java
index 624e1385a637..dd5e172d208e 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/LoggerAction.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/LoggerAction.java
@@ -93,7 +93,7 @@ public class LoggerAction extends ActionBaseCommand {
     protected Integer callList() {
         List<Row> rows = new ArrayList<>();
 
-        List<Long> pids = findPids("*");
+        List<Long> pids = findPids(name);
         ProcessHandle.allProcesses()
                 .filter(ph -> pids.contains(ph.pid()))
                 .forEach(ph -> {
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/RouteControllerAction.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/RouteControllerAction.java
index d6a8022b54d5..82ea1ac8f646 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/RouteControllerAction.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/RouteControllerAction.java
@@ -122,6 +122,10 @@ public class RouteControllerAction extends ActionWatchCommand {
             supervising = "SupervisingRouteController".equals(jo.getString("controller"));
 
             JsonArray arr = (JsonArray) jo.get("routes");
+            if (arr == null) {
+                printer().printErr("Route controller data not available from the running integration");
+                return 0;
+            }
             for (int i = 0; i < arr.size(); i++) {
                 JsonObject jt = (JsonObject) arr.get(i);
 
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelContextStatus.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelContextStatus.java
index 15780358eef7..15afd78dd9d9 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelContextStatus.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelContextStatus.java
@@ -20,6 +20,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.stream.Collectors;
 
 import com.github.freva.asciitable.AsciiTable;
@@ -146,7 +147,7 @@ public class CamelContextStatus extends ProcessWatchCommand {
                                 row.reloadedFailed = stats.get("failed").toString();
                                 stats = (Map<String, ?>) stats.get("lastError");
                                 if (stats != null) {
-                                    row.reloadedError = stats.get("message").toString();
+                                    row.reloadedError = Objects.toString(stats.get("message"), "");
                                 }
                             }
                         }
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelContextTop.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelContextTop.java
index 79a1e6963209..b5f656ac96a6 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelContextTop.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelContextTop.java
@@ -82,7 +82,6 @@ public class CamelContextTop extends ProcessWatchCommand {
                     // there must be a status file for the running Camel integration
                     if (root != null) {
                         Row row = new Row();
-                        rows.add(row);
                         JsonObject context = (JsonObject) root.get("context");
                         if (context == null) {
                             return;
@@ -143,6 +142,7 @@ public class CamelContextTop extends ProcessWatchCommand {
                             row.gcCount = gc.getLong("collectionCount");
                             row.gcTime = gc.getLong("collectionTime");
                         }
+                        rows.add(row);
                     }
                 });
 
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelCount.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelCount.java
index b181b2370d76..a2b6492c74bb 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelCount.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelCount.java
@@ -84,7 +84,8 @@ public class CamelCount extends ProcessWatchCommand {
                             row.name = ProcessHelper.extractName(root, ph);
                         }
                         row.pid = Long.toString(ph.pid());
-                        row.age = TimeUtils.printSince(extractSince(ph));
+                        row.uptime = extractSince(ph);
+                        row.age = TimeUtils.printSince(row.uptime);
                         Map<String, ?> stats = context.getMap("statistics");
                         if (stats != null) {
                             row.total = stats.get("exchangesTotal").toString();
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelRouteGroupStatus.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelRouteGroupStatus.java
index 960c4d3cd38e..f655a5dffde1 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelRouteGroupStatus.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelRouteGroupStatus.java
@@ -99,6 +99,9 @@ public class CamelRouteGroupStatus extends ProcessWatchCommand {
                             return;
                         }
                         JsonArray array = (JsonArray) root.get("routeGroups");
+                        if (array == null) {
+                            return;
+                        }
                         for (int i = 0; i < array.size(); i++) {
                             JsonObject o = (JsonObject) array.get(i);
                             Row row = new Row();
@@ -173,9 +176,6 @@ public class CamelRouteGroupStatus extends ProcessWatchCommand {
                             if (mean > 0 && (row.mean == null || Long.parseLong(row.mean) < mean)) {
                                 add = false;
                             }
-                            if (limit > 0 && rows.size() >= limit) {
-                                add = false;
-                            }
                             if (add && filter != null) {
                                 boolean match = false;
                                 for (String f : filter) {
@@ -200,6 +200,10 @@ public class CamelRouteGroupStatus extends ProcessWatchCommand {
         // sort rows
         rows.sort(this::sortRow);
 
+        if (limit > 0 && rows.size() > limit) {
+            rows.subList(limit, rows.size()).clear();
+        }
+
         if (!rows.isEmpty()) {
             printTable(rows);
         }
@@ -270,7 +274,7 @@ public class CamelRouteGroupStatus extends ProcessWatchCommand {
             case "name":
                 return o1.name.compareToIgnoreCase(o2.name) * negate;
             case "group":
-                return o1.name.compareToIgnoreCase(o2.group) * negate;
+                return o1.group.compareToIgnoreCase(o2.group) * negate;
             case "age":
                 return Long.compare(o1.uptime, o2.uptime) * negate;
             default:
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelRouteStatus.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelRouteStatus.java
index 70ef00c2e468..7c0f4add2155 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelRouteStatus.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelRouteStatus.java
@@ -215,9 +215,6 @@ public class CamelRouteStatus extends ProcessWatchCommand {
                             if (mean > 0 && (row.mean == null || Long.parseLong(row.mean) < mean)) {
                                 add = false;
                             }
-                            if (limit > 0 && rows.size() >= limit) {
-                                add = false;
-                            }
                             if (add && filter != null) {
                                 boolean match = false;
                                 for (String f : filter) {
@@ -248,6 +245,10 @@ public class CamelRouteStatus extends ProcessWatchCommand {
         // sort rows
         rows.sort(this::sortRow);
 
+        if (limit > 0 && rows.size() > limit) {
+            rows.subList(limit, rows.size()).clear();
+        }
+
         if (!rows.isEmpty()) {
             if (error) {
                 for (Row r : rows) {
@@ -369,7 +370,7 @@ public class CamelRouteStatus extends ProcessWatchCommand {
                 new Column().header("MESSAGE").dataAlign(HorizontalAlign.LEFT)
                         .maxWidth(msgW, OverflowBehaviour.NEWLINE)
                         .with(r -> r.lastErrorMessage))));
-        if (!er.stackTrace.isEmpty()) {
+        if (er.stackTrace != null && !er.stackTrace.isEmpty()) {
             printer().println();
             printer().println(StringHelper.fillChars('-', 120));
             printer().println(StringHelper.padString(1, 55) + "STACK-TRACE");
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/Hawtio.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/Hawtio.java
index 0fdee11a213f..b9b63c71000d 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/Hawtio.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/Hawtio.java
@@ -78,7 +78,9 @@ public class Hawtio extends CamelCommand {
                     exit = callHawtio();
                 }
             } finally {
-                disconnectJolokia();
+                if (pid != 0) {
+                    disconnectJolokia();
+                }
             }
         }
         return exit;
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/Jolokia.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/Jolokia.java
index 9759810ccdb3..1c6490dc029a 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/Jolokia.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/Jolokia.java
@@ -63,6 +63,7 @@ public class Jolokia extends ProcessBaseCommand {
     public Integer doCall() throws Exception {
         List<Long> pids = findPids(name);
         if (pids.isEmpty()) {
+            printer().printErr("No running Camel integration matches: " + name);
             return 1;
         } else if (pids.size() > 1) {
             printer().println("Name or pid " + name + " matches " + pids.size()
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListMetric.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListMetric.java
index 8573ff77a986..bfd68b3073f8 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListMetric.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListMetric.java
@@ -119,7 +119,8 @@ public class ListMetric extends ProcessWatchCommand {
                                     if (!all && getNumber(row.count).isEmpty()) {
                                         continue;
                                     }
-                                    if (filter == null || row.type.equals(filter) || row.metricName.contains(filter)) {
+                                    if (filter == null || row.type.equals(filter) || row.metricName.contains(filter)
+                                            || row.tags.contains(filter)) {
                                         rows.add(row);
                                     }
                                 }
@@ -172,7 +173,8 @@ public class ListMetric extends ProcessWatchCommand {
                                     if (!all && getNumber(row.count).isEmpty()) {
                                         continue;
                                     }
-                                    if (filter == null || row.type.equals(filter) || row.metricName.contains(filter)) {
+                                    if (filter == null || row.type.equals(filter) || row.metricName.contains(filter)
+                                            || row.tags.contains(filter)) {
                                         rows.add(row);
                                     }
                                 }
@@ -198,7 +200,8 @@ public class ListMetric extends ProcessWatchCommand {
                                     if (!all && getNumber(row.count).isEmpty()) {
                                         continue;
                                     }
-                                    if (filter == null || row.type.equals(filter) || row.metricName.contains(filter)) {
+                                    if (filter == null || row.type.equals(filter) || row.metricName.contains(filter)
+                                            || row.tags.contains(filter)) {
                                         rows.add(row);
                                     }
                                 }


(camel) 05/07: chore: fix bare validate and kubernetes commands printing nothing

Posted by da...@apache.org.
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

commit c581f266509ee85add2afc8d609eb9af7357f1a7
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Fri Jul 10 21:53:33 2026 +0200

    chore: fix bare validate and kubernetes commands printing nothing
    
    Replace standalone HelpCommand (prints nothing without parent context)
    with CommandLine(this).usage() so running 'camel validate' or
    'camel kubernetes' without subcommands prints proper usage help.
    
    Co-Authored-By: Claude Opus 4.6 <no...@anthropic.com>
    Signed-off-by: Claus Ibsen <cl...@gmail.com>
---
 .../camel/dsl/jbang/core/commands/kubernetes/KubernetesCommand.java    | 3 +--
 .../apache/camel/dsl/jbang/core/commands/validate/ValidateCommand.java | 3 +--
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesCommand.java b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesCommand.java
index 9dc4c9cf81f1..a2c0ee4999a7 100644
--- a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesCommand.java
+++ b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesCommand.java
@@ -29,8 +29,7 @@ public class KubernetesCommand extends KubernetesBaseCommand {
 
     @Override
     public Integer doCall() throws Exception {
-        // defaults to printing the help message
-        new CommandLine(new CommandLine.HelpCommand()).execute();
+        new CommandLine(this).usage(System.out);
         return 0;
     }
 }
diff --git a/dsl/camel-jbang/camel-jbang-plugin-validate/src/main/java/org/apache/camel/dsl/jbang/core/commands/validate/ValidateCommand.java b/dsl/camel-jbang/camel-jbang-plugin-validate/src/main/java/org/apache/camel/dsl/jbang/core/commands/validate/ValidateCommand.java
index 045b4e2fc0d0..3c4499c8d4ee 100644
--- a/dsl/camel-jbang/camel-jbang-plugin-validate/src/main/java/org/apache/camel/dsl/jbang/core/commands/validate/ValidateCommand.java
+++ b/dsl/camel-jbang/camel-jbang-plugin-validate/src/main/java/org/apache/camel/dsl/jbang/core/commands/validate/ValidateCommand.java
@@ -30,8 +30,7 @@ public class ValidateCommand extends CamelCommand {
 
     @Override
     public Integer doCall() throws Exception {
-        // defaults to printing the help message
-        new CommandLine(new CommandLine.HelpCommand()).execute();
+        new CommandLine(this).usage(System.out);
         return 0;
     }
 }


(camel) 02/07: chore: fix version list EOL filter, update command bugs, and Windows compatibility

Posted by da...@apache.org.
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

commit 8aa7bd17f2d9548249993eec9fc8c7311946e505
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Fri Jul 10 20:05:24 2026 +0200

    chore: fix version list EOL filter, update command bugs, and Windows compatibility
    
    - VersionList: invert EOL filter to keep active releases (not EOL ones)
    - UpdateRun: return process exit code instead of always returning 0
    - Update: return separate tokens for Windows cmd /c mvn to fix ProcessBuilder
    - CamelUpdate/UpdateList: split recipe YAML on \R instead of platform separator
    - UpdateList: fix Quarkus stream prefix match with dot boundary and use
      ComparableVersion for proper version sorting
    - CamelQuarkusUpdate: throw CamelUpdateException when no catalog entry matches
      instead of passing -Dstream=null, guard lastIndexOf result
    
    Co-Authored-By: Claude Opus 4.6 <no...@anthropic.com>
    Signed-off-by: Claus Ibsen <cl...@gmail.com>
---
 .../jbang/core/commands/update/CamelQuarkusUpdate.java    | 15 ++++++++++++---
 .../camel/dsl/jbang/core/commands/update/CamelUpdate.java |  4 ++--
 .../camel/dsl/jbang/core/commands/update/Update.java      |  9 +++------
 .../camel/dsl/jbang/core/commands/update/UpdateList.java  | 10 ++++++----
 .../camel/dsl/jbang/core/commands/update/UpdateRun.java   |  4 +---
 .../dsl/jbang/core/commands/version/VersionList.java      |  4 ++--
 6 files changed, 26 insertions(+), 20 deletions(-)

diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/update/CamelQuarkusUpdate.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/update/CamelQuarkusUpdate.java
index 35541a6081ff..da0f4f38e290 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/update/CamelQuarkusUpdate.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/update/CamelQuarkusUpdate.java
@@ -41,7 +41,7 @@ public final class CamelQuarkusUpdate implements Update {
      *
      * @return
      */
-    public String getQuarkusStream() {
+    public String getQuarkusStream() throws CamelUpdateException {
         // Assume that the quarkus updates are in the form 3.8, 3.15, 3.16...
         List<String[]> qVersions
                 = downloader.resolveAvailableVersions("org.apache.camel.quarkus", QUARKUS_UPDATE_ARTIFACTID,
@@ -50,10 +50,19 @@ public final class CamelQuarkusUpdate implements Update {
         String streamVersion = null;
         for (String[] qVersion : qVersions) {
             if (qVersion[0].equals(updateMixin.version)) {
-                streamVersion = qVersion[1].substring(0, qVersion[1].lastIndexOf('.'));
+                int dotIdx = qVersion[1].lastIndexOf('.');
+                if (dotIdx > 0) {
+                    streamVersion = qVersion[1].substring(0, dotIdx);
+                }
             }
         }
 
+        if (streamVersion == null) {
+            throw new CamelUpdateException(
+                    "Cannot determine Quarkus stream version for Camel version " + updateMixin.version
+                                           + ". No matching entry found in camel-quarkus-catalog.");
+        }
+
         return streamVersion;
     }
 
@@ -79,7 +88,7 @@ public final class CamelQuarkusUpdate implements Update {
 
     @Override
     public List<String> command() throws CamelUpdateException {
-        commands.add(mvnProgramCall());
+        commands.addAll(mvnProgramCall());
         commands.add(debug());
         MavenGav gav = updateMixin.resolveQuarkusMavenPlugin();
         commands.add(String.format(
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/update/CamelUpdate.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/update/CamelUpdate.java
index 591275beb6a3..d3e927c7c2cf 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/update/CamelUpdate.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/update/CamelUpdate.java
@@ -120,7 +120,7 @@ public final class CamelUpdate implements Update {
 
     @Override
     public List<String> command() throws CamelUpdateException {
-        commands.add(mvnProgramCall());
+        commands.addAll(mvnProgramCall());
         commands.add(debug());
         commands.add("org.openrewrite.maven:rewrite-maven-plugin:" + updateMixin.openRewriteVersion + ":"
                      + runMode());
@@ -158,7 +158,7 @@ public final class CamelUpdate implements Update {
          * @return an Optional containing the recipe name if it is a Camel upgrade recipe, otherwise empty
          */
         public Optional<String> recipeName() {
-            return Arrays.stream(content().split(System.lineSeparator()))
+            return Arrays.stream(content().split("\\R"))
                     .filter(l -> l.startsWith("name") && l.contains("org.apache.camel.upgrade"))
                     .map(l -> l.substring(l.indexOf("org.apache.camel.upgrade")))
                     .findFirst();
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/update/Update.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/update/Update.java
index 9bd5714d230c..a407bb194b91 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/update/Update.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/update/Update.java
@@ -42,14 +42,11 @@ public sealed interface Update permits CamelUpdate, CamelQuarkusUpdate {
 
     String getArtifactCoordinates();
 
-    default String mvnProgramCall() {
-        String mvnProgramCall;
+    default List<String> mvnProgramCall() {
         if (FileUtil.isWindows()) {
-            mvnProgramCall = "cmd /c mvn";
+            return List.of("cmd", "/c", "mvn");
         } else {
-            mvnProgramCall = "mvn";
+            return List.of("mvn");
         }
-
-        return mvnProgramCall;
     }
 }
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/update/UpdateList.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/update/UpdateList.java
index 739aafdce5ca..9dafbe038f69 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/update/UpdateList.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/update/UpdateList.java
@@ -158,10 +158,11 @@ public class UpdateList extends CamelCommand {
             // Translate quarkus versions to Camel
             recipesVersions.camelQuarkusRecipesVersions();
             recipesVersions.quarkusUpdateRecipes().forEach(l -> {
-                List<String[]> runtimeVersions = recipesVersions.qVersions().stream().filter(v -> v[1].startsWith(l.version()))
+                List<String[]> runtimeVersions = recipesVersions.qVersions().stream()
+                        .filter(v -> v[1].equals(l.version()) || v[1].startsWith(l.version() + "."))
                         .collect(Collectors.toList());
                 if (!runtimeVersions.isEmpty()) {
-                    runtimeVersions.sort(Comparator.comparing(o -> o[1]));
+                    runtimeVersions.sort(Comparator.comparing(o -> new ComparableVersion(o[1])));
                     String[] runtimeVersion = runtimeVersions.get(runtimeVersions.size() - 1);
                     // Quarkus may release patches independently, therefore, we do not know the real micro version
                     String quarkusVersion = runtimeVersion[1];
@@ -320,8 +321,9 @@ public class UpdateList extends CamelCommand {
                         /* Quarkus specific, maybe in the future can be removed */
                         && !name.contains("alpha")) {
 
-                    String content = new String(jarFile.getInputStream(jarEntry).readAllBytes());
-                    String description = Arrays.stream(content.split(System.lineSeparator()))
+                    String content = new String(
+                            jarFile.getInputStream(jarEntry).readAllBytes(), java.nio.charset.StandardCharsets.UTF_8);
+                    String description = Arrays.stream(content.split("\\R"))
                             .filter(l -> l.startsWith("description"))
                             .map(l -> l.substring(l.indexOf(":") + 1).trim())
                             .findFirst().orElse("");
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/update/UpdateRun.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/update/UpdateRun.java
index ee7f0191296f..e12d9785bb9c 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/update/UpdateRun.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/update/UpdateRun.java
@@ -99,9 +99,7 @@ public class UpdateRun extends CamelCommand {
             }
         }
 
-        executeCommand(command);
-
-        return 0;
+        return executeCommand(command);
     }
 
     /**
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/version/VersionList.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/version/VersionList.java
index 3f0025c298c8..b879aec3bf4b 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/version/VersionList.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/version/VersionList.java
@@ -214,12 +214,12 @@ public class VersionList extends CamelCommand {
                 if (eol != null) {
                     try {
                         Date d = sdf.parse(r.eolDate);
-                        return d.before(now);
+                        return d.after(now);
                     } catch (Exception e) {
                         // ignore
                     }
                 }
-                return false;
+                return true;
             });
         }
 


(camel) 07/07: chore: do not log stacktrace for theme preference read failure

Posted by da...@apache.org.
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

commit 9fdc6b4a0acc2326c0d374797d5c4a8a80b3567a
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Fri Jul 10 23:08:49 2026 +0200

    chore: do not log stacktrace for theme preference read failure
    
    A single WARN line is sufficient when the TUI config file cannot be
    read. The stacktrace is noise in test output and normal operation.
    
    Co-Authored-By: Claude Opus 4.6 <no...@anthropic.com>
    Signed-off-by: Claus Ibsen <cl...@gmail.com>
---
 .../main/java/org/apache/camel/dsl/jbang/core/commands/tui/Theme.java  | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/Theme.java b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/Theme.java
index a91368c54a89..8b397a5b6c73 100644
--- a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/Theme.java
+++ b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/Theme.java
@@ -555,8 +555,7 @@ public final class Theme {
     private static void logPersistedReadFallbackOnce(Throwable t) {
         if (!persistedReadFallbackLogged) {
             persistedReadFallbackLogged = true;
-            LOG.warn("Camel TUI theme preference could not be read; falling back to the default theme for this session",
-                    t);
+            LOG.warn("Camel TUI theme preference could not be read; falling back to the default theme for this session");
         }
     }