Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
All notable changes to this project will be documented in this file.

## Unreleased
- **Fix: `server start --dry-run` Writes Nothing and Shows `--name`:** In a folder without `lucee.json`, the dry run wrote a default `lucee.json` into the project, and its preview showed the folder name even when `--name` was given. A dry run now loads the configuration without persisting the default (`LuceeServerConfig.loadConfig(projectDir, file, persistDefault)`), and the preview applies `--name` as a real start does. Upstream: cybersonic/LuCLI#139. Adds two `ServerCommandHandlerTest` cases.

- **Fix: REPL History and Settings Follow `LUCLI_HOME`:** `lucli repl` history, the interactive terminal's history and `Settings` (`settings.json`, used e.g. by `secrets provider use`) were written under `user.home` (`~/.lucli` or `~/<profile home>`) even when `LUCLI_HOME` / `-Dlucli.home` pointed elsewhere, so an isolated LuCLI home still wrote into the real home, and `settings.json` was not the file `system paths` reports. They now use the active LuCLI home (`LucliPaths`). Settings saved under the old location (`~/.lucli/settings.json`) are read once and copied to the active home when it has none; the old file is left as it is. Upstream: cybersonic/LuCLI#140. Adds `SettingsTest` cases and `ReplCommandHistoryTest`.

