Skip to content

Commit 0e631fa

Browse files
committed
feat: Add usage warning for cache clean command
1 parent aa59ae8 commit 0e631fa

2 files changed

Lines changed: 41 additions & 7 deletions

File tree

packages/cli/lib/cli/commands/cache.js

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,20 @@ import Configuration from "@ui5/project/config/Configuration";
77
import FrameworkCache from "@ui5/project/ui5Framework/cache";
88
import CacheManager from "@ui5/project/build/cache/CacheManager";
99

10+
const LABEL_FRAMEWORK = "UI5 Framework packages";
11+
const LABEL_BUILD = "Build cache (Db)";
12+
const LABEL_ORPHANED_FRAMEWORK = "Orphaned UI5 Framework packages";
13+
const LABEL_ORPHANED_BUILD = "Orphaned build cache (Db)";
14+
const CACHE_CLEAN_WARNING =
15+
"Only run ui5 cache clean when no UI5 CLI process and no @ui5/* API consumer is actively running.";
16+
const CACHE_CLEAN_WARNING_IMPACT =
17+
"Running ui5 cache clean while ui5 build or ui5 serve is in progress can break the running process " +
18+
"and lead to failed or inconsistent results.";
19+
const CACHE_CLEAN_HELP_USAGE =
20+
`WARNING: ${CACHE_CLEAN_WARNING}\n${CACHE_CLEAN_WARNING_IMPACT}\n\nUsage: ui5 cache clean [options]`;
21+
// Pad main labels to equal width for two-column alignment (orphaned labels are bold headers, not padded)
22+
const LABEL_WIDTH = Math.max(LABEL_FRAMEWORK.length, LABEL_BUILD.length);
23+
1024
const cacheCommand = {
1125
command: "cache",
1226
describe: "Manage the UI5 CLI cache (downloaded framework packages and build data)",
@@ -21,6 +35,7 @@ cacheCommand.builder = function(cli) {
2135
handler: handleCache,
2236
builder: function(yargs) {
2337
return yargs
38+
.usage(CACHE_CLEAN_HELP_USAGE)
2439
.option("yes", {
2540
alias: "y",
2641
describe: "Skip the confirmation prompt, e.g. for use in CI pipelines",
@@ -38,13 +53,6 @@ cacheCommand.builder = function(cli) {
3853
});
3954
};
4055

41-
const LABEL_FRAMEWORK = "UI5 Framework packages";
42-
const LABEL_BUILD = "Build cache (Db)";
43-
const LABEL_ORPHANED_FRAMEWORK = "Orphaned UI5 Framework packages";
44-
const LABEL_ORPHANED_BUILD = "Orphaned build cache (Db)";
45-
// Pad main labels to equal width for two-column alignment (orphaned labels are bold headers, not padded)
46-
const LABEL_WIDTH = Math.max(LABEL_FRAMEWORK.length, LABEL_BUILD.length);
47-
4856
/**
4957
* Format a byte size as a human-readable string.
5058
*
@@ -86,6 +94,11 @@ function padLabel(label) {
8694
return label.padEnd(LABEL_WIDTH);
8795
}
8896

97+
function displayCacheCleanWarning() {
98+
process.stderr.write(`${chalk.bold.yellow("Warning:")} ${chalk.italic(CACHE_CLEAN_WARNING)}\n`);
99+
process.stderr.write(`${chalk.italic(CACHE_CLEAN_WARNING_IMPACT)}\n\n`);
100+
}
101+
89102
/**
90103
* Display information about the cached data that will be removed,
91104
* including the absolute paths and details about the framework and build caches.
@@ -223,6 +236,7 @@ async function getConfirmation(argv) {
223236
if (argv.yes) {
224237
return true;
225238
}
239+
displayCacheCleanWarning();
226240
const {default: yesno} = await import("yesno");
227241
return yesno({
228242
question: "Do you want to continue? (y/N)",

packages/cli/test/lib/cli/commands/cache.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ const TEST_UI5_DATA_DIR = path.resolve("test-ui5-home");
2121

2222
// Typical framework stub result shape: { path, libraryCount, versionCount }
2323
const FRAMEWORK_STUB = {path: "framework", libraryCount: 18, versionCount: 5};
24+
const WARNING_PREFIX = "Warning:";
25+
const WARNING_TEXT =
26+
"Only run ui5 cache clean when no UI5 CLI process and no @ui5/* API consumer is actively running.";
27+
const WARNING_IMPACT_TEXT =
28+
"Running ui5 cache clean while ui5 build or ui5 serve is in progress can break the running process " +
29+
"and lead to failed or inconsistent results.";
2430

2531
test.beforeEach(async (t) => {
2632
t.context.argv = getDefaultArgv();
@@ -85,6 +91,7 @@ test.afterEach.always((t) => {
8591
test("Command builder", async (t) => {
8692
const cacheModule = await import("../../../../lib/cli/commands/cache.js");
8793
const yargsStub = {
94+
usage: sinon.stub().returnsThis(),
8895
option: sinon.stub().returnsThis(),
8996
example: sinon.stub().returnsThis(),
9097
};
@@ -102,6 +109,9 @@ test("Command builder", async (t) => {
102109
t.is(result, cliStub, "Builder returns cli instance");
103110
t.is(cliStub.demandCommand.callCount, 1, "demandCommand called once");
104111
t.is(cliStub.command.callCount, 1, "command called once");
112+
t.is(yargsStub.usage.callCount, 1, "usage called once for warning help banner");
113+
t.true(yargsStub.usage.firstCall.args[0].startsWith("WARNING:"),
114+
"usage banner starts with warning");
105115
t.is(yargsStub.option.callCount, 1, "option called for --yes flag");
106116
t.is(yargsStub.example.callCount, 3, "example called 3 times");
107117
});
@@ -214,13 +224,22 @@ test.serial("ui5 cache clean: removes both entries and reports", async (t) => {
214224
const allOutput = stderrWriteStub.args.map((a) => a[0]).join("");
215225
t.true(allOutput.includes("Checking cache at"), "Prints checking line");
216226
t.true(allOutput.includes(TEST_UI5_DATA_DIR), "Shows resolved ui5DataDir");
227+
t.true(allOutput.includes(WARNING_PREFIX), "Shows safety warning before interactive confirmation");
228+
t.true(allOutput.includes(WARNING_TEXT), "Shows safety warning details");
229+
t.true(allOutput.includes(WARNING_IMPACT_TEXT), "Shows warning impact details");
217230
t.true(allOutput.includes(path.join(TEST_UI5_DATA_DIR, "framework")), "Shows absolute framework path");
218231
t.true(allOutput.includes(path.join(TEST_UI5_DATA_DIR, "buildCache/v0_7")), "Shows absolute build path");
219232
t.true(allOutput.includes("5 versions of 18 libraries"), "Shows library stats format");
220233
t.true(allOutput.includes("8.0 MB"), "Shows pre-clean build cache size");
221234
t.false(allOutput.includes("7.0 MB"), "Does not show VACUUM-freed size");
222235
t.true(allOutput.includes("Cleaned UI5 Framework packages and Build cache (Db)"),
223236
"Shows success summary");
237+
const warningCall = stderrWriteStub.getCalls().find((call) => {
238+
return call.args[0].includes(WARNING_PREFIX);
239+
});
240+
t.truthy(warningCall, "Warning line is written to stderr");
241+
t.true(warningCall.callId < yesnoStub.firstCall.callId,
242+
"Warning is displayed before the confirmation prompt is shown");
224243
});
225244

226245
test.serial("ui5 cache clean: user cancels", async (t) => {
@@ -374,6 +393,7 @@ test.serial("ui5 cache clean --yes: skips confirmation prompt", async (t) => {
374393

375394
const allOutput = stderrWriteStub.args.map((a) => a[0]).join("");
376395
t.true(allOutput.includes("Success"), "Shows success message");
396+
t.false(allOutput.includes(WARNING_PREFIX), "Does not show warning when --yes is used");
377397
});
378398

379399
test.serial("ui5 cache clean: shows orphaned framework data in pre-confirmation summary", async (t) => {

0 commit comments

Comments
 (0)