From 1d20ee4486ebb75aab6304920fd3c12b282be6fe Mon Sep 17 00:00:00 2001 From: Matthias Osswald Date: Mon, 27 Jul 2026 12:48:30 +0200 Subject: [PATCH 1/3] fix(cli): Keep interactive serve banner for verbose and perf Rework the live banner documentation to reflect the updated states and document UI5_CLI_NO_INTERACTIVE for forcing plain output. --- internal/documentation/docs/pages/Server.md | 17 +++++++------ .../docs/pages/Troubleshooting.md | 24 +++++++++++++++++++ .../documentation/docs/updates/migrate-v5.md | 2 +- packages/cli/lib/cli/middlewares/logger.js | 9 +++---- .../cli/test/lib/cli/middlewares/logger.js | 22 ++++++++++++++++- 5 files changed, 59 insertions(+), 15 deletions(-) diff --git a/internal/documentation/docs/pages/Server.md b/internal/documentation/docs/pages/Server.md index 64d6ae46155..d10723f8049 100644 --- a/internal/documentation/docs/pages/Server.md +++ b/internal/documentation/docs/pages/Server.md @@ -25,20 +25,19 @@ Please be aware of the following risks when using the server: ## Live Status Banner -When started in an interactive terminal, `ui5 serve` renders a live status banner that shows the server URLs, the root project's name/type/version, the configured UI5 framework, and a single-line status indicator that cycles between three states as you work: +When started in an interactive terminal, `ui5 serve` renders a live status banner that shows the server URLs, the root project's name/type/version, the configured UI5 framework, and a single status line that reflects what the server is doing: -- **● ready** — the server is idle; no source changes are pending and no build is in flight. -- **○ stale · files changed, rebuild on next request** — one or more watched source files changed; the next request will trigger a rebuild. -- **◐ building — *N*/*M* projects · *current project* · *current task*** — a build cycle is running. The counter, project name, and task name update in place. +- **ready** — the server is idle. Once source files change, a `N projects stale` count appears here until the next request rebuilds them. +- **building** — a build cycle is running; the project counter, current project, and current task update in place. +- **validating cache** / **settling** — the server is checking dependency caches or waiting for a burst of file changes to settle before rebuilding. +- **error** — the last build failed. The error message is also logged above the banner. -The status line stays pinned at the bottom of the terminal; warnings and errors scroll above it and remain in your terminal scrollback. While the banner is active, `info`-level log messages are suppressed — the status line already shows what they would report. The header repaints in place as more information becomes known (project graph resolved, server bound), so early frames may show dim placeholders for sections that have not been populated yet. +The status line stays pinned at the bottom of the terminal; log messages scroll above it and remain in your terminal scrollback. Log lines that would only duplicate what the banner already shows are suppressed. The banner repaints in place as more information becomes known (project graph resolved, server bound), so early frames may show dim placeholders for sections that have not been populated yet. The banner is automatically disabled and `ui5 serve` falls back to plain log output when: - `stderr` is not a TTY (e.g. output is piped to a file or another process). -- The log level is set to `--silent`, `--perf`, `--verbose`, or `--silly` — these levels emit per-task chatter that the status line cannot represent. - -In every other case (the default `info` level, `--loglevel warn`, and `--loglevel error`), the banner is active. +- The log level is set to `--silent` or `--silly`. ### Plain Output (Non-TTY) @@ -49,7 +48,7 @@ Server started URL: ``` -The remote-connections warning (when `--accept-remote-connections` is used) is written to `stderr`. Tools and scripts that capture the URL by parsing `ui5 serve` output should run the command in a non-TTY context (pipe, redirect, or CI environment), or pass `--verbose` to force plain output in an interactive terminal. +The remote-connections warning (when `--accept-remote-connections` is used) is written to `stderr`. Tools and scripts that capture the URL by parsing `ui5 serve` output should run the command in a non-TTY context (for example with `stderr` redirected, or in CI), or set `UI5_CLI_NO_INTERACTIVE=1` to force plain output in an interactive terminal. ## Standard Middleware diff --git a/internal/documentation/docs/pages/Troubleshooting.md b/internal/documentation/docs/pages/Troubleshooting.md index aff2f642c0c..7fe8c4486a3 100644 --- a/internal/documentation/docs/pages/Troubleshooting.md +++ b/internal/documentation/docs/pages/Troubleshooting.md @@ -75,6 +75,30 @@ The combination of the `UI5_LOG_LVL` environment variable with the `--log-level` ::: +### Disabling Interactive `ui5 serve` Output + +When `ui5 serve` runs in an interactive terminal, it can render a live status banner instead of plain log output. + +#### Resolution + +Set the `UI5_CLI_NO_INTERACTIVE` environment variable to any value to force plain output. + +Unix: +```sh +UI5_CLI_NO_INTERACTIVE=1 ui5 serve +``` + +Windows: +```sh +set UI5_CLI_NO_INTERACTIVE=1 ui5 serve +``` + +Cross Environment via [cross-env](https://www.npmjs.com/package/cross-env): + +```sh +cross-env UI5_CLI_NO_INTERACTIVE=1 ui5 serve +``` + ### Changing UI5 CLI's Data Directory UI5 CLI's data directory is by default at `~/.ui5`. It's the place where the framework artifacts are stored. diff --git a/internal/documentation/docs/updates/migrate-v5.md b/internal/documentation/docs/updates/migrate-v5.md index c9db7b58dac..b91451b024f 100644 --- a/internal/documentation/docs/updates/migrate-v5.md +++ b/internal/documentation/docs/updates/migrate-v5.md @@ -294,7 +294,7 @@ When `ui5 serve` is started in an interactive terminal, it now renders a live st See [Live Status Banner](../pages/Server.md#live-status-banner) for details on what is shown and when the banner is active. ::: tip Parsing `ui5 serve` output -The banner is automatically disabled in non-TTY contexts (pipes, redirects, CI logs). The plain output — `Server started` followed by `URL: ` on `stdout` — is unchanged from previous versions, so scripts that parse the URL from a non-interactive `ui5 serve` continue to work. To force plain output inside an interactive terminal, pass `--verbose` or pipe the output (e.g. `ui5 serve | cat`). +The banner is automatically disabled in non-TTY contexts. The plain output — `Server started` followed by `URL: ` on `stdout` — is unchanged from previous versions, so scripts that parse the URL from a non-interactive `ui5 serve` continue to work. To force plain output inside an interactive terminal, set `UI5_CLI_NO_INTERACTIVE=1`. ::: ## Removal of Standard Server Middleware diff --git a/packages/cli/lib/cli/middlewares/logger.js b/packages/cli/lib/cli/middlewares/logger.js index 63f85ca6a2a..b461677f3f0 100644 --- a/packages/cli/lib/cli/middlewares/logger.js +++ b/packages/cli/lib/cli/middlewares/logger.js @@ -3,10 +3,11 @@ import {setLogLevel, isLogLevelEnabled, getLogger, getLogLevel} from "@ui5/logge import ConsoleWriter from "@ui5/logger/writers/Console"; import {getVersion, getVersionWithLocation} from "../version.js"; -// Log levels that the interactive writer cannot represent (firehose verbose -// logging, or user-requested silence). Fall back to the plain Console writer -// in those cases. -const NON_INTERACTIVE_LEVELS = new Set(["perf", "verbose", "silly", "silent"]); +// Log levels at which the interactive banner is counterproductive, so we fall +// back to the plain Console writer: +// - silent: the user asked for minimal or no output, so we honor that intent +// - silly: high-volume tracing where a pinned status region hinders debugging +const NON_INTERACTIVE_LEVELS = new Set(["silly", "silent"]); /** * Logger middleware to enable logging capabilities diff --git a/packages/cli/test/lib/cli/middlewares/logger.js b/packages/cli/test/lib/cli/middlewares/logger.js index 3c4892cb03c..8c43244ad5f 100644 --- a/packages/cli/test/lib/cli/middlewares/logger.js +++ b/packages/cli/test/lib/cli/middlewares/logger.js @@ -187,12 +187,32 @@ test.serial("Interactive writer: skipped when stderr is not a TTY", async (t) => t.is(consoleInitStub.callCount, 1, "Plain ConsoleWriter.init called instead"); }); -test.serial("Interactive writer: skipped for non-interactive log level (verbose)", async (t) => { +test.serial("Interactive writer: enabled for log level verbose", async (t) => { const {logger, consoleInitStub, interactiveInitStub, getLogLevelStub} = t.context; getLogLevelStub.returns("verbose"); await withInteractiveEnv({isTTY: true, noInteractive: undefined}, () => logger.initLogger({_: ["serve"]}) ); + t.is(interactiveInitStub.callCount, 1, "InteractiveConsole.init called"); + t.is(consoleInitStub.callCount, 0, "Plain ConsoleWriter.init not called"); +}); + +test.serial("Interactive writer: enabled for log level perf", async (t) => { + const {logger, consoleInitStub, interactiveInitStub, getLogLevelStub} = t.context; + getLogLevelStub.returns("perf"); + await withInteractiveEnv({isTTY: true, noInteractive: undefined}, () => + logger.initLogger({_: ["serve"]}) + ); + t.is(interactiveInitStub.callCount, 1, "InteractiveConsole.init called"); + t.is(consoleInitStub.callCount, 0, "Plain ConsoleWriter.init not called"); +}); + +test.serial("Interactive writer: skipped for non-interactive log level (silly)", async (t) => { + const {logger, consoleInitStub, interactiveInitStub, getLogLevelStub} = t.context; + getLogLevelStub.returns("silly"); + await withInteractiveEnv({isTTY: true, noInteractive: undefined}, () => + logger.initLogger({_: ["serve"]}) + ); t.is(interactiveInitStub.callCount, 0, "InteractiveConsole.init not called"); t.is(consoleInitStub.callCount, 1, "Plain ConsoleWriter.init called instead"); }); From 1a3181ef6345caa08df4dd799acf2401ff5dfb9c Mon Sep 17 00:00:00 2001 From: Matthias Osswald Date: Mon, 27 Jul 2026 12:48:43 +0200 Subject: [PATCH 2/3] fix(logger): Label remote connections notice as warning --- .../lib/writers/interactiveConsole/remoteConnectionsWarning.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/logger/lib/writers/interactiveConsole/remoteConnectionsWarning.js b/packages/logger/lib/writers/interactiveConsole/remoteConnectionsWarning.js index 6202e9e8bea..51205f78997 100644 --- a/packages/logger/lib/writers/interactiveConsole/remoteConnectionsWarning.js +++ b/packages/logger/lib/writers/interactiveConsole/remoteConnectionsWarning.js @@ -8,7 +8,7 @@ import figures from "figures"; export const REMOTE_CONNECTIONS_WARNING_LINES = Object.freeze([ chalk.bold.yellow( `${figures.warning} This server is accepting connections from all hosts on your network`), - chalk.dim.underline("Please Note:"), + chalk.dim.underline("Warning:"), chalk.dim(`${figures.pointerSmall} `) + chalk.dim.bold("This server is intended for development purposes only. Do not use it in production."), chalk.dim(`${figures.pointerSmall} ` + From 11c838aa53dac221698e4c48822c2b6207eca9dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20O=C3=9Fwald?= Date: Mon, 27 Jul 2026 15:05:30 +0200 Subject: [PATCH 3/3] docs: Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Günter Klatt --- internal/documentation/docs/pages/Server.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/documentation/docs/pages/Server.md b/internal/documentation/docs/pages/Server.md index d10723f8049..66b6cf49ef6 100644 --- a/internal/documentation/docs/pages/Server.md +++ b/internal/documentation/docs/pages/Server.md @@ -30,9 +30,9 @@ When started in an interactive terminal, `ui5 serve` renders a live status banne - **ready** — the server is idle. Once source files change, a `N projects stale` count appears here until the next request rebuilds them. - **building** — a build cycle is running; the project counter, current project, and current task update in place. - **validating cache** / **settling** — the server is checking dependency caches or waiting for a burst of file changes to settle before rebuilding. -- **error** — the last build failed. The error message is also logged above the banner. +- **error** — the last build failed. The error message is logged above the banner. -The status line stays pinned at the bottom of the terminal; log messages scroll above it and remain in your terminal scrollback. Log lines that would only duplicate what the banner already shows are suppressed. The banner repaints in place as more information becomes known (project graph resolved, server bound), so early frames may show dim placeholders for sections that have not been populated yet. +The status line stays pinned at the bottom of the terminal; log messages scroll above it and remain in your terminal scrollback. Log lines duplicating what the banner already shows are suppressed. The banner repaints in place as more information becomes known (project graph resolved, server bound), so early frames may show dim placeholders for sections that have not been populated yet. The banner is automatically disabled and `ui5 serve` falls back to plain log output when: @@ -48,7 +48,7 @@ Server started URL: ``` -The remote-connections warning (when `--accept-remote-connections` is used) is written to `stderr`. Tools and scripts that capture the URL by parsing `ui5 serve` output should run the command in a non-TTY context (for example with `stderr` redirected, or in CI), or set `UI5_CLI_NO_INTERACTIVE=1` to force plain output in an interactive terminal. +The remote-connections warning (when `--accept-remote-connections` is used) is written to `stderr`. Tools and scripts that capture the URL by parsing `ui5 serve` output should run the command in a non-TTY context (for example, with `stderr` redirected, or in CI), or set `UI5_CLI_NO_INTERACTIVE=1` to force plain output in an interactive terminal. ## Standard Middleware