@squiz/dxp-cli-next 5.31.0 → 5.32.0-develop.2

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 (61) hide show
  1. package/lib/cdp/instance/activate/activate.js +6 -7
  2. package/lib/cdp/instance/activate/activate.spec.js +2 -8
  3. package/lib/cdp/utils.d.ts +2 -1
  4. package/lib/cdp/utils.js +4 -2
  5. package/lib/migration/create/create.js +5 -8
  6. package/lib/migration/create/create.spec.js +1 -0
  7. package/lib/migration/index.js +2 -0
  8. package/lib/migration/pre/pre.d.ts +3 -0
  9. package/lib/migration/pre/pre.js +54 -0
  10. package/lib/migration/pre/pre.spec.d.ts +1 -0
  11. package/lib/migration/pre/pre.spec.js +269 -0
  12. package/lib/migration/types/common.types.d.ts +10 -0
  13. package/lib/migration/types/createMigration.types.d.ts +4 -0
  14. package/lib/migration/types/index.d.ts +1 -0
  15. package/lib/migration/types/index.js +1 -0
  16. package/lib/migration/types/preMigration.types.d.ts +10 -0
  17. package/lib/migration/types/preMigration.types.js +2 -0
  18. package/lib/migration/utils/common.d.ts +8 -0
  19. package/lib/migration/utils/common.js +19 -1
  20. package/lib/migration/utils/createMigration.d.ts +26 -2
  21. package/lib/migration/utils/createMigration.js +13 -6
  22. package/lib/migration/utils/loadCctIdsFromFile.d.ts +1 -0
  23. package/lib/migration/utils/loadCctIdsFromFile.js +32 -0
  24. package/lib/migration/utils/loadCctIdsFromFile.spec.d.ts +1 -0
  25. package/lib/migration/utils/loadCctIdsFromFile.spec.js +91 -0
  26. package/lib/migration/utils/options.d.ts +2 -1
  27. package/lib/migration/utils/options.js +8 -0
  28. package/lib/page/layouts/deploy/deploy.js +44 -9
  29. package/lib/page/layouts/deploy/deploy.spec.js +110 -19
  30. package/lib/page/layouts/dev/dev.js +18 -4
  31. package/lib/page/layouts/dev/dev.spec.js +117 -8
  32. package/lib/page/layouts/validation/index.d.ts +2 -0
  33. package/lib/page/layouts/validation/index.js +5 -1
  34. package/lib/page/layouts/validation/property-consistency.d.ts +7 -0
  35. package/lib/page/layouts/validation/property-consistency.js +92 -0
  36. package/lib/page/layouts/validation/property-consistency.spec.d.ts +1 -0
  37. package/lib/page/layouts/validation/property-consistency.spec.js +305 -0
  38. package/lib/page/layouts/validation/validateLayoutFormat.d.ts +2 -0
  39. package/lib/page/layouts/validation/validateLayoutFormat.js +27 -0
  40. package/lib/page/layouts/validation/validateLayoutFormat.spec.d.ts +1 -0
  41. package/lib/page/layouts/validation/validateLayoutFormat.spec.js +42 -0
  42. package/lib/page/layouts/validation/zone-consistency.d.ts +1 -1
  43. package/lib/page/layouts/validation/zone-consistency.js +10 -9
  44. package/lib/page/layouts/validation/zone-consistency.spec.js +32 -34
  45. package/lib/page/utils/definitions.d.ts +347 -50
  46. package/lib/page/utils/definitions.js +103 -22
  47. package/lib/page/utils/definitions.spec.js +516 -267
  48. package/lib/page/utils/normalize.d.ts +8 -0
  49. package/lib/page/utils/normalize.js +61 -0
  50. package/lib/page/utils/normalize.spec.d.ts +1 -0
  51. package/lib/page/utils/normalize.spec.js +315 -0
  52. package/lib/page/utils/parse-args.d.ts +20 -4
  53. package/lib/page/utils/parse-args.js +48 -13
  54. package/lib/page/utils/parse-args.spec.js +159 -21
  55. package/lib/page/utils/render.d.ts +27 -9
  56. package/lib/page/utils/render.js +66 -12
  57. package/lib/page/utils/render.spec.js +14 -14
  58. package/lib/page/utils/server.d.ts +1 -1
  59. package/lib/page/utils/server.js +2 -2
  60. package/lib/page/utils/server.spec.js +13 -13
  61. package/package.json +1 -1
