@lenne.tech/cli 1.37.2 → 1.38.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -26,7 +26,12 @@ const workspace_integration_1 = require("../../lib/workspace-integration");
|
|
|
26
26
|
* `lt ticket stop --keep-db` are never touched.
|
|
27
27
|
* 2. STALE SHARD TEST DATABASES (`<base>-test-<n>` from `lt dev test --shard`)
|
|
28
28
|
* when no test session is running — they are reset on every run anyway.
|
|
29
|
-
* 3.
|
|
29
|
+
* 3. ORPHANED SMOKE-TEST DATABASES (global): the `/lt-dev:fullstack:smoke-test`
|
|
30
|
+
* throwaway projects use the reserved `lt-smoke-test` slug; their DBs are
|
|
31
|
+
* ephemeral by convention. Leftovers (e.g. a blocked drop during the run's
|
|
32
|
+
* cleanup) would be REUSED by the next run's stack and leak state between
|
|
33
|
+
* test runs — swept here whenever no live smoke-test run is registered.
|
|
34
|
+
* 4. DEAD REGISTRY ENTRIES (all projects): path no longer exists → the entry and
|
|
30
35
|
* its reserved ports are reclaimed. Databases of dead MAIN projects are NEVER
|
|
31
36
|
* dropped (a deleted folder is not consent to destroy data).
|
|
32
37
|
*
|
|
@@ -62,9 +67,9 @@ const PruneCommand = {
|
|
|
62
67
|
projectDevDb,
|
|
63
68
|
slug,
|
|
64
69
|
});
|
|
65
|
-
const dbTargets = [...new Set([...plan.orphan.targets, ...plan.shardTargets])];
|
|
70
|
+
const dbTargets = [...new Set([...plan.orphan.targets, ...plan.shardTargets, ...plan.smokeTargets])];
|
|
66
71
|
if (dbTargets.length === 0 && plan.registryPrune.length === 0) {
|
|
67
|
-
success('Nothing to prune — no orphaned ticket DBs, no stale shard DBs, no dead registry entries.');
|
|
72
|
+
success('Nothing to prune — no orphaned ticket DBs, no stale shard DBs, no smoke-test DBs, no dead registry entries.');
|
|
68
73
|
if (plan.orphan.protected.length > 0) {
|
|
69
74
|
info(colors.dim(` kept (registry keptDbs / referenced): ${plan.orphan.protected.join(', ')}`));
|
|
70
75
|
}
|
|
@@ -80,6 +85,10 @@ const PruneCommand = {
|
|
|
80
85
|
info(colors.bold('Stale shard test databases (no test session running):'));
|
|
81
86
|
plan.shardTargets.forEach((db) => info(colors.dim(` • ${db}`)));
|
|
82
87
|
}
|
|
88
|
+
if (plan.smokeTargets.length > 0) {
|
|
89
|
+
info(colors.bold('Orphaned smoke-test databases (reserved lt-smoke-test prefix, no live run):'));
|
|
90
|
+
plan.smokeTargets.forEach((db) => info(colors.dim(` • ${db}`)));
|
|
91
|
+
}
|
|
83
92
|
if (plan.orphan.protected.length > 0) {
|
|
84
93
|
info(colors.dim(`Kept (recorded via --keep-db or still referenced): ${plan.orphan.protected.join(', ')}`));
|
|
85
94
|
}
|
package/build/commands/dev/up.js
CHANGED
|
@@ -458,7 +458,7 @@ const UpCommand = {
|
|
|
458
458
|
projectDevDb: (0, dev_project_1.deriveDbName)(mainLayout.apiDir, baseSlug),
|
|
459
459
|
slug: baseSlug,
|
|
460
460
|
});
|
|
461
|
-
const dbTargets = [...new Set([...plan.orphan.targets, ...plan.shardTargets])];
|
|
461
|
+
const dbTargets = [...new Set([...plan.orphan.targets, ...plan.shardTargets, ...plan.smokeTargets])];
|
|
462
462
|
if (dbTargets.length > 0) {
|
|
463
463
|
const { dropped, reason } = (0, dev_ticket_1.dropDatabases)(dbTargets, undefined, [mainLayout.apiDir, mainRepoRoot]);
|
|
464
464
|
if (dropped.length > 0) {
|
package/build/lib/dev-prune.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SMOKE_TEST_DB_PREFIX = void 0;
|
|
3
4
|
exports.collectDevPrunePlan = collectDevPrunePlan;
|
|
4
5
|
exports.listLiveTicketIds = listLiveTicketIds;
|
|
5
6
|
exports.listPastTicketIds = listPastTicketIds;
|
|
6
7
|
exports.planOrphanTicketDbSweep = planOrphanTicketDbSweep;
|
|
7
8
|
exports.planRegistryPrune = planRegistryPrune;
|
|
9
|
+
exports.planSmokeTestDbSweep = planSmokeTestDbSweep;
|
|
8
10
|
exports.planStaleShardDbSweep = planStaleShardDbSweep;
|
|
9
11
|
/**
|
|
10
12
|
* Garbage collection for `lt dev` / `lt ticket` leftovers.
|
|
@@ -44,6 +46,13 @@ const dev_project_1 = require("./dev-project");
|
|
|
44
46
|
const dev_ticket_1 = require("./dev-ticket");
|
|
45
47
|
/** Branch prefix `lt ticket start` creates worktrees on. */
|
|
46
48
|
const TICKET_BRANCH_PREFIX = 'feat/';
|
|
49
|
+
/**
|
|
50
|
+
* Slug convention of the lt-dev fullstack smoke test (`/lt-dev:fullstack:smoke-test`).
|
|
51
|
+
* Its throwaway projects are named `lt-smoke-test`, so every database under this
|
|
52
|
+
* prefix is ephemeral BY CONVENTION — reserve the prefix for smoke-test runs and
|
|
53
|
+
* never name a real project like this.
|
|
54
|
+
*/
|
|
55
|
+
exports.SMOKE_TEST_DB_PREFIX = 'lt-smoke-test';
|
|
47
56
|
/**
|
|
48
57
|
* Collect the full prune plan for one project. Reads the registry and the Mongo
|
|
49
58
|
* database listing; performs NO destructive action.
|
|
@@ -66,6 +75,7 @@ function collectDevPrunePlan(args) {
|
|
|
66
75
|
projectDevDb,
|
|
67
76
|
projectRoot: mainRepoRoot,
|
|
68
77
|
}),
|
|
78
|
+
smokeTargets: planSmokeTestDbSweep({ observedDbNames, registry }),
|
|
69
79
|
};
|
|
70
80
|
}
|
|
71
81
|
/** Ticket ids that still have a live environment (worktree and/or live registry entry). */
|
|
@@ -182,6 +192,47 @@ function planRegistryPrune(registry) {
|
|
|
182
192
|
.filter(([, entry]) => entry.path && !(0, fs_1.existsSync)(entry.path))
|
|
183
193
|
.map(([key]) => key);
|
|
184
194
|
}
|
|
195
|
+
/**
|
|
196
|
+
* Orphaned smoke-test databases. The `/lt-dev:fullstack:smoke-test` command
|
|
197
|
+
* scaffolds throwaway projects under the reserved {@link SMOKE_TEST_DB_PREFIX}
|
|
198
|
+
* slug; their databases (`lt-smoke-test-local`, `lt-smoke-test-test`, ticket
|
|
199
|
+
* variants, …) are ephemeral by convention. When the run's cleanup could not
|
|
200
|
+
* drop them (e.g. a blocking policy hook) they linger and — worse — get
|
|
201
|
+
* REUSED by the next run's stack, leaking state between test runs (observed:
|
|
202
|
+
* a previous run's user made a fresh sign-up probe fail with
|
|
203
|
+
* "Email already registered").
|
|
204
|
+
*
|
|
205
|
+
* Fail-closed gates, in line with the rest of this module:
|
|
206
|
+
* - No server listing → empty plan.
|
|
207
|
+
* - A LIVE registry entry under the prefix (path exists ⇒ a smoke test is
|
|
208
|
+
* running right now) → empty plan; never pull the DB out from under an
|
|
209
|
+
* active run.
|
|
210
|
+
* - Names recorded as kept (`keptDbs`) or referenced by any live entry's
|
|
211
|
+
* `dbName` are never touched.
|
|
212
|
+
*/
|
|
213
|
+
function planSmokeTestDbSweep(args) {
|
|
214
|
+
var _a;
|
|
215
|
+
const { observedDbNames, registry } = args;
|
|
216
|
+
if (!observedDbNames || observedDbNames.length === 0)
|
|
217
|
+
return [];
|
|
218
|
+
const entries = Object.entries(registry.projects);
|
|
219
|
+
const smokeRunLive = entries.some(([key, entry]) => (key === exports.SMOKE_TEST_DB_PREFIX || key.startsWith(`${exports.SMOKE_TEST_DB_PREFIX}-`)) &&
|
|
220
|
+
entry.path &&
|
|
221
|
+
(0, fs_1.existsSync)(entry.path));
|
|
222
|
+
if (smokeRunLive)
|
|
223
|
+
return [];
|
|
224
|
+
const protectedNames = new Set();
|
|
225
|
+
for (const [, entry] of entries) {
|
|
226
|
+
if (entry.dbName && entry.path && (0, fs_1.existsSync)(entry.path)) {
|
|
227
|
+
protectedNames.add(entry.dbName);
|
|
228
|
+
protectedNames.add((0, dev_project_1.deriveTestDbName)(entry.dbName));
|
|
229
|
+
}
|
|
230
|
+
for (const kept of (_a = entry.keptDbs) !== null && _a !== void 0 ? _a : []) {
|
|
231
|
+
protectedNames.add(kept);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return observedDbNames.filter((name) => (name === exports.SMOKE_TEST_DB_PREFIX || name.startsWith(`${exports.SMOKE_TEST_DB_PREFIX}-`)) && !protectedNames.has(name));
|
|
235
|
+
}
|
|
185
236
|
/**
|
|
186
237
|
* Stale sharded-test databases of the project itself (`<base>-test-<n>` from
|
|
187
238
|
* `lt dev test --shard`). They are ephemeral by definition — every shard run
|