- **Fix: `--env` / `--envfile` Reach Modules Run Through the Module Shortcut:** `lucli <module> … --env=x`, `lucli --env=x <module> …` and an aliased binary (`-Dlucli.binary.name=<module>`, e.g. `wheels start --env=prod`) re-execute `modules run …` on the root command, which reset the root's options, so the module saw `LuCLI.getCurrentEnvironment() == null` (only `LUCLI_ENV` worked). The shortcut now re-injects `--env` / `--envfile` at the root position, as it already did for `--verbose` / `--debug` (after the module args). Upstream: cybersonic/LuCLI#136. Adds `ModuleShortcutArgsTest`.
Expand Down
1 change: 1 addition & 0 deletions FORK.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ No release is tagged for this queue yet; tagging needs the Wheels release owner'
| 8 | wheels-dev/LuCLI [#19](https://github.com/wheels-dev/LuCLI/pull/19) (issue [#17](https://github.com/wheels-dev/LuCLI/issues/17)) | A module function run by an MCP `tools/call` receives the runtime-owned `__lucliMcpCall=true` argument; any caller-supplied argument of that name is dropped, and a terminal call never carries it |
| 9 | wheels-dev/LuCLI [#21](https://github.com/wheels-dev/LuCLI/pull/21) (issue: upstream [cybersonic/LuCLI#136](https://github.com/cybersonic/LuCLI/issues/136)) | `--env` / `--envfile` reach a module run through the module shortcut or an aliased binary (re-injected at the root position) |
| 10 | wheels-dev/LuCLI [#22](https://github.com/wheels-dev/LuCLI/pull/22) (issue: upstream [cybersonic/LuCLI#140](https://github.com/cybersonic/LuCLI/issues/140)) | REPL / terminal history and `settings.json` follow the active LuCLI home instead of `user.home`; legacy `~/.lucli/settings.json` read once and copied |
| 11 | wheels-dev/LuCLI [#23](https://github.com/wheels-dev/LuCLI/pull/23) (issue: upstream [cybersonic/LuCLI#139](https://github.com/cybersonic/LuCLI/issues/139)) | `server start --dry-run` no longer writes a default `lucee.json`; the preview shows `--name` |

Upstream (row 8): issue [cybersonic/LuCLI#133](https://github.com/cybersonic/LuCLI/issues/133),
PR [cybersonic/LuCLI#134](https://github.com/cybersonic/LuCLI/pull/134) (a `cherry-pick -x` of
Expand Down
14 changes: 13 additions & 1 deletion src/main/java/org/lucee/lucli/server/LuceeServerConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,16 @@ public static ServerConfig loadConfig(Path projectDir) throws IOException {
* @param configFileName The configuration file name (e.g., "lucee.json", "lucee-simple.json")
*/
public static ServerConfig loadConfig(Path projectDir, String configFileName) throws IOException {
return loadConfig(projectDir, configFileName, true);
}

/**
* Load configuration from a specified file in the directory.
* @param persistDefault when the file doesn't exist, whether to write the default
* configuration to it. A preview ({@code server start --dry-run}) passes false so
* it never writes to the project (upstream cybersonic/LuCLI#139).
*/
public static ServerConfig loadConfig(Path projectDir, String configFileName, boolean persistDefault) throws IOException {
// Reset any previously loaded .env variables for this new project/config load
clearLoadedEnvFileVariables();
clearRealizedEnvVariables();
Expand All @@ -347,7 +357,9 @@ public static ServerConfig loadConfig(Path projectDir, String configFileName) th
if (!Files.exists(configFile)) {
// Create default configuration
ServerConfig defaultConfig = createDefaultConfig(projectDir);
saveConfig(defaultConfig, configFile);
if (persistDefault) {
saveConfig(defaultConfig, configFile);
}
return defaultConfig;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,8 @@ private String handleServerStart(LuceeServerManager serverManager, String[] args
String cfgFile = configFileName != null ? configFileName : "lucee.json";
Path cfgPath = projectDir.resolve(cfgFile);
boolean configFileExisted = Files.exists(cfgPath);
LuceeServerConfig.ServerConfig finalConfig = LuceeServerConfig.loadConfig(projectDir, cfgFile);
// A dry run is a preview: it must not write a default lucee.json into the project.
LuceeServerConfig.ServerConfig finalConfig = LuceeServerConfig.loadConfig(projectDir, cfgFile, !dryRun);

// Apply environment overrides if --env flag was provided
if (environment != null && !environment.trim().isEmpty()) {
Expand Down Expand Up @@ -413,6 +414,11 @@ private String handleServerStart(LuceeServerManager serverManager, String[] args

// If dry-run, show what would happen and exit
if (dryRun) {
// --name applies to the started server (LuceeServerManager.startServerInternal);
// show it in the preview too.
if (customName != null && !customName.trim().isEmpty()) {
finalConfig.name = customName.trim();
}
StringBuilder result = new StringBuilder();
result.append("📋 DRY RUN: Server configuration that would be used:\n\n");
if (includeSelection.includeConfig) {
Expand Down
37 changes: 37 additions & 0 deletions src/test/java/org/lucee/lucli/server/ServerCommandHandlerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,43 @@ class ServerCommandHandlerTest {

private static final ObjectMapper MAPPER = new ObjectMapper();

// upstream cybersonic/LuCLI#139: a dry run is a preview and must not write to the project
@Test
void serverStartDryRun_withoutLuceeJson_writesNothing() throws Exception {
Files.writeString(tempDir.resolve("index.cfm"), "hi");

ServerCommandHandler handler = new ServerCommandHandler(true, tempDir);
String output = handler.executeCommand("server", new String[] {
"start", "--dry-run", "--port", "63301"
});

assertNotNull(output);
assertTrue(output.contains("DRY RUN"), "a preview is still printed");
assertFalse(Files.exists(tempDir.resolve("lucee.json")), "start --dry-run must not create lucee.json");
}

// upstream cybersonic/LuCLI#139: --name applies to the started server, so the preview shows it
@Test
void serverStartDryRun_previewShowsTheNameOverride() throws Exception {
Files.writeString(tempDir.resolve("lucee.json"), """
{
"name": "from-config",
"port": 8080
}
""");

ServerCommandHandler handler = new ServerCommandHandler(true, tempDir);
String output = handler.executeCommand("server", new String[] {
"start", "--dry-run", "--name", "foo"
});

assertNotNull(output);
assertTrue(output.contains("\"name\" : \"foo\"") || output.contains("\"name\": \"foo\""),
"Dry-run output should show the --name override");
assertTrue(Files.readString(tempDir.resolve("lucee.json")).contains("from-config"),
"lucee.json is not modified");
}

@Test
void serverStartDryRun_portOverrideDoesNotMutateLuceeJson() throws Exception {
Path configFile = tempDir.resolve("lucee.json");
Expand Down
Loading