sb-mig 6.0.0-beta.3 → 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.
@@ -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) => {
@@ -507,6 +508,25 @@ export const doTheMigration = async ({ itemType = "story", from, itemsToMigrate,
507
508
  }, config);
508
509
  }
509
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
+ }
510
530
  if (writeSummary.failed === 0) {
511
531
  Logger.success(`[MIGRATION] Update complete. ${writeSummary.successful}/${writeSummary.total} ${itemType}(s) updated successfully.`);
512
532
  return;
@@ -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
+ };
@@ -3,6 +3,9 @@ export interface MutationWriteResult {
3
3
  id?: number | string;
4
4
  name?: string;
5
5
  slug?: string;
6
+ spaceId?: string;
7
+ status?: number | string;
8
+ response?: string | null;
6
9
  error?: unknown;
7
10
  }
8
11
  export interface MutationWriteSummary {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sb-mig",
3
- "version": "6.0.0-beta.3",
3
+ "version": "6.0.0-beta.4",
4
4
  "description": "CLI to rule the world. (and handle stuff related to Storyblok CMS)",
5
5
  "author": "Marcin Krawczyk <marckraw@icloud.com>",
6
6
  "license": "MIT",