@squiz/dxp-cli-next 5.33.0-develop.3 → 5.33.0-develop.5

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.
Files changed (73) hide show
  1. package/README.md +1 -0
  2. package/lib/migration/batch-get/batch-get.d.ts +3 -0
  3. package/lib/migration/batch-get/batch-get.js +45 -0
  4. package/lib/migration/batch-get/batch-get.spec.js +182 -0
  5. package/lib/migration/batch-next/batch-next.d.ts +3 -0
  6. package/lib/migration/batch-next/batch-next.js +60 -0
  7. package/lib/migration/batch-next/batch-next.spec.d.ts +1 -0
  8. package/lib/migration/batch-next/batch-next.spec.js +251 -0
  9. package/lib/migration/batch-revert/batch-revert.d.ts +3 -0
  10. package/lib/migration/batch-revert/batch-revert.js +45 -0
  11. package/lib/migration/batch-revert/batch-revert.spec.d.ts +1 -0
  12. package/lib/migration/batch-revert/batch-revert.spec.js +197 -0
  13. package/lib/migration/create/create.js +27 -7
  14. package/lib/migration/create/create.spec.js +48 -20
  15. package/lib/migration/get/get.js +3 -3
  16. package/lib/migration/get/get.spec.js +8 -19
  17. package/lib/migration/index.js +9 -1
  18. package/lib/migration/list/list.spec.js +7 -6
  19. package/lib/migration/mark-deployed/mark-deployed.d.ts +3 -0
  20. package/lib/migration/mark-deployed/mark-deployed.js +55 -0
  21. package/lib/migration/mark-deployed/mark-deployed.spec.d.ts +1 -0
  22. package/lib/migration/mark-deployed/mark-deployed.spec.js +217 -0
  23. package/lib/migration/next/next.spec.js +6 -5
  24. package/lib/migration/pre/pre.js +3 -3
  25. package/lib/migration/pre/pre.spec.js +8 -8
  26. package/lib/migration/revert/revert.js +1 -1
  27. package/lib/migration/revert/revert.spec.js +1 -1
  28. package/lib/migration/settings/settings.spec.js +2 -2
  29. package/lib/migration/types/common.types.d.ts +33 -2
  30. package/lib/migration/types/common.types.js +17 -0
  31. package/lib/migration/types/createMigration.types.d.ts +41 -3
  32. package/lib/migration/types/getMigration.types.d.ts +5 -1
  33. package/lib/migration/types/index.d.ts +1 -0
  34. package/lib/migration/types/index.js +1 -0
  35. package/lib/migration/types/markDeployed.types.d.ts +20 -0
  36. package/lib/migration/types/markDeployed.types.js +2 -0
  37. package/lib/migration/types/nextStage.types.d.ts +22 -1
  38. package/lib/migration/types/revert.types.d.ts +12 -0
  39. package/lib/migration/utils/common.d.ts +17 -3
  40. package/lib/migration/utils/common.js +56 -24
  41. package/lib/migration/utils/common.spec.js +73 -2
  42. package/lib/migration/utils/createMigration.d.ts +4 -21
  43. package/lib/migration/utils/createMigration.js +23 -32
  44. package/lib/migration/utils/createMigration.spec.js +19 -18
  45. package/lib/migration/utils/getMigration.d.ts +2 -1
  46. package/lib/migration/utils/getMigration.js +23 -18
  47. package/lib/migration/utils/getMigration.spec.js +146 -7
  48. package/lib/migration/utils/index.d.ts +1 -0
  49. package/lib/migration/utils/index.js +1 -0
  50. package/lib/migration/utils/listMigrations.spec.js +7 -6
  51. package/lib/migration/utils/loadAssetIdsFromFile.d.ts +9 -0
  52. package/lib/migration/utils/loadAssetIdsFromFile.js +40 -0
  53. package/lib/migration/utils/loadAssetIdsFromFile.spec.d.ts +1 -0
  54. package/lib/migration/utils/{loadCctIdsFromFile.spec.js → loadAssetIdsFromFile.spec.js} +13 -13
  55. package/lib/migration/utils/loadStageOptionsFromFile.d.ts +2 -1
  56. package/lib/migration/utils/markComponentsDeployed.d.ts +2 -0
  57. package/lib/migration/utils/markComponentsDeployed.js +37 -0
  58. package/lib/migration/utils/markComponentsDeployed.spec.d.ts +1 -0
  59. package/lib/migration/utils/markComponentsDeployed.spec.js +222 -0
  60. package/lib/migration/utils/nextStage.d.ts +2 -1
  61. package/lib/migration/utils/nextStage.js +32 -22
  62. package/lib/migration/utils/nextStage.spec.js +179 -7
  63. package/lib/migration/utils/options.d.ts +4 -1
  64. package/lib/migration/utils/options.js +32 -2
  65. package/lib/migration/utils/revertMigration.d.ts +2 -1
  66. package/lib/migration/utils/revertMigration.js +21 -1
  67. package/lib/migration/utils/revertMigration.spec.js +115 -0
  68. package/lib/page/utils/definitions.js +7 -1
  69. package/lib/page/utils/definitions.spec.js +26 -0
  70. package/package.json +1 -1
  71. package/lib/migration/utils/loadCctIdsFromFile.d.ts +0 -1
  72. package/lib/migration/utils/loadCctIdsFromFile.js +0 -32
  73. /package/lib/migration/{utils/loadCctIdsFromFile.spec.d.ts → batch-get/batch-get.spec.d.ts} +0 -0
