sb-mig 6.0.0-beta.2 → 6.0.0-beta.4
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/dist/api/data-migration/component-data-migration.d.ts +5 -3
- package/dist/api/data-migration/component-data-migration.js +29 -5
- package/dist/api/data-migration/migration-run-log.d.ts +64 -0
- package/dist/api/data-migration/migration-run-log.js +109 -0
- package/dist/api/data-migration/write-summary.d.ts +3 -0
- package/dist/cli/cli-descriptions.d.ts +1 -1
- package/dist/cli/cli-descriptions.js +2 -0
- package/dist/cli/commands/migrate.js +8 -0
- package/dist/cli/index.js +4 -0
- package/package.json +1 -1
|
@@ -43,6 +43,7 @@ interface MigrateItems {
|
|
|
43
43
|
startsWith?: string;
|
|
44
44
|
};
|
|
45
45
|
dryRun?: boolean;
|
|
46
|
+
publish?: boolean;
|
|
46
47
|
fromFilePath?: string;
|
|
47
48
|
fileName?: string;
|
|
48
49
|
preparedMigrationConfigs?: PreparedMigrationConfig[];
|
|
@@ -67,8 +68,8 @@ export declare const runMigrationPipelineInMemory: ({ itemType, itemsToMigrate,
|
|
|
67
68
|
itemsToMigrate: any[];
|
|
68
69
|
preparedMigrationConfigs: PreparedMigrationConfig[];
|
|
69
70
|
}) => MigrationPipelineResult;
|
|
70
|
-
export declare const migrateAllComponentsDataInStories: ({ itemType, migrationConfig, migrateFrom, from, to, filters, dryRun, fromFilePath, fileName, migrationComponentAliases, migrationComponentOverrides, }: Omit<MigrateItems, "componentsToMigrate" | "preparedMigrationConfigs">, config: RequestBaseConfig) => Promise<void>;
|
|
71
|
-
export declare const doTheMigration: ({ itemType, from, itemsToMigrate, migrationConfig, migrationConfigs, to, dryRun, migrateFrom, fromFilePath, fileName, }: {
|
|
71
|
+
export declare const migrateAllComponentsDataInStories: ({ itemType, migrationConfig, migrateFrom, from, to, filters, dryRun, publish, fromFilePath, fileName, migrationComponentAliases, migrationComponentOverrides, }: Omit<MigrateItems, "componentsToMigrate" | "preparedMigrationConfigs">, config: RequestBaseConfig) => Promise<void>;
|
|
72
|
+
export declare const doTheMigration: ({ itemType, from, itemsToMigrate, migrationConfig, migrationConfigs, to, dryRun, publish, migrateFrom, fromFilePath, fileName, }: {
|
|
72
73
|
itemType?: "story" | "preset";
|
|
73
74
|
from: string;
|
|
74
75
|
itemsToMigrate: any[];
|
|
@@ -76,9 +77,10 @@ export declare const doTheMigration: ({ itemType, from, itemsToMigrate, migratio
|
|
|
76
77
|
migrationConfigs?: PreparedMigrationConfig[];
|
|
77
78
|
to: string;
|
|
78
79
|
dryRun?: boolean;
|
|
80
|
+
publish?: boolean;
|
|
79
81
|
migrateFrom: MigrateFrom;
|
|
80
82
|
fromFilePath?: string;
|
|
81
83
|
fileName?: string;
|
|
82
84
|
}, config: RequestBaseConfig) => Promise<void>;
|
|
83
|
-
export declare const migrateProvidedComponentsDataInStories: ({ itemType, migrationConfig, migrateFrom, from, to, componentsToMigrate, filters, dryRun, fromFilePath, fileName, preparedMigrationConfigs, migrationComponentAliases, migrationComponentOverrides, }: MigrateItems, config: RequestBaseConfig) => Promise<void>;
|
|
85
|
+
export declare const migrateProvidedComponentsDataInStories: ({ itemType, migrationConfig, migrateFrom, from, to, componentsToMigrate, filters, dryRun, publish, fromFilePath, fileName, preparedMigrationConfigs, migrationComponentAliases, migrationComponentOverrides, }: MigrateItems, config: RequestBaseConfig) => Promise<void>;
|
|
84
86
|
export {};
|
|
@@ -9,6 +9,7 @@ import { isObjectEmpty } from "../../utils/object-utils.js";
|
|
|
9
9
|
import { managementApi } from "../managementApi.js";
|
|
10
10
|
import { buildPreMigrationBackupBaseName, resolveOutputFileBaseName, shouldUseDatestampForArtifacts, } from "./file-naming.js";
|
|
11
11
|
import { extendMigrationMapperWithAliases, resolveMigrationComponentsToMigrate, } from "./migration-component-scope.js";
|
|
12
|
+
import { saveMigrationRunLog } from "./migration-run-log.js";
|
|
12
13
|
import { discoverMigrationValidatorForMigrationFile, MigrationValidationFailedError, runPreparedMigrationValidator, } from "./migration-validation.js";
|
|
13
14
|
import { summarizeMutationWriteResults } from "./write-summary.js";
|
|
14
15
|
export const normalizeMigrationConfigNames = (migrationConfig) => {
|
|
@@ -295,7 +296,7 @@ export const runMigrationPipelineInMemory = ({ itemType, itemsToMigrate, prepare
|
|
|
295
296
|
totalItems: workingItems.length,
|
|
296
297
|
};
|
|
297
298
|
};
|
|
298
|
-
const savePipelineSummary = async ({ artifactBaseName, useDatestamp, from, itemType, dryRun, migrateFrom, fromFilePath, pipelineResult, }, config) => {
|
|
299
|
+
const savePipelineSummary = async ({ artifactBaseName, useDatestamp, from, itemType, dryRun, publish, migrateFrom, fromFilePath, pipelineResult, }, config) => {
|
|
299
300
|
await createAndSaveToFile({
|
|
300
301
|
datestamp: useDatestamp,
|
|
301
302
|
ext: "json",
|
|
@@ -308,6 +309,7 @@ const savePipelineSummary = async ({ artifactBaseName, useDatestamp, from, itemT
|
|
|
308
309
|
from,
|
|
309
310
|
fromFilePath: fromFilePath || null,
|
|
310
311
|
},
|
|
312
|
+
writeMode: itemType === "story" && publish ? "publish" : "save",
|
|
311
313
|
totalItems: pipelineResult.totalItems,
|
|
312
314
|
totalChangedItems: pipelineResult.changedItems.length,
|
|
313
315
|
steps: pipelineResult.stepReports,
|
|
@@ -378,7 +380,7 @@ const loadItemsToMigrate = async ({ itemType, migrateFrom, from, filters, fromFi
|
|
|
378
380
|
spaceId: from,
|
|
379
381
|
});
|
|
380
382
|
};
|
|
381
|
-
export const migrateAllComponentsDataInStories = async ({ itemType, migrationConfig, migrateFrom, from, to, filters, dryRun, fromFilePath, fileName, migrationComponentAliases, migrationComponentOverrides, }, config) => {
|
|
383
|
+
export const migrateAllComponentsDataInStories = async ({ itemType, migrationConfig, migrateFrom, from, to, filters, dryRun, publish, fromFilePath, fileName, migrationComponentAliases, migrationComponentOverrides, }, config) => {
|
|
382
384
|
Logger.warning(`Trying to migrate all ${itemType} from ${migrateFrom}, ${from} to ${to}...`);
|
|
383
385
|
const preparedMigrationConfigs = prepareMigrationConfigs({
|
|
384
386
|
migrationConfig,
|
|
@@ -397,12 +399,13 @@ export const migrateAllComponentsDataInStories = async ({ itemType, migrationCon
|
|
|
397
399
|
to,
|
|
398
400
|
filters,
|
|
399
401
|
dryRun,
|
|
402
|
+
publish,
|
|
400
403
|
fromFilePath,
|
|
401
404
|
fileName,
|
|
402
405
|
preparedMigrationConfigs,
|
|
403
406
|
}, config);
|
|
404
407
|
};
|
|
405
|
-
export const doTheMigration = async ({ itemType = "story", from, itemsToMigrate, migrationConfig, migrationConfigs, to, dryRun, migrateFrom, fromFilePath, fileName, }, config) => {
|
|
408
|
+
export const doTheMigration = async ({ itemType = "story", from, itemsToMigrate, migrationConfig, migrationConfigs, to, dryRun, publish, migrateFrom, fromFilePath, fileName, }, config) => {
|
|
406
409
|
const preparedMigrationConfigs = migrationConfigs ||
|
|
407
410
|
prepareMigrationConfigs({
|
|
408
411
|
migrationConfig: migrationConfig || [],
|
|
@@ -472,6 +475,7 @@ export const doTheMigration = async ({ itemType = "story", from, itemsToMigrate,
|
|
|
472
475
|
from,
|
|
473
476
|
itemType,
|
|
474
477
|
dryRun,
|
|
478
|
+
publish,
|
|
475
479
|
migrateFrom,
|
|
476
480
|
fromFilePath,
|
|
477
481
|
pipelineResult,
|
|
@@ -493,7 +497,7 @@ export const doTheMigration = async ({ itemType = "story", from, itemsToMigrate,
|
|
|
493
497
|
writeResults = await managementApi.stories.updateStories({
|
|
494
498
|
stories: pipelineResult.changedItems,
|
|
495
499
|
spaceId: to,
|
|
496
|
-
options: { publish:
|
|
500
|
+
options: { publish: Boolean(publish) },
|
|
497
501
|
}, config);
|
|
498
502
|
}
|
|
499
503
|
else if (itemType === "preset") {
|
|
@@ -504,6 +508,25 @@ export const doTheMigration = async ({ itemType = "story", from, itemsToMigrate,
|
|
|
504
508
|
}, config);
|
|
505
509
|
}
|
|
506
510
|
const writeSummary = summarizeMutationWriteResults(writeResults);
|
|
511
|
+
try {
|
|
512
|
+
await saveMigrationRunLog({
|
|
513
|
+
artifactBaseName,
|
|
514
|
+
useDatestamp,
|
|
515
|
+
from,
|
|
516
|
+
to,
|
|
517
|
+
itemType,
|
|
518
|
+
dryRun,
|
|
519
|
+
publish,
|
|
520
|
+
migrateFrom,
|
|
521
|
+
fromFilePath,
|
|
522
|
+
pipelineResult,
|
|
523
|
+
writeResults,
|
|
524
|
+
writeSummary,
|
|
525
|
+
}, config);
|
|
526
|
+
}
|
|
527
|
+
catch (error) {
|
|
528
|
+
Logger.warning(`[MIGRATION] Could not write migration run log: ${error instanceof Error ? error.message : String(error)}`);
|
|
529
|
+
}
|
|
507
530
|
if (writeSummary.failed === 0) {
|
|
508
531
|
Logger.success(`[MIGRATION] Update complete. ${writeSummary.successful}/${writeSummary.total} ${itemType}(s) updated successfully.`);
|
|
509
532
|
return;
|
|
@@ -527,7 +550,7 @@ const saveBackupToFile = async ({ itemType, res, folder, filename }, config) =>
|
|
|
527
550
|
res: res,
|
|
528
551
|
}, config);
|
|
529
552
|
};
|
|
530
|
-
export const migrateProvidedComponentsDataInStories = async ({ itemType, migrationConfig, migrateFrom, from, to, componentsToMigrate, filters, dryRun, fromFilePath, fileName, preparedMigrationConfigs, migrationComponentAliases, migrationComponentOverrides, }, config) => {
|
|
553
|
+
export const migrateProvidedComponentsDataInStories = async ({ itemType, migrationConfig, migrateFrom, from, to, componentsToMigrate, filters, dryRun, publish, fromFilePath, fileName, preparedMigrationConfigs, migrationComponentAliases, migrationComponentOverrides, }, config) => {
|
|
531
554
|
const resolvedMigrationConfigs = preparedMigrationConfigs ||
|
|
532
555
|
prepareMigrationConfigs({
|
|
533
556
|
migrationConfig,
|
|
@@ -562,6 +585,7 @@ export const migrateProvidedComponentsDataInStories = async ({ itemType, migrati
|
|
|
562
585
|
from,
|
|
563
586
|
to,
|
|
564
587
|
dryRun,
|
|
588
|
+
publish,
|
|
565
589
|
migrateFrom,
|
|
566
590
|
fromFilePath,
|
|
567
591
|
fileName,
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { MigrateFrom, MigrationPipelineResult } from "./component-data-migration.js";
|
|
2
|
+
import type { MutationWriteResult, MutationWriteSummary } from "./write-summary.js";
|
|
3
|
+
import type { RequestBaseConfig } from "../utils/request.js";
|
|
4
|
+
type MigrationRunLogEvent = "update_success" | "update_failed" | "migration_write_summary";
|
|
5
|
+
export interface MigrationRunLogRecord {
|
|
6
|
+
timestamp: string;
|
|
7
|
+
event: MigrationRunLogEvent;
|
|
8
|
+
runId: string;
|
|
9
|
+
itemType: "story" | "preset";
|
|
10
|
+
source: {
|
|
11
|
+
migrateFrom: MigrateFrom;
|
|
12
|
+
from: string;
|
|
13
|
+
fromFilePath: string | null;
|
|
14
|
+
};
|
|
15
|
+
target: {
|
|
16
|
+
to: string;
|
|
17
|
+
};
|
|
18
|
+
writeMode: "publish" | "save";
|
|
19
|
+
dryRun: boolean;
|
|
20
|
+
migrationConfigs: string[];
|
|
21
|
+
totalItems: number;
|
|
22
|
+
totalChangedItems: number;
|
|
23
|
+
writeSummary?: {
|
|
24
|
+
total: number;
|
|
25
|
+
successful: number;
|
|
26
|
+
failed: number;
|
|
27
|
+
failedItems: Array<{
|
|
28
|
+
id?: number | string;
|
|
29
|
+
name?: string;
|
|
30
|
+
slug?: string;
|
|
31
|
+
spaceId?: string;
|
|
32
|
+
status?: number | string;
|
|
33
|
+
response?: string | null;
|
|
34
|
+
}>;
|
|
35
|
+
};
|
|
36
|
+
item?: {
|
|
37
|
+
index: number;
|
|
38
|
+
id?: number | string;
|
|
39
|
+
name?: string;
|
|
40
|
+
slug?: string;
|
|
41
|
+
spaceId?: string;
|
|
42
|
+
};
|
|
43
|
+
status?: number | string | null;
|
|
44
|
+
response?: string | null;
|
|
45
|
+
error?: unknown;
|
|
46
|
+
}
|
|
47
|
+
interface SaveMigrationRunLogArgs {
|
|
48
|
+
artifactBaseName: string;
|
|
49
|
+
useDatestamp: boolean;
|
|
50
|
+
from: string;
|
|
51
|
+
to: string;
|
|
52
|
+
itemType: "story" | "preset";
|
|
53
|
+
dryRun?: boolean;
|
|
54
|
+
publish?: boolean;
|
|
55
|
+
migrateFrom: MigrateFrom;
|
|
56
|
+
fromFilePath?: string;
|
|
57
|
+
pipelineResult: MigrationPipelineResult;
|
|
58
|
+
writeResults: PromiseSettledResult<MutationWriteResult>[];
|
|
59
|
+
writeSummary: MutationWriteSummary;
|
|
60
|
+
}
|
|
61
|
+
export declare const buildMigrationRunLogRecords: ({ from, to, itemType, dryRun, publish, migrateFrom, fromFilePath, pipelineResult, writeResults, writeSummary, }: Omit<SaveMigrationRunLogArgs, "artifactBaseName" | "useDatestamp">) => MigrationRunLogRecord[];
|
|
62
|
+
export declare const recordsToJsonl: (records: MigrationRunLogRecord[]) => string;
|
|
63
|
+
export declare const saveMigrationRunLog: (args: SaveMigrationRunLogArgs, config: RequestBaseConfig) => Promise<void>;
|
|
64
|
+
export {};
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { generateDatestamp } from "../../utils/date-utils.js";
|
|
2
|
+
import { createDir, createJsonFile } from "../../utils/files.js";
|
|
3
|
+
import Logger from "../../utils/logger.js";
|
|
4
|
+
const serializeError = (error) => {
|
|
5
|
+
if (!error) {
|
|
6
|
+
return null;
|
|
7
|
+
}
|
|
8
|
+
if (error instanceof Error) {
|
|
9
|
+
return {
|
|
10
|
+
name: error.name,
|
|
11
|
+
message: error.message,
|
|
12
|
+
stack: error.stack,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
return JSON.parse(JSON.stringify(error));
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return String(error);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
const resolveChangedItemPayload = (item) => item?.story || item;
|
|
23
|
+
const resolveWriteResultValue = (result) => {
|
|
24
|
+
if (result.status === "fulfilled") {
|
|
25
|
+
return (result.value || {
|
|
26
|
+
ok: false,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
ok: false,
|
|
31
|
+
error: result.reason,
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
export const buildMigrationRunLogRecords = ({ from, to, itemType, dryRun, publish, migrateFrom, fromFilePath, pipelineResult, writeResults, writeSummary, }) => {
|
|
35
|
+
const timestamp = new Date().toISOString();
|
|
36
|
+
const runId = `${itemType}-${timestamp}`;
|
|
37
|
+
const baseRecord = {
|
|
38
|
+
timestamp,
|
|
39
|
+
runId,
|
|
40
|
+
itemType,
|
|
41
|
+
source: {
|
|
42
|
+
migrateFrom,
|
|
43
|
+
from,
|
|
44
|
+
fromFilePath: fromFilePath || null,
|
|
45
|
+
},
|
|
46
|
+
target: {
|
|
47
|
+
to,
|
|
48
|
+
},
|
|
49
|
+
writeMode: itemType === "story" && publish ? "publish" : "save",
|
|
50
|
+
dryRun: Boolean(dryRun),
|
|
51
|
+
migrationConfigs: pipelineResult.stepReports.map((step) => step.migrationConfig),
|
|
52
|
+
totalItems: pipelineResult.totalItems,
|
|
53
|
+
totalChangedItems: pipelineResult.changedItems.length,
|
|
54
|
+
};
|
|
55
|
+
const updateRecords = writeResults.map((result, index) => {
|
|
56
|
+
const value = resolveWriteResultValue(result);
|
|
57
|
+
const changedItem = resolveChangedItemPayload(pipelineResult.changedItems[index]);
|
|
58
|
+
const event = value.ok
|
|
59
|
+
? "update_success"
|
|
60
|
+
: "update_failed";
|
|
61
|
+
return {
|
|
62
|
+
...baseRecord,
|
|
63
|
+
event,
|
|
64
|
+
item: {
|
|
65
|
+
index,
|
|
66
|
+
id: value.id || changedItem?.id,
|
|
67
|
+
name: value.name || changedItem?.name,
|
|
68
|
+
slug: value.slug ||
|
|
69
|
+
changedItem?.full_slug ||
|
|
70
|
+
changedItem?.slug,
|
|
71
|
+
spaceId: value.spaceId || to,
|
|
72
|
+
},
|
|
73
|
+
status: value.status || null,
|
|
74
|
+
response: value.response || null,
|
|
75
|
+
...(value.ok ? {} : { error: serializeError(value.error) }),
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
const summaryRecord = {
|
|
79
|
+
...baseRecord,
|
|
80
|
+
event: "migration_write_summary",
|
|
81
|
+
writeSummary: {
|
|
82
|
+
total: writeSummary.total,
|
|
83
|
+
successful: writeSummary.successful,
|
|
84
|
+
failed: writeSummary.failed,
|
|
85
|
+
failedItems: writeSummary.failedItems.map((item) => ({
|
|
86
|
+
id: item.id,
|
|
87
|
+
name: item.name,
|
|
88
|
+
slug: item.slug,
|
|
89
|
+
spaceId: item.spaceId,
|
|
90
|
+
status: item.status,
|
|
91
|
+
response: item.response || null,
|
|
92
|
+
})),
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
return [...updateRecords, summaryRecord];
|
|
96
|
+
};
|
|
97
|
+
export const recordsToJsonl = (records) => `${records.map((record) => JSON.stringify(record)).join("\n")}\n`;
|
|
98
|
+
export const saveMigrationRunLog = async (args, config) => {
|
|
99
|
+
const { sbmigWorkingDirectory } = config;
|
|
100
|
+
const { artifactBaseName, useDatestamp, itemType, dryRun } = args;
|
|
101
|
+
const timestamp = generateDatestamp(new Date());
|
|
102
|
+
const finalFilename = `${dryRun ? "dry-run--" : ""}${artifactBaseName}---${itemType}-migration-run-log${useDatestamp ? `__${timestamp}` : ""}.jsonl`;
|
|
103
|
+
const folderPath = `${sbmigWorkingDirectory}/migrations/`;
|
|
104
|
+
const fullPath = `${folderPath}${finalFilename}`;
|
|
105
|
+
const records = buildMigrationRunLogRecords(args);
|
|
106
|
+
await createDir(folderPath);
|
|
107
|
+
await createJsonFile(recordsToJsonl(records), fullPath);
|
|
108
|
+
Logger.success(`Migration run log written to a file: ${fullPath}`);
|
|
109
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export declare const mainDescription = "\n USAGE\n $ sb-mig [command]\n \n COMMANDS\n sync Synchronize components, datasources, roles, stories, assets with Storyblok space.\n discover Discover components, migration configs and write to file or stdout.\n backup Command for backing up anything related to Storyblok\n migrate Migrate content from space to space, or from file to space.\n debug Output extra debugging information\n help This screen\n \n Examples\n $ sb-mig sync components --all\n $ sb-mig debug \n";
|
|
2
2
|
export declare const syncDescription = "\n Usage\n $ sb-mig sync [components|roles|datasources|plugins|content] [space separated file names] or --all\n \n Description\n Synchronize components, roles, datasources, plugins, content with Storyblok space.\n \n COMMANDS\n components - sync components\n roles - sync roles\n datasources - sync datasources\n plugins - sync plugins\n content - sync content (stories, assets) - ! right now destructive, it will move content from 1 space to another, completelly overwriting it\n \n FLAGS\n --all - Sync all components, roles, datasources [components, roles, datasources]\n --presets - Pass it, if u want to sync also with presets (will take longer) [components only]\n --dry-run - Preview planned changes without making writes [components, roles, datasources, plugins, content]\n \n --yes - Skip ask for confirmation (dangerous, but useful in CI/CD) [content only]\n --from - Space ID from which you want to sync content [content only]\n --to - Space ID to which you want to sync content [content only]\n --syncDirection [fromSpaceToFile|fromFileToSpace|fromSpaceToSpace|fromAWStoSpace] \n - Sync direction (from, to) [content only]\n \n EXAMPLES\n $ sb-mig sync components --all\n $ sb-mig sync components --all --dry-run\n $ sb-mig sync components --all --presets\n $ sb-mig sync components accordion accordion-item\n $ sb-mig sync components accordion accordion-item --presets\n \n $ sb-mig sync roles --all\n $ sb-mig sync roles --all --dry-run\n \n $ sb-mig sync datasources --all\n $ sb-mig sync datasources --all --dry-run\n \n $ sb-mig sync plugins my-awesome-plugin - (you have to be in catalog which has ./dist/export.js file with compiled plugin)\n \n $ sb-mig sync content --all --from 12345 --to 12345\n $ sb-mig sync content --stories --from 12345 --to 12345\n $ sb-mig sync content --assets --from 12345 --to 12345\n";
|
|
3
3
|
export declare const copyDescription = "\n Usage\n $ sb-mig copy\n \n Description\n Copy stuff\n \n COMMANDS\n ?\n \n FLAGS\n ?\n \n EXAMPLES\n $ sb-mig copy ?\n";
|
|
4
|
-
export declare const migrateDescription = "\n Usage\n $ sb-mig migrate [content] [space separated file names] or --all --from [spaceId] --to [spaceId] --migration [migration-config-filename]\n $ sb-mig migrate content --all --migration migration-a --migration migration-b --migration migration-c\n \n Description\n Migrate content from space to space, or from file to space. It's potentially dangerous command, so it will ask for confirmation.\n Use with care.\n \n COMMANDS\n content - migrate content \n \n FLAGS\n --from - Space ID from which you want to migrate / or file name if passed '--migrate-from file'\n --fromFilePath - Direct path to stories JSON file when using '--migrate-from file'\n --to - Space ID to which you want to migrate\n --migrate-from - Migrate from (space, file) default: space\n --migration - File name of migration file (without extension). Can be repeated for ordered pipeline in content migration.\n --migrationComponentAlias - Add extra component aliases for a migration. Repeatable. Format: <migration>:<source>=<alias1>,<alias2>\n --migrationComponents - Override the exact component scope for a migration. Repeatable. Format: <migration>:<component1>,<component2>\n --withSlug - Filter stories by full slug (can be repeated)\n --startsWith - Filter stories by starts_with prefix\n --yes - Skip ask for confirmation (dangerous, but useful in CI/CD)\n --dry-run - Preview what would be migrated without making any API changes\n --fileName - Stable base name for migration output files (disables timestamp suffix for migration artifacts)\n\n EXAMPLES\n $ sb-mig migrate content --all --from 12345 --to 12345 --migration file-with-migration\n $ sb-mig migrate content --all --from 12345 --to 12345 --migration migration-a --migration migration-b --migration migration-c\n $ sb-mig migrate content --all --from 12345 --to 12345 --migration colorPickerModeValues --migrationComponentAlias colorPickerModeValues:sb-button=sb-open-drift-button\n $ sb-mig migrate content --all --from 12345 --to 12345 --migration colorPickerModeValues --migrationComponentAlias colorPickerModeValues:sb-section=sb-tour-page-section --migrationComponents colorPickerModeValues:sb-section,sb-tour-page-section\n $ sb-mig migrate content --all --from 12345 --to 12345 --migration file-with-migration --withSlug blog/home --withSlug docs/getting-started\n $ sb-mig migrate content --all --from 12345 --to 12345 --migration file-with-migration --startsWith blog/\n $ sb-mig migrate content --all --from 12345 --to 12345 --migration v3toV4AllMigrations --dry-run --fileName brand-hub-v3-v4-run\n $ sb-mig migrate content --all --migrate-from file --from file-with-stories --to 12345 --migration file-with-migration\n $ sb-mig migrate content --all --migrate-from file --fromFilePath sbmig/migrations/dry-run--123---story-to-migrate__2026-2-9_20-51.json --to 12345 --migration migration-a --migration migration-b\n $ sb-mig migrate content my-component-1 my-component-2 --from 12345 --to 12345 --migration file-with-migration\n $ sb-mig migrate content my-component-1 my-component-2 --migrate-from file --from file-with-stories --to 12345 --migration file-with-migration \n";
|
|
4
|
+
export declare const migrateDescription = "\n Usage\n $ sb-mig migrate [content] [space separated file names] or --all --from [spaceId] --to [spaceId] --migration [migration-config-filename]\n $ sb-mig migrate content --all --migration migration-a --migration migration-b --migration migration-c\n \n Description\n Migrate content from space to space, or from file to space. It's potentially dangerous command, so it will ask for confirmation.\n Use with care.\n \n COMMANDS\n content - migrate content \n \n FLAGS\n --from - Space ID from which you want to migrate / or file name if passed '--migrate-from file'\n --fromFilePath - Direct path to stories JSON file when using '--migrate-from file'\n --to - Space ID to which you want to migrate\n --migrate-from - Migrate from (space, file) default: space\n --migration - File name of migration file (without extension). Can be repeated for ordered pipeline in content migration.\n --migrationComponentAlias - Add extra component aliases for a migration. Repeatable. Format: <migration>:<source>=<alias1>,<alias2>\n --migrationComponents - Override the exact component scope for a migration. Repeatable. Format: <migration>:<component1>,<component2>\n --withSlug - Filter stories by full slug (can be repeated)\n --startsWith - Filter stories by starts_with prefix\n --yes - Skip ask for confirmation (dangerous, but useful in CI/CD)\n --dry-run - Preview what would be migrated without making any API changes\n --publish - Publish changed stories immediately after migration. Default: save draft. [content only]\n --fileName - Stable base name for migration output files (disables timestamp suffix for migration artifacts)\n\n EXAMPLES\n $ sb-mig migrate content --all --from 12345 --to 12345 --migration file-with-migration\n $ sb-mig migrate content --all --from 12345 --to 12345 --migration migration-a --migration migration-b --migration migration-c\n $ sb-mig migrate content --all --from 12345 --to 12345 --migration colorPickerModeValues --migrationComponentAlias colorPickerModeValues:sb-button=sb-open-drift-button\n $ sb-mig migrate content --all --from 12345 --to 12345 --migration colorPickerModeValues --migrationComponentAlias colorPickerModeValues:sb-section=sb-tour-page-section --migrationComponents colorPickerModeValues:sb-section,sb-tour-page-section\n $ sb-mig migrate content --all --from 12345 --to 12345 --migration file-with-migration --withSlug blog/home --withSlug docs/getting-started\n $ sb-mig migrate content --all --from 12345 --to 12345 --migration file-with-migration --startsWith blog/\n $ sb-mig migrate content --all --from 12345 --to 12345 --migration file-with-migration --publish --yes\n $ sb-mig migrate content --all --from 12345 --to 12345 --migration v3toV4AllMigrations --dry-run --fileName brand-hub-v3-v4-run\n $ sb-mig migrate content --all --migrate-from file --from file-with-stories --to 12345 --migration file-with-migration\n $ sb-mig migrate content --all --migrate-from file --fromFilePath sbmig/migrations/dry-run--123---story-to-migrate__2026-2-9_20-51.json --to 12345 --migration migration-a --migration migration-b\n $ sb-mig migrate content my-component-1 my-component-2 --from 12345 --to 12345 --migration file-with-migration\n $ sb-mig migrate content my-component-1 my-component-2 --migrate-from file --from file-with-stories --to 12345 --migration file-with-migration \n";
|
|
5
5
|
export declare const revertDescription = "\n Usage\n $ sb-mig revert [content] --migration\n \n Description\n Revert content migration\n \n COMMANDS\n content - revert content migration \n \n FLAGS\n --migration - ???\n --yes - Skip ask for confirmation (dangerous, but useful in CI/CD) \n \n EXAMPLES\n $ sb-mig revert content --migration \n";
|
|
6
6
|
export declare const discoverDescription = "\n Usage\n $ sb-mig discover [components|migrations] --all --write\n\n Description\n Discover all components or migration configs and write to file or stdout\n\n COMMANDS\n components - discover components\n migrations - discover migration config files\n\n FLAGS\n --all - Discover all components or migration configs\n --write - Write to file\n\n EXAMPLES\n $ sb-mig discover components --all\n $ sb-mig discover components --all --write\n $ sb-mig discover migrations --all\n";
|
|
7
7
|
export declare const migrationsDescription = "\n Usage\n $ sb-mig migrations recognize\n \n Description\n Recognize migrations you need to apply\n \n COMMANDS\n recognize - recognize migrations\n \n FLAGS \n \n EXAMPLES\n $ sb-mig migrations recognize\n\n";
|
|
@@ -98,6 +98,7 @@ export const migrateDescription = `
|
|
|
98
98
|
--startsWith - Filter stories by starts_with prefix
|
|
99
99
|
--yes - Skip ask for confirmation (dangerous, but useful in CI/CD)
|
|
100
100
|
--dry-run - Preview what would be migrated without making any API changes
|
|
101
|
+
--publish - Publish changed stories immediately after migration. Default: save draft. [content only]
|
|
101
102
|
--fileName - Stable base name for migration output files (disables timestamp suffix for migration artifacts)
|
|
102
103
|
|
|
103
104
|
EXAMPLES
|
|
@@ -107,6 +108,7 @@ export const migrateDescription = `
|
|
|
107
108
|
$ sb-mig migrate content --all --from 12345 --to 12345 --migration colorPickerModeValues --migrationComponentAlias colorPickerModeValues:sb-section=sb-tour-page-section --migrationComponents colorPickerModeValues:sb-section,sb-tour-page-section
|
|
108
109
|
$ sb-mig migrate content --all --from 12345 --to 12345 --migration file-with-migration --withSlug blog/home --withSlug docs/getting-started
|
|
109
110
|
$ sb-mig migrate content --all --from 12345 --to 12345 --migration file-with-migration --startsWith blog/
|
|
111
|
+
$ sb-mig migrate content --all --from 12345 --to 12345 --migration file-with-migration --publish --yes
|
|
110
112
|
$ sb-mig migrate content --all --from 12345 --to 12345 --migration v3toV4AllMigrations --dry-run --fileName brand-hub-v3-v4-run
|
|
111
113
|
$ sb-mig migrate content --all --migrate-from file --from file-with-stories --to 12345 --migration file-with-migration
|
|
112
114
|
$ sb-mig migrate content --all --migrate-from file --fromFilePath sbmig/migrations/dry-run--123---story-to-migrate__2026-2-9_20-51.json --to 12345 --migration migration-a --migration migration-b
|
|
@@ -41,6 +41,7 @@ export const migrate = async (props) => {
|
|
|
41
41
|
"withSlug",
|
|
42
42
|
"startsWith",
|
|
43
43
|
"dryRun",
|
|
44
|
+
"publish",
|
|
44
45
|
"fileName",
|
|
45
46
|
]);
|
|
46
47
|
Logger.warning(`This feature is in BETA. Use it at your own risk. The API might change in the future. (Probably in a standard Prisma like migration way)`);
|
|
@@ -60,6 +61,7 @@ export const migrate = async (props) => {
|
|
|
60
61
|
const migrationComponentAliases = parseMigrationComponentAliasFlags(flags["migrationComponentAlias"]);
|
|
61
62
|
const migrationComponentOverrides = parseMigrationComponentOverrideFlags(flags["migrationComponents"]);
|
|
62
63
|
const dryRun = flags["dryRun"];
|
|
64
|
+
const publish = Boolean(flags["publish"]);
|
|
63
65
|
const fileName = flags["fileName"];
|
|
64
66
|
const withSlugFlag = flags["withSlug"];
|
|
65
67
|
const withSlug = Array.isArray(withSlugFlag)
|
|
@@ -97,6 +99,7 @@ export const migrate = async (props) => {
|
|
|
97
99
|
migrationComponentOverrides,
|
|
98
100
|
filters: { withSlug, startsWith },
|
|
99
101
|
dryRun,
|
|
102
|
+
publish,
|
|
100
103
|
fromFilePath,
|
|
101
104
|
fileName,
|
|
102
105
|
}, apiConfig);
|
|
@@ -124,6 +127,7 @@ export const migrate = async (props) => {
|
|
|
124
127
|
migrationComponentOverrides,
|
|
125
128
|
filters: { withSlug, startsWith },
|
|
126
129
|
dryRun,
|
|
130
|
+
publish,
|
|
127
131
|
fromFilePath,
|
|
128
132
|
fileName,
|
|
129
133
|
}, apiConfig);
|
|
@@ -158,9 +162,13 @@ export const migrate = async (props) => {
|
|
|
158
162
|
fromFallback ||
|
|
159
163
|
getFrom(flags, apiConfig);
|
|
160
164
|
const to = getTo(flags, apiConfig);
|
|
165
|
+
const publish = Boolean(flags["publish"]);
|
|
161
166
|
if (migrationConfigs.length === 0) {
|
|
162
167
|
throw new Error("Missing migration config. Pass exactly one --migration value for presets.");
|
|
163
168
|
}
|
|
169
|
+
if (publish) {
|
|
170
|
+
throw new Error("--publish is only supported for 'migrate content'. Presets cannot be published.");
|
|
171
|
+
}
|
|
164
172
|
if (migrationConfigs.length > 1) {
|
|
165
173
|
throw new Error("Multiple --migration values are currently supported only for 'migrate content'. Presets support a single migration config.");
|
|
166
174
|
}
|
package/dist/cli/index.js
CHANGED
package/package.json
CHANGED