sb-mig 5.6.2-beta.1 → 5.7.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 +43 -0
- package/dist/api/data-migration/component-data-migration.d.ts +8 -3
- package/dist/api/data-migration/component-data-migration.js +38 -30
- package/dist/api/data-migration/file-naming.d.ts +14 -0
- package/dist/api/data-migration/file-naming.js +19 -0
- package/dist/api/data-migration/migration-component-scope.d.ts +12 -0
- package/dist/api/data-migration/migration-component-scope.js +73 -0
- package/dist/api/data-migration/write-summary.d.ts +14 -0
- package/dist/api/data-migration/write-summary.js +26 -0
- package/dist/api/presets/presets.js +13 -2
- package/dist/api/stories/stories.js +17 -2
- package/dist/cli/cli-descriptions.d.ts +1 -1
- package/dist/cli/cli-descriptions.js +4 -0
- package/dist/cli/commands/migrate.js +18 -1
- package/dist/cli/helpers.js +16 -11
- package/dist/cli/index.js +8 -0
- package/dist-cjs/api/presets/presets.js +13 -2
- package/dist-cjs/api/stories/stories.js +17 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -189,6 +189,49 @@ This command will look for `row.sb.js` and `column.sb.js` files inside a directo
|
|
|
189
189
|
|
|
190
190
|
## Syncing datasources
|
|
191
191
|
|
|
192
|
+
## Migrating content
|
|
193
|
+
|
|
194
|
+
Use `sb-mig migrate content` to run one or more migration configs against
|
|
195
|
+
stories from a space or from a file.
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
sb-mig migrate content --all --from 12345 --to 12345 --migration itemsToContent
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Extending migration component scope
|
|
202
|
+
|
|
203
|
+
Migration files export a mapper keyed by component name. By default, `sb-mig`
|
|
204
|
+
runs a migration only for the component keys exported by that migration file.
|
|
205
|
+
|
|
206
|
+
Use these flags when a consuming app has wrapper components that should reuse an
|
|
207
|
+
existing migration function:
|
|
208
|
+
|
|
209
|
+
- `--migrationComponentAlias`
|
|
210
|
+
Format: `<migration>:<source>=<alias1>,<alias2>`
|
|
211
|
+
- `--migrationComponents`
|
|
212
|
+
Format: `<migration>:<component1>,<component2>`
|
|
213
|
+
|
|
214
|
+
`--migrationComponentAlias` extends the migration mapper at runtime by reusing
|
|
215
|
+
the source component's migration function for extra component names.
|
|
216
|
+
|
|
217
|
+
`--migrationComponents` overrides the exact component scope for that migration.
|
|
218
|
+
|
|
219
|
+
Example:
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
sb-mig migrate content --all \
|
|
223
|
+
--from 12345 \
|
|
224
|
+
--to 12345 \
|
|
225
|
+
--migration colorPickerModeValues \
|
|
226
|
+
--migrationComponentAlias colorPickerModeValues:sb-button=sb-open-drift-button \
|
|
227
|
+
--migrationComponentAlias colorPickerModeValues:sb-section=sb-tour-page-section \
|
|
228
|
+
--migrationComponents colorPickerModeValues:sb-button,sb-open-drift-button,sb-section,sb-tour-page-section
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
This runs `colorPickerModeValues` for the normal Backpack keys and also for the
|
|
232
|
+
two wrapper component names by aliasing them onto the existing `sb-button` and
|
|
233
|
+
`sb-section` migration handlers.
|
|
234
|
+
|
|
192
235
|
You can also sync your `datasources`.
|
|
193
236
|
|
|
194
237
|
Add `datasourceExt: "your-own-extension",` to your `storyblok.config.js`. If u will not add it, will be used default one (`sb.datasource.js`)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { RequestBaseConfig } from "../utils/request.js";
|
|
2
|
+
import { type MigrationComponentAliasesByMigration, type MigrationComponentOverridesByMigration } from "./migration-component-scope.js";
|
|
2
3
|
import { type PreparedMigrationValidator } from "./migration-validation.js";
|
|
3
4
|
export type MigrateFrom = "file" | "space";
|
|
4
5
|
export interface PreparedMigrationConfig {
|
|
@@ -35,6 +36,8 @@ interface MigrateItems {
|
|
|
35
36
|
migrateFrom: MigrateFrom;
|
|
36
37
|
migrationConfig: string | string[];
|
|
37
38
|
componentsToMigrate?: string[];
|
|
39
|
+
migrationComponentAliases?: MigrationComponentAliasesByMigration;
|
|
40
|
+
migrationComponentOverrides?: MigrationComponentOverridesByMigration;
|
|
38
41
|
filters?: {
|
|
39
42
|
withSlug?: string[];
|
|
40
43
|
startsWith?: string;
|
|
@@ -50,9 +53,11 @@ export declare const prepareStoriesFromLocalFile: ({ from, fromFilePath, }: {
|
|
|
50
53
|
from?: string;
|
|
51
54
|
fromFilePath?: string;
|
|
52
55
|
}) => any;
|
|
53
|
-
export declare const prepareMigrationConfigs: ({ migrationConfig, componentsToMigrate, }: {
|
|
56
|
+
export declare const prepareMigrationConfigs: ({ migrationConfig, componentsToMigrate, migrationComponentAliases, migrationComponentOverrides, }: {
|
|
54
57
|
migrationConfig: string | string[];
|
|
55
58
|
componentsToMigrate?: string[];
|
|
59
|
+
migrationComponentAliases?: MigrationComponentAliasesByMigration;
|
|
60
|
+
migrationComponentOverrides?: MigrationComponentOverridesByMigration;
|
|
56
61
|
}) => PreparedMigrationConfig[];
|
|
57
62
|
export declare const prepareMigrationConfig: ({ migrationConfig, }: {
|
|
58
63
|
migrationConfig: string;
|
|
@@ -62,7 +67,7 @@ export declare const runMigrationPipelineInMemory: ({ itemType, itemsToMigrate,
|
|
|
62
67
|
itemsToMigrate: any[];
|
|
63
68
|
preparedMigrationConfigs: PreparedMigrationConfig[];
|
|
64
69
|
}) => MigrationPipelineResult;
|
|
65
|
-
export declare const migrateAllComponentsDataInStories: ({ itemType, migrationConfig, migrateFrom, from, to, filters, dryRun, fromFilePath, fileName, }: Omit<MigrateItems, "componentsToMigrate" | "preparedMigrationConfigs">, config: RequestBaseConfig) => Promise<void>;
|
|
70
|
+
export declare const migrateAllComponentsDataInStories: ({ itemType, migrationConfig, migrateFrom, from, to, filters, dryRun, fromFilePath, fileName, migrationComponentAliases, migrationComponentOverrides, }: Omit<MigrateItems, "componentsToMigrate" | "preparedMigrationConfigs">, config: RequestBaseConfig) => Promise<void>;
|
|
66
71
|
export declare const doTheMigration: ({ itemType, from, itemsToMigrate, migrationConfig, migrationConfigs, to, dryRun, migrateFrom, fromFilePath, fileName, }: {
|
|
67
72
|
itemType?: "story" | "preset";
|
|
68
73
|
from: string;
|
|
@@ -75,5 +80,5 @@ export declare const doTheMigration: ({ itemType, from, itemsToMigrate, migratio
|
|
|
75
80
|
fromFilePath?: string;
|
|
76
81
|
fileName?: string;
|
|
77
82
|
}, config: RequestBaseConfig) => Promise<void>;
|
|
78
|
-
export declare const migrateProvidedComponentsDataInStories: ({ itemType, migrationConfig, migrateFrom, from, to, componentsToMigrate, filters, dryRun, fromFilePath, fileName, preparedMigrationConfigs, }: MigrateItems, 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>;
|
|
79
84
|
export {};
|
|
@@ -7,7 +7,10 @@ import Logger from "../../utils/logger.js";
|
|
|
7
7
|
import { modifyOrCreateAppliedMigrationsFile } from "../../utils/migrations.js";
|
|
8
8
|
import { isObjectEmpty } from "../../utils/object-utils.js";
|
|
9
9
|
import { managementApi } from "../managementApi.js";
|
|
10
|
+
import { buildPreMigrationBackupBaseName, resolveOutputFileBaseName, shouldUseDatestampForArtifacts, } from "./file-naming.js";
|
|
11
|
+
import { extendMigrationMapperWithAliases, resolveMigrationComponentsToMigrate, } from "./migration-component-scope.js";
|
|
10
12
|
import { discoverMigrationValidatorForMigrationFile, MigrationValidationFailedError, runPreparedMigrationValidator, } from "./migration-validation.js";
|
|
13
|
+
import { summarizeMutationWriteResults } from "./write-summary.js";
|
|
11
14
|
export const normalizeMigrationConfigNames = (migrationConfig) => {
|
|
12
15
|
if (Array.isArray(migrationConfig)) {
|
|
13
16
|
return migrationConfig.filter((name) => Boolean(name));
|
|
@@ -107,7 +110,7 @@ export const prepareStoriesFromLocalFile = ({ from, fromFilePath, }) => {
|
|
|
107
110
|
}
|
|
108
111
|
return storiesFileContent;
|
|
109
112
|
};
|
|
110
|
-
export const prepareMigrationConfigs = ({ migrationConfig, componentsToMigrate, }) => {
|
|
113
|
+
export const prepareMigrationConfigs = ({ migrationConfig, componentsToMigrate, migrationComponentAliases, migrationComponentOverrides, }) => {
|
|
111
114
|
const migrationConfigNames = normalizeMigrationConfigNames(migrationConfig);
|
|
112
115
|
if (migrationConfigNames.length === 0) {
|
|
113
116
|
throw new Error("Migration config is required. Pass at least one --migration value.");
|
|
@@ -138,13 +141,17 @@ export const prepareMigrationConfigs = ({ migrationConfig, componentsToMigrate,
|
|
|
138
141
|
if (!validator) {
|
|
139
142
|
Logger.warning(`[VALIDATION] No co-located validator found for migration '${migrationConfigName}'. Expected a sibling '*.validation.*' file.`);
|
|
140
143
|
}
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
:
|
|
144
|
+
const aliasedMigrationConfigFileContent = extendMigrationMapperWithAliases(migrationConfigFileContent, migrationComponentAliases?.[migrationConfigName]);
|
|
145
|
+
const resolvedComponentsToMigrate = resolveMigrationComponentsToMigrate({
|
|
146
|
+
mapper: aliasedMigrationConfigFileContent,
|
|
147
|
+
migrationName: migrationConfigName,
|
|
148
|
+
globalComponentsToMigrate: componentsToMigrate,
|
|
149
|
+
perMigrationOverrides: migrationComponentOverrides,
|
|
150
|
+
});
|
|
144
151
|
return {
|
|
145
152
|
migrationConfigName,
|
|
146
153
|
migrationConfigPath,
|
|
147
|
-
migrationConfigFileContent,
|
|
154
|
+
migrationConfigFileContent: aliasedMigrationConfigFileContent,
|
|
148
155
|
componentsToMigrate: resolvedComponentsToMigrate,
|
|
149
156
|
validator,
|
|
150
157
|
};
|
|
@@ -162,23 +169,6 @@ export const prepareMigrationConfig = ({ migrationConfig, }) => {
|
|
|
162
169
|
};
|
|
163
170
|
const deepClone = (input) => JSON.parse(JSON.stringify(input));
|
|
164
171
|
const sumValues = (obj) => Object.values(obj).reduce((sum, value) => sum + value, 0);
|
|
165
|
-
const sanitizeOutputFileBaseName = (value) => {
|
|
166
|
-
const sanitized = value
|
|
167
|
-
.trim()
|
|
168
|
-
.replace(/[\\/]/g, "-")
|
|
169
|
-
.replace(/\s+/g, "-")
|
|
170
|
-
.replace(/[^a-zA-Z0-9._-]/g, "-")
|
|
171
|
-
.replace(/-+/g, "-")
|
|
172
|
-
.replace(/^[-.]+|[-.]+$/g, "");
|
|
173
|
-
return sanitized || "migration-output";
|
|
174
|
-
};
|
|
175
|
-
const resolveOutputFileBaseName = ({ from, fileName, }) => {
|
|
176
|
-
if (typeof fileName === "string" && fileName.trim().length > 0) {
|
|
177
|
-
return sanitizeOutputFileBaseName(fileName);
|
|
178
|
-
}
|
|
179
|
-
return sanitizeOutputFileBaseName(from);
|
|
180
|
-
};
|
|
181
|
-
const shouldUseDatestampForArtifacts = (fileName) => !(typeof fileName === "string" && fileName.trim().length > 0);
|
|
182
172
|
const applySingleMigrationToItems = ({ itemType, itemsToMigrate, preparedMigrationConfig, }) => {
|
|
183
173
|
const arrayOfMaxDepths = [];
|
|
184
174
|
const replacementsByComponent = {};
|
|
@@ -388,10 +378,12 @@ const loadItemsToMigrate = async ({ itemType, migrateFrom, from, filters, fromFi
|
|
|
388
378
|
spaceId: from,
|
|
389
379
|
});
|
|
390
380
|
};
|
|
391
|
-
export const migrateAllComponentsDataInStories = async ({ itemType, migrationConfig, migrateFrom, from, to, filters, dryRun, fromFilePath, fileName, }, config) => {
|
|
381
|
+
export const migrateAllComponentsDataInStories = async ({ itemType, migrationConfig, migrateFrom, from, to, filters, dryRun, fromFilePath, fileName, migrationComponentAliases, migrationComponentOverrides, }, config) => {
|
|
392
382
|
Logger.warning(`Trying to migrate all ${itemType} from ${migrateFrom}, ${from} to ${to}...`);
|
|
393
383
|
const preparedMigrationConfigs = prepareMigrationConfigs({
|
|
394
384
|
migrationConfig,
|
|
385
|
+
migrationComponentAliases,
|
|
386
|
+
migrationComponentOverrides,
|
|
395
387
|
});
|
|
396
388
|
if (storyblokConfig.debug) {
|
|
397
389
|
Logger.warning("_________ Components in stories to migrate ___________");
|
|
@@ -496,20 +488,34 @@ export const doTheMigration = async ({ itemType = "story", from, itemsToMigrate,
|
|
|
496
488
|
if (pipelineResult.changedItems.length === 0) {
|
|
497
489
|
return;
|
|
498
490
|
}
|
|
491
|
+
let writeResults = [];
|
|
499
492
|
if (itemType === "story") {
|
|
500
|
-
await managementApi.stories.updateStories({
|
|
493
|
+
writeResults = await managementApi.stories.updateStories({
|
|
501
494
|
stories: pipelineResult.changedItems,
|
|
502
495
|
spaceId: to,
|
|
503
496
|
options: { publish: false },
|
|
504
497
|
}, config);
|
|
505
498
|
}
|
|
506
499
|
else if (itemType === "preset") {
|
|
507
|
-
await managementApi.presets.updatePresets({
|
|
500
|
+
writeResults = await managementApi.presets.updatePresets({
|
|
508
501
|
presets: pipelineResult.changedItems,
|
|
509
502
|
spaceId: to,
|
|
510
503
|
options: {},
|
|
511
504
|
}, config);
|
|
512
505
|
}
|
|
506
|
+
const writeSummary = summarizeMutationWriteResults(writeResults);
|
|
507
|
+
if (writeSummary.failed === 0) {
|
|
508
|
+
Logger.success(`[MIGRATION] Update complete. ${writeSummary.successful}/${writeSummary.total} ${itemType}(s) updated successfully.`);
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
Logger.warning(`[MIGRATION] Update complete with partial failures. ${writeSummary.successful}/${writeSummary.total} ${itemType}(s) updated successfully, ${writeSummary.failed} failed.`);
|
|
512
|
+
writeSummary.failedItems.slice(0, 10).forEach((item) => {
|
|
513
|
+
const label = item.slug || item.name || item.id || "unknown";
|
|
514
|
+
Logger.error(`[MIGRATION] Failed ${itemType}: ${String(label)}`);
|
|
515
|
+
});
|
|
516
|
+
if (writeSummary.failedItems.length > 10) {
|
|
517
|
+
Logger.warning(`[MIGRATION] Showing first 10 failed ${itemType}(s) only.`);
|
|
518
|
+
}
|
|
513
519
|
};
|
|
514
520
|
const saveBackupToFile = async ({ itemType, res, folder, filename }, config) => {
|
|
515
521
|
await createAndSaveToFile({
|
|
@@ -521,11 +527,13 @@ const saveBackupToFile = async ({ itemType, res, folder, filename }, config) =>
|
|
|
521
527
|
res: res,
|
|
522
528
|
}, config);
|
|
523
529
|
};
|
|
524
|
-
export const migrateProvidedComponentsDataInStories = async ({ itemType, migrationConfig, migrateFrom, from, to, componentsToMigrate, filters, dryRun, fromFilePath, fileName, preparedMigrationConfigs, }, config) => {
|
|
530
|
+
export const migrateProvidedComponentsDataInStories = async ({ itemType, migrationConfig, migrateFrom, from, to, componentsToMigrate, filters, dryRun, fromFilePath, fileName, preparedMigrationConfigs, migrationComponentAliases, migrationComponentOverrides, }, config) => {
|
|
525
531
|
const resolvedMigrationConfigs = preparedMigrationConfigs ||
|
|
526
532
|
prepareMigrationConfigs({
|
|
527
533
|
migrationConfig,
|
|
528
534
|
componentsToMigrate,
|
|
535
|
+
migrationComponentAliases,
|
|
536
|
+
migrationComponentOverrides,
|
|
529
537
|
});
|
|
530
538
|
const itemsToMigrate = await loadItemsToMigrate({
|
|
531
539
|
itemType,
|
|
@@ -536,12 +544,12 @@ export const migrateProvidedComponentsDataInStories = async ({ itemType, migrati
|
|
|
536
544
|
}, config);
|
|
537
545
|
if (migrateFrom === "space" && !dryRun) {
|
|
538
546
|
const backupFolder = path.join("backup", itemType);
|
|
539
|
-
const migrationLabel = resolvedMigrationConfigs
|
|
540
|
-
.map((preparedMigrationConfig) => preparedMigrationConfig.migrationConfigName)
|
|
541
|
-
.join("__");
|
|
542
547
|
await saveBackupToFile({
|
|
543
548
|
itemType,
|
|
544
|
-
filename:
|
|
549
|
+
filename: buildPreMigrationBackupBaseName({
|
|
550
|
+
from,
|
|
551
|
+
fileName,
|
|
552
|
+
}),
|
|
545
553
|
folder: backupFolder,
|
|
546
554
|
res: itemsToMigrate,
|
|
547
555
|
}, config);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare const sanitizeOutputFileBaseName: (value: string) => string;
|
|
2
|
+
export declare const resolveOutputFileBaseName: ({ from, fileName, }: {
|
|
3
|
+
from: string;
|
|
4
|
+
fileName?: string;
|
|
5
|
+
}) => string;
|
|
6
|
+
export declare const shouldUseDatestampForArtifacts: (fileName?: string) => boolean;
|
|
7
|
+
export declare const buildPreMigrationBackupBaseName: ({ from, fileName, }: {
|
|
8
|
+
from: string;
|
|
9
|
+
fileName?: string;
|
|
10
|
+
}) => string;
|
|
11
|
+
export declare const buildStoryBackupBaseName: ({ from, fileName, }: {
|
|
12
|
+
from: string;
|
|
13
|
+
fileName?: string;
|
|
14
|
+
}) => string;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export const sanitizeOutputFileBaseName = (value) => {
|
|
2
|
+
const sanitized = value
|
|
3
|
+
.trim()
|
|
4
|
+
.replace(/[\\/]/g, "-")
|
|
5
|
+
.replace(/\s+/g, "-")
|
|
6
|
+
.replace(/[^a-zA-Z0-9._-]/g, "-")
|
|
7
|
+
.replace(/-+/g, "-")
|
|
8
|
+
.replace(/^[-.]+|[-.]+$/g, "");
|
|
9
|
+
return sanitized || "migration-output";
|
|
10
|
+
};
|
|
11
|
+
export const resolveOutputFileBaseName = ({ from, fileName, }) => {
|
|
12
|
+
if (typeof fileName === "string" && fileName.trim().length > 0) {
|
|
13
|
+
return sanitizeOutputFileBaseName(fileName);
|
|
14
|
+
}
|
|
15
|
+
return sanitizeOutputFileBaseName(from);
|
|
16
|
+
};
|
|
17
|
+
export const shouldUseDatestampForArtifacts = (fileName) => !(typeof fileName === "string" && fileName.trim().length > 0);
|
|
18
|
+
export const buildPreMigrationBackupBaseName = ({ from, fileName, }) => `before__${resolveOutputFileBaseName({ from, fileName })}`;
|
|
19
|
+
export const buildStoryBackupBaseName = ({ from, fileName, }) => `${resolveOutputFileBaseName({ from, fileName })}--backup-before-migration`;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { MapperDefinition } from "./component-data-migration.js";
|
|
2
|
+
export type MigrationComponentAliasesByMigration = Record<string, Record<string, string[]>>;
|
|
3
|
+
export type MigrationComponentOverridesByMigration = Record<string, string[]>;
|
|
4
|
+
export declare const parseMigrationComponentAliasFlags: (value: string | string[] | undefined) => MigrationComponentAliasesByMigration;
|
|
5
|
+
export declare const parseMigrationComponentOverrideFlags: (value: string | string[] | undefined) => MigrationComponentOverridesByMigration;
|
|
6
|
+
export declare const extendMigrationMapperWithAliases: (mapper: Record<string, MapperDefinition>, aliases: Record<string, string[]> | undefined) => Record<string, MapperDefinition>;
|
|
7
|
+
export declare const resolveMigrationComponentsToMigrate: ({ mapper, migrationName, globalComponentsToMigrate, perMigrationOverrides, }: {
|
|
8
|
+
mapper: Record<string, MapperDefinition>;
|
|
9
|
+
migrationName: string;
|
|
10
|
+
globalComponentsToMigrate?: string[];
|
|
11
|
+
perMigrationOverrides?: MigrationComponentOverridesByMigration;
|
|
12
|
+
}) => string[];
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
const normalizeFlagValues = (value) => {
|
|
2
|
+
if (Array.isArray(value)) {
|
|
3
|
+
return value.filter(Boolean);
|
|
4
|
+
}
|
|
5
|
+
if (typeof value === "string" && value.length > 0) {
|
|
6
|
+
return [value];
|
|
7
|
+
}
|
|
8
|
+
return [];
|
|
9
|
+
};
|
|
10
|
+
export const parseMigrationComponentAliasFlags = (value) => {
|
|
11
|
+
const result = {};
|
|
12
|
+
normalizeFlagValues(value).forEach((entry) => {
|
|
13
|
+
const [migrationName, mapping] = entry.split(":");
|
|
14
|
+
const [sourceComponent, aliasesRaw] = (mapping || "").split("=");
|
|
15
|
+
const aliases = (aliasesRaw || "")
|
|
16
|
+
.split(",")
|
|
17
|
+
.map((item) => item.trim())
|
|
18
|
+
.filter(Boolean);
|
|
19
|
+
if (!migrationName || !sourceComponent || aliases.length === 0) {
|
|
20
|
+
throw new Error(`Invalid --migrationComponentAlias value '${entry}'. Expected '<migration>:<source>=<alias1>,<alias2>'.`);
|
|
21
|
+
}
|
|
22
|
+
result[migrationName] = result[migrationName] || {};
|
|
23
|
+
result[migrationName][sourceComponent] = [
|
|
24
|
+
...(result[migrationName][sourceComponent] || []),
|
|
25
|
+
...aliases,
|
|
26
|
+
];
|
|
27
|
+
});
|
|
28
|
+
return result;
|
|
29
|
+
};
|
|
30
|
+
export const parseMigrationComponentOverrideFlags = (value) => {
|
|
31
|
+
const result = {};
|
|
32
|
+
normalizeFlagValues(value).forEach((entry) => {
|
|
33
|
+
const [migrationName, componentsRaw] = entry.split(":");
|
|
34
|
+
const components = (componentsRaw || "")
|
|
35
|
+
.split(",")
|
|
36
|
+
.map((item) => item.trim())
|
|
37
|
+
.filter(Boolean);
|
|
38
|
+
if (!migrationName || components.length === 0) {
|
|
39
|
+
throw new Error(`Invalid --migrationComponents value '${entry}'. Expected '<migration>:<component1>,<component2>'.`);
|
|
40
|
+
}
|
|
41
|
+
result[migrationName] = components;
|
|
42
|
+
});
|
|
43
|
+
return result;
|
|
44
|
+
};
|
|
45
|
+
export const extendMigrationMapperWithAliases = (mapper, aliases) => {
|
|
46
|
+
if (!aliases) {
|
|
47
|
+
return mapper;
|
|
48
|
+
}
|
|
49
|
+
const extendedMapper = { ...mapper };
|
|
50
|
+
Object.entries(aliases).forEach(([sourceComponent, extraComponents]) => {
|
|
51
|
+
const sourceMapper = mapper[sourceComponent];
|
|
52
|
+
if (!sourceMapper) {
|
|
53
|
+
throw new Error(`Cannot alias migration component '${sourceComponent}' because it is not defined in the migration config.`);
|
|
54
|
+
}
|
|
55
|
+
extraComponents.forEach((extraComponent) => {
|
|
56
|
+
extendedMapper[extraComponent] = sourceMapper;
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
return extendedMapper;
|
|
60
|
+
};
|
|
61
|
+
export const resolveMigrationComponentsToMigrate = ({ mapper, migrationName, globalComponentsToMigrate, perMigrationOverrides, }) => {
|
|
62
|
+
const resolvedComponents = perMigrationOverrides?.[migrationName] &&
|
|
63
|
+
perMigrationOverrides[migrationName].length > 0
|
|
64
|
+
? perMigrationOverrides[migrationName]
|
|
65
|
+
: globalComponentsToMigrate && globalComponentsToMigrate.length > 0
|
|
66
|
+
? globalComponentsToMigrate
|
|
67
|
+
: Object.keys(mapper);
|
|
68
|
+
const missingComponents = resolvedComponents.filter((componentName) => !mapper[componentName]);
|
|
69
|
+
if (missingComponents.length > 0) {
|
|
70
|
+
throw new Error(`Migration '${migrationName}' cannot run for unknown components: ${missingComponents.join(", ")}. Add aliases first or adjust the component override list.`);
|
|
71
|
+
}
|
|
72
|
+
return resolvedComponents;
|
|
73
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface MutationWriteResult {
|
|
2
|
+
ok: boolean;
|
|
3
|
+
id?: number | string;
|
|
4
|
+
name?: string;
|
|
5
|
+
slug?: string;
|
|
6
|
+
error?: unknown;
|
|
7
|
+
}
|
|
8
|
+
export interface MutationWriteSummary {
|
|
9
|
+
total: number;
|
|
10
|
+
successful: number;
|
|
11
|
+
failed: number;
|
|
12
|
+
failedItems: MutationWriteResult[];
|
|
13
|
+
}
|
|
14
|
+
export declare const summarizeMutationWriteResults: (results: PromiseSettledResult<MutationWriteResult>[]) => MutationWriteSummary;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export const summarizeMutationWriteResults = (results) => {
|
|
2
|
+
const failedItems = [];
|
|
3
|
+
let successful = 0;
|
|
4
|
+
for (const result of results) {
|
|
5
|
+
if (result.status === "fulfilled" && result.value?.ok) {
|
|
6
|
+
successful++;
|
|
7
|
+
continue;
|
|
8
|
+
}
|
|
9
|
+
if (result.status === "fulfilled") {
|
|
10
|
+
failedItems.push(result.value || {
|
|
11
|
+
ok: false,
|
|
12
|
+
});
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
failedItems.push({
|
|
16
|
+
ok: false,
|
|
17
|
+
error: result.reason,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
total: results.length,
|
|
22
|
+
successful,
|
|
23
|
+
failed: failedItems.length,
|
|
24
|
+
failedItems,
|
|
25
|
+
};
|
|
26
|
+
};
|
|
@@ -63,10 +63,21 @@ export const updatePreset = (args, config) => {
|
|
|
63
63
|
})
|
|
64
64
|
.then((res) => {
|
|
65
65
|
Logger.warning(`Preset: '${p.preset.name}' with '${p.preset.id}' id has been updated.`);
|
|
66
|
-
return
|
|
66
|
+
return {
|
|
67
|
+
ok: true,
|
|
68
|
+
id: p.preset.id,
|
|
69
|
+
name: p.preset.name,
|
|
70
|
+
data: res,
|
|
71
|
+
};
|
|
67
72
|
})
|
|
68
|
-
.catch(() => {
|
|
73
|
+
.catch((error) => {
|
|
69
74
|
Logger.error(`Error happened. Preset: '${p.preset.name}' with '${p.preset.id}' id has been not updated.`);
|
|
75
|
+
return {
|
|
76
|
+
ok: false,
|
|
77
|
+
id: p.preset.id,
|
|
78
|
+
name: p.preset.name,
|
|
79
|
+
error,
|
|
80
|
+
};
|
|
70
81
|
});
|
|
71
82
|
};
|
|
72
83
|
export const updatePresets = (args, config) => {
|
|
@@ -118,9 +118,24 @@ export const updateStory = (content, storyId, options, config) => {
|
|
|
118
118
|
})
|
|
119
119
|
.then((res) => {
|
|
120
120
|
console.log(`${chalk.green(res.data.story.full_slug)} updated.`);
|
|
121
|
-
return
|
|
121
|
+
return {
|
|
122
|
+
ok: true,
|
|
123
|
+
id: res.data.story.id,
|
|
124
|
+
name: res.data.story.name,
|
|
125
|
+
slug: res.data.story.full_slug,
|
|
126
|
+
data: res.data,
|
|
127
|
+
};
|
|
122
128
|
})
|
|
123
|
-
.catch((err) =>
|
|
129
|
+
.catch((err) => {
|
|
130
|
+
console.error(err);
|
|
131
|
+
return {
|
|
132
|
+
ok: false,
|
|
133
|
+
id: storyId,
|
|
134
|
+
name: content?.name,
|
|
135
|
+
slug: content?.full_slug || content?.slug,
|
|
136
|
+
error: err,
|
|
137
|
+
};
|
|
138
|
+
});
|
|
124
139
|
};
|
|
125
140
|
export const updateStories = (args, config) => {
|
|
126
141
|
const { stories, options, spaceId } = args;
|
|
@@ -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 \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 --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 \n $ sb-mig sync datasources --all\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 --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 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 --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";
|
|
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";
|
|
@@ -88,6 +88,8 @@ export const migrateDescription = `
|
|
|
88
88
|
--to - Space ID to which you want to migrate
|
|
89
89
|
--migrate-from - Migrate from (space, file) default: space
|
|
90
90
|
--migration - File name of migration file (without extension). Can be repeated for ordered pipeline in content migration.
|
|
91
|
+
--migrationComponentAlias - Add extra component aliases for a migration. Repeatable. Format: <migration>:<source>=<alias1>,<alias2>
|
|
92
|
+
--migrationComponents - Override the exact component scope for a migration. Repeatable. Format: <migration>:<component1>,<component2>
|
|
91
93
|
--withSlug - Filter stories by full slug (can be repeated)
|
|
92
94
|
--startsWith - Filter stories by starts_with prefix
|
|
93
95
|
--yes - Skip ask for confirmation (dangerous, but useful in CI/CD)
|
|
@@ -97,6 +99,8 @@ export const migrateDescription = `
|
|
|
97
99
|
EXAMPLES
|
|
98
100
|
$ sb-mig migrate content --all --from 12345 --to 12345 --migration file-with-migration
|
|
99
101
|
$ sb-mig migrate content --all --from 12345 --to 12345 --migration migration-a --migration migration-b --migration migration-c
|
|
102
|
+
$ sb-mig migrate content --all --from 12345 --to 12345 --migration colorPickerModeValues --migrationComponentAlias colorPickerModeValues:sb-button=sb-open-drift-button
|
|
103
|
+
$ 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
|
|
100
104
|
$ sb-mig migrate content --all --from 12345 --to 12345 --migration file-with-migration --withSlug blog/home --withSlug docs/getting-started
|
|
101
105
|
$ sb-mig migrate content --all --from 12345 --to 12345 --migration file-with-migration --startsWith blog/
|
|
102
106
|
$ sb-mig migrate content --all --from 12345 --to 12345 --migration v3toV4AllMigrations --dry-run --fileName brand-hub-v3-v4-run
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import path from "path";
|
|
2
2
|
import { migrateAllComponentsDataInStories, migrateProvidedComponentsDataInStories, } from "../../api/data-migration/component-data-migration.js";
|
|
3
|
+
import { buildStoryBackupBaseName } from "../../api/data-migration/file-naming.js";
|
|
4
|
+
import { parseMigrationComponentAliasFlags, parseMigrationComponentOverrideFlags, } from "../../api/data-migration/migration-component-scope.js";
|
|
3
5
|
import { managementApi } from "../../api/managementApi.js";
|
|
4
6
|
import { backupStories } from "../../api/stories/backup.js";
|
|
5
7
|
import { createAndSaveToFile } from "../../utils/files.js";
|
|
@@ -33,6 +35,8 @@ export const migrate = async (props) => {
|
|
|
33
35
|
"fromFilePath",
|
|
34
36
|
"pageId",
|
|
35
37
|
"migration",
|
|
38
|
+
"migrationComponentAlias",
|
|
39
|
+
"migrationComponents",
|
|
36
40
|
"yes",
|
|
37
41
|
"withSlug",
|
|
38
42
|
"startsWith",
|
|
@@ -53,6 +57,8 @@ export const migrate = async (props) => {
|
|
|
53
57
|
getFrom(flags, apiConfig);
|
|
54
58
|
const to = getTo(flags, apiConfig);
|
|
55
59
|
const migrationConfigs = normalizeMigrationFlags(flags["migration"]);
|
|
60
|
+
const migrationComponentAliases = parseMigrationComponentAliasFlags(flags["migrationComponentAlias"]);
|
|
61
|
+
const migrationComponentOverrides = parseMigrationComponentOverrideFlags(flags["migrationComponents"]);
|
|
56
62
|
const dryRun = flags["dryRun"];
|
|
57
63
|
const fileName = flags["fileName"];
|
|
58
64
|
const withSlugFlag = flags["withSlug"];
|
|
@@ -72,7 +78,10 @@ export const migrate = async (props) => {
|
|
|
72
78
|
Logger.warning("Preparing to migrate...");
|
|
73
79
|
if (!dryRun) {
|
|
74
80
|
await backupStories({
|
|
75
|
-
filename:
|
|
81
|
+
filename: buildStoryBackupBaseName({
|
|
82
|
+
from,
|
|
83
|
+
fileName,
|
|
84
|
+
}),
|
|
76
85
|
suffix: ".sb.stories",
|
|
77
86
|
spaceId: from,
|
|
78
87
|
}, apiConfig);
|
|
@@ -84,6 +93,8 @@ export const migrate = async (props) => {
|
|
|
84
93
|
migrateFrom,
|
|
85
94
|
componentsToMigrate,
|
|
86
95
|
migrationConfig: migrationConfigs,
|
|
96
|
+
migrationComponentAliases,
|
|
97
|
+
migrationComponentOverrides,
|
|
87
98
|
filters: { withSlug, startsWith },
|
|
88
99
|
dryRun,
|
|
89
100
|
fromFilePath,
|
|
@@ -109,6 +120,8 @@ export const migrate = async (props) => {
|
|
|
109
120
|
to,
|
|
110
121
|
migrateFrom,
|
|
111
122
|
migrationConfig: migrationConfigs,
|
|
123
|
+
migrationComponentAliases,
|
|
124
|
+
migrationComponentOverrides,
|
|
112
125
|
filters: { withSlug, startsWith },
|
|
113
126
|
dryRun,
|
|
114
127
|
fromFilePath,
|
|
@@ -134,6 +147,8 @@ export const migrate = async (props) => {
|
|
|
134
147
|
case MIGRATE_COMMANDS.presets: {
|
|
135
148
|
Logger.log(`Migrating content with command: ${command}`);
|
|
136
149
|
const migrationConfigs = normalizeMigrationFlags(flags["migration"]);
|
|
150
|
+
const migrationComponentAliases = parseMigrationComponentAliasFlags(flags["migrationComponentAlias"]);
|
|
151
|
+
const migrationComponentOverrides = parseMigrationComponentOverrideFlags(flags["migrationComponents"]);
|
|
137
152
|
const fromFilePath = flags["fromFilePath"];
|
|
138
153
|
const migrateFromFlag = flags["migrateFrom"];
|
|
139
154
|
const fromFallback = migrateFromFlag === "file" && fromFilePath
|
|
@@ -169,6 +184,8 @@ export const migrate = async (props) => {
|
|
|
169
184
|
to,
|
|
170
185
|
migrateFrom,
|
|
171
186
|
migrationConfig: migrationConfigs[0],
|
|
187
|
+
migrationComponentAliases,
|
|
188
|
+
migrationComponentOverrides,
|
|
172
189
|
dryRun,
|
|
173
190
|
fromFilePath,
|
|
174
191
|
fileName,
|
package/dist/cli/helpers.js
CHANGED
|
@@ -19,18 +19,23 @@ export const askForConfirmation = async (message, resolveYes, resolveNo, ci) =>
|
|
|
19
19
|
output: process.stdout,
|
|
20
20
|
prompt: chalk.red(`${message} (y/n) > `),
|
|
21
21
|
});
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
22
|
+
try {
|
|
23
|
+
rl.prompt();
|
|
24
|
+
for await (const deletionConfirmation of rl) {
|
|
25
|
+
if (deletionConfirmation.trim() !== "y") {
|
|
26
|
+
await resolveNo();
|
|
27
|
+
process.exit(0);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
if (deletionConfirmation) {
|
|
31
|
+
await resolveYes();
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
32
34
|
}
|
|
35
|
+
rl.prompt();
|
|
33
36
|
}
|
|
34
|
-
|
|
37
|
+
}
|
|
38
|
+
finally {
|
|
39
|
+
rl.close();
|
|
35
40
|
}
|
|
36
41
|
};
|
package/dist/cli/index.js
CHANGED
|
@@ -61,6 +61,14 @@ app.migrate = () => ({
|
|
|
61
61
|
type: "string",
|
|
62
62
|
isMultiple: true,
|
|
63
63
|
},
|
|
64
|
+
migrationComponentAlias: {
|
|
65
|
+
type: "string",
|
|
66
|
+
isMultiple: true,
|
|
67
|
+
},
|
|
68
|
+
migrationComponents: {
|
|
69
|
+
type: "string",
|
|
70
|
+
isMultiple: true,
|
|
71
|
+
},
|
|
64
72
|
withSlug: {
|
|
65
73
|
type: "string",
|
|
66
74
|
isMultiple: true,
|
|
@@ -72,10 +72,21 @@ const updatePreset = (args, config) => {
|
|
|
72
72
|
})
|
|
73
73
|
.then((res) => {
|
|
74
74
|
logger_js_1.default.warning(`Preset: '${p.preset.name}' with '${p.preset.id}' id has been updated.`);
|
|
75
|
-
return
|
|
75
|
+
return {
|
|
76
|
+
ok: true,
|
|
77
|
+
id: p.preset.id,
|
|
78
|
+
name: p.preset.name,
|
|
79
|
+
data: res,
|
|
80
|
+
};
|
|
76
81
|
})
|
|
77
|
-
.catch(() => {
|
|
82
|
+
.catch((error) => {
|
|
78
83
|
logger_js_1.default.error(`Error happened. Preset: '${p.preset.name}' with '${p.preset.id}' id has been not updated.`);
|
|
84
|
+
return {
|
|
85
|
+
ok: false,
|
|
86
|
+
id: p.preset.id,
|
|
87
|
+
name: p.preset.name,
|
|
88
|
+
error,
|
|
89
|
+
};
|
|
79
90
|
});
|
|
80
91
|
};
|
|
81
92
|
exports.updatePreset = updatePreset;
|
|
@@ -130,9 +130,24 @@ const updateStory = (content, storyId, options, config) => {
|
|
|
130
130
|
})
|
|
131
131
|
.then((res) => {
|
|
132
132
|
console.log(`${chalk_1.default.green(res.data.story.full_slug)} updated.`);
|
|
133
|
-
return
|
|
133
|
+
return {
|
|
134
|
+
ok: true,
|
|
135
|
+
id: res.data.story.id,
|
|
136
|
+
name: res.data.story.name,
|
|
137
|
+
slug: res.data.story.full_slug,
|
|
138
|
+
data: res.data,
|
|
139
|
+
};
|
|
134
140
|
})
|
|
135
|
-
.catch((err) =>
|
|
141
|
+
.catch((err) => {
|
|
142
|
+
console.error(err);
|
|
143
|
+
return {
|
|
144
|
+
ok: false,
|
|
145
|
+
id: storyId,
|
|
146
|
+
name: content?.name,
|
|
147
|
+
slug: content?.full_slug || content?.slug,
|
|
148
|
+
error: err,
|
|
149
|
+
};
|
|
150
|
+
});
|
|
136
151
|
};
|
|
137
152
|
exports.updateStory = updateStory;
|
|
138
153
|
const updateStories = (args, config) => {
|