package/README.md CHANGED
@@ -25,6 +25,7 @@ Commands:
25
25
  job-runner Job Runner Service Commands
26
26
  datastore Datastore Service Commands
27
27
  cdp Customer Data Platform Service Commands
28
+ migration Asset/Page Migrator Tool Commands (internal)
28
29
  ```
29
30
 
30
31
  <!-- TODO: porter command is hidden behind feature flag -->
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ declare const batchGetMigrationCommand: () => Command;
3
+ export default batchGetMigrationCommand;
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ const chalk_1 = __importDefault(require("chalk"));
16
+ const commander_1 = require("commander");
17
+ const utils_1 = require("../utils");
18
+ const ora_1 = __importDefault(require("ora"));
19
+ const batchGetMigrationCommand = () => {
20
+ const batchGetCommand = new commander_1.Command('batch-get')
21
+ .name('batch-get')
22
+ .description('Get migration summary for all assets in a migration batch using the AI Page migration service')
23
+ .addOption((0, utils_1.getParamOption)(utils_1.OptionName.MIGRATION_ID))
24
+ .addOption((0, utils_1.getParamOption)(utils_1.OptionName.TENANT, false))
25
+ .configureOutput({
26
+ outputError(str, write) {
27
+ write(chalk_1.default.red(str));
28
+ },
29
+ })
30
+ .action((options) => __awaiter(void 0, void 0, void 0, function* () {
31
+ yield (0, utils_1.throwErrorIfNotLoggedIn)(batchGetCommand);
32
+ const spinner = (0, ora_1.default)('Getting migration summary').start();
33
+ try {
34
+ const response = yield (0, utils_1.batchGetMigration)(options);
35
+ spinner.succeed(`Migration summary: ${JSON.stringify(response, null, 2)}`);
36
+ }
37
+ catch (error) {
38
+ spinner.fail();
39
+ (0, utils_1.handleCommandError)(batchGetCommand, error);
40
+ }
41
+ }));
42
+ (0, utils_1.addOverrideUrlOption)(batchGetCommand);
43
+ return batchGetCommand;
44
+ };
45
+ exports.default = batchGetMigrationCommand;
@@ -0,0 +1,182 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
+ return new (P || (P = Promise))(function (resolve, reject) {
28
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
32
+ });
33
+ };
34
+ var __importDefault = (this && this.__importDefault) || function (mod) {
35
+ return (mod && mod.__esModule) ? mod : { "default": mod };
36
+ };
37
+ Object.defineProperty(exports, "__esModule", { value: true });
38
+ const nock_1 = __importDefault(require("nock"));
39
+ const batch_get_1 = __importDefault(require("./batch-get"));
40
+ const utils = __importStar(require("../utils/common"));
41
+ const ApplicationStore = __importStar(require("../../ApplicationStore"));
42
+ const getMigrationModule = __importStar(require("../utils/getMigration"));
43
+ jest.mock('../utils/common');
44
+ jest.mock('../utils/getMigration');
45
+ jest.mock('../../ApplicationStore');
46
+ const mockUtils = utils;
47
+ const mockGetMigration = getMigrationModule;
48
+ const mockApplicationStore = ApplicationStore;
49
+ describe('batchGetMigrationCommand', () => {
50
+ let logSpy;
51
+ let mockBatchGetMigrationResponse;
52
+ beforeEach(() => {
53
+ nock_1.default.cleanAll();
54
+ jest.clearAllMocks();
55
+ jest.resetAllMocks();
56
+ logSpy = jest.spyOn(console, 'log').mockImplementation(() => { });
57
+ mockApplicationStore.getApplicationFile.mockResolvedValue('session-cookie');
58
+ mockUtils.throwErrorIfNotLoggedIn.mockResolvedValue(undefined);
59
+ mockBatchGetMigrationResponse = {
60
+ migrationId: 'migration-123',
61
+ created: 1718230800000,
62
+ expiry: 1718317200000,
63
+ };
64
+ mockGetMigration.batchGetMigration.mockResolvedValue(mockBatchGetMigrationResponse);
65
+ });
66
+ afterEach(() => {
67
+ logSpy.mockRestore();
68
+ });
69
+ describe('successful batch migration retrieval', () => {
70
+ it('should get batch migration successfully with required options', () => __awaiter(void 0, void 0, void 0, function* () {
71
+ const program = (0, batch_get_1.default)();
72
+ yield program.parseAsync([
73
+ 'node',
74
+ 'dxp-cli',
75
+ '--migration-id',
76
+ 'migration-123',
77
+ ]);
78
+ expect(mockUtils.throwErrorIfNotLoggedIn).toHaveBeenCalledWith(program);
79
+ expect(mockGetMigration.batchGetMigration).toHaveBeenCalledWith({
80
+ migrationId: 'migration-123',
81
+ });
82
+ expect(mockGetMigration.batchGetMigration).toHaveBeenCalledTimes(1);
83
+ expect(mockUtils.handleCommandError).not.toHaveBeenCalled();
84
+ }));
85
+ it('should get batch migration with tenant option', () => __awaiter(void 0, void 0, void 0, function* () {
86
+ const program = (0, batch_get_1.default)();
87
+ yield program.parseAsync([
88
+ 'node',
89
+ 'dxp-cli',
90
+ '--migration-id',
91
+ 'migration-123',
92
+ '--tenant',
93
+ 'test-tenant',
94
+ ]);
95
+ expect(mockGetMigration.batchGetMigration).toHaveBeenCalledWith({
96
+ migrationId: 'migration-123',
97
+ tenant: 'test-tenant',
98
+ });
99
+ }));
100
+ it('should get batch migration with override URL when environment variable is set', () => __awaiter(void 0, void 0, void 0, function* () {
101
+ const originalEnv = process.env.ENABLE_OVERRIDE_MIGRATION_URL;
102
+ process.env.ENABLE_OVERRIDE_MIGRATION_URL = 'true';
103
+ const program = (0, batch_get_1.default)();
104
+ yield program.parseAsync([
105
+ 'node',
106
+ 'dxp-cli',
107
+ '--migration-id',
108
+ 'migration-123',
109
+ '--overrideUrl',
110
+ 'https://custom.migration.url',
111
+ ]);
112
+ expect(mockGetMigration.batchGetMigration).toHaveBeenCalledWith({
113
+ migrationId: 'migration-123',
114
+ overrideUrl: 'https://custom.migration.url',
115
+ });
116
+ process.env.ENABLE_OVERRIDE_MIGRATION_URL = originalEnv;
117
+ }));
118
+ });
119
+ describe('error scenarios', () => {
120
+ it('should handle batchGetMigration API error', () => __awaiter(void 0, void 0, void 0, function* () {
121
+ const apiError = new Error('Migration not found');
122
+ mockGetMigration.batchGetMigration.mockRejectedValue(apiError);
123
+ mockUtils.handleCommandError.mockImplementation((() => { }));
124
+ const program = (0, batch_get_1.default)();
125
+ yield program.parseAsync([
126
+ 'node',
127
+ 'dxp-cli',
128
+ '--migration-id',
129
+ 'migration-123',
130
+ ]);
131
+ expect(mockUtils.handleCommandError).toHaveBeenCalledWith(program, apiError);
132
+ }));
133
+ it('should handle network error', () => __awaiter(void 0, void 0, void 0, function* () {
134
+ const networkError = new Error('Network connection failed');
135
+ mockGetMigration.batchGetMigration.mockRejectedValue(networkError);
136
+ mockUtils.handleCommandError.mockImplementation((() => { }));
137
+ const program = (0, batch_get_1.default)();
138
+ yield program.parseAsync([
139
+ 'node',
140
+ 'dxp-cli',
141
+ '--migration-id',
142
+ 'migration-123',
143
+ ]);
144
+ expect(mockUtils.handleCommandError).toHaveBeenCalledWith(program, networkError);
145
+ }));
146
+ });
147
+ describe('required options validation', () => {
148
+ it('should require migration-id option', () => {
149
+ const program = (0, batch_get_1.default)().exitOverride();
150
+ expect(() => {
151
+ program.parse(['node', 'dxp-cli']);
152
+ }).toThrow();
153
+ });
154
+ it('should not require tenant option', () => {
155
+ const program = (0, batch_get_1.default)().exitOverride();
156
+ expect(() => {
157
+ program.parse(['node', 'dxp-cli', '--migration-id', 'migration-123']);
158
+ }).not.toThrow();
159
+ });
160
+ });
161
+ describe('command configuration', () => {
162
+ it('should have correct command name and description', () => {
163
+ const program = (0, batch_get_1.default)();
164
+ expect(program.name()).toBe('batch-get');
165
+ expect(program.description()).toBe('Get migration summary for all assets in a migration batch using the AI Page migration service');
166
+ });
167
+ it('should parse options correctly', () => {
168
+ const program = (0, batch_get_1.default)();
169
+ program.parse([
170
+ 'node',
171
+ 'dxp-cli',
172
+ '--migration-id',
173
+ 'migration-123',
174
+ '--tenant',
175
+ 'test-tenant',
176
+ ]);
177
+ const opts = program.opts();
178
+ expect(opts.migrationId).toBe('migration-123');
179
+ expect(opts.tenant).toBe('test-tenant');
180
+ });
181
+ });
182
+ });
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ declare const batchNextStageCommand: () => Command;
3
+ export default batchNextStageCommand;
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __rest = (this && this.__rest) || function (s, e) {
12
+ var t = {};
13
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
14
+ t[p] = s[p];
15
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
16
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
17
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
18
+ t[p[i]] = s[p[i]];
19
+ }
20
+ return t;
21
+ };
22
+ var __importDefault = (this && this.__importDefault) || function (mod) {
23
+ return (mod && mod.__esModule) ? mod : { "default": mod };
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ const commander_1 = require("commander");
27
+ const chalk_1 = __importDefault(require("chalk"));
28
+ const ora_1 = __importDefault(require("ora"));
29
+ const utils_1 = require("../utils");
30
+ const batchNextStageCommand = () => {
31
+ const batchNextCommand = new commander_1.Command('batch-next')
32
+ .name('batch-next')
33
+ .description('Triggers the next step of the migration for all assets in the migration batch')
34
+ .addOption((0, utils_1.getParamOption)(utils_1.OptionName.MIGRATION_ID))
35
+ .addOption((0, utils_1.getParamOption)(utils_1.OptionName.STAGE))
36
+ .addOption((0, utils_1.getParamOption)(utils_1.OptionName.TENANT, false))
37
+ .addOption((0, utils_1.getParamOption)(utils_1.OptionName.STAGE_OPTIONS, false))
38
+ .configureOutput({
39
+ outputError(str, write) {
40
+ write(chalk_1.default.red(str));
41
+ },
42
+ })
43
+ .action((options) => __awaiter(void 0, void 0, void 0, function* () {
44
+ yield (0, utils_1.throwErrorIfNotLoggedIn)(batchNextCommand);
45
+ const spinner = (0, ora_1.default)('Starting batch next stage').start();
46
+ try {
47
+ const { stageOptions: stageOptionsPath } = options, otherOptions = __rest(options, ["stageOptions"]);
48
+ const stageOptions = (0, utils_1.loadStageOptionsFromFile)(stageOptionsPath);
49
+ const response = yield (0, utils_1.batchNextStage)(Object.assign(Object.assign({}, otherOptions), (stageOptions && { stageOptions })));
50
+ spinner.succeed((0, utils_1.formatBatchOperationResult)(response.success, response.failed));
51
+ }
52
+ catch (error) {
53
+ spinner.fail();
54
+ (0, utils_1.handleCommandError)(batchNextCommand, error);
55
+ }
56
+ }));
57
+ (0, utils_1.addOverrideUrlOption)(batchNextCommand);
58
+ return batchNextCommand;
59
+ };
60
+ exports.default = batchNextStageCommand;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,251 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
+ return new (P || (P = Promise))(function (resolve, reject) {
28
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
32
+ });
33
+ };
34
+ var __importDefault = (this && this.__importDefault) || function (mod) {
35
+ return (mod && mod.__esModule) ? mod : { "default": mod };
36
+ };
37
+ Object.defineProperty(exports, "__esModule", { value: true });
38
+ const nock_1 = __importDefault(require("nock"));
39
+ const batch_next_1 = __importDefault(require("./batch-next"));
40
+ const utils = __importStar(require("../utils/common"));
41
+ const ApplicationStore = __importStar(require("../../ApplicationStore"));
42
+ const nextStageModule = __importStar(require("../utils/nextStage"));
43
+ const loadStageOptionsModule = __importStar(require("../utils/loadStageOptionsFromFile"));
44
+ jest.mock('../utils/common');
45
+ jest.mock('../utils/nextStage');
46
+ jest.mock('../utils/loadStageOptionsFromFile');
47
+ jest.mock('../../ApplicationStore');
48
+ const mockUtils = utils;
49
+ const mockNextStage = nextStageModule;
50
+ const mockLoadStageOptions = loadStageOptionsModule;
51
+ const mockApplicationStore = ApplicationStore;
52
+ describe('batchNextStageCommand', () => {
53
+ let logSpy;
54
+ let mockBatchNextStageResponse;
55
+ beforeEach(() => {
56
+ nock_1.default.cleanAll();
57
+ jest.clearAllMocks();
58
+ jest.resetAllMocks();
59
+ logSpy = jest.spyOn(console, 'log').mockImplementation(() => { });
60
+ mockApplicationStore.getApplicationFile.mockResolvedValue('session-cookie');
61
+ mockUtils.throwErrorIfNotLoggedIn.mockResolvedValue(undefined);
62
+ mockLoadStageOptions.loadStageOptionsFromFile.mockReturnValue(undefined);
63
+ mockBatchNextStageResponse = {
64
+ success: [
65
+ { assetIds: ['asset-1', 'asset-2'], message: 'Stage completed' },
66
+ ],
67
+ failed: [],
68
+ };
69
+ mockNextStage.batchNextStage.mockResolvedValue(mockBatchNextStageResponse);
70
+ });
71
+ afterEach(() => {
72
+ logSpy.mockRestore();
73
+ });
74
+ describe('successful batch next stage execution', () => {
75
+ it('should execute batch next stage successfully with required options', () => __awaiter(void 0, void 0, void 0, function* () {
76
+ const program = (0, batch_next_1.default)();
77
+ yield program.parseAsync([
78
+ 'node',
79
+ 'dxp-cli',
80
+ '--migration-id',
81
+ 'migration-123',
82
+ '--stage',
83
+ 'preview',
84
+ ]);
85
+ expect(mockUtils.throwErrorIfNotLoggedIn).toHaveBeenCalledWith(program);
86
+ expect(mockNextStage.batchNextStage).toHaveBeenCalledWith({
87
+ migrationId: 'migration-123',
88
+ stage: 'preview',
89
+ });
90
+ expect(mockNextStage.batchNextStage).toHaveBeenCalledTimes(1);
91
+ expect(mockUtils.handleCommandError).not.toHaveBeenCalled();
92
+ }));
93
+ it('should execute batch next stage with tenant option', () => __awaiter(void 0, void 0, void 0, function* () {
94
+ const program = (0, batch_next_1.default)();
95
+ yield program.parseAsync([
96
+ 'node',
97
+ 'dxp-cli',
98
+ '--migration-id',
99
+ 'migration-123',
100
+ '--stage',
101
+ 'preview',
102
+ '--tenant',
103
+ 'test-tenant',
104
+ ]);
105
+ expect(mockNextStage.batchNextStage).toHaveBeenCalledWith({
106
+ migrationId: 'migration-123',
107
+ stage: 'preview',
108
+ tenant: 'test-tenant',
109
+ });
110
+ }));
111
+ it('should execute batch next stage with stage options', () => __awaiter(void 0, void 0, void 0, function* () {
112
+ mockLoadStageOptions.loadStageOptionsFromFile.mockReturnValue({
113
+ skipValidation: true,
114
+ });
115
+ const program = (0, batch_next_1.default)();
116
+ yield program.parseAsync([
117
+ 'node',
118
+ 'dxp-cli',
119
+ '--migration-id',
120
+ 'migration-123',
121
+ '--stage',
122
+ 'preview',
123
+ '--stage-options',
124
+ './options.json',
125
+ ]);
126
+ expect(mockLoadStageOptions.loadStageOptionsFromFile).toHaveBeenCalledWith('./options.json');
127
+ expect(mockNextStage.batchNextStage).toHaveBeenCalledWith({
128
+ migrationId: 'migration-123',
129
+ stage: 'preview',
130
+ stageOptions: { skipValidation: true },
131
+ });
132
+ }));
133
+ it('should execute batch next stage with override URL when environment variable is set', () => __awaiter(void 0, void 0, void 0, function* () {
134
+ const originalEnv = process.env.ENABLE_OVERRIDE_MIGRATION_URL;
135
+ process.env.ENABLE_OVERRIDE_MIGRATION_URL = 'true';
136
+ const program = (0, batch_next_1.default)();
137
+ yield program.parseAsync([
138
+ 'node',
139
+ 'dxp-cli',
140
+ '--migration-id',
141
+ 'migration-123',
142
+ '--stage',
143
+ 'preview',
144
+ '--overrideUrl',
145
+ 'https://custom.migration.url',
146
+ ]);
147
+ expect(mockNextStage.batchNextStage).toHaveBeenCalledWith({
148
+ migrationId: 'migration-123',
149
+ stage: 'preview',
150
+ overrideUrl: 'https://custom.migration.url',
151
+ });
152
+ process.env.ENABLE_OVERRIDE_MIGRATION_URL = originalEnv;
153
+ }));
154
+ });
155
+ describe('error scenarios', () => {
156
+ it('should handle batchNextStage API error', () => __awaiter(void 0, void 0, void 0, function* () {
157
+ const apiError = new Error('Failed to trigger next stage');
158
+ mockNextStage.batchNextStage.mockRejectedValue(apiError);
159
+ mockUtils.handleCommandError.mockImplementation((() => { }));
160
+ const program = (0, batch_next_1.default)();
161
+ yield program.parseAsync([
162
+ 'node',
163
+ 'dxp-cli',
164
+ '--migration-id',
165
+ 'migration-123',
166
+ '--stage',
167
+ 'preview',
168
+ ]);
169
+ expect(mockUtils.handleCommandError).toHaveBeenCalledWith(program, apiError);
170
+ }));
171
+ it('should handle network error', () => __awaiter(void 0, void 0, void 0, function* () {
172
+ const networkError = new Error('Network connection failed');
173
+ mockNextStage.batchNextStage.mockRejectedValue(networkError);
174
+ mockUtils.handleCommandError.mockImplementation((() => { }));
175
+ const program = (0, batch_next_1.default)();
176
+ yield program.parseAsync([
177
+ 'node',
178
+ 'dxp-cli',
179
+ '--migration-id',
180
+ 'migration-123',
181
+ '--stage',
182
+ 'preview',
183
+ ]);
184
+ expect(mockUtils.handleCommandError).toHaveBeenCalledWith(program, networkError);
185
+ }));
186
+ });
187
+ describe('required options validation', () => {
188
+ it('should require migration-id option', () => {
189
+ const program = (0, batch_next_1.default)().exitOverride();
190
+ expect(() => {
191
+ program.parse(['node', 'dxp-cli', '--stage', 'preview']);
192
+ }).toThrow();
193
+ });
194
+ it('should require stage option', () => {
195
+ const program = (0, batch_next_1.default)().exitOverride();
196
+ expect(() => {
197
+ program.parse(['node', 'dxp-cli', '--migration-id', 'migration-123']);
198
+ }).toThrow();
199
+ });
200
+ it('should not require tenant option', () => {
201
+ const program = (0, batch_next_1.default)().exitOverride();
202
+ expect(() => {
203
+ program.parse([
204
+ 'node',
205
+ 'dxp-cli',
206
+ '--migration-id',
207
+ 'migration-123',
208
+ '--stage',
209
+ 'preview',
210
+ ]);
211
+ }).not.toThrow();
212
+ });
213
+ });
214
+ describe('command configuration', () => {
215
+ it('should have correct command name and description', () => {
216
+ const program = (0, batch_next_1.default)();
217
+ expect(program.name()).toBe('batch-next');
218
+ expect(program.description()).toBe('Triggers the next step of the migration for all assets in the migration batch');
219
+ });
220
+ it('should parse options correctly', () => {
221
+ const program = (0, batch_next_1.default)();
222
+ program.parse([
223
+ 'node',
224
+ 'dxp-cli',
225
+ '--migration-id',
226
+ 'migration-123',
227
+ '--stage',
228
+ 'preview',
229
+ '--tenant',
230
+ 'test-tenant',
231
+ ]);
232
+ const opts = program.opts();
233
+ expect(opts.migrationId).toBe('migration-123');
234
+ expect(opts.stage).toBe('preview');
235
+ expect(opts.tenant).toBe('test-tenant');
236
+ });
237
+ it('should validate stage option choices', () => {
238
+ const program = (0, batch_next_1.default)().exitOverride();
239
+ expect(() => {
240
+ program.parse([
241
+ 'node',
242
+ 'dxp-cli',
243
+ '--migration-id',
244
+ 'migration-123',
245
+ '--stage',
246
+ 'invalid-stage',
247
+ ]);
248
+ }).toThrow();
249
+ });
250
+ });
251
+ });
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ declare const batchRevertMigrationCommand: () => Command;
3
+ export default batchRevertMigrationCommand;
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ const commander_1 = require("commander");
16
+ const chalk_1 = __importDefault(require("chalk"));
17
+ const ora_1 = __importDefault(require("ora"));
18
+ const utils_1 = require("../utils");
19
+ const batchRevertMigrationCommand = () => {
20
+ const batchRevertCommand = new commander_1.Command('batch-revert')
21
+ .name('batch-revert')
22
+ .description('Revert all assets with stage "morph" and status "awaiting-confirmation" in a migration batch using the AI Page migration service')
23
+ .addOption((0, utils_1.getParamOption)(utils_1.OptionName.MIGRATION_ID))
24
+ .addOption((0, utils_1.getParamOption)(utils_1.OptionName.TENANT, false))
25
+ .configureOutput({
26
+ outputError(str, write) {
27
+ write(chalk_1.default.red(str));
28
+ },
29
+ })
30
+ .action((options) => __awaiter(void 0, void 0, void 0, function* () {
31
+ yield (0, utils_1.throwErrorIfNotLoggedIn)(batchRevertCommand);
32
+ const spinner = (0, ora_1.default)('Reverting migration batch...').start();
33
+ try {
34
+ const response = yield (0, utils_1.batchRevertMigration)(options);
35
+ spinner.succeed((0, utils_1.formatBatchOperationResult)(response.success, response.failed));
36
+ }
37
+ catch (error) {
38
+ spinner.fail();
39
+ (0, utils_1.handleCommandError)(batchRevertCommand, error);
40
+ }
41
+ }));
42
+ (0, utils_1.addOverrideUrlOption)(batchRevertCommand);
43
+ return batchRevertCommand;
44
+ };
45
+ exports.default = batchRevertMigrationCommand;
@@ -0,0 +1 @@
1
+ export {};