@@ -62,10 +62,11 @@ const createActivateCommand = () => {
62
62
  else {
63
63
  apiUrl = `${scvDeployBaseUrl.dxpUrl}`;
64
64
  }
65
+ const headerConfig = {
66
+ headers: Object.assign({}, (!hasRegion && { 'x-dxp-tenant': tenant })),
67
+ };
65
68
  const getDeployResponse = (yield apiService.client
66
- .get(apiUrl, {
67
- headers: Object.assign({ 'Content-Type': 'application/json' }, (!hasRegion && { 'x-dxp-tenant': tenant })),
68
- })
69
+ .get(apiUrl, headerConfig)
69
70
  .catch((err) => {
70
71
  (0, utils_1.logDebug)(`RAW ERROR: ${JSON.stringify(err)}`);
71
72
  if (err.response && err.response.status != 404) {
@@ -77,9 +78,7 @@ const createActivateCommand = () => {
77
78
  }
78
79
  (0, utils_1.logDebug)(`PUT ${apiUrl}`);
79
80
  const activateInstanceAndDeploySchemaResponse = (yield apiService.client
80
- .put(apiUrl, undefined, {
81
- headers: Object.assign({ 'Content-Type': 'application/json' }, (!hasRegion && { 'x-dxp-tenant': tenant })),
82
- })
81
+ .put(apiUrl, undefined, headerConfig)
83
82
  .catch((err) => {
84
83
  (0, utils_1.logDebug)(`RAW ERROR: ${JSON.stringify(err)}`);
85
84
  if (err.response) {
@@ -90,7 +89,7 @@ const createActivateCommand = () => {
90
89
  if (activateInstanceAndDeploySchemaResponse.status === 409) {
91
90
  throw new Error('Currently activating instance. Please try again later.');
92
91
  }
93
- yield (0, utils_1.pollForDeployedSchema)(apiUrl, apiService);
92
+ yield (0, utils_1.pollForDeployedSchema)(apiUrl, apiService, headerConfig);
94
93
  spinner.succeed('Done!');
95
94
  console.log('');
96
95
  console.log('Your Schema has been deployed and instance has been activated.');
@@ -103,9 +103,7 @@ describe('cdpInstanceCommand', () => {
103
103
  const program = (0, activate_1.default)();
104
104
  yield program.parseAsync((0, utils_1.createMockActivateArgs)(region));
105
105
  expect(mockedAxiosInstance.put).toHaveBeenCalledWith(`http://localhost:9999/__dxp/${region}/scv-deploy/${mockTenant}`, undefined, {
106
- headers: {
107
- 'Content-Type': 'application/json',
108
- },
106
+ headers: {},
109
107
  });
110
108
  expect(logSpy).toHaveBeenNthCalledWith(1, '');
111
109
  expect(logSpy).toHaveBeenNthCalledWith(2, '');
@@ -139,9 +137,7 @@ describe('cdpInstanceCommand', () => {
139
137
  const program = (0, activate_1.default)();
140
138
  yield program.parseAsync((0, utils_1.createMockActivateArgs)(region));
141
139
  expect(mockedAxios.put).toHaveBeenCalledWith(`http://localhost:9999/__dxp/${region}/scv-deploy/${mockTenant}`, undefined, {
142
- headers: {
143
- 'Content-Type': 'application/json',
144
- },
140
+ headers: {},
145
141
  });
146
142
  expect(errorSpy).toHaveBeenCalledWith(expect.stringContaining('Currently activating instance. Please try again later.'));
147
143
  }));
@@ -209,7 +205,6 @@ describe('cdpInstanceCommand', () => {
209
205
  yield program.parseAsync(createMockArgs());
210
206
  expect(mockedAxiosInstance.put).toHaveBeenCalledWith('http://localhost:9999/__dxp/service/scv-deploy', undefined, {
211
207
  headers: {
212
- 'Content-Type': 'application/json',
213
208
  'x-dxp-tenant': 'myTenant',
214
209
  },
215
210
  });
@@ -250,7 +245,6 @@ describe('cdpInstanceCommand', () => {
250
245
  yield program.parseAsync(createMockArgs());
251
246
  expect(mockedAxios.put).toHaveBeenCalledWith('http://localhost:9999/__dxp/service/scv-deploy', undefined, {
252
247
  headers: {
253
- 'Content-Type': 'application/json',
254
248
  'x-dxp-tenant': 'myTenant',
255
249
  },
256
250
  });
@@ -1,4 +1,5 @@
1
1
  import { Command } from 'commander';
2
+ import { AxiosRequestConfig } from 'axios';
2
3
  import { ApiService } from '../ApiService';
3
4
  export interface tenantDetails {
4
5
  tenantid: string;
@@ -19,4 +20,4 @@ export declare function createMockActivateArgs(region: string): Array<string>;
19
20
  /**
20
21
  * Poll the schema to be deployed.
21
22
  */
22
- export declare function pollForDeployedSchema(endpointUrl: string, apiService: ApiService): Promise<unknown>;
23
+ export declare function pollForDeployedSchema(endpointUrl: string, apiService: ApiService, requestConfig?: AxiosRequestConfig | null): Promise<unknown>;
package/lib/cdp/utils.js CHANGED
@@ -93,7 +93,7 @@ exports.createMockActivateArgs = createMockActivateArgs;
93
93
  /**
94
94
  * Poll the schema to be deployed.
95
95
  */
96
- function pollForDeployedSchema(endpointUrl, apiService) {
96
+ function pollForDeployedSchema(endpointUrl, apiService, requestConfig = null) {
97
97
  return __awaiter(this, void 0, void 0, function* () {
98
98
  return new Promise((resolve, reject) => {
99
99
  const errHandler = (err) => {
@@ -104,7 +104,9 @@ function pollForDeployedSchema(endpointUrl, apiService) {
104
104
  }, API_TIMEOUT);
105
105
  const poll = () => __awaiter(this, void 0, void 0, function* () {
106
106
  logDebug(`GET ${endpointUrl}`);
107
- const { data, status } = yield apiService.client.get(endpointUrl);
107
+ const { data, status } = requestConfig
108
+ ? yield apiService.client.get(endpointUrl, requestConfig)
109
+ : yield apiService.client.get(endpointUrl);
108
110
  logDebug(`Response: ${JSON.stringify(data)}`);
109
111
  if (status !== 200) {
110
112
  return reject(`Unexpected poll request status: ${status}`);
@@ -16,6 +16,7 @@ const commander_1 = require("commander");
16
16
  const chalk_1 = __importDefault(require("chalk"));
17
17
  const ora_1 = __importDefault(require("ora"));
18
18
  const utils_1 = require("../utils");
19
+ const loadCctIdsFromFile_1 = require("../utils/loadCctIdsFromFile");
19
20
  const createMigrationCommand = () => {
20
21
  const createCommand = new commander_1.Command('create')
21
22
  .name('create')
@@ -23,6 +24,7 @@ const createMigrationCommand = () => {
23
24
  .addOption((0, utils_1.getParamOption)(utils_1.OptionName.ASSET_ID))
24
25
  .addOption((0, utils_1.getParamOption)(utils_1.OptionName.PREVIEW_ASSET_ID))
25
26
  .addOption((0, utils_1.getParamOption)(utils_1.OptionName.MATRIX_URL))
27
+ .addOption((0, utils_1.getParamOption)(utils_1.OptionName.CCT_IDS, false))
26
28
  .addOption((0, utils_1.getParamOption)(utils_1.OptionName.TENANT, false))
27
29
  .configureOutput({
28
30
  outputError(str, write) {
@@ -33,18 +35,13 @@ const createMigrationCommand = () => {
33
35
  yield (0, utils_1.throwErrorIfNotLoggedIn)(createCommand);
34
36
  const spinner = (0, ora_1.default)('Creating migration').start();
35
37
  try {
38
+ const cctIds = (0, loadCctIdsFromFile_1.loadCctIdsFromFile)(options.cctIds);
36
39
  // Create migration
37
- const response = yield (0, utils_1.createMigration)(options);
40
+ const response = yield (0, utils_1.createMigration)(Object.assign(Object.assign({}, options), { cctIds }));
38
41
  if (!response) {
39
42
  throw new Error('Migration creation failed');
40
43
  }
41
- spinner.succeed('Migration created successfully');
42
- spinner.succeed(`Successfully created migration: ${JSON.stringify({
43
- migrationId: response.assetMigration.migrationId,
44
- assetId: response.assetMigration.assetId,
45
- stage: response.assetMigration.stage,
46
- status: response.assetMigration.status,
47
- })}`);
44
+ spinner.succeed((0, utils_1.buildMigrationSuccessMessage)('migration', response.assetMigration));
48
45
  }
49
46
  catch (error) {
50
47
  spinner.fail();
@@ -52,6 +52,7 @@ describe('createMigrationCommand', () => {
52
52
  jest.resetAllMocks();
53
53
  logSpy = jest.spyOn(console, 'log').mockImplementation(() => { });
54
54
  mockUtils.throwErrorIfNotLoggedIn.mockResolvedValue(undefined);
55
+ mockUtils.buildMigrationSuccessMessage.mockReturnValue('Migration created successfully');
55
56
  mockCreateMigrationResponse = {
56
57
  assetMigration: {
57
58
  migrationId: 'migration-123',
@@ -7,6 +7,7 @@ const commander_1 = require("commander");
7
7
  const create_1 = __importDefault(require("./create/create"));
8
8
  const get_1 = __importDefault(require("./get/get"));
9
9
  const next_1 = __importDefault(require("./next/next"));
10
+ const pre_1 = __importDefault(require("./pre/pre"));
10
11
  const settings_1 = __importDefault(require("./settings/settings"));
11
12
  const revert_1 = __importDefault(require("./revert/revert"));
12
13
  const list_1 = __importDefault(require("./list/list"));
@@ -17,6 +18,7 @@ migrationCommand
17
18
  .addCommand((0, get_1.default)())
18
19
  .addCommand((0, list_1.default)())
19
20
  .addCommand((0, next_1.default)())
21
+ .addCommand((0, pre_1.default)())
20
22
  .addCommand((0, settings_1.default)())
21
23
  .addCommand((0, revert_1.default)());
22
24
  exports.default = migrationCommand;
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ declare const preMigrationCommand: () => Command;
3
+ export default preMigrationCommand;
@@ -0,0 +1,54 @@
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 loadCctIdsFromFile_1 = require("../utils/loadCctIdsFromFile");
20
+ const preMigrationCommand = () => {
21
+ const preCommand = new commander_1.Command('pre')
22
+ .name('pre')
23
+ .description('Create a new pre-migration using the AI Page Migration service')
24
+ .addOption((0, utils_1.getParamOption)(utils_1.OptionName.MATRIX_URL))
25
+ .addOption((0, utils_1.getParamOption)(utils_1.OptionName.CCT_IDS))
26
+ .addOption((0, utils_1.getParamOption)(utils_1.OptionName.TENANT, false))
27
+ .configureOutput({
28
+ outputError(str, write) {
29
+ write(chalk_1.default.red(str));
30
+ },
31
+ })
32
+ .action((options) => __awaiter(void 0, void 0, void 0, function* () {
33
+ yield (0, utils_1.throwErrorIfNotLoggedIn)(preCommand);
34
+ const spinner = (0, ora_1.default)('Creating pre-migration').start();
35
+ try {
36
+ const cctIds = (0, loadCctIdsFromFile_1.loadCctIdsFromFile)(options.cctIds);
37
+ // Create pre-migration
38
+ const response = yield (0, utils_1.createMigration)(Object.assign(Object.assign({}, options), { cctIds }));
39
+ if (!response) {
40
+ throw new Error('Pre-migration creation failed');
41
+ }
42
+ spinner.succeed((0, utils_1.buildMigrationSuccessMessage)('pre-migration', response.assetMigration));
43
+ }
44
+ catch (error) {
45
+ spinner.fail();
46
+ (0, utils_1.handleCommandError)(preCommand, error);
47
+ }
48
+ }));
49
+ if (process.env.ENABLE_OVERRIDE_MIGRATION_URL === 'true') {
50
+ preCommand.addOption(new commander_1.Option('-ou, --overrideUrl <string>', 'Developer option to override the entire migration url with a custom value'));
51
+ }
52
+ return preCommand;
53
+ };
54
+ exports.default = preMigrationCommand;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,269 @@
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 pre_1 = __importDefault(require("./pre"));
40
+ const utils = __importStar(require("../utils/common"));
41
+ const createMigration = __importStar(require("../utils/createMigration"));
42
+ const loadCctIdsFromFile = __importStar(require("../utils/loadCctIdsFromFile"));
43
+ jest.mock('../utils/common');
44
+ jest.mock('../utils/createMigration');
45
+ jest.mock('../utils/loadCctIdsFromFile');
46
+ const mockUtils = utils;
47
+ const mockCreateMigration = createMigration;
48
+ const mockLoadCctIdsFromFile = loadCctIdsFromFile;
49
+ describe('preMigrationCommand', () => {
50
+ let logSpy;
51
+ let mockCreateMigrationResponse;
52
+ beforeEach(() => {
53
+ nock_1.default.cleanAll();
54
+ jest.clearAllMocks();
55
+ jest.resetAllMocks();
56
+ logSpy = jest.spyOn(console, 'log').mockImplementation(() => { });
57
+ mockUtils.throwErrorIfNotLoggedIn.mockResolvedValue(undefined);
58
+ mockUtils.buildMigrationSuccessMessage.mockReturnValue('Pre-migration created successfully');
59
+ mockLoadCctIdsFromFile.loadCctIdsFromFile.mockReturnValue([
60
+ 'cct-id-1',
61
+ 'cct-id-2',
62
+ ]);
63
+ mockCreateMigrationResponse = {
64
+ assetMigration: {
65
+ migrationId: 'migration-123',
66
+ assetId: 'asset-456',
67
+ stage: 'pending',
68
+ status: 'created',
69
+ xmlFilePath: '/path/to/xml',
70
+ matrixUrl: 'https://matrix.example.com',
71
+ previewAssetId: 'preview-789',
72
+ created: 1234567890,
73
+ updated: 1234567890,
74
+ migrationIdAssetId: 'migration-123-asset-456',
75
+ },
76
+ };
77
+ mockCreateMigration.createMigration.mockResolvedValue(mockCreateMigrationResponse);
78
+ });
79
+ afterEach(() => {
80
+ logSpy.mockRestore();
81
+ });
82
+ describe('successful pre-migration creation', () => {
83
+ it('should create pre-migration successfully with all required options', () => __awaiter(void 0, void 0, void 0, function* () {
84
+ const program = (0, pre_1.default)();
85
+ yield program.parseAsync([
86
+ 'node',
87
+ 'dxp-cli',
88
+ '--matrix-url',
89
+ 'https://matrix.example.com',
90
+ '--cct-ids',
91
+ '/path/to/cct-ids.json',
92
+ ]);
93
+ expect(mockUtils.throwErrorIfNotLoggedIn).toHaveBeenCalledWith(program);
94
+ expect(mockLoadCctIdsFromFile.loadCctIdsFromFile).toHaveBeenCalledWith('/path/to/cct-ids.json');
95
+ expect(mockCreateMigration.createMigration).toHaveBeenCalledWith({
96
+ matrixUrl: 'https://matrix.example.com',
97
+ cctIds: ['cct-id-1', 'cct-id-2'],
98
+ });
99
+ expect(mockCreateMigration.createMigration).toHaveBeenCalledTimes(1);
100
+ expect(mockUtils.handleCommandError).not.toHaveBeenCalled();
101
+ }));
102
+ it('should create pre-migration with tenant option', () => __awaiter(void 0, void 0, void 0, function* () {
103
+ const program = (0, pre_1.default)();
104
+ yield program.parseAsync([
105
+ 'node',
106
+ 'dxp-cli',
107
+ '--matrix-url',
108
+ 'https://matrix.example.com',
109
+ '--cct-ids',
110
+ '/path/to/cct-ids.json',
111
+ '--tenant',
112
+ 'test-tenant',
113
+ ]);
114
+ expect(mockCreateMigration.createMigration).toHaveBeenCalledWith({
115
+ matrixUrl: 'https://matrix.example.com',
116
+ cctIds: ['cct-id-1', 'cct-id-2'],
117
+ tenant: 'test-tenant',
118
+ });
119
+ }));
120
+ it('should create pre-migration with override URL when environment variable is set', () => __awaiter(void 0, void 0, void 0, function* () {
121
+ const originalEnv = process.env.ENABLE_OVERRIDE_MIGRATION_URL;
122
+ process.env.ENABLE_OVERRIDE_MIGRATION_URL = 'true';
123
+ const program = (0, pre_1.default)();
124
+ yield program.parseAsync([
125
+ 'node',
126
+ 'dxp-cli',
127
+ '--matrix-url',
128
+ 'https://matrix.example.com',
129
+ '--cct-ids',
130
+ '/path/to/cct-ids.json',
131
+ '--overrideUrl',
132
+ 'https://custom.migration.url',
133
+ ]);
134
+ expect(mockCreateMigration.createMigration).toHaveBeenCalledWith({
135
+ matrixUrl: 'https://matrix.example.com',
136
+ cctIds: ['cct-id-1', 'cct-id-2'],
137
+ overrideUrl: 'https://custom.migration.url',
138
+ });
139
+ process.env.ENABLE_OVERRIDE_MIGRATION_URL = originalEnv;
140
+ }));
141
+ });
142
+ describe('error scenarios', () => {
143
+ it('should handle pre-migration creation failure', () => __awaiter(void 0, void 0, void 0, function* () {
144
+ mockCreateMigration.createMigration.mockResolvedValue(null);
145
+ mockUtils.handleCommandError.mockImplementation(() => { });
146
+ const program = (0, pre_1.default)();
147
+ yield program.parseAsync([
148
+ 'node',
149
+ 'dxp-cli',
150
+ '--matrix-url',
151
+ 'https://matrix.example.com',
152
+ '--cct-ids',
153
+ '/path/to/cct-ids.json',
154
+ ]);
155
+ expect(mockUtils.handleCommandError).toHaveBeenCalledWith(program, new Error('Pre-migration creation failed'));
156
+ }));
157
+ it('should handle migration API error', () => __awaiter(void 0, void 0, void 0, function* () {
158
+ const apiError = new Error('Migration API failed');
159
+ mockCreateMigration.createMigration.mockRejectedValue(apiError);
160
+ mockUtils.handleCommandError.mockImplementation(() => { });
161
+ const program = (0, pre_1.default)();
162
+ yield program.parseAsync([
163
+ 'node',
164
+ 'dxp-cli',
165
+ '--matrix-url',
166
+ 'https://matrix.example.com',
167
+ '--cct-ids',
168
+ '/path/to/cct-ids.json',
169
+ ]);
170
+ expect(mockUtils.handleCommandError).toHaveBeenCalledWith(program, apiError);
171
+ }));
172
+ it('should handle not being logged in', () => __awaiter(void 0, void 0, void 0, function* () {
173
+ const loginError = new Error('Not logged in');
174
+ mockUtils.throwErrorIfNotLoggedIn.mockImplementation(() => {
175
+ throw loginError;
176
+ });
177
+ const program = (0, pre_1.default)();
178
+ yield expect(program.parseAsync([
179
+ 'node',
180
+ 'dxp-cli',
181
+ '--matrix-url',
182
+ 'https://matrix.example.com',
183
+ '--cct-ids',
184
+ '/path/to/cct-ids.json',
185
+ ])).rejects.toThrow('Not logged in');
186
+ expect(mockCreateMigration.createMigration).not.toHaveBeenCalled();
187
+ }));
188
+ it('should handle loadCctIdsFromFile error', () => __awaiter(void 0, void 0, void 0, function* () {
189
+ const loadError = new Error('Failed to load CCT IDs from file');
190
+ mockLoadCctIdsFromFile.loadCctIdsFromFile.mockImplementation(() => {
191
+ throw loadError;
192
+ });
193
+ mockUtils.handleCommandError.mockImplementation(() => { });
194
+ const program = (0, pre_1.default)();
195
+ yield program.parseAsync([
196
+ 'node',
197
+ 'dxp-cli',
198
+ '--matrix-url',
199
+ 'https://matrix.example.com',
200
+ '--cct-ids',
201
+ '/path/to/invalid.json',
202
+ ]);
203
+ expect(mockUtils.handleCommandError).toHaveBeenCalledWith(program, loadError);
204
+ expect(mockCreateMigration.createMigration).not.toHaveBeenCalled();
205
+ }));
206
+ });
207
+ describe('required options validation', () => {
208
+ it('should require matrixUrl option', () => {
209
+ const program = (0, pre_1.default)().exitOverride();
210
+ expect(() => {
211
+ program.parse([
212
+ 'node',
213
+ 'dxp-cli',
214
+ '--cct-ids',
215
+ '/path/to/cct-ids.json',
216
+ ]);
217
+ }).toThrow();
218
+ });
219
+ it('should require cctIds option', () => {
220
+ const program = (0, pre_1.default)().exitOverride();
221
+ expect(() => {
222
+ program.parse([
223
+ 'node',
224
+ 'dxp-cli',
225
+ '--matrix-url',
226
+ 'https://matrix.example.com',
227
+ ]);
228
+ }).toThrow();
229
+ });
230
+ });
231
+ describe('command configuration', () => {
232
+ it('should have correct command name and description', () => {
233
+ const program = (0, pre_1.default)();
234
+ expect(program.name()).toBe('pre');
235
+ expect(program.description()).toBe('Create a new pre-migration using the AI Page Migration service');
236
+ });
237
+ it('should parse options correctly', () => {
238
+ const program = (0, pre_1.default)();
239
+ program.parse([
240
+ 'node',
241
+ 'dxp-cli',
242
+ '--matrix-url',
243
+ 'https://matrix.example.com',
244
+ '--cct-ids',
245
+ '/path/to/cct-ids.json',
246
+ '--tenant',
247
+ 'test-tenant',
248
+ ]);
249
+ const opts = program.opts();
250
+ expect(opts.matrixUrl).toBe('https://matrix.example.com');
251
+ expect(opts.cctIds).toBe('/path/to/cct-ids.json');
252
+ expect(opts.tenant).toBe('test-tenant');
253
+ });
254
+ });
255
+ describe('spinner and output behavior', () => {
256
+ it('should display appropriate spinner messages during execution', () => __awaiter(void 0, void 0, void 0, function* () {
257
+ const program = (0, pre_1.default)();
258
+ yield program.parseAsync([
259
+ 'node',
260
+ 'dxp-cli',
261
+ '--matrix-url',
262
+ 'https://matrix.example.com',
263
+ '--cct-ids',
264
+ '/path/to/cct-ids.json',
265
+ ]);
266
+ expect(mockCreateMigration.createMigration).toHaveBeenCalled();
267
+ }));
268
+ });
269
+ });
@@ -3,6 +3,16 @@ export interface CommonCommandOptions {
3
3
  overrideUrl?: string;
4
4
  }
5
5
  export interface AssetMigration {
6
+ /**
7
+ * Will be programmatically set while creating a migration or pre-migration,
8
+ * depending on whether assetId and cctIds are provided.
9
+ */
10
+ isPreMigration?: boolean;
11
+ /**
12
+ * In pre-migrations, this will be the CCT IDs to generate specs for.
13
+ * In migrations, this will be the CCT IDs to be skipped (because they were already converted and deployed).
14
+ */
15
+ cctIds?: string[];
6
16
  migrationId: string;
7
17
  assetId: string;
8
18
  xmlFilePath: string;
@@ -1,5 +1,9 @@
1
1
  import { AssetMigration, CommonCommandOptions } from '.';
2
2
  export interface CreateMigrationOptions extends CommonCommandOptions, Pick<AssetMigration, 'assetId' | 'previewAssetId' | 'matrixUrl'> {
3
+ /**
4
+ * The path to a JSON file containing the CCT IDs to be skipped in a migration (because they were already converted and deployed)
5
+ */
6
+ cctIds?: string;
3
7
  }
4
8
  export interface CreateMigrationApiResponse {
5
9
  assetMigration: AssetMigration;
@@ -2,5 +2,6 @@ export * from './common.types';
2
2
  export * from './createMigration.types';
3
3
  export * from './getMigration.types';
4
4
  export * from './nextStage.types';
5
+ export * from './preMigration.types';
5
6
  export * from './settings.types';
6
7
  export * from './revert.types';
@@ -18,5 +18,6 @@ __exportStar(require("./common.types"), exports);
18
18
  __exportStar(require("./createMigration.types"), exports);
19
19
  __exportStar(require("./getMigration.types"), exports);
20
20
  __exportStar(require("./nextStage.types"), exports);
21
+ __exportStar(require("./preMigration.types"), exports);
21
22
  __exportStar(require("./settings.types"), exports);
22
23
  __exportStar(require("./revert.types"), exports);
@@ -0,0 +1,10 @@
1
+ import { AssetMigration, CommonCommandOptions } from '.';
2
+ export interface PreMigrationOptions extends CommonCommandOptions, Pick<AssetMigration, 'matrixUrl'> {
3
+ /**
4
+ * The path to a JSON file containing the CCT IDs to generate specs
5
+ */
6
+ cctIds: string;
7
+ }
8
+ export interface PreMigrationApiResponse {
9
+ assetMigration: AssetMigration;
10
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,4 +1,5 @@
1
1
  import { Command } from 'commander';
2
+ import { AssetMigration } from '../types';
2
3
  /**
3
4
  * The purpose of this file is to provide utilities in common
4
5
  * such as functions that can be reused across the migration service.
@@ -29,3 +30,10 @@ export declare function buildMigrationUrl(tenantID?: string, overrideUrl?: strin
29
30
  export declare function validateAxiosStatus(status: number): boolean;
30
31
  export declare function getMigrationHeaders(tenantID?: string, isJson?: boolean): Promise<Record<string, string>>;
31
32
  export declare function redactKey(key: string, visibleChars?: number): string;
33
+ /**
34
+ * Builds a success message for migration creation.
35
+ * @param label - The label for the migration type (e.g., "migration" or "pre-migration").
36
+ * @param assetMigration - The asset migration response.
37
+ * @returns The formatted success message.
38
+ */
39
+ export declare function buildMigrationSuccessMessage(label: string, assetMigration: AssetMigration): string;
@@ -12,7 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.redactKey = exports.getMigrationHeaders = exports.validateAxiosStatus = exports.buildMigrationUrl = exports.throwErrorIfNotLoggedIn = exports.handleCommandError = void 0;
15
+ exports.buildMigrationSuccessMessage = exports.redactKey = exports.getMigrationHeaders = exports.validateAxiosStatus = exports.buildMigrationUrl = exports.throwErrorIfNotLoggedIn = exports.handleCommandError = void 0;
16
16
  const chalk_1 = __importDefault(require("chalk"));
17
17
  const ApplicationConfig_1 = require("../../ApplicationConfig");
18
18
  const axios_1 = __importDefault(require("axios"));
@@ -114,3 +114,21 @@ function redactKey(key, visibleChars = 3) {
114
114
  return masked + key.slice(-visibleChars);
115
115
  }
116
116
  exports.redactKey = redactKey;
117
+ /**
118
+ * Builds a success message for migration creation.
119
+ * @param label - The label for the migration type (e.g., "migration" or "pre-migration").
120
+ * @param assetMigration - The asset migration response.
121
+ * @returns The formatted success message.
122
+ */
123
+ function buildMigrationSuccessMessage(label, assetMigration) {
124
+ const { isPreMigration, cctIds, migrationId, assetId, stage, status } = assetMigration;
125
+ return `Successfully created ${label}: ${JSON.stringify({
126
+ isPreMigration,
127
+ migrationId,
128
+ assetId,
129
+ stage,
130
+ status,
131
+ cctIds: (cctIds === null || cctIds === void 0 ? void 0 : cctIds.length) ? JSON.stringify(cctIds).substring(0, 100) : '[]',
132
+ })}`;
133
+ }
134
+ exports.buildMigrationSuccessMessage = buildMigrationSuccessMessage;
@@ -1,5 +1,29 @@
1
- import { CreateMigrationOptions, CreateMigrationApiResponse } from '../types';
2
- export declare function createMigration(options: CreateMigrationOptions): Promise<CreateMigrationApiResponse>;
1
+ import { CommonCommandOptions, CreateMigrationApiResponse } from '../types';
2
+ export interface CreateMigrationInput extends CommonCommandOptions {
3
+ /**
4
+ * Optional for pre-migrations, required for migrations.
5
+ */
6
+ assetId?: string;
7
+ /**
8
+ * Optional for pre-migrations, required for migrations.
9
+ */
10
+ previewAssetId?: string;
11
+ /**
12
+ * Required for both migrations and pre-migrations.
13
+ */
14
+ matrixUrl: string;
15
+ /**
16
+ * Optional for migrations, required for pre-migrations.
17
+ */
18
+ cctIds?: string[];
19
+ }
20
+ /**
21
+ * Creates a new migration or pre-migration using the AI Page Migration service.
22
+ * Pre-migrations are used to generate specs for CCTs so they can be converted and deployed in advance.
23
+ * @param {CreateMigrationInput} input - The input parameters for the migration/pre-migration creation.
24
+ * @returns {Promise<CreateMigrationApiResponse>}
25
+ */
26
+ export declare function createMigration({ tenant, overrideUrl, assetId, previewAssetId, matrixUrl, cctIds, }: CreateMigrationInput): Promise<CreateMigrationApiResponse>;
3
27
  export declare function validateExportFolder(exportPath: string): void;
4
28
  /**
5
29
  * Creates a tar file from the export path.