@prisma-next/cli 0.11.0 → 0.12.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.
- package/README.md +13 -9
- package/dist/cli.mjs +259 -12
- package/dist/cli.mjs.map +1 -1
- package/dist/{client-oXO2WCPD.mjs → client-KgJorIvG.mjs} +72 -60
- package/dist/client-KgJorIvG.mjs.map +1 -0
- package/dist/{command-helpers-BSb0tRC8.mjs → command-helpers-Bbw1GbwL.mjs} +646 -46
- package/dist/command-helpers-Bbw1GbwL.mjs.map +1 -0
- package/dist/commands/contract-emit.d.mts.map +1 -1
- package/dist/commands/contract-emit.mjs +1 -1
- package/dist/commands/contract-infer.d.mts.map +1 -1
- package/dist/commands/contract-infer.mjs +1 -1
- package/dist/commands/db-init.d.mts.map +1 -1
- package/dist/commands/db-init.mjs +32 -7
- package/dist/commands/db-init.mjs.map +1 -1
- package/dist/commands/db-schema.d.mts.map +1 -1
- package/dist/commands/db-schema.mjs +3 -4
- package/dist/commands/db-schema.mjs.map +1 -1
- package/dist/commands/db-sign.d.mts.map +1 -1
- package/dist/commands/db-sign.mjs +12 -10
- package/dist/commands/db-sign.mjs.map +1 -1
- package/dist/commands/db-update.d.mts.map +1 -1
- package/dist/commands/db-update.mjs +41 -11
- package/dist/commands/db-update.mjs.map +1 -1
- package/dist/commands/db-verify.d.mts.map +1 -1
- package/dist/commands/db-verify.mjs +1 -1
- package/dist/commands/migrate.d.mts +6 -2
- package/dist/commands/migrate.d.mts.map +1 -1
- package/dist/commands/migrate.mjs +75 -40
- package/dist/commands/migrate.mjs.map +1 -1
- package/dist/commands/migration-check.d.mts +4 -3
- package/dist/commands/migration-check.d.mts.map +1 -1
- package/dist/commands/migration-check.mjs +1 -280
- package/dist/commands/migration-graph.d.mts +13 -2
- package/dist/commands/migration-graph.d.mts.map +1 -1
- package/dist/commands/migration-graph.mjs +2 -137
- package/dist/commands/migration-list.d.mts +64 -4
- package/dist/commands/migration-list.d.mts.map +1 -1
- package/dist/commands/migration-list.mjs +143 -56
- package/dist/commands/migration-list.mjs.map +1 -1
- package/dist/commands/migration-log.d.mts +10 -1
- package/dist/commands/migration-log.d.mts.map +1 -1
- package/dist/commands/migration-log.mjs +10 -15
- package/dist/commands/migration-log.mjs.map +1 -1
- package/dist/commands/migration-new.d.mts.map +1 -1
- package/dist/commands/migration-new.mjs +32 -38
- package/dist/commands/migration-new.mjs.map +1 -1
- package/dist/commands/migration-plan.d.mts +3 -2
- package/dist/commands/migration-plan.d.mts.map +1 -1
- package/dist/commands/migration-plan.mjs +1 -1
- package/dist/commands/migration-show.d.mts +4 -55
- package/dist/commands/migration-show.d.mts.map +1 -1
- package/dist/commands/migration-show.mjs +61 -153
- package/dist/commands/migration-show.mjs.map +1 -1
- package/dist/commands/migration-status.d.mts +12 -49
- package/dist/commands/migration-status.d.mts.map +1 -1
- package/dist/commands/migration-status.mjs +85 -81
- package/dist/commands/migration-status.mjs.map +1 -1
- package/dist/commands/ref.d.mts +1 -1
- package/dist/commands/ref.d.mts.map +1 -1
- package/dist/commands/ref.mjs +38 -10
- package/dist/commands/ref.mjs.map +1 -1
- package/dist/config-loader-B6sJjXTv.mjs.map +1 -1
- package/dist/config-loader.d.mts.map +1 -1
- package/dist/contract-at-errors-BxP-TOMl.mjs +42 -0
- package/dist/contract-at-errors-BxP-TOMl.mjs.map +1 -0
- package/dist/{contract-emit-bcrpT-wD.mjs → contract-emit-D-4jrNve.mjs} +25 -10
- package/dist/contract-emit-D-4jrNve.mjs.map +1 -0
- package/dist/{contract-emit-r4y8Zhf1.mjs → contract-emit-DxcGl4Uq.mjs} +19 -14
- package/dist/contract-emit-DxcGl4Uq.mjs.map +1 -0
- package/dist/{contract-enrichment-Dani0mMW.mjs → contract-enrichment-a0V5Y_mL.mjs} +4 -25
- package/dist/contract-enrichment-a0V5Y_mL.mjs.map +1 -0
- package/dist/{contract-infer-BmySmqVT.mjs → contract-infer-D8uEbJuu.mjs} +4 -5
- package/dist/{contract-infer-BmySmqVT.mjs.map → contract-infer-D8uEbJuu.mjs.map} +1 -1
- package/dist/contract-space-aggregate-loader-DvZwdkrr.mjs +247 -0
- package/dist/contract-space-aggregate-loader-DvZwdkrr.mjs.map +1 -0
- package/dist/{db-verify-BClPs3ph.mjs → db-verify-v_vUKXTU.mjs} +5 -7
- package/dist/{db-verify-BClPs3ph.mjs.map → db-verify-v_vUKXTU.mjs.map} +1 -1
- package/dist/exports/control-api.d.mts +3 -3
- package/dist/exports/control-api.d.mts.map +1 -1
- package/dist/exports/control-api.mjs +3 -3
- package/dist/exports/index.d.mts.map +1 -1
- package/dist/exports/index.mjs +1 -1
- package/dist/exports/index.mjs.map +1 -1
- package/dist/exports/init-output.d.mts.map +1 -1
- package/dist/exports/init-output.mjs +1 -1
- package/dist/extension-pack-inputs-IDvjRCi3.mjs +62 -0
- package/dist/extension-pack-inputs-IDvjRCi3.mjs.map +1 -0
- package/dist/{framework-components-65gOHkHB.mjs → framework-components-fYXjz_in.mjs} +2 -2
- package/dist/{framework-components-65gOHkHB.mjs.map → framework-components-fYXjz_in.mjs.map} +1 -1
- package/dist/global-flags-DEHjV8_s.d.mts +34 -0
- package/dist/global-flags-DEHjV8_s.d.mts.map +1 -0
- package/dist/{graph-render-DJVv0_uf.mjs → graph-render-rFAqZujX.mjs} +2 -2
- package/dist/{graph-render-DJVv0_uf.mjs.map → graph-render-rFAqZujX.mjs.map} +1 -1
- package/dist/{init-BCJZPWE1.mjs → init-Cv9UzWL5.mjs} +20 -269
- package/dist/init-Cv9UzWL5.mjs.map +1 -0
- package/dist/{inspect-live-schema-DSRbFoOL.mjs → inspect-live-schema-C6ohV_oQ.mjs} +4 -5
- package/dist/{inspect-live-schema-DSRbFoOL.mjs.map → inspect-live-schema-C6ohV_oQ.mjs.map} +1 -1
- package/dist/migration-check-BiBJoYYW.mjs +341 -0
- package/dist/migration-check-BiBJoYYW.mjs.map +1 -0
- package/dist/migration-cli.d.mts.map +1 -1
- package/dist/migration-cli.mjs +4 -4
- package/dist/migration-cli.mjs.map +1 -1
- package/dist/{migration-command-scaffold-Bzd9La5c.mjs → migration-command-scaffold-CjvwO6at.mjs} +4 -5
- package/dist/{migration-command-scaffold-Bzd9La5c.mjs.map → migration-command-scaffold-CjvwO6at.mjs.map} +1 -1
- package/dist/migration-graph-D7DVUElV.mjs +1232 -0
- package/dist/migration-graph-D7DVUElV.mjs.map +1 -0
- package/dist/migration-list-styler-BRwF4-gy.mjs +399 -0
- package/dist/migration-list-styler-BRwF4-gy.mjs.map +1 -0
- package/dist/{migration-plan-CFwqw3Gk.mjs → migration-plan-9DJ7q7_z.mjs} +372 -133
- package/dist/migration-plan-9DJ7q7_z.mjs.map +1 -0
- package/dist/{migration-types-BXWvz12q.d.mts → migration-types-D2FW63pr.d.mts} +1 -1
- package/dist/{migration-types-BXWvz12q.d.mts.map → migration-types-D2FW63pr.d.mts.map} +1 -1
- package/dist/{migrations-CwZMa1Ck.mjs → migrations-Cv2jxNNK.mjs} +12 -13
- package/dist/migrations-Cv2jxNNK.mjs.map +1 -0
- package/dist/{output-BlsrGMEF.mjs → output-B60Gw5fu.mjs} +1 -1
- package/dist/{output-BlsrGMEF.mjs.map → output-B60Gw5fu.mjs.map} +1 -1
- package/dist/{progress-adapter-DFfvZcYL.mjs → progress-adapter-C644QK8l.mjs} +1 -1
- package/dist/{progress-adapter-DFfvZcYL.mjs.map → progress-adapter-C644QK8l.mjs.map} +1 -1
- package/dist/ref-advancement-DUZqsue6.mjs +50 -0
- package/dist/ref-advancement-DUZqsue6.mjs.map +1 -0
- package/dist/terminal-ui-5Y6mrg93.d.mts +133 -0
- package/dist/terminal-ui-5Y6mrg93.d.mts.map +1 -0
- package/dist/{types--CqjMdk0.d.mts → types-Dt_SfqFm.d.mts} +28 -28
- package/dist/types-Dt_SfqFm.d.mts.map +1 -0
- package/dist/{verify-Bom75OYI.mjs → verify-DCA9Sldu.mjs} +2 -2
- package/dist/{verify-Bom75OYI.mjs.map → verify-DCA9Sldu.mjs.map} +1 -1
- package/package.json +35 -24
- package/src/commands/contract-emit.ts +19 -7
- package/src/commands/contract-infer.ts +1 -1
- package/src/commands/db-init.ts +48 -2
- package/src/commands/db-sign.ts +9 -5
- package/src/commands/db-update.ts +54 -8
- package/src/commands/init/hygiene-gitattributes.ts +2 -2
- package/src/commands/init/index.ts +2 -1
- package/src/commands/init/templates/code-templates.ts +4 -2
- package/src/commands/init/templates/env.ts +13 -14
- package/src/commands/migrate.ts +125 -44
- package/src/commands/migration-check.ts +43 -83
- package/src/commands/migration-graph.ts +75 -60
- package/src/commands/migration-list.ts +220 -74
- package/src/commands/migration-log.ts +8 -14
- package/src/commands/migration-new.ts +44 -48
- package/src/commands/migration-plan.ts +412 -197
- package/src/commands/migration-show.ts +65 -284
- package/src/commands/migration-status.ts +127 -124
- package/src/commands/ref.ts +53 -8
- package/src/control-api/client.ts +0 -1
- package/src/control-api/contract-enrichment.ts +6 -42
- package/src/control-api/operations/{apply-aggregate.ts → apply.ts} +44 -75
- package/src/control-api/operations/contract-emit.ts +14 -6
- package/src/control-api/operations/{db-apply-aggregate.ts → db-apply.ts} +19 -19
- package/src/control-api/operations/db-init.ts +4 -4
- package/src/control-api/operations/db-update.ts +4 -4
- package/src/control-api/operations/db-verify.ts +15 -11
- package/src/control-api/operations/migration-apply.ts +56 -47
- package/src/control-api/types.ts +26 -27
- package/src/migration-cli.ts +4 -4
- package/src/utils/cli-errors.ts +234 -0
- package/src/utils/command-helpers.ts +9 -24
- package/src/utils/contract-at-errors.ts +96 -0
- package/src/utils/contract-space-aggregate-loader.ts +336 -117
- package/src/utils/formatters/migration-graph-layout.ts +1119 -0
- package/src/utils/formatters/migration-graph-rows.ts +336 -0
- package/src/utils/formatters/migration-graph-tree-render.ts +459 -0
- package/src/utils/formatters/migration-list-data-column.ts +115 -0
- package/src/utils/formatters/migration-list-graph-topology.ts +368 -0
- package/src/utils/formatters/migration-list-render.ts +191 -0
- package/src/utils/formatters/migration-list-styler.ts +63 -0
- package/src/utils/formatters/migration-list-types.ts +21 -0
- package/src/utils/formatters/migrations.ts +37 -46
- package/src/utils/glyph-mode.ts +22 -0
- package/src/utils/integrity-violation-to-check-failure.ts +130 -0
- package/src/utils/plan-resolution.ts +258 -0
- package/src/utils/ref-advancement.ts +68 -0
- package/src/utils/terminal-ui.ts +42 -1
- package/dist/cli-errors-Czmx92Zy.d.mts +0 -3
- package/dist/cli-errors-Djtz98Vm.mjs +0 -71
- package/dist/cli-errors-Djtz98Vm.mjs.map +0 -1
- package/dist/client-oXO2WCPD.mjs.map +0 -1
- package/dist/command-helpers-BSb0tRC8.mjs.map +0 -1
- package/dist/commands/migration-check.mjs.map +0 -1
- package/dist/commands/migration-graph.mjs.map +0 -1
- package/dist/contract-emit-bcrpT-wD.mjs.map +0 -1
- package/dist/contract-emit-r4y8Zhf1.mjs.map +0 -1
- package/dist/contract-enrichment-Dani0mMW.mjs.map +0 -1
- package/dist/contract-space-aggregate-loader-BmNQwlws.mjs +0 -160
- package/dist/contract-space-aggregate-loader-BmNQwlws.mjs.map +0 -1
- package/dist/global-flags-CdE7M0d9.d.mts +0 -15
- package/dist/global-flags-CdE7M0d9.d.mts.map +0 -1
- package/dist/init-BCJZPWE1.mjs.map +0 -1
- package/dist/migration-plan-CFwqw3Gk.mjs.map +0 -1
- package/dist/migrations-CwZMa1Ck.mjs.map +0 -1
- package/dist/rolldown-runtime-twds-ZHy.mjs +0 -14
- package/dist/terminal-ui-BiB_8KNo.mjs +0 -379
- package/dist/terminal-ui-BiB_8KNo.mjs.map +0 -1
- package/dist/types--CqjMdk0.d.mts.map +0 -1
package/src/commands/db-sign.ts
CHANGED
|
@@ -5,7 +5,6 @@ import type {
|
|
|
5
5
|
} from '@prisma-next/framework-components/control';
|
|
6
6
|
import { MigrationToolsError } from '@prisma-next/migration-tools/errors';
|
|
7
7
|
import { parseContractRef } from '@prisma-next/migration-tools/ref-resolution';
|
|
8
|
-
import { readRefs } from '@prisma-next/migration-tools/refs';
|
|
9
8
|
import { notOk, ok, type Result } from '@prisma-next/utils/result';
|
|
10
9
|
import { Command } from 'commander';
|
|
11
10
|
import { join, relative, resolve } from 'pathe';
|
|
@@ -25,13 +24,13 @@ import {
|
|
|
25
24
|
} from '../utils/cli-errors';
|
|
26
25
|
import {
|
|
27
26
|
addGlobalOptions,
|
|
28
|
-
loadMigrationPackages,
|
|
29
27
|
maskConnectionUrl,
|
|
30
28
|
resolveContractPath,
|
|
31
29
|
resolveMigrationPaths,
|
|
32
30
|
setCommandDescriptions,
|
|
33
31
|
setCommandExamples,
|
|
34
32
|
} from '../utils/command-helpers';
|
|
33
|
+
import { buildReadAggregate } from '../utils/contract-space-aggregate-loader';
|
|
35
34
|
import { formatStyledHeader } from '../utils/formatters/styled';
|
|
36
35
|
import {
|
|
37
36
|
formatSchemaVerifyJson,
|
|
@@ -99,9 +98,14 @@ async function executeDbSignCommand(
|
|
|
99
98
|
|
|
100
99
|
if (effectiveContractArg) {
|
|
101
100
|
try {
|
|
102
|
-
const {
|
|
103
|
-
const
|
|
104
|
-
|
|
101
|
+
const { migrationsDir } = resolveMigrationPaths(options.config, config);
|
|
102
|
+
const loaded = await buildReadAggregate(config, { migrationsDir });
|
|
103
|
+
if (!loaded.ok) {
|
|
104
|
+
return notOk(loaded.failure);
|
|
105
|
+
}
|
|
106
|
+
const graph = loaded.value.aggregate.app.graph();
|
|
107
|
+
const bundles = loaded.value.aggregate.app.packages;
|
|
108
|
+
const refs = loaded.value.aggregate.app.refs;
|
|
105
109
|
const refResult = parseContractRef(effectiveContractArg, { graph, refs });
|
|
106
110
|
if (!refResult.ok) {
|
|
107
111
|
return notOk(mapRefResolutionError(refResult.failure));
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
2
|
import { MigrationToolsError } from '@prisma-next/migration-tools/errors';
|
|
3
3
|
import { parseContractRef } from '@prisma-next/migration-tools/ref-resolution';
|
|
4
|
-
import { readRefs } from '@prisma-next/migration-tools/refs';
|
|
5
4
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
6
5
|
import { notOk, ok, type Result } from '@prisma-next/utils/result';
|
|
7
6
|
import { Command } from 'commander';
|
|
@@ -21,12 +20,12 @@ import {
|
|
|
21
20
|
} from '../utils/cli-errors';
|
|
22
21
|
import type { MigrationCommandOptions } from '../utils/command-helpers';
|
|
23
22
|
import {
|
|
24
|
-
loadMigrationPackages,
|
|
25
23
|
resolveMigrationPaths,
|
|
26
24
|
sanitizeErrorMessage,
|
|
27
25
|
setCommandDescriptions,
|
|
28
26
|
setCommandExamples,
|
|
29
27
|
} from '../utils/command-helpers';
|
|
28
|
+
import { buildReadAggregate } from '../utils/contract-space-aggregate-loader';
|
|
30
29
|
import {
|
|
31
30
|
formatMigrationApplyOutput,
|
|
32
31
|
formatMigrationJson,
|
|
@@ -38,11 +37,18 @@ import {
|
|
|
38
37
|
addMigrationCommandOptions,
|
|
39
38
|
prepareMigrationContext,
|
|
40
39
|
} from '../utils/migration-command-scaffold';
|
|
40
|
+
import {
|
|
41
|
+
buildRefAdvancementFields,
|
|
42
|
+
computeRefAdvancementName,
|
|
43
|
+
type RefAdvancementFields,
|
|
44
|
+
readContractIR,
|
|
45
|
+
} from '../utils/ref-advancement';
|
|
41
46
|
import { handleResult } from '../utils/result-handler';
|
|
42
47
|
import { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';
|
|
43
48
|
|
|
44
49
|
interface DbUpdateOptions extends MigrationCommandOptions {
|
|
45
50
|
readonly to?: string;
|
|
51
|
+
readonly advanceRef?: string;
|
|
46
52
|
}
|
|
47
53
|
|
|
48
54
|
/**
|
|
@@ -101,15 +107,18 @@ async function executeDbUpdateCommand(
|
|
|
101
107
|
}
|
|
102
108
|
const { client, config, dbConnection, onProgress, contractPathAbsolute } = ctxResult.value;
|
|
103
109
|
let { contractJson } = ctxResult.value;
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
config,
|
|
107
|
-
);
|
|
110
|
+
let contractJsonPathForSnapshot = contractPathAbsolute;
|
|
111
|
+
const { migrationsDir, refsDir } = resolveMigrationPaths(options.config, config);
|
|
108
112
|
|
|
109
113
|
if (options.to) {
|
|
110
114
|
try {
|
|
111
|
-
const
|
|
112
|
-
|
|
115
|
+
const loaded = await buildReadAggregate(config, { migrationsDir });
|
|
116
|
+
if (!loaded.ok) {
|
|
117
|
+
return notOk(loaded.failure);
|
|
118
|
+
}
|
|
119
|
+
const graph = loaded.value.aggregate.app.graph();
|
|
120
|
+
const bundles = loaded.value.aggregate.app.packages;
|
|
121
|
+
const refs = loaded.value.aggregate.app.refs;
|
|
113
122
|
const refResult = parseContractRef(options.to, { graph, refs });
|
|
114
123
|
if (!refResult.ok) {
|
|
115
124
|
return notOk(mapRefResolutionError(refResult.failure));
|
|
@@ -130,6 +139,7 @@ async function executeDbUpdateCommand(
|
|
|
130
139
|
const endContractPath = join(matchingBundle.dirPath, 'end-contract.json');
|
|
131
140
|
const raw = await readFile(endContractPath, 'utf-8');
|
|
132
141
|
contractJson = JSON.parse(raw) as Record<string, unknown>;
|
|
142
|
+
contractJsonPathForSnapshot = endContractPath;
|
|
133
143
|
} catch (error) {
|
|
134
144
|
if (MigrationToolsError.is(error)) {
|
|
135
145
|
return notOk(mapMigrationToolsError(error));
|
|
@@ -157,6 +167,39 @@ async function executeDbUpdateCommand(
|
|
|
157
167
|
return notOk(mapDbUpdateFailure(result.failure));
|
|
158
168
|
}
|
|
159
169
|
|
|
170
|
+
const advancementHash =
|
|
171
|
+
result.value.mode === 'apply'
|
|
172
|
+
? (result.value.marker?.storageHash ?? result.value.destination.storageHash)
|
|
173
|
+
: result.value.destination.storageHash;
|
|
174
|
+
|
|
175
|
+
let refAdvancementFields: RefAdvancementFields = {
|
|
176
|
+
advancedRef: null,
|
|
177
|
+
plannedAdvanceRef: null,
|
|
178
|
+
};
|
|
179
|
+
if (
|
|
180
|
+
computeRefAdvancementName({
|
|
181
|
+
...ifDefined('advanceRef', options.advanceRef),
|
|
182
|
+
...ifDefined('db', options.db),
|
|
183
|
+
}) !== null
|
|
184
|
+
) {
|
|
185
|
+
try {
|
|
186
|
+
const contractIR = await readContractIR(contractJson, contractJsonPathForSnapshot);
|
|
187
|
+
refAdvancementFields = await buildRefAdvancementFields({
|
|
188
|
+
...ifDefined('advanceRef', options.advanceRef),
|
|
189
|
+
...ifDefined('db', options.db),
|
|
190
|
+
refsDir,
|
|
191
|
+
contractIR,
|
|
192
|
+
mode: result.value.mode,
|
|
193
|
+
hash: advancementHash,
|
|
194
|
+
});
|
|
195
|
+
} catch (error) {
|
|
196
|
+
if (MigrationToolsError.is(error)) {
|
|
197
|
+
return notOk(mapMigrationToolsError(error));
|
|
198
|
+
}
|
|
199
|
+
throw error;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
160
203
|
// Convert success result to CLI output format
|
|
161
204
|
const dbUpdateResult: MigrationCommandResult = {
|
|
162
205
|
ok: true,
|
|
@@ -193,6 +236,8 @@ async function executeDbUpdateCommand(
|
|
|
193
236
|
: undefined,
|
|
194
237
|
),
|
|
195
238
|
...ifDefined('perSpace', result.value.perSpace),
|
|
239
|
+
advancedRef: refAdvancementFields.advancedRef,
|
|
240
|
+
plannedAdvanceRef: refAdvancementFields.plannedAdvanceRef,
|
|
196
241
|
summary: result.value.summary,
|
|
197
242
|
timings: { total: Date.now() - startTime },
|
|
198
243
|
};
|
|
@@ -245,6 +290,7 @@ export function createDbUpdateCommand(): Command {
|
|
|
245
290
|
'--to <contract>',
|
|
246
291
|
'Target contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path)',
|
|
247
292
|
);
|
|
293
|
+
command.option('--advance-ref <name>', 'Ref to advance to the post-command contract hash');
|
|
248
294
|
command.action(async (options: DbUpdateOptions) => {
|
|
249
295
|
const flags = parseGlobalFlagsOrExit(options);
|
|
250
296
|
const startTime = Date.now();
|
|
@@ -20,7 +20,7 @@ import type { TargetId } from './templates/code-templates';
|
|
|
20
20
|
* `db/contract.json linguist-generated` — not the workspace-glob form
|
|
21
21
|
* `<glob>/contract.json` (which would over-match any unrelated
|
|
22
22
|
* `contract.json` the user has elsewhere) and not the absolute
|
|
23
|
-
* `
|
|
23
|
+
* `DEFAULT_CONTRACT_SOURCE_DIR/contract.json` (which would silently break for a non-default
|
|
24
24
|
* schema path).
|
|
25
25
|
*/
|
|
26
26
|
const ARTEFACT_FILENAMES: readonly string[] = [
|
|
@@ -59,7 +59,7 @@ export function requiredGitattributesLines(
|
|
|
59
59
|
*
|
|
60
60
|
* Equivalence is exact-line: a user-customised line like
|
|
61
61
|
* `prisma/*.json linguist-generated` is *not* recognised as covering
|
|
62
|
-
* `
|
|
62
|
+
* `DEFAULT_CONTRACT_SOURCE_DIR/contract.json linguist-generated`. We accept that
|
|
63
63
|
* over-specification — preserving the user's broad pattern *and*
|
|
64
64
|
* appending the narrow one — because the narrow lines are what the
|
|
65
65
|
* acceptance criteria pin (FR3.4 AC).
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
INIT_EXIT_SKILL_INSTALL_FAILED,
|
|
16
16
|
INIT_EXIT_USER_ABORTED,
|
|
17
17
|
} from './exit-codes';
|
|
18
|
+
import { defaultSchemaPath } from './templates/code-templates';
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* Commander.js parsed options for `init`. The init-specific options live
|
|
@@ -72,7 +73,7 @@ export function createInitCommand(): Command {
|
|
|
72
73
|
.option('--authoring <style>', 'Schema authoring style: psl or typescript')
|
|
73
74
|
.option(
|
|
74
75
|
'--schema-path <path>',
|
|
75
|
-
|
|
76
|
+
`Where to write the starter schema (default: ${defaultSchemaPath('psl')})`,
|
|
76
77
|
)
|
|
77
78
|
.option('--force', 'Overwrite an existing scaffold without prompting')
|
|
78
79
|
.option(
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { DEFAULT_CONTRACT_SOURCE_DIR } from '@prisma-next/config/config-types';
|
|
2
|
+
|
|
1
3
|
export type TargetId = 'postgres' | 'mongo';
|
|
2
4
|
export type AuthoringId = 'psl' | 'typescript';
|
|
3
5
|
|
|
@@ -11,9 +13,9 @@ export function targetLabel(target: TargetId): string {
|
|
|
11
13
|
|
|
12
14
|
export function defaultSchemaPath(authoring: AuthoringId): string {
|
|
13
15
|
if (authoring === 'typescript') {
|
|
14
|
-
return
|
|
16
|
+
return `${DEFAULT_CONTRACT_SOURCE_DIR}/contract.ts`;
|
|
15
17
|
}
|
|
16
|
-
return
|
|
18
|
+
return `${DEFAULT_CONTRACT_SOURCE_DIR}/contract.prisma`;
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
export function starterSchema(target: TargetId, authoring: AuthoringId): string {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { TargetId } from './code-templates';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* The minimum supported server version for each target
|
|
4
|
+
* The minimum supported server version for each target. The
|
|
5
5
|
* authoritative source of truth is each target package's
|
|
6
6
|
* `package.json#prismaNext.minServerVersion` field — this module
|
|
7
7
|
* mirrors those values and a workspace-level test asserts the two
|
|
@@ -9,13 +9,13 @@ import type { TargetId } from './code-templates';
|
|
|
9
9
|
*
|
|
10
10
|
* Bumping a value here in isolation is **not** safe: edit the
|
|
11
11
|
* corresponding target package's `package.json` first, then mirror
|
|
12
|
-
* here. The scaffold's `.env.example`
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* here. The scaffold's `.env.example` and the "Requirements" section
|
|
13
|
+
* of `prisma-next.md` both read from this constant, so a stale value
|
|
14
|
+
* lies to every freshly initialised user.
|
|
15
15
|
*/
|
|
16
16
|
export const MIN_SERVER_VERSION: Record<TargetId, string> = {
|
|
17
|
-
postgres: '
|
|
18
|
-
mongo: '
|
|
17
|
+
postgres: '17',
|
|
18
|
+
mongo: '8.0',
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
export const TARGET_LABEL: Record<TargetId, string> = {
|
|
@@ -41,7 +41,7 @@ function envPlaceholderBody(target: TargetId): string {
|
|
|
41
41
|
lines.push('DATABASE_URL="postgresql://user:password@localhost:5432/mydb"');
|
|
42
42
|
} else {
|
|
43
43
|
lines.push(
|
|
44
|
-
'# Standalone local mongod / `docker run mongo:
|
|
44
|
+
'# Standalone local mongod / `docker run mongo:8` — no replica set required for first-run queries.',
|
|
45
45
|
);
|
|
46
46
|
lines.push(
|
|
47
47
|
'# Transactions and change streams need a replica set; add ?replicaSet=... only after initiating one.',
|
|
@@ -54,7 +54,7 @@ function envPlaceholderBody(target: TargetId): string {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
/**
|
|
57
|
-
* Renders the `.env.example` content for a given target
|
|
57
|
+
* Renders the `.env.example` content for a given target:
|
|
58
58
|
*
|
|
59
59
|
* - Carries a "Copy this file to `.env`…" intro that only makes sense
|
|
60
60
|
* for the example file (the real `.env` is the destination of that
|
|
@@ -63,8 +63,7 @@ function envPlaceholderBody(target: TargetId): string {
|
|
|
63
63
|
* shape (Postgres: standard `postgresql://`, Mongo: `mongodb://` plus
|
|
64
64
|
* a `mydb` database segment so the lazy facade has a `dbName`).
|
|
65
65
|
* - Carries a `# Requires <db> >= <version>` comment so a fresh user
|
|
66
|
-
* knows the minimum supported server before they first try to
|
|
67
|
-
* connect (FR8.2).
|
|
66
|
+
* knows the minimum supported server before they first try to connect.
|
|
68
67
|
*/
|
|
69
68
|
export function envExampleContent(target: TargetId): string {
|
|
70
69
|
const lines: string[] = [];
|
|
@@ -77,10 +76,10 @@ export function envExampleContent(target: TargetId): string {
|
|
|
77
76
|
|
|
78
77
|
/**
|
|
79
78
|
* Renders the initial `.env` content for `--write-env` / interactive
|
|
80
|
-
* opt-in
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
* file is gitignored (
|
|
79
|
+
* opt-in. Same placeholder body as `.env.example`, **without** the
|
|
80
|
+
* example file's "Copy this file to `.env`…" intro: the real `.env` is
|
|
81
|
+
* the destination of that copy, so the line would lie. Writing this
|
|
82
|
+
* file is gitignored (`.env` lands in `.gitignore` during init).
|
|
84
83
|
*/
|
|
85
84
|
export function envFileContent(target: TargetId): string {
|
|
86
85
|
return envPlaceholderBody(target);
|
package/src/commands/migrate.ts
CHANGED
|
@@ -2,19 +2,18 @@ import { readFile } from 'node:fs/promises';
|
|
|
2
2
|
import type { Contract } from '@prisma-next/contract/types';
|
|
3
3
|
import { createControlStack } from '@prisma-next/framework-components/control';
|
|
4
4
|
import { errorUnknownInvariant, MigrationToolsError } from '@prisma-next/migration-tools/errors';
|
|
5
|
+
import { findLatestMigration, isGraphNode } from '@prisma-next/migration-tools/migration-graph';
|
|
5
6
|
import { parseContractRef } from '@prisma-next/migration-tools/ref-resolution';
|
|
6
7
|
import type { RefEntry } from '@prisma-next/migration-tools/refs';
|
|
7
|
-
import { readRefs } from '@prisma-next/migration-tools/refs';
|
|
8
8
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
9
9
|
import { notOk, ok, type Result } from '@prisma-next/utils/result';
|
|
10
10
|
import { Command } from 'commander';
|
|
11
|
-
|
|
12
11
|
import { loadConfig } from '../config-loader';
|
|
13
12
|
import { createControlClient } from '../control-api/client';
|
|
14
13
|
import type {
|
|
15
|
-
AggregatePerSpaceExecutionEntry,
|
|
16
14
|
MigrationApplyFailure,
|
|
17
15
|
MigrationApplyPathDecision,
|
|
16
|
+
PerSpaceExecutionEntry,
|
|
18
17
|
} from '../control-api/types';
|
|
19
18
|
import {
|
|
20
19
|
CliStructuredError,
|
|
@@ -23,6 +22,8 @@ import {
|
|
|
23
22
|
errorDatabaseConnectionRequired,
|
|
24
23
|
errorDriverRequired,
|
|
25
24
|
errorFileNotFound,
|
|
25
|
+
errorMarkerMismatch,
|
|
26
|
+
errorPathUnreachable,
|
|
26
27
|
errorRuntime,
|
|
27
28
|
errorTargetMigrationNotSupported,
|
|
28
29
|
errorUnexpected,
|
|
@@ -32,7 +33,6 @@ import {
|
|
|
32
33
|
import {
|
|
33
34
|
addGlobalOptions,
|
|
34
35
|
collectDeclaredInvariants,
|
|
35
|
-
loadMigrationPackages,
|
|
36
36
|
maskConnectionUrl,
|
|
37
37
|
resolveContractPath,
|
|
38
38
|
resolveMigrationPaths,
|
|
@@ -40,10 +40,17 @@ import {
|
|
|
40
40
|
setCommandExamples,
|
|
41
41
|
targetSupportsMigrations,
|
|
42
42
|
} from '../utils/command-helpers';
|
|
43
|
+
import { mapContractAtError } from '../utils/contract-at-errors';
|
|
44
|
+
import {
|
|
45
|
+
loadContractSpaceAggregateForCli,
|
|
46
|
+
refuseContractSpaceIntegrity,
|
|
47
|
+
} from '../utils/contract-space-aggregate-loader';
|
|
48
|
+
import { toDeclaredExtensionsFromRaw } from '../utils/extension-pack-inputs';
|
|
43
49
|
import { formatMigrationApplyCommandOutput } from '../utils/formatters/migrations';
|
|
44
50
|
import { formatStyledHeader } from '../utils/formatters/styled';
|
|
45
51
|
import type { CommonCommandOptions } from '../utils/global-flags';
|
|
46
52
|
import { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';
|
|
53
|
+
import { executeRefAdvancement, readContractIR } from '../utils/ref-advancement';
|
|
47
54
|
import { handleResult } from '../utils/result-handler';
|
|
48
55
|
import { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';
|
|
49
56
|
|
|
@@ -51,6 +58,7 @@ interface MigrateCommandOptions extends CommonCommandOptions {
|
|
|
51
58
|
readonly db?: string;
|
|
52
59
|
readonly config?: string;
|
|
53
60
|
readonly to?: string;
|
|
61
|
+
readonly advanceRef?: string;
|
|
54
62
|
}
|
|
55
63
|
|
|
56
64
|
export interface MigrateResult {
|
|
@@ -67,14 +75,18 @@ export interface MigrateResult {
|
|
|
67
75
|
readonly operationsExecuted: number;
|
|
68
76
|
}[];
|
|
69
77
|
readonly summary: string;
|
|
70
|
-
readonly perSpace: readonly
|
|
78
|
+
readonly perSpace: readonly PerSpaceExecutionEntry[];
|
|
71
79
|
readonly pathDecision?: MigrationApplyPathDecision;
|
|
72
80
|
readonly timings: {
|
|
73
81
|
readonly total: number;
|
|
74
82
|
};
|
|
83
|
+
readonly advancedRef?: { readonly name: string; readonly hash: string } | null;
|
|
75
84
|
}
|
|
76
85
|
|
|
77
86
|
function mapApplyFailure(failure: MigrationApplyFailure): CliStructuredErrorType {
|
|
87
|
+
if (failure.code === 'MIGRATION_PATH_NOT_FOUND') {
|
|
88
|
+
return errorPathUnreachable(failure);
|
|
89
|
+
}
|
|
78
90
|
return errorRuntime(failure.summary, {
|
|
79
91
|
why: failure.why ?? 'Migration runner failed',
|
|
80
92
|
fix: 'Fix the issue and re-run `prisma-next migrate --to <contract>` — previously applied migrations are preserved.',
|
|
@@ -89,8 +101,10 @@ async function executeMigrateCommand(
|
|
|
89
101
|
startTime: number,
|
|
90
102
|
): Promise<Result<MigrateResult, CliStructuredErrorType>> {
|
|
91
103
|
const config = await loadConfig(options.config);
|
|
92
|
-
const { configPath, migrationsDir,
|
|
93
|
-
|
|
104
|
+
const { configPath, migrationsDir, appMigrationsRelative, refsDir } = resolveMigrationPaths(
|
|
105
|
+
options.config,
|
|
106
|
+
config,
|
|
107
|
+
);
|
|
94
108
|
|
|
95
109
|
const dbConnection = options.db ?? config.db?.connection;
|
|
96
110
|
if (!dbConnection) {
|
|
@@ -118,31 +132,8 @@ async function executeMigrateCommand(
|
|
|
118
132
|
);
|
|
119
133
|
}
|
|
120
134
|
|
|
121
|
-
let refEntry: RefEntry | undefined;
|
|
122
135
|
const toArg = options.to;
|
|
123
136
|
|
|
124
|
-
if (toArg) {
|
|
125
|
-
try {
|
|
126
|
-
const refs = await readRefs(refsDir);
|
|
127
|
-
const { graph } = await loadMigrationPackages(appMigrationsDir);
|
|
128
|
-
const refResult = parseContractRef(toArg, { graph, refs });
|
|
129
|
-
if (!refResult.ok) {
|
|
130
|
-
return notOk(mapRefResolutionError(refResult.failure));
|
|
131
|
-
}
|
|
132
|
-
if (refResult.value.provenance.kind === 'ref') {
|
|
133
|
-
const resolved = refs[refResult.value.provenance.refName];
|
|
134
|
-
if (resolved) refEntry = resolved;
|
|
135
|
-
} else {
|
|
136
|
-
refEntry = { hash: refResult.value.hash, invariants: [] };
|
|
137
|
-
}
|
|
138
|
-
} catch (error) {
|
|
139
|
-
if (MigrationToolsError.is(error)) {
|
|
140
|
-
return notOk(mapMigrationToolsError(error));
|
|
141
|
-
}
|
|
142
|
-
throw error;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
137
|
// Construct the family instance up-front so the on-disk contract read
|
|
147
138
|
// crosses the serializer seam (`familyInstance.deserializeContract`) at
|
|
148
139
|
// the read site. The downstream `client.migrationApply({ contract })`
|
|
@@ -184,6 +175,44 @@ async function executeMigrateCommand(
|
|
|
184
175
|
);
|
|
185
176
|
}
|
|
186
177
|
|
|
178
|
+
const loadedAggregate = await loadContractSpaceAggregateForCli({
|
|
179
|
+
targetId: config.target.targetId,
|
|
180
|
+
migrationsDir,
|
|
181
|
+
appContract: contractRaw,
|
|
182
|
+
extensionPacks: config.extensionPacks ?? [],
|
|
183
|
+
deserializeContract: (json) => familyInstance.deserializeContract(json),
|
|
184
|
+
});
|
|
185
|
+
if (!loadedAggregate.ok) {
|
|
186
|
+
return notOk(loadedAggregate.failure);
|
|
187
|
+
}
|
|
188
|
+
const aggregate = loadedAggregate.value;
|
|
189
|
+
const integrityFailure = refuseContractSpaceIntegrity(aggregate, {
|
|
190
|
+
declaredExtensions: toDeclaredExtensionsFromRaw(
|
|
191
|
+
(config.extensionPacks ?? []) as ReadonlyArray<unknown>,
|
|
192
|
+
),
|
|
193
|
+
checkContracts: true,
|
|
194
|
+
});
|
|
195
|
+
if (integrityFailure) {
|
|
196
|
+
return notOk(integrityFailure);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
let refEntry: RefEntry | undefined;
|
|
200
|
+
let refName: string | undefined;
|
|
201
|
+
if (toArg) {
|
|
202
|
+
const refs = aggregate.app.refs;
|
|
203
|
+
const refResult = parseContractRef(toArg, { graph: aggregate.app.graph(), refs });
|
|
204
|
+
if (!refResult.ok) {
|
|
205
|
+
return notOk(mapRefResolutionError(refResult.failure));
|
|
206
|
+
}
|
|
207
|
+
if (refResult.value.provenance.kind === 'ref') {
|
|
208
|
+
refName = refResult.value.provenance.refName;
|
|
209
|
+
const resolved = refs[refName];
|
|
210
|
+
if (resolved) refEntry = resolved;
|
|
211
|
+
} else {
|
|
212
|
+
refEntry = { hash: refResult.value.hash, invariants: [] };
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
187
216
|
if (!flags.json && !flags.quiet) {
|
|
188
217
|
const details: Array<{ label: string; value: string }> = [
|
|
189
218
|
{ label: 'config', value: configPath },
|
|
@@ -208,15 +237,7 @@ async function executeMigrateCommand(
|
|
|
208
237
|
ui.stderr(header);
|
|
209
238
|
}
|
|
210
239
|
|
|
211
|
-
|
|
212
|
-
try {
|
|
213
|
-
appPackages = await loadMigrationPackages(appMigrationsDir);
|
|
214
|
-
} catch (error) {
|
|
215
|
-
if (MigrationToolsError.is(error)) {
|
|
216
|
-
return notOk(mapMigrationToolsError(error));
|
|
217
|
-
}
|
|
218
|
-
throw error;
|
|
219
|
-
}
|
|
240
|
+
const appGraph = aggregate.app.graph();
|
|
220
241
|
|
|
221
242
|
const client = createControlClient({
|
|
222
243
|
family: config.family,
|
|
@@ -229,10 +250,21 @@ async function executeMigrateCommand(
|
|
|
229
250
|
try {
|
|
230
251
|
await client.connect(dbConnection);
|
|
231
252
|
|
|
253
|
+
const allMarkers = await client.readAllMarkers();
|
|
254
|
+
const appMarker = allMarkers.get('app') ?? null;
|
|
255
|
+
|
|
256
|
+
if (appMarker !== null && !isGraphNode(appMarker.storageHash, appGraph)) {
|
|
257
|
+
return notOk(
|
|
258
|
+
errorMarkerMismatch(
|
|
259
|
+
appMarker.storageHash,
|
|
260
|
+
[...appGraph.nodes].sort(),
|
|
261
|
+
findLatestMigration(appGraph)?.to ?? null,
|
|
262
|
+
),
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
|
|
232
266
|
if (refEntry && refEntry.invariants.length > 0) {
|
|
233
|
-
const
|
|
234
|
-
const appMarker = allMarkers.get('app') ?? null;
|
|
235
|
-
const declared = collectDeclaredInvariants(appPackages.graph);
|
|
267
|
+
const declared = collectDeclaredInvariants(appGraph);
|
|
236
268
|
const known = new Set<string>(declared);
|
|
237
269
|
for (const id of appMarker?.invariants ?? []) known.add(id);
|
|
238
270
|
const unknown = refEntry.invariants.filter((id) => !known.has(id));
|
|
@@ -253,10 +285,36 @@ async function executeMigrateCommand(
|
|
|
253
285
|
ui.step('Loading contract spaces…');
|
|
254
286
|
}
|
|
255
287
|
|
|
288
|
+
// When `--to` resolves to an on-disk graph node with a matching bundle,
|
|
289
|
+
// verify and apply against THAT bundle's destination contract via
|
|
290
|
+
// `contractAt` — not the emitted `contract.json`. With `--to` omitted,
|
|
291
|
+
// or a target with no matching bundle, the emitted contract stays the
|
|
292
|
+
// apply contract (the only migrate-specific default). The same
|
|
293
|
+
// `contractAt` artifacts feed the optional ref-advancement snapshot.
|
|
294
|
+
let applyContract: Contract = contractRaw;
|
|
295
|
+
let snapshotContractJson: Record<string, unknown> = JSON.parse(contractContent);
|
|
296
|
+
let snapshotContractDts: string | undefined;
|
|
297
|
+
if (toArg && refEntry) {
|
|
298
|
+
const targetHash = refEntry.hash;
|
|
299
|
+
const matchingBundle = aggregate.app.packages.find((p) => p.metadata.to === targetHash);
|
|
300
|
+
if (matchingBundle) {
|
|
301
|
+
try {
|
|
302
|
+
const at = await aggregate.app.contractAt(
|
|
303
|
+
targetHash,
|
|
304
|
+
refName !== undefined ? { refName } : undefined,
|
|
305
|
+
);
|
|
306
|
+
applyContract = at.contract;
|
|
307
|
+
snapshotContractJson = at.contractJson as Record<string, unknown>;
|
|
308
|
+
snapshotContractDts = at.contractDts;
|
|
309
|
+
} catch (error) {
|
|
310
|
+
return mapContractAtError(error, { artifactRole: 'to' });
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
256
315
|
const applyResult = await client.migrationApply({
|
|
257
|
-
contract:
|
|
316
|
+
contract: applyContract,
|
|
258
317
|
migrationsDir,
|
|
259
|
-
appMigrationPackages: appPackages.bundles,
|
|
260
318
|
...ifDefined('refHash', refEntry?.hash),
|
|
261
319
|
...(refEntry?.invariants ? { refInvariants: refEntry.invariants } : {}),
|
|
262
320
|
...(refEntry !== undefined ? ifDefined('refName', toArg) : {}),
|
|
@@ -268,6 +326,27 @@ async function executeMigrateCommand(
|
|
|
268
326
|
|
|
269
327
|
const { value } = applyResult;
|
|
270
328
|
|
|
329
|
+
let advancedRef: { name: string; hash: string } | null = null;
|
|
330
|
+
if (options.advanceRef !== undefined) {
|
|
331
|
+
try {
|
|
332
|
+
const contractIR =
|
|
333
|
+
snapshotContractDts !== undefined
|
|
334
|
+
? { contract: snapshotContractJson, contractDts: snapshotContractDts }
|
|
335
|
+
: await readContractIR(snapshotContractJson, contractPathAbsolute);
|
|
336
|
+
advancedRef = await executeRefAdvancement(
|
|
337
|
+
refsDir,
|
|
338
|
+
options.advanceRef,
|
|
339
|
+
value.markerHash,
|
|
340
|
+
contractIR,
|
|
341
|
+
);
|
|
342
|
+
} catch (error) {
|
|
343
|
+
if (MigrationToolsError.is(error)) {
|
|
344
|
+
return notOk(mapMigrationToolsError(error));
|
|
345
|
+
}
|
|
346
|
+
throw error;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
271
350
|
return ok({
|
|
272
351
|
ok: true,
|
|
273
352
|
migrationsApplied: value.migrationsApplied,
|
|
@@ -278,6 +357,7 @@ async function executeMigrateCommand(
|
|
|
278
357
|
perSpace: value.perSpace,
|
|
279
358
|
...ifDefined('pathDecision', value.pathDecision),
|
|
280
359
|
timings: { total: Date.now() - startTime },
|
|
360
|
+
advancedRef,
|
|
281
361
|
});
|
|
282
362
|
} catch (error) {
|
|
283
363
|
if (CliStructuredError.is(error)) {
|
|
@@ -318,6 +398,7 @@ export function createMigrateCommand(): Command {
|
|
|
318
398
|
'--to <contract>',
|
|
319
399
|
'Target contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path)',
|
|
320
400
|
)
|
|
401
|
+
.option('--advance-ref <name>', 'Advance the named ref to the post-apply marker after success')
|
|
321
402
|
.action(async (options: MigrateCommandOptions) => {
|
|
322
403
|
const flags = parseGlobalFlagsOrExit(options);
|
|
323
404
|
const startTime = Date.now();
|