@prisma-next/cli 0.5.0-dev.1 → 0.5.0-dev.11
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/README.md +17 -18
- package/dist/agent-skill-mongo.md +63 -31
- package/dist/agent-skill-postgres.md +1 -1
- package/dist/cli-errors-By1iVE3z.mjs +34 -0
- package/dist/cli-errors-By1iVE3z.mjs.map +1 -0
- package/dist/{cli-errors-C0JhVj0c.d.mts → cli-errors-D2NPMaxW.d.mts} +1 -0
- package/dist/cli.mjs +126 -13
- package/dist/cli.mjs.map +1 -1
- package/dist/{client-TG7rbCWT.mjs → client-faKQqcix.mjs} +19 -4
- package/dist/client-faKQqcix.mjs.map +1 -0
- package/dist/commands/contract-emit.mjs +7 -2
- package/dist/commands/contract-infer.mjs +8 -2
- package/dist/commands/db-init.mjs +8 -7
- package/dist/commands/db-init.mjs.map +1 -1
- package/dist/commands/db-schema.mjs +8 -5
- package/dist/commands/db-schema.mjs.map +1 -1
- package/dist/commands/db-sign.mjs +8 -7
- package/dist/commands/db-sign.mjs.map +1 -1
- package/dist/commands/db-update.mjs +8 -7
- package/dist/commands/db-update.mjs.map +1 -1
- package/dist/commands/db-verify.mjs +8 -7
- package/dist/commands/db-verify.mjs.map +1 -1
- package/dist/commands/migration-apply.d.mts +1 -1
- package/dist/commands/migration-apply.d.mts.map +1 -1
- package/dist/commands/migration-apply.mjs +15 -38
- package/dist/commands/migration-apply.mjs.map +1 -1
- package/dist/commands/migration-new.d.mts.map +1 -1
- package/dist/commands/migration-new.mjs +21 -26
- package/dist/commands/migration-new.mjs.map +1 -1
- package/dist/commands/migration-plan.d.mts +6 -3
- package/dist/commands/migration-plan.d.mts.map +1 -1
- package/dist/commands/migration-plan.mjs +31 -36
- package/dist/commands/migration-plan.mjs.map +1 -1
- package/dist/commands/migration-ref.d.mts +6 -4
- package/dist/commands/migration-ref.d.mts.map +1 -1
- package/dist/commands/migration-ref.mjs +31 -40
- package/dist/commands/migration-ref.mjs.map +1 -1
- package/dist/commands/migration-show.d.mts +4 -4
- package/dist/commands/migration-show.d.mts.map +1 -1
- package/dist/commands/migration-show.mjs +19 -26
- package/dist/commands/migration-show.mjs.map +1 -1
- package/dist/commands/migration-status.d.mts +5 -4
- package/dist/commands/migration-status.d.mts.map +1 -1
- package/dist/commands/migration-status.mjs +7 -2
- package/dist/{config-loader-_W4T21X1.mjs → config-loader-C25b63rJ.mjs} +1 -1
- package/dist/{config-loader-_W4T21X1.mjs.map → config-loader-C25b63rJ.mjs.map} +1 -1
- package/dist/config-loader.mjs +1 -1
- package/dist/contract-emit-B9wkchud.mjs +6 -0
- package/dist/{contract-emit-CNYyzJwF.mjs → contract-emit-Cf3fjDL6.mjs} +8 -8
- package/dist/{contract-emit-CNYyzJwF.mjs.map → contract-emit-Cf3fjDL6.mjs.map} +1 -1
- package/dist/{contract-emit-CQfj7xJn.mjs → contract-emit-PeB96eHy.mjs} +6 -6
- package/dist/{contract-emit-CQfj7xJn.mjs.map → contract-emit-PeB96eHy.mjs.map} +1 -1
- package/dist/{contract-enrichment-CGW6mm-E.mjs → contract-enrichment-CAOELa-H.mjs} +1 -1
- package/dist/{contract-enrichment-CGW6mm-E.mjs.map → contract-enrichment-CAOELa-H.mjs.map} +1 -1
- package/dist/{contract-infer-BP3DrGgz.mjs → contract-infer-BgnsSkGp.mjs} +4 -4
- package/dist/{contract-infer-BP3DrGgz.mjs.map → contract-infer-BgnsSkGp.mjs.map} +1 -1
- package/dist/exports/control-api.mjs +6 -4
- package/dist/exports/index.mjs +7 -2
- package/dist/exports/index.mjs.map +1 -1
- package/dist/exports/init-output.d.mts +39 -0
- package/dist/exports/init-output.d.mts.map +1 -0
- package/dist/exports/init-output.mjs +3 -0
- package/dist/{extract-operation-statements-DZUJNmL3.mjs → extract-operation-statements-DsFfxXVZ.mjs} +2 -2
- package/dist/{extract-operation-statements-DZUJNmL3.mjs.map → extract-operation-statements-DsFfxXVZ.mjs.map} +1 -1
- package/dist/{extract-sql-ddl-DDMX-9mz.mjs → extract-sql-ddl-D9UbZDyz.mjs} +1 -1
- package/dist/{extract-sql-ddl-DDMX-9mz.mjs.map → extract-sql-ddl-D9UbZDyz.mjs.map} +1 -1
- package/dist/{framework-components-DfZKQBQ2.mjs → framework-components-C6el-5x_.mjs} +2 -2
- package/dist/{framework-components-DfZKQBQ2.mjs.map → framework-components-C6el-5x_.mjs.map} +1 -1
- package/dist/init-jf33mNQ6.mjs +2062 -0
- package/dist/init-jf33mNQ6.mjs.map +1 -0
- package/dist/{inspect-live-schema-DWzf4Q_m.mjs → inspect-live-schema-yCu0JT0I.mjs} +6 -6
- package/dist/{inspect-live-schema-DWzf4Q_m.mjs.map → inspect-live-schema-yCu0JT0I.mjs.map} +1 -1
- package/dist/migration-cli.mjs +14 -7
- package/dist/migration-cli.mjs.map +1 -1
- package/dist/{migration-command-scaffold-CLMD302g.mjs → migration-command-scaffold-B8HAEGhQ.mjs} +6 -6
- package/dist/{migration-command-scaffold-CLMD302g.mjs.map → migration-command-scaffold-B8HAEGhQ.mjs.map} +1 -1
- package/dist/{migration-status-B0HLF7So.mjs → migration-status-8QUxCJHE.mjs} +19 -33
- package/dist/migration-status-8QUxCJHE.mjs.map +1 -0
- package/dist/{migrations-B0dOQlk0.mjs → migrations-CKRMAKka.mjs} +3 -3
- package/dist/migrations-CKRMAKka.mjs.map +1 -0
- package/dist/output-BpcQrnnq.mjs +103 -0
- package/dist/output-BpcQrnnq.mjs.map +1 -0
- package/dist/{progress-adapter-B-YvmcDu.mjs → progress-adapter-DvQWB1nK.mjs} +1 -1
- package/dist/{progress-adapter-B-YvmcDu.mjs.map → progress-adapter-DvQWB1nK.mjs.map} +1 -1
- package/dist/quick-reference-mongo.md +34 -13
- package/dist/quick-reference-postgres.md +11 -9
- package/dist/{result-handler-CIyu0Pdt.mjs → result-handler-CuhZ3kNu.mjs} +10 -91
- package/dist/result-handler-CuhZ3kNu.mjs.map +1 -0
- package/dist/{terminal-ui-C5k88MmW.mjs → terminal-ui-C3ZLwQxK.mjs} +76 -2
- package/dist/terminal-ui-C3ZLwQxK.mjs.map +1 -0
- package/dist/{validate-contract-deps-esa-VQ0h.mjs → validate-contract-deps-B_Cs29TL.mjs} +1 -1
- package/dist/{validate-contract-deps-esa-VQ0h.mjs.map → validate-contract-deps-B_Cs29TL.mjs.map} +1 -1
- package/dist/{verify-BxiVp50b.mjs → verify-Bkycc-Tf.mjs} +2 -2
- package/dist/{verify-BxiVp50b.mjs.map → verify-Bkycc-Tf.mjs.map} +1 -1
- package/package.json +20 -15
- package/src/commands/init/detect-pnpm-catalog.ts +141 -0
- package/src/commands/init/errors.ts +254 -0
- package/src/commands/init/exit-codes.ts +62 -0
- package/src/commands/init/hygiene-gitattributes.ts +97 -0
- package/src/commands/init/hygiene-gitignore.ts +48 -0
- package/src/commands/init/hygiene-package-scripts.ts +91 -0
- package/src/commands/init/index.ts +112 -7
- package/src/commands/init/init.ts +766 -144
- package/src/commands/init/inputs.ts +421 -0
- package/src/commands/init/output.ts +147 -0
- package/src/commands/init/probe-db.ts +308 -0
- package/src/commands/init/reinit-cleanup.ts +83 -0
- package/src/commands/init/templates/agent-skill-mongo.md +63 -31
- package/src/commands/init/templates/agent-skill-postgres.md +1 -1
- package/src/commands/init/templates/agent-skill.ts +25 -3
- package/src/commands/init/templates/code-templates.ts +125 -32
- package/src/commands/init/templates/env.ts +80 -0
- package/src/commands/init/templates/quick-reference-mongo.md +34 -13
- package/src/commands/init/templates/quick-reference-postgres.md +11 -9
- package/src/commands/init/templates/quick-reference.ts +42 -3
- package/src/commands/init/templates/tsconfig.ts +167 -5
- package/src/commands/migration-apply.ts +15 -50
- package/src/commands/migration-new.ts +23 -28
- package/src/commands/migration-plan.ts +53 -42
- package/src/commands/migration-ref.ts +40 -54
- package/src/commands/migration-show.ts +27 -28
- package/src/commands/migration-status.ts +33 -50
- package/src/control-api/operations/migration-apply.ts +15 -0
- package/src/exports/init-output.ts +10 -0
- package/src/migration-cli.ts +16 -9
- package/src/utils/cli-errors.ts +45 -1
- package/src/utils/command-helpers.ts +13 -26
- package/src/utils/formatters/graph-migration-mapper.ts +2 -2
- package/src/utils/formatters/migrations.ts +2 -2
- package/dist/cli-errors-DHq6GQGu.mjs +0 -5
- package/dist/client-TG7rbCWT.mjs.map +0 -1
- package/dist/contract-emit-fhNwwhkQ.mjs +0 -4
- package/dist/init-CQfo_4Ro.mjs +0 -430
- package/dist/init-CQfo_4Ro.mjs.map +0 -1
- package/dist/migration-status-B0HLF7So.mjs.map +0 -1
- package/dist/migrations-B0dOQlk0.mjs.map +0 -1
- package/dist/result-handler-CIyu0Pdt.mjs.map +0 -1
- package/dist/terminal-ui-C5k88MmW.mjs.map +0 -1
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { verifyMigrationBundle } from '@prisma-next/migration-tools/attestation';
|
|
2
1
|
import { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';
|
|
3
|
-
import {
|
|
2
|
+
import { MigrationToolsError } from '@prisma-next/migration-tools/errors';
|
|
3
|
+
import { findPathWithDecision } from '@prisma-next/migration-tools/migration-graph';
|
|
4
|
+
import type { MigrationPackage } from '@prisma-next/migration-tools/package';
|
|
4
5
|
import { readRefs, resolveRef } from '@prisma-next/migration-tools/refs';
|
|
5
|
-
import type { MigrationBundle } from '@prisma-next/migration-tools/types';
|
|
6
|
-
import { MigrationToolsError } from '@prisma-next/migration-tools/types';
|
|
7
6
|
import { notOk, ok, type Result } from '@prisma-next/utils/result';
|
|
8
7
|
import { Command } from 'commander';
|
|
9
8
|
|
|
@@ -18,11 +17,11 @@ import {
|
|
|
18
17
|
errorRuntime,
|
|
19
18
|
errorTargetMigrationNotSupported,
|
|
20
19
|
errorUnexpected,
|
|
20
|
+
mapMigrationToolsError,
|
|
21
21
|
} from '../utils/cli-errors';
|
|
22
22
|
import {
|
|
23
23
|
addGlobalOptions,
|
|
24
|
-
|
|
25
|
-
type MigrationBundleSet,
|
|
24
|
+
loadMigrationPackages,
|
|
26
25
|
maskConnectionUrl,
|
|
27
26
|
readContractEnvelope,
|
|
28
27
|
resolveMigrationPaths,
|
|
@@ -64,7 +63,7 @@ export interface MigrationApplyResult {
|
|
|
64
63
|
readonly refName?: string;
|
|
65
64
|
readonly selectedPath: readonly {
|
|
66
65
|
readonly dirName: string;
|
|
67
|
-
readonly
|
|
66
|
+
readonly migrationHash: string;
|
|
68
67
|
readonly from: string;
|
|
69
68
|
readonly to: string;
|
|
70
69
|
}[];
|
|
@@ -74,19 +73,6 @@ export interface MigrationApplyResult {
|
|
|
74
73
|
};
|
|
75
74
|
}
|
|
76
75
|
|
|
77
|
-
function mapMigrationToolsError(error: unknown): CliStructuredErrorType {
|
|
78
|
-
if (MigrationToolsError.is(error)) {
|
|
79
|
-
return errorRuntime(error.message, {
|
|
80
|
-
why: error.why,
|
|
81
|
-
fix: error.fix,
|
|
82
|
-
meta: { code: error.code, ...(error.details ?? {}) },
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
return errorUnexpected(error instanceof Error ? error.message : String(error), {
|
|
86
|
-
why: `Unexpected error during migration apply: ${error instanceof Error ? error.message : String(error)}`,
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
|
|
90
76
|
function mapApplyFailure(failure: MigrationApplyFailure): CliStructuredErrorType {
|
|
91
77
|
return errorRuntime(failure.summary, {
|
|
92
78
|
why: failure.why ?? 'Migration runner failed',
|
|
@@ -95,12 +81,12 @@ function mapApplyFailure(failure: MigrationApplyFailure): CliStructuredErrorType
|
|
|
95
81
|
});
|
|
96
82
|
}
|
|
97
83
|
|
|
98
|
-
function packageToStep(pkg:
|
|
84
|
+
function packageToStep(pkg: MigrationPackage): MigrationApplyStep {
|
|
99
85
|
return {
|
|
100
86
|
dirName: pkg.dirName,
|
|
101
|
-
from: pkg.
|
|
102
|
-
to: pkg.
|
|
103
|
-
toContract: pkg.
|
|
87
|
+
from: pkg.metadata.from,
|
|
88
|
+
to: pkg.metadata.to,
|
|
89
|
+
toContract: pkg.metadata.toContract,
|
|
104
90
|
operations: pkg.ops,
|
|
105
91
|
};
|
|
106
92
|
}
|
|
@@ -112,7 +98,7 @@ async function executeMigrationApplyCommand(
|
|
|
112
98
|
startTime: number,
|
|
113
99
|
): Promise<Result<MigrationApplyResult, CliStructuredErrorType>> {
|
|
114
100
|
const config = await loadConfig(options.config);
|
|
115
|
-
const { configPath, migrationsDir, migrationsRelative,
|
|
101
|
+
const { configPath, migrationsDir, migrationsRelative, refsDir } = resolveMigrationPaths(
|
|
116
102
|
options.config,
|
|
117
103
|
config,
|
|
118
104
|
);
|
|
@@ -149,8 +135,8 @@ async function executeMigrationApplyCommand(
|
|
|
149
135
|
if (options.ref) {
|
|
150
136
|
refName = options.ref;
|
|
151
137
|
try {
|
|
152
|
-
const refs = await readRefs(
|
|
153
|
-
destinationHash = resolveRef(refs, refName);
|
|
138
|
+
const refs = await readRefs(refsDir);
|
|
139
|
+
destinationHash = resolveRef(refs, refName).hash;
|
|
154
140
|
} catch (error) {
|
|
155
141
|
if (MigrationToolsError.is(error)) {
|
|
156
142
|
return notOk(mapMigrationToolsError(error));
|
|
@@ -196,9 +182,9 @@ async function executeMigrationApplyCommand(
|
|
|
196
182
|
}
|
|
197
183
|
|
|
198
184
|
// Read migrations and build migration chain model (offline — no DB needed)
|
|
199
|
-
let migrations:
|
|
185
|
+
let migrations: Awaited<ReturnType<typeof loadMigrationPackages>>;
|
|
200
186
|
try {
|
|
201
|
-
migrations = await
|
|
187
|
+
migrations = await loadMigrationPackages(migrationsDir);
|
|
202
188
|
} catch (error) {
|
|
203
189
|
if (MigrationToolsError.is(error)) {
|
|
204
190
|
return notOk(mapMigrationToolsError(error));
|
|
@@ -206,27 +192,6 @@ async function executeMigrationApplyCommand(
|
|
|
206
192
|
throw error;
|
|
207
193
|
}
|
|
208
194
|
|
|
209
|
-
// Defense in depth: re-hash every bundle and confirm the recorded
|
|
210
|
-
// `migrationId` matches the on-disk `(manifest, ops)`. Catches FS
|
|
211
|
-
// corruption, partial writes, and post-emit hand edits before we
|
|
212
|
-
// start touching the database.
|
|
213
|
-
for (const bundle of migrations.bundles) {
|
|
214
|
-
const verified = verifyMigrationBundle(bundle);
|
|
215
|
-
if (!verified.ok) {
|
|
216
|
-
return notOk(
|
|
217
|
-
errorRuntime(`Migration package is corrupt: ${bundle.dirName}`, {
|
|
218
|
-
why: `Stored migrationId "${verified.storedMigrationId}" does not match the recomputed hash "${verified.computedMigrationId}" for ${migrationsRelative}/${bundle.dirName}. The migration.json or ops.json has been edited or partially written since emit.`,
|
|
219
|
-
fix: `Re-emit the package by running \`node "${migrationsRelative}/${bundle.dirName}/migration.ts"\`, or restore the directory from version control.`,
|
|
220
|
-
meta: {
|
|
221
|
-
dirName: bundle.dirName,
|
|
222
|
-
storedMigrationId: verified.storedMigrationId,
|
|
223
|
-
computedMigrationId: verified.computedMigrationId,
|
|
224
|
-
},
|
|
225
|
-
}),
|
|
226
|
-
);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
195
|
const client = createControlClient({
|
|
231
196
|
family: config.family,
|
|
232
197
|
target: config.target,
|
|
@@ -12,31 +12,36 @@ import { readFileSync } from 'node:fs';
|
|
|
12
12
|
import type { Contract } from '@prisma-next/contract/types';
|
|
13
13
|
import { getEmittedArtifactPaths } from '@prisma-next/emitter';
|
|
14
14
|
import { createControlStack } from '@prisma-next/framework-components/control';
|
|
15
|
-
import { computeMigrationId } from '@prisma-next/migration-tools/attestation';
|
|
16
15
|
import { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';
|
|
17
|
-
import {
|
|
16
|
+
import { MigrationToolsError } from '@prisma-next/migration-tools/errors';
|
|
17
|
+
import { computeMigrationHash } from '@prisma-next/migration-tools/hash';
|
|
18
18
|
import {
|
|
19
19
|
copyFilesWithRename,
|
|
20
20
|
formatMigrationDirName,
|
|
21
21
|
readMigrationsDir,
|
|
22
22
|
writeMigrationPackage,
|
|
23
23
|
} from '@prisma-next/migration-tools/io';
|
|
24
|
+
import type { MigrationMetadata } from '@prisma-next/migration-tools/metadata';
|
|
25
|
+
import {
|
|
26
|
+
findLatestMigration,
|
|
27
|
+
reconstructGraph,
|
|
28
|
+
} from '@prisma-next/migration-tools/migration-graph';
|
|
24
29
|
import { writeMigrationTs } from '@prisma-next/migration-tools/migration-ts';
|
|
25
|
-
import type { MigrationManifest } from '@prisma-next/migration-tools/types';
|
|
26
|
-
import { MigrationToolsError } from '@prisma-next/migration-tools/types';
|
|
27
30
|
import { notOk, ok, type Result } from '@prisma-next/utils/result';
|
|
28
31
|
import { Command } from 'commander';
|
|
29
|
-
import { join, relative
|
|
32
|
+
import { join, relative } from 'pathe';
|
|
30
33
|
import { loadConfig } from '../config-loader';
|
|
31
34
|
import {
|
|
32
35
|
CliStructuredError,
|
|
33
36
|
errorRuntime,
|
|
34
37
|
errorTargetMigrationNotSupported,
|
|
35
38
|
errorUnexpected,
|
|
39
|
+
mapMigrationToolsError,
|
|
36
40
|
} from '../utils/cli-errors';
|
|
37
41
|
import {
|
|
38
42
|
addGlobalOptions,
|
|
39
43
|
getTargetMigrations,
|
|
44
|
+
resolveContractPath,
|
|
40
45
|
resolveMigrationPaths,
|
|
41
46
|
setCommandDescriptions,
|
|
42
47
|
setCommandExamples,
|
|
@@ -68,11 +73,7 @@ async function executeMigrationNewCommand(
|
|
|
68
73
|
const config = await loadConfig(options.config);
|
|
69
74
|
const { migrationsDir, migrationsRelative } = resolveMigrationPaths(options.config, config);
|
|
70
75
|
|
|
71
|
-
const
|
|
72
|
-
const contractPathAbsolute = resolve(
|
|
73
|
-
options.config ? resolve(options.config, '..') : process.cwd(),
|
|
74
|
-
contractPath,
|
|
75
|
-
);
|
|
76
|
+
const contractPathAbsolute = resolveContractPath(config);
|
|
76
77
|
|
|
77
78
|
let contractJsonContent: string;
|
|
78
79
|
try {
|
|
@@ -126,7 +127,7 @@ async function executeMigrationNewCommand(
|
|
|
126
127
|
const graph = reconstructGraph(packages);
|
|
127
128
|
|
|
128
129
|
if (options.from) {
|
|
129
|
-
const match = packages.find((p) => p.
|
|
130
|
+
const match = packages.find((p) => p.metadata.to.startsWith(options.from!));
|
|
130
131
|
if (!match) {
|
|
131
132
|
return notOk(
|
|
132
133
|
errorRuntime('Starting contract not found', {
|
|
@@ -135,18 +136,18 @@ async function executeMigrationNewCommand(
|
|
|
135
136
|
}),
|
|
136
137
|
);
|
|
137
138
|
}
|
|
138
|
-
fromHash = match.
|
|
139
|
-
fromContract = match.
|
|
139
|
+
fromHash = match.metadata.to;
|
|
140
|
+
fromContract = match.metadata.toContract;
|
|
140
141
|
fromContractSourceDir = match.dirPath;
|
|
141
142
|
} else {
|
|
142
143
|
const latestMigration = findLatestMigration(graph);
|
|
143
144
|
if (latestMigration) {
|
|
144
145
|
fromHash = latestMigration.to;
|
|
145
146
|
const leafPkg = packages.find(
|
|
146
|
-
(p) => p.
|
|
147
|
+
(p) => p.metadata.migrationHash === latestMigration.migrationHash,
|
|
147
148
|
);
|
|
148
149
|
if (leafPkg) {
|
|
149
|
-
fromContract = leafPkg.
|
|
150
|
+
fromContract = leafPkg.metadata.toContract;
|
|
150
151
|
fromContractSourceDir = leafPkg.dirPath;
|
|
151
152
|
}
|
|
152
153
|
}
|
|
@@ -154,13 +155,7 @@ async function executeMigrationNewCommand(
|
|
|
154
155
|
}
|
|
155
156
|
} catch (error) {
|
|
156
157
|
if (MigrationToolsError.is(error)) {
|
|
157
|
-
return notOk(
|
|
158
|
-
errorRuntime(error.message, {
|
|
159
|
-
why: error.why,
|
|
160
|
-
fix: error.fix,
|
|
161
|
-
meta: { code: error.code },
|
|
162
|
-
}),
|
|
163
|
-
);
|
|
158
|
+
return notOk(mapMigrationToolsError(error));
|
|
164
159
|
}
|
|
165
160
|
throw error;
|
|
166
161
|
}
|
|
@@ -181,9 +176,9 @@ async function executeMigrationNewCommand(
|
|
|
181
176
|
|
|
182
177
|
// `migration new` scaffolds an empty `migration.ts` for the user to
|
|
183
178
|
// fill, so we attest over `ops: []`. Re-running self-emit after the
|
|
184
|
-
// user adds operations will produce a different `
|
|
179
|
+
// user adds operations will produce a different `migrationHash` (over
|
|
185
180
|
// the real ops). This is intentional — there is no on-disk draft.
|
|
186
|
-
const
|
|
181
|
+
const baseMetadata: Omit<MigrationMetadata, 'migrationHash'> = {
|
|
187
182
|
from: fromHash,
|
|
188
183
|
to: toStorageHash,
|
|
189
184
|
kind: 'regular',
|
|
@@ -197,9 +192,9 @@ async function executeMigrationNewCommand(
|
|
|
197
192
|
labels: [],
|
|
198
193
|
createdAt: timestamp.toISOString(),
|
|
199
194
|
};
|
|
200
|
-
const
|
|
201
|
-
...
|
|
202
|
-
|
|
195
|
+
const metadata: MigrationMetadata = {
|
|
196
|
+
...baseMetadata,
|
|
197
|
+
migrationHash: computeMigrationHash(baseMetadata, []),
|
|
203
198
|
};
|
|
204
199
|
|
|
205
200
|
const migrations = getTargetMigrations(config.target);
|
|
@@ -218,7 +213,7 @@ async function executeMigrationNewCommand(
|
|
|
218
213
|
...(config.extensionPacks ?? []),
|
|
219
214
|
]);
|
|
220
215
|
|
|
221
|
-
await writeMigrationPackage(packageDir,
|
|
216
|
+
await writeMigrationPackage(packageDir, metadata, []);
|
|
222
217
|
const destinationArtifacts = getEmittedArtifactPaths(contractPathAbsolute);
|
|
223
218
|
await copyFilesWithRename(packageDir, [
|
|
224
219
|
{ sourcePath: destinationArtifacts.jsonPath, destName: 'end-contract.json' },
|
|
@@ -5,16 +5,17 @@ import {
|
|
|
5
5
|
createControlStack,
|
|
6
6
|
type MigrationPlanOperation,
|
|
7
7
|
} from '@prisma-next/framework-components/control';
|
|
8
|
-
import { computeMigrationId } from '@prisma-next/migration-tools/attestation';
|
|
9
8
|
import { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';
|
|
10
|
-
import {
|
|
9
|
+
import { MigrationToolsError } from '@prisma-next/migration-tools/errors';
|
|
10
|
+
import { computeMigrationHash } from '@prisma-next/migration-tools/hash';
|
|
11
11
|
import {
|
|
12
12
|
copyFilesWithRename,
|
|
13
13
|
formatMigrationDirName,
|
|
14
14
|
writeMigrationPackage,
|
|
15
15
|
} from '@prisma-next/migration-tools/io';
|
|
16
|
+
import type { MigrationMetadata } from '@prisma-next/migration-tools/metadata';
|
|
17
|
+
import { findLatestMigration } from '@prisma-next/migration-tools/migration-graph';
|
|
16
18
|
import { writeMigrationTs } from '@prisma-next/migration-tools/migration-ts';
|
|
17
|
-
import { type MigrationManifest, MigrationToolsError } from '@prisma-next/migration-tools/types';
|
|
18
19
|
import { notOk, ok, type Result } from '@prisma-next/utils/result';
|
|
19
20
|
import { Command } from 'commander';
|
|
20
21
|
import { join, relative } from 'pathe';
|
|
@@ -29,11 +30,12 @@ import {
|
|
|
29
30
|
errorRuntime,
|
|
30
31
|
errorTargetMigrationNotSupported,
|
|
31
32
|
errorUnexpected,
|
|
33
|
+
mapMigrationToolsError,
|
|
32
34
|
} from '../utils/cli-errors';
|
|
33
35
|
import {
|
|
34
36
|
addGlobalOptions,
|
|
35
37
|
getTargetMigrations,
|
|
36
|
-
|
|
38
|
+
loadMigrationPackages,
|
|
37
39
|
resolveContractPath,
|
|
38
40
|
resolveMigrationPaths,
|
|
39
41
|
setCommandDescriptions,
|
|
@@ -76,22 +78,6 @@ export interface MigrationPlanResult {
|
|
|
76
78
|
};
|
|
77
79
|
}
|
|
78
80
|
|
|
79
|
-
function mapMigrationToolsError(error: unknown): CliStructuredError {
|
|
80
|
-
if (CliStructuredError.is(error)) {
|
|
81
|
-
return error;
|
|
82
|
-
}
|
|
83
|
-
if (MigrationToolsError.is(error)) {
|
|
84
|
-
return errorRuntime(error.message, {
|
|
85
|
-
why: error.why,
|
|
86
|
-
fix: error.fix,
|
|
87
|
-
meta: { code: error.code, ...(error.details ?? {}) },
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
return errorUnexpected(error instanceof Error ? error.message : String(error), {
|
|
91
|
-
why: `Unexpected error during migration plan: ${error instanceof Error ? error.message : String(error)}`,
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
|
|
95
81
|
async function executeMigrationPlanCommand(
|
|
96
82
|
options: MigrationPlanOptions,
|
|
97
83
|
flags: GlobalFlags,
|
|
@@ -177,7 +163,7 @@ async function executeMigrationPlanCommand(
|
|
|
177
163
|
let fromContractSourceDir: string | null = null;
|
|
178
164
|
|
|
179
165
|
try {
|
|
180
|
-
const { bundles, graph } = await
|
|
166
|
+
const { bundles, graph } = await loadMigrationPackages(migrationsDir);
|
|
181
167
|
|
|
182
168
|
if (options.from) {
|
|
183
169
|
const resolved = resolveBundleByPrefix(bundles, options.from);
|
|
@@ -195,16 +181,18 @@ async function executeMigrationPlanCommand(
|
|
|
195
181
|
}),
|
|
196
182
|
);
|
|
197
183
|
}
|
|
198
|
-
fromHash = resolved.value.
|
|
199
|
-
fromContract = resolved.value.
|
|
184
|
+
fromHash = resolved.value.metadata.to;
|
|
185
|
+
fromContract = resolved.value.metadata.toContract;
|
|
200
186
|
fromContractSourceDir = resolved.value.dirPath;
|
|
201
187
|
} else {
|
|
202
188
|
const latestMigration = findLatestMigration(graph);
|
|
203
189
|
if (latestMigration) {
|
|
204
190
|
fromHash = latestMigration.to;
|
|
205
|
-
const leafPkg = bundles.find(
|
|
191
|
+
const leafPkg = bundles.find(
|
|
192
|
+
(p) => p.metadata.migrationHash === latestMigration.migrationHash,
|
|
193
|
+
);
|
|
206
194
|
if (leafPkg) {
|
|
207
|
-
fromContract = leafPkg.
|
|
195
|
+
fromContract = leafPkg.metadata.toContract;
|
|
208
196
|
fromContractSourceDir = leafPkg.dirPath;
|
|
209
197
|
}
|
|
210
198
|
}
|
|
@@ -213,7 +201,16 @@ async function executeMigrationPlanCommand(
|
|
|
213
201
|
if (MigrationToolsError.is(error)) {
|
|
214
202
|
return notOk(mapMigrationToolsError(error));
|
|
215
203
|
}
|
|
216
|
-
|
|
204
|
+
// Wrap unexpected (non-MigrationToolsError) failures from the migration
|
|
205
|
+
// load phase in a structured CLI envelope. Letting them throw would
|
|
206
|
+
// bypass `handleResult()` and crash the command — see CLI structured-
|
|
207
|
+
// errors guideline (CliStructuredError + Result pattern).
|
|
208
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
209
|
+
return notOk(
|
|
210
|
+
errorUnexpected(message, {
|
|
211
|
+
why: `Unexpected error while loading migrations: ${message}`,
|
|
212
|
+
}),
|
|
213
|
+
);
|
|
217
214
|
}
|
|
218
215
|
|
|
219
216
|
// Check for no-op (same hash means no changes)
|
|
@@ -251,7 +248,7 @@ async function executeMigrationPlanCommand(
|
|
|
251
248
|
const dirName = formatMigrationDirName(timestamp, slug);
|
|
252
249
|
const packageDir = join(migrationsDir, dirName);
|
|
253
250
|
|
|
254
|
-
const
|
|
251
|
+
const baseMetadata: Omit<MigrationMetadata, 'migrationHash'> = {
|
|
255
252
|
from: fromHash,
|
|
256
253
|
to: toStorageHash,
|
|
257
254
|
kind: 'regular',
|
|
@@ -320,18 +317,18 @@ async function executeMigrationPlanCommand(
|
|
|
320
317
|
|
|
321
318
|
const migrationTsContent = plannerResult.plan.renderTypeScript();
|
|
322
319
|
|
|
323
|
-
// Always-attest: compute
|
|
324
|
-
// placeholders blocked lowering, ops is `[]` and the
|
|
325
|
-
// the empty list — re-emitting after the user fills the placeholder
|
|
326
|
-
// produces a different
|
|
320
|
+
// Always-attest: compute migrationHash over (metadata, ops). When
|
|
321
|
+
// placeholders blocked lowering, ops is `[]` and the hash is computed
|
|
322
|
+
// over the empty list — re-emitting after the user fills the placeholder
|
|
323
|
+
// produces a different hash (over the real ops). This is intentional;
|
|
327
324
|
// there is no on-disk "draft" state.
|
|
328
325
|
const opsForWrite = hasPlaceholders ? [] : plannedOps;
|
|
329
|
-
const
|
|
330
|
-
...
|
|
331
|
-
|
|
326
|
+
const metadata: MigrationMetadata = {
|
|
327
|
+
...baseMetadata,
|
|
328
|
+
migrationHash: computeMigrationHash(baseMetadata, opsForWrite),
|
|
332
329
|
};
|
|
333
330
|
|
|
334
|
-
await writeMigrationPackage(packageDir,
|
|
331
|
+
await writeMigrationPackage(packageDir, metadata, opsForWrite);
|
|
335
332
|
const destinationArtifacts = getEmittedArtifactPaths(contractPathAbsolute);
|
|
336
333
|
await copyFilesWithRename(packageDir, [
|
|
337
334
|
{ sourcePath: destinationArtifacts.jsonPath, destName: 'end-contract.json' },
|
|
@@ -382,7 +379,18 @@ async function executeMigrationPlanCommand(
|
|
|
382
379
|
};
|
|
383
380
|
return ok(result);
|
|
384
381
|
} catch (error) {
|
|
385
|
-
|
|
382
|
+
if (CliStructuredError.is(error)) {
|
|
383
|
+
return notOk(error);
|
|
384
|
+
}
|
|
385
|
+
if (MigrationToolsError.is(error)) {
|
|
386
|
+
return notOk(mapMigrationToolsError(error));
|
|
387
|
+
}
|
|
388
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
389
|
+
return notOk(
|
|
390
|
+
errorUnexpected(message, {
|
|
391
|
+
why: `Unexpected error during migration plan: ${message}`,
|
|
392
|
+
}),
|
|
393
|
+
);
|
|
386
394
|
}
|
|
387
395
|
}
|
|
388
396
|
|
|
@@ -489,7 +497,7 @@ function formatMigrationPlanOutput(result: MigrationPlanResult, flags: GlobalFla
|
|
|
489
497
|
|
|
490
498
|
lines.push('');
|
|
491
499
|
lines.push(
|
|
492
|
-
`Next: ${green_(
|
|
500
|
+
`Next: review ${green_(result.dir ?? '<dir>')} if needed, then run ${green_('prisma-next migration apply')}.`,
|
|
493
501
|
);
|
|
494
502
|
|
|
495
503
|
if (result.sql && result.sql.length > 0) {
|
|
@@ -517,24 +525,27 @@ export type PrefixResolutionFailure =
|
|
|
517
525
|
| { reason: 'not-found' };
|
|
518
526
|
|
|
519
527
|
/**
|
|
520
|
-
* Resolve a migration
|
|
528
|
+
* Resolve a migration package by **target contract hash** (`metadata.to`)
|
|
529
|
+
* using exact match or prefix match.
|
|
521
530
|
*
|
|
531
|
+
* Note: matches `metadata.to` (the contract hash this migration produces),
|
|
532
|
+
* not `metadata.migrationHash` (the package's content-addressed identity).
|
|
522
533
|
* Tries exact match first, then prefix match (auto-prepending `sha256:` when
|
|
523
|
-
* the needle omits the scheme). Returns the matched
|
|
534
|
+
* the needle omits the scheme). Returns the matched package on success, or a
|
|
524
535
|
* discriminated failure indicating whether the prefix was ambiguous or simply
|
|
525
536
|
* not found.
|
|
526
537
|
*
|
|
527
538
|
* @internal Exported for testing only.
|
|
528
539
|
*/
|
|
529
|
-
export function resolveBundleByPrefix<T extends {
|
|
540
|
+
export function resolveBundleByPrefix<T extends { metadata: { to: string } }>(
|
|
530
541
|
bundles: readonly T[],
|
|
531
542
|
needle: string,
|
|
532
543
|
): Result<T, PrefixResolutionFailure> {
|
|
533
|
-
const exact = bundles.find((p) => p.
|
|
544
|
+
const exact = bundles.find((p) => p.metadata.to === needle);
|
|
534
545
|
if (exact) return ok(exact);
|
|
535
546
|
|
|
536
547
|
const prefixWithScheme = needle.startsWith('sha256:') ? needle : `sha256:${needle}`;
|
|
537
|
-
const candidates = bundles.filter((p) => p.
|
|
548
|
+
const candidates = bundles.filter((p) => p.metadata.to.startsWith(prefixWithScheme));
|
|
538
549
|
|
|
539
550
|
if (candidates.length === 1) return ok(candidates[0]!);
|
|
540
551
|
if (candidates.length > 1) return notOk({ reason: 'ambiguous', count: candidates.length });
|
|
@@ -1,17 +1,27 @@
|
|
|
1
|
+
import { MigrationToolsError } from '@prisma-next/migration-tools/errors';
|
|
2
|
+
import type { RefEntry } from '@prisma-next/migration-tools/refs';
|
|
1
3
|
import {
|
|
4
|
+
deleteRef,
|
|
5
|
+
readRef,
|
|
2
6
|
readRefs,
|
|
3
|
-
resolveRef,
|
|
4
7
|
validateRefName,
|
|
5
8
|
validateRefValue,
|
|
6
|
-
|
|
9
|
+
writeRef,
|
|
7
10
|
} from '@prisma-next/migration-tools/refs';
|
|
8
|
-
import { MigrationToolsError } from '@prisma-next/migration-tools/types';
|
|
9
11
|
import { notOk, ok, type Result } from '@prisma-next/utils/result';
|
|
10
12
|
import { Command } from 'commander';
|
|
11
|
-
import { resolve } from 'pathe';
|
|
12
13
|
import { loadConfig } from '../config-loader';
|
|
13
|
-
import {
|
|
14
|
-
|
|
14
|
+
import {
|
|
15
|
+
CliStructuredError,
|
|
16
|
+
errorRuntime,
|
|
17
|
+
errorUnexpected,
|
|
18
|
+
mapMigrationToolsError,
|
|
19
|
+
} from '../utils/cli-errors';
|
|
20
|
+
import {
|
|
21
|
+
addGlobalOptions,
|
|
22
|
+
resolveMigrationPaths,
|
|
23
|
+
setCommandDescriptions,
|
|
24
|
+
} from '../utils/command-helpers';
|
|
15
25
|
import { formatCommandHelp } from '../utils/formatters/help';
|
|
16
26
|
import { parseGlobalFlags } from '../utils/global-flags';
|
|
17
27
|
import { handleResult } from '../utils/result-handler';
|
|
@@ -21,12 +31,14 @@ interface RefSetResult {
|
|
|
21
31
|
readonly ok: true;
|
|
22
32
|
readonly ref: string;
|
|
23
33
|
readonly hash: string;
|
|
34
|
+
readonly invariants: readonly string[];
|
|
24
35
|
}
|
|
25
36
|
|
|
26
37
|
interface RefGetResult {
|
|
27
38
|
readonly ok: true;
|
|
28
39
|
readonly ref: string;
|
|
29
40
|
readonly hash: string;
|
|
41
|
+
readonly invariants: readonly string[];
|
|
30
42
|
}
|
|
31
43
|
|
|
32
44
|
interface RefDeleteResult {
|
|
@@ -37,21 +49,12 @@ interface RefDeleteResult {
|
|
|
37
49
|
|
|
38
50
|
interface RefListResult {
|
|
39
51
|
readonly ok: true;
|
|
40
|
-
readonly refs: Record<string,
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function resolveRefsPath(configPath?: string, config?: { migrations?: { dir?: string } }): string {
|
|
44
|
-
const base = configPath ? resolve(configPath, '..') : process.cwd();
|
|
45
|
-
return resolve(base, config?.migrations?.dir ?? 'migrations', 'refs.json');
|
|
52
|
+
readonly refs: Record<string, RefEntry>;
|
|
46
53
|
}
|
|
47
54
|
|
|
48
55
|
function mapError(error: unknown): CliStructuredError {
|
|
49
56
|
if (MigrationToolsError.is(error)) {
|
|
50
|
-
return
|
|
51
|
-
why: error.why,
|
|
52
|
-
fix: error.fix,
|
|
53
|
-
meta: { code: error.code },
|
|
54
|
-
});
|
|
57
|
+
return mapMigrationToolsError(error);
|
|
55
58
|
}
|
|
56
59
|
return errorUnexpected(error instanceof Error ? error.message : String(error));
|
|
57
60
|
}
|
|
@@ -70,13 +73,6 @@ function cliErrorInvalidRefValue(hash: string): CliStructuredError {
|
|
|
70
73
|
});
|
|
71
74
|
}
|
|
72
75
|
|
|
73
|
-
function errorRefNotFound(name: string): CliStructuredError {
|
|
74
|
-
return errorRuntime(`Ref "${name}" does not exist`, {
|
|
75
|
-
why: `No ref named "${name}" found in refs.json`,
|
|
76
|
-
fix: `Run \`prisma-next migration ref list\` to see available refs, or \`prisma-next migration ref set ${name} <hash>\` to create it`,
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
|
|
80
76
|
async function executeRefSetCommand(
|
|
81
77
|
name: string,
|
|
82
78
|
hash: string,
|
|
@@ -91,11 +87,10 @@ async function executeRefSetCommand(
|
|
|
91
87
|
|
|
92
88
|
try {
|
|
93
89
|
const config = await loadConfig(options.config);
|
|
94
|
-
const
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
return ok({ ok: true as const, ref: name, hash });
|
|
90
|
+
const { refsDir } = resolveMigrationPaths(options.config, config);
|
|
91
|
+
const entry: RefEntry = { hash, invariants: [] };
|
|
92
|
+
await writeRef(refsDir, name, entry);
|
|
93
|
+
return ok({ ok: true as const, ref: name, hash, invariants: [] });
|
|
99
94
|
} catch (error) {
|
|
100
95
|
if (error instanceof CliStructuredError) return notOk(error);
|
|
101
96
|
return notOk(mapError(error));
|
|
@@ -108,10 +103,9 @@ async function executeRefGetCommand(
|
|
|
108
103
|
): Promise<Result<RefGetResult, CliStructuredError>> {
|
|
109
104
|
try {
|
|
110
105
|
const config = await loadConfig(options.config);
|
|
111
|
-
const
|
|
112
|
-
const
|
|
113
|
-
const hash
|
|
114
|
-
return ok({ ok: true as const, ref: name, hash });
|
|
106
|
+
const { refsDir } = resolveMigrationPaths(options.config, config);
|
|
107
|
+
const entry = await readRef(refsDir, name);
|
|
108
|
+
return ok({ ok: true as const, ref: name, hash: entry.hash, invariants: entry.invariants });
|
|
115
109
|
} catch (error) {
|
|
116
110
|
if (error instanceof CliStructuredError) return notOk(error);
|
|
117
111
|
return notOk(mapError(error));
|
|
@@ -124,13 +118,8 @@ async function executeRefDeleteCommand(
|
|
|
124
118
|
): Promise<Result<RefDeleteResult, CliStructuredError>> {
|
|
125
119
|
try {
|
|
126
120
|
const config = await loadConfig(options.config);
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
if (!Object.hasOwn(refs, name)) {
|
|
130
|
-
return notOk(errorRefNotFound(name));
|
|
131
|
-
}
|
|
132
|
-
const { [name]: _, ...remaining } = refs;
|
|
133
|
-
await writeRefs(refsPath, remaining);
|
|
121
|
+
const { refsDir } = resolveMigrationPaths(options.config, config);
|
|
122
|
+
await deleteRef(refsDir, name);
|
|
134
123
|
return ok({ ok: true as const, ref: name, deleted: true as const });
|
|
135
124
|
} catch (error) {
|
|
136
125
|
if (error instanceof CliStructuredError) return notOk(error);
|
|
@@ -143,8 +132,8 @@ async function executeRefListCommand(options: {
|
|
|
143
132
|
}): Promise<Result<RefListResult, CliStructuredError>> {
|
|
144
133
|
try {
|
|
145
134
|
const config = await loadConfig(options.config);
|
|
146
|
-
const
|
|
147
|
-
const refs = await readRefs(
|
|
135
|
+
const { refsDir } = resolveMigrationPaths(options.config, config);
|
|
136
|
+
const refs = await readRefs(refsDir);
|
|
148
137
|
return ok({ ok: true as const, refs });
|
|
149
138
|
} catch (error) {
|
|
150
139
|
if (error instanceof CliStructuredError) return notOk(error);
|
|
@@ -157,7 +146,7 @@ function createRefSetCommand(): Command {
|
|
|
157
146
|
setCommandDescriptions(
|
|
158
147
|
command,
|
|
159
148
|
'Set a ref to a contract hash',
|
|
160
|
-
'Sets a named ref to point to a contract hash in migrations/refs
|
|
149
|
+
'Sets a named ref to point to a contract hash in migrations/refs/.',
|
|
161
150
|
);
|
|
162
151
|
addGlobalOptions(command)
|
|
163
152
|
.argument('<name>', 'Ref name (e.g., staging, production)')
|
|
@@ -190,7 +179,7 @@ function createRefGetCommand(): Command {
|
|
|
190
179
|
setCommandDescriptions(
|
|
191
180
|
command,
|
|
192
181
|
'Get the hash for a ref',
|
|
193
|
-
'Reads a named ref from migrations/refs
|
|
182
|
+
'Reads a named ref from migrations/refs/ and prints its contract hash.',
|
|
194
183
|
);
|
|
195
184
|
addGlobalOptions(command)
|
|
196
185
|
.argument('<name>', 'Ref name to look up')
|
|
@@ -218,7 +207,7 @@ function createRefGetCommand(): Command {
|
|
|
218
207
|
|
|
219
208
|
function createRefDeleteCommand(): Command {
|
|
220
209
|
const command = new Command('delete');
|
|
221
|
-
setCommandDescriptions(command, 'Delete a ref', 'Removes a named ref from migrations/refs
|
|
210
|
+
setCommandDescriptions(command, 'Delete a ref', 'Removes a named ref from migrations/refs/.');
|
|
222
211
|
addGlobalOptions(command)
|
|
223
212
|
.argument('<name>', 'Ref name to delete')
|
|
224
213
|
.option('--config <path>', 'Path to prisma-next.config.ts')
|
|
@@ -245,11 +234,7 @@ function createRefDeleteCommand(): Command {
|
|
|
245
234
|
|
|
246
235
|
function createRefListCommand(): Command {
|
|
247
236
|
const command = new Command('list');
|
|
248
|
-
setCommandDescriptions(
|
|
249
|
-
command,
|
|
250
|
-
'List all refs',
|
|
251
|
-
'Lists all named refs from migrations/refs.json.',
|
|
252
|
-
);
|
|
237
|
+
setCommandDescriptions(command, 'List all refs', 'Lists all named refs from migrations/refs/.');
|
|
253
238
|
addGlobalOptions(command)
|
|
254
239
|
.option('--config <path>', 'Path to prisma-next.config.ts')
|
|
255
240
|
.action(async (options: { config?: string; json?: string | boolean; quiet?: boolean }) => {
|
|
@@ -264,8 +249,10 @@ function createRefListCommand(): Command {
|
|
|
264
249
|
if (entries.length === 0) {
|
|
265
250
|
ui.output('No refs defined');
|
|
266
251
|
} else {
|
|
267
|
-
for (const [refName,
|
|
268
|
-
|
|
252
|
+
for (const [refName, entry] of entries) {
|
|
253
|
+
const invariantsSuffix =
|
|
254
|
+
entry.invariants.length > 0 ? ` [invariants: ${entry.invariants.join(', ')}]` : '';
|
|
255
|
+
ui.output(`${refName} → ${entry.hash}${invariantsSuffix}`);
|
|
269
256
|
}
|
|
270
257
|
}
|
|
271
258
|
}
|
|
@@ -282,7 +269,6 @@ export {
|
|
|
282
269
|
executeRefListCommand,
|
|
283
270
|
cliErrorInvalidRefName,
|
|
284
271
|
cliErrorInvalidRefValue,
|
|
285
|
-
errorRefNotFound,
|
|
286
272
|
};
|
|
287
273
|
|
|
288
274
|
export function createMigrationRefCommand(): Command {
|
|
@@ -290,7 +276,7 @@ export function createMigrationRefCommand(): Command {
|
|
|
290
276
|
setCommandDescriptions(
|
|
291
277
|
command,
|
|
292
278
|
'Manage migration refs',
|
|
293
|
-
'Manage named refs in migrations/refs
|
|
279
|
+
'Manage named refs in migrations/refs/. Refs map logical environment\n' +
|
|
294
280
|
'names (e.g., staging, production) to contract hashes.',
|
|
295
281
|
);
|
|
296
282
|
addGlobalOptions(command).configureHelp({
|