@topogram/cli 0.3.73 → 0.3.75
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.
- package/package.json +1 -1
- package/src/agent-brief.js +18 -3
- package/src/cli/commands/check.js +15 -1
- package/src/cli/commands/release-rollout.js +191 -10
- package/src/cli/commands/release-shared.js +51 -2
- package/src/cli/commands/release.js +16 -3
- package/src/cli/help.js +1 -1
- package/src/generator/adapters.js +1 -1
- package/src/generator/runtime/app-bundle.js +3 -2
- package/src/generator/runtime/environment/index.js +15 -6
- package/src/generator/runtime/shared/index.js +1 -0
- package/src/generator/surfaces/databases/lifecycle-shared.js +175 -13
- package/src/import/extractors/cli/generic.js +107 -40
- package/src/project-config/index.js +97 -0
- package/src/project-config.js +1 -0
|
@@ -18,6 +18,17 @@ import { DEFAULT_WORKSPACE_PATH, normalizeWorkspaceConfigPath } from "../workspa
|
|
|
18
18
|
* @property {string} [package]
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
+
/**
|
|
22
|
+
* @typedef {Object} RuntimeMigrationStrategy
|
|
23
|
+
* @property {"generated"|"maintained"} ownership
|
|
24
|
+
* @property {"sql"|"prisma"|"drizzle"} tool
|
|
25
|
+
* @property {"never"|"script"} apply
|
|
26
|
+
* @property {string} [statePath]
|
|
27
|
+
* @property {string} [snapshotPath]
|
|
28
|
+
* @property {string} [schemaPath]
|
|
29
|
+
* @property {string} [migrationsPath]
|
|
30
|
+
*/
|
|
31
|
+
|
|
21
32
|
/**
|
|
22
33
|
* @typedef {Object} RuntimeTopologyRuntime
|
|
23
34
|
* @property {string} id
|
|
@@ -28,6 +39,7 @@ import { DEFAULT_WORKSPACE_PATH, normalizeWorkspaceConfigPath } from "../workspa
|
|
|
28
39
|
* @property {string} [uses_api]
|
|
29
40
|
* @property {string} [uses_database]
|
|
30
41
|
* @property {Record<string, string>} [env]
|
|
42
|
+
* @property {RuntimeMigrationStrategy} [migration]
|
|
31
43
|
*/
|
|
32
44
|
|
|
33
45
|
/**
|
|
@@ -58,6 +70,10 @@ const PROJECT_CONFIG_FILE = "topogram.project.json";
|
|
|
58
70
|
const LEGACY_IMPLEMENTATION_FILE = "topogram.implementation.json";
|
|
59
71
|
const GENERATED_OUTPUT_SENTINEL = ".topogram-generated.json";
|
|
60
72
|
const IDENTIFIER_PATTERN = /^[a-z][a-z0-9_]*$/;
|
|
73
|
+
const MIGRATION_OWNERSHIPS = new Set(["generated", "maintained"]);
|
|
74
|
+
const MIGRATION_TOOLS = new Set(["sql", "prisma", "drizzle"]);
|
|
75
|
+
const MIGRATION_APPLY_MODES = new Set(["never", "script"]);
|
|
76
|
+
const MIGRATION_PATH_FIELDS = ["statePath", "snapshotPath", "schemaPath", "migrationsPath"];
|
|
61
77
|
|
|
62
78
|
/**
|
|
63
79
|
* @param {string|null|undefined} root
|
|
@@ -249,6 +265,21 @@ function validateWorkspaceConfig(errors, config) {
|
|
|
249
265
|
}
|
|
250
266
|
}
|
|
251
267
|
|
|
268
|
+
/**
|
|
269
|
+
* @param {string} value
|
|
270
|
+
* @returns {boolean}
|
|
271
|
+
*/
|
|
272
|
+
function isProjectRelativePath(value) {
|
|
273
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
276
|
+
if (path.isAbsolute(value)) {
|
|
277
|
+
return false;
|
|
278
|
+
}
|
|
279
|
+
const normalized = path.posix.normalize(value.replace(/\\/g, "/"));
|
|
280
|
+
return normalized !== ".." && !normalized.startsWith("../");
|
|
281
|
+
}
|
|
282
|
+
|
|
252
283
|
/**
|
|
253
284
|
* @param {string} root
|
|
254
285
|
* @returns {ProjectConfigInfo|null}
|
|
@@ -388,9 +419,75 @@ function validateRuntimeShape(errors, runtime, seenIds) {
|
|
|
388
419
|
if (runtime.port != null && (!Number.isInteger(runtime.port) || runtime.port <= 0 || runtime.port > 65535)) {
|
|
389
420
|
pushError(errors, `${runtimeLabel(runtime)} port must be an integer from 1 to 65535`);
|
|
390
421
|
}
|
|
422
|
+
validateRuntimeMigrationStrategy(errors, runtime);
|
|
391
423
|
return true;
|
|
392
424
|
}
|
|
393
425
|
|
|
426
|
+
/**
|
|
427
|
+
* @param {ValidationError[]} errors
|
|
428
|
+
* @param {any} runtime
|
|
429
|
+
* @returns {void}
|
|
430
|
+
*/
|
|
431
|
+
function validateRuntimeMigrationStrategy(errors, runtime) {
|
|
432
|
+
if (runtime.migration == null) {
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
if (runtime.kind !== "database") {
|
|
436
|
+
pushError(errors, `${runtimeLabel(runtime)} migration is only supported on database runtimes`);
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
const migration = runtime.migration;
|
|
440
|
+
if (!migration || typeof migration !== "object" || Array.isArray(migration)) {
|
|
441
|
+
pushError(errors, `${runtimeLabel(runtime)} migration must be an object`);
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
if (!MIGRATION_OWNERSHIPS.has(migration.ownership)) {
|
|
445
|
+
pushError(errors, `${runtimeLabel(runtime)} migration.ownership must be generated or maintained`);
|
|
446
|
+
}
|
|
447
|
+
if (!MIGRATION_TOOLS.has(migration.tool)) {
|
|
448
|
+
pushError(errors, `${runtimeLabel(runtime)} migration.tool must be sql, prisma, or drizzle`);
|
|
449
|
+
}
|
|
450
|
+
if (!MIGRATION_APPLY_MODES.has(migration.apply)) {
|
|
451
|
+
pushError(errors, `${runtimeLabel(runtime)} migration.apply must be never or script`);
|
|
452
|
+
}
|
|
453
|
+
if (migration.ownership === "maintained" && migration.apply !== "never") {
|
|
454
|
+
pushError(errors, `${runtimeLabel(runtime)} maintained migration.apply must be never`);
|
|
455
|
+
}
|
|
456
|
+
if (migration.ownership === "generated" && migration.apply !== "script") {
|
|
457
|
+
pushError(errors, `${runtimeLabel(runtime)} generated migration.apply must be script`);
|
|
458
|
+
}
|
|
459
|
+
for (const field of MIGRATION_PATH_FIELDS) {
|
|
460
|
+
if (migration[field] != null && !isProjectRelativePath(migration[field])) {
|
|
461
|
+
pushError(errors, `${runtimeLabel(runtime)} migration.${field} must be a non-empty relative path that stays inside the project root`);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
if (migration.ownership === "generated" && typeof migration.statePath !== "string") {
|
|
465
|
+
pushError(errors, `${runtimeLabel(runtime)} generated migration requires statePath`);
|
|
466
|
+
}
|
|
467
|
+
if (migration.ownership === "maintained" && typeof migration.snapshotPath !== "string") {
|
|
468
|
+
pushError(errors, `${runtimeLabel(runtime)} maintained migration requires snapshotPath`);
|
|
469
|
+
}
|
|
470
|
+
if (migration.ownership === "maintained" && migration.tool === "prisma") {
|
|
471
|
+
if (typeof migration.schemaPath !== "string") {
|
|
472
|
+
pushError(errors, `${runtimeLabel(runtime)} maintained prisma migration requires schemaPath`);
|
|
473
|
+
}
|
|
474
|
+
if (typeof migration.migrationsPath !== "string") {
|
|
475
|
+
pushError(errors, `${runtimeLabel(runtime)} maintained prisma migration requires migrationsPath`);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
if (migration.ownership === "maintained" && migration.tool === "drizzle") {
|
|
479
|
+
if (typeof migration.schemaPath !== "string") {
|
|
480
|
+
pushError(errors, `${runtimeLabel(runtime)} maintained drizzle migration requires schemaPath`);
|
|
481
|
+
}
|
|
482
|
+
if (typeof migration.migrationsPath !== "string") {
|
|
483
|
+
pushError(errors, `${runtimeLabel(runtime)} maintained drizzle migration requires migrationsPath`);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
if (migration.ownership === "maintained" && migration.tool === "sql" && typeof migration.migrationsPath !== "string") {
|
|
487
|
+
pushError(errors, `${runtimeLabel(runtime)} maintained sql migration requires migrationsPath`);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
394
491
|
/**
|
|
395
492
|
* @param {ValidationError[]} errors
|
|
396
493
|
* @param {RuntimeTopologyRuntime} runtime
|
package/src/project-config.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @typedef {import("./project-config/index.js").GeneratorBinding} GeneratorBinding
|
|
5
|
+
* @typedef {import("./project-config/index.js").RuntimeMigrationStrategy} RuntimeMigrationStrategy
|
|
5
6
|
* @typedef {import("./project-config/index.js").RuntimeTopologyRuntime} RuntimeTopologyRuntime
|
|
6
7
|
* @typedef {import("./project-config/index.js").ProjectConfig} ProjectConfig
|
|
7
8
|
* @typedef {import("./project-config/index.js").ProjectConfigInfo} ProjectConfigInfo
|