This is an automated email from the ASF dual-hosted git repository. gnodet pushed a commit to branch copy-shroud in repository https://gitbox.apache.org/repos/asf/camel.git
commit df6b1abb4bb10876460a1e15b087a3fb8de40caf Author: Guillaume Nodet <[email protected]> AuthorDate: Tue Mar 24 07:53:46 2026 +0100 CAMEL-23236: Add interactive template picker to camel init When `camel init` is invoked with no arguments in an interactive terminal (TTY, non-CI), show an interactive template picker that guides the user through selecting a category, template, and filename. Non-interactive behavior is unchanged. Co-Authored-By: Claude Opus 4.6 <[email protected]> --- .../apache/camel/dsl/jbang/core/commands/Init.java | 93 ++++++++++++++++++++++ 1 file changed, 93 insertions(+) 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 1a0f967b8bff..c4fb6846e299 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 @@ -22,8 +22,11 @@ import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.ArrayList; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; +import java.util.Scanner; import java.util.Stack; import java.util.StringJoiner; @@ -95,7 +98,12 @@ public class Init extends CamelCommand { return listTemplates(); } if (file == null) { + // try interactive picker if running in a TTY and not in CI + if (System.console() != null && System.getenv("CI") == null) { + return interactivePicker(); + } printer().printErr("Missing required parameter: <file>"); + printer().printErr("Run 'camel init --list' to see available templates, or run interactively in a terminal."); return 1; } int code = execute(); @@ -271,6 +279,91 @@ public class Init extends CamelCommand { return 0; } + private int interactivePicker() throws Exception { + // Build template categories + Map<String, List<String[]>> categories = new LinkedHashMap<>(); + categories.put("Routes", List.of( + new String[] { "yaml", "YAML DSL route", ".yaml" }, + new String[] { "java", "Java DSL route", ".java" }, + new String[] { "xml", "XML DSL route", ".xml" })); + categories.put("Kamelets", List.of( + new String[] { "kamelet-source.yaml", "Kamelet source connector", ".kamelet.yaml" }, + new String[] { "kamelet-sink.yaml", "Kamelet sink connector", ".kamelet.yaml" }, + new String[] { "kamelet-action.yaml", "Kamelet action processor", ".kamelet.yaml" })); + categories.put("Pipes and CRs", List.of( + new String[] { "init-pipe.yaml", "Pipe CR (source to sink)", ".yaml" })); + + Scanner scanner = new Scanner(System.in); + + // Step 1: Pick a category + printer().println("Select a template category:"); + List<String> categoryNames = new ArrayList<>(categories.keySet()); + for (int i = 0; i < categoryNames.size(); i++) { + printer().printf(" %d) %s%n", i + 1, categoryNames.get(i)); + } + printer().print("Choice [1]: "); + String categoryInput = scanner.nextLine().trim(); + int categoryIdx = categoryInput.isEmpty() ? 0 : Integer.parseInt(categoryInput) - 1; + if (categoryIdx < 0 || categoryIdx >= categoryNames.size()) { + printer().printErr("Invalid choice."); + return 1; + } + + // Step 2: Pick a template + String selectedCategory = categoryNames.get(categoryIdx); + List<String[]> templates = categories.get(selectedCategory); + printer().println(); + printer().println("Select a template:"); + for (int i = 0; i < templates.size(); i++) { + printer().printf(" %d) %s%n", i + 1, templates.get(i)[1]); + } + printer().print("Choice [1]: "); + String templateInput = scanner.nextLine().trim(); + int templateIdx = templateInput.isEmpty() ? 0 : Integer.parseInt(templateInput) - 1; + if (templateIdx < 0 || templateIdx >= templates.size()) { + printer().printErr("Invalid choice."); + return 1; + } + + String[] selected = templates.get(templateIdx); + String ext = selected[2]; + String defaultName = "MyRoute" + ext; + if (ext.endsWith(".kamelet.yaml")) { + if (selected[0].contains("source")) { + defaultName = "my-source.kamelet.yaml"; + } else if (selected[0].contains("sink")) { + defaultName = "my-sink.kamelet.yaml"; + } else { + defaultName = "my-action.kamelet.yaml"; + } + } else if (selected[0].contains("pipe")) { + defaultName = "my-pipe.yaml"; + pipe = true; + } + + // Step 3: Prompt for filename + printer().println(); + printer().printf("Filename [%s]: ", defaultName); + String filename = scanner.nextLine().trim(); + if (filename.isEmpty()) { + filename = defaultName; + } + + this.file = filename; + int code = execute(); + if (code == 0) { + createWorkingDirectoryIfAbsent(); + printer().println(); + printer().println("Created: " + filename); + printer().println(); + printer().println("Next steps:"); + printer().println(" Run: camel run " + filename); + printer().println(" Run (live): camel run " + filename + " --dev"); + printer().println(" Documentation: camel doc <component>"); + } + return code; + } + private void createWorkingDirectoryIfAbsent() { Path work = CommandLineHelper.getWorkDir(); if (!Files.exists(work)) {
