@squiz/dxp-cli-next 5.26.0-develop.4 → 5.26.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/lib/migration/create/{createMigration.js → create.js} +5 -5
- package/lib/migration/create/{createMigration.spec.js → create.spec.js} +44 -41
- package/lib/migration/get/{getMigration.js → get.js} +4 -6
- package/lib/migration/get/{getMigration.spec.js → get.spec.js} +39 -30
- package/lib/migration/index.js +9 -7
- package/lib/migration/next/next.d.ts +3 -0
- package/lib/migration/next/next.js +46 -0
- package/lib/migration/next/next.spec.js +186 -0
- package/lib/migration/revert/revert.js +5 -6
- package/lib/migration/revert/revert.spec.js +10 -7
- package/lib/migration/settings/{setMigrationSettings.js → settings.js} +7 -8
- package/lib/migration/settings/{setMigrationSettings.spec.js → settings.spec.js} +34 -26
- package/lib/migration/types/common.types.d.ts +19 -0
- package/lib/migration/types/createMigration.types.d.ts +7 -0
- package/lib/migration/types/createMigration.types.js +2 -0
- package/lib/migration/types/getMigration.types.d.ts +5 -0
- package/lib/migration/types/getMigration.types.js +2 -0
- package/lib/migration/types/index.d.ts +6 -0
- package/lib/migration/types/index.js +22 -0
- package/lib/migration/types/nextStage.types.d.ts +6 -0
- package/lib/migration/types/nextStage.types.js +2 -0
- package/lib/migration/types/revert.types.d.ts +6 -0
- package/lib/migration/types/revert.types.js +2 -0
- package/lib/migration/types/settings.types.d.ts +10 -0
- package/lib/migration/types/settings.types.js +2 -0
- package/lib/migration/utils/common.d.ts +32 -0
- package/lib/migration/utils/common.js +129 -0
- package/lib/migration/utils/common.spec.d.ts +1 -0
- package/lib/migration/utils/common.spec.js +196 -0
- package/lib/migration/utils/createMigration.d.ts +9 -0
- package/lib/migration/utils/createMigration.js +122 -0
- package/lib/migration/utils/createMigration.spec.d.ts +1 -0
- package/lib/migration/utils/createMigration.spec.js +276 -0
- package/lib/migration/utils/getMigration.d.ts +2 -0
- package/lib/migration/utils/getMigration.js +41 -0
- package/lib/migration/utils/getMigration.spec.d.ts +1 -0
- package/lib/migration/utils/getMigration.spec.js +156 -0
- package/lib/migration/utils/index.d.ts +7 -0
- package/lib/migration/utils/index.js +23 -0
- package/lib/migration/utils/nextStage.d.ts +2 -0
- package/lib/migration/utils/nextStage.js +44 -0
- package/lib/migration/utils/nextStage.spec.d.ts +1 -0
- package/lib/migration/utils/nextStage.spec.js +151 -0
- package/lib/migration/utils/options.d.ts +12 -0
- package/lib/migration/utils/options.js +82 -0
- package/lib/migration/utils/options.spec.d.ts +1 -0
- package/lib/migration/utils/options.spec.js +115 -0
- package/lib/migration/utils/revertMigration.d.ts +2 -0
- package/lib/migration/utils/revertMigration.js +38 -0
- package/lib/migration/utils/revertMigration.spec.d.ts +1 -0
- package/lib/migration/utils/revertMigration.spec.js +95 -0
- package/lib/migration/utils/setMigrationSettings.d.ts +2 -0
- package/lib/migration/utils/setMigrationSettings.js +53 -0
- package/lib/migration/utils/setMigrationSettings.spec.d.ts +1 -0
- package/lib/migration/utils/setMigrationSettings.spec.js +156 -0
- package/package.json +1 -1
- package/lib/migration/types.d.ts +0 -54
- package/lib/migration/utils.d.ts +0 -15
- package/lib/migration/utils.js +0 -298
- package/lib/migration/utils.spec.js +0 -617
- /package/lib/migration/create/{createMigration.d.ts → create.d.ts} +0 -0
- /package/lib/migration/create/{createMigration.spec.d.ts → create.spec.d.ts} +0 -0
- /package/lib/migration/get/{getMigration.d.ts → get.d.ts} +0 -0
- /package/lib/migration/get/{getMigration.spec.d.ts → get.spec.d.ts} +0 -0
- /package/lib/migration/{settings/setMigrationSettings.spec.d.ts → next/next.spec.d.ts} +0 -0
- /package/lib/migration/settings/{setMigrationSettings.d.ts → settings.d.ts} +0 -0
- /package/lib/migration/{utils.spec.d.ts → settings/settings.spec.d.ts} +0 -0
- /package/lib/migration/{types.js → types/common.types.js} +0 -0
|
@@ -0,0 +1,276 @@
|
|
|
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 fs_1 = __importDefault(require("fs"));
|
|
16
|
+
const path_1 = __importDefault(require("path"));
|
|
17
|
+
const child_process_1 = require("child_process");
|
|
18
|
+
const ApplicationConfig_1 = require("../../ApplicationConfig");
|
|
19
|
+
const ApiService_1 = require("../../ApiService");
|
|
20
|
+
const _1 = require(".");
|
|
21
|
+
// Mock all external dependencies
|
|
22
|
+
jest.mock('fs');
|
|
23
|
+
jest.mock('path');
|
|
24
|
+
jest.mock('child_process');
|
|
25
|
+
jest.mock('axios');
|
|
26
|
+
jest.mock('../../ApplicationConfig');
|
|
27
|
+
jest.mock('../../ApplicationStore');
|
|
28
|
+
jest.mock('../../ApiService');
|
|
29
|
+
// Mock global fetch
|
|
30
|
+
const mockFetch = jest.fn();
|
|
31
|
+
global.fetch = mockFetch;
|
|
32
|
+
const mockFs = fs_1.default;
|
|
33
|
+
const mockPath = path_1.default;
|
|
34
|
+
const mockSpawn = child_process_1.spawn;
|
|
35
|
+
const mockFetchApplicationConfig = ApplicationConfig_1.fetchApplicationConfig;
|
|
36
|
+
const mockApiService = ApiService_1.ApiService;
|
|
37
|
+
describe('createMigration', () => {
|
|
38
|
+
beforeEach(() => {
|
|
39
|
+
jest.clearAllMocks();
|
|
40
|
+
jest.resetAllMocks();
|
|
41
|
+
});
|
|
42
|
+
describe('validateExportFolder', () => {
|
|
43
|
+
beforeEach(() => {
|
|
44
|
+
mockPath.join.mockImplementation((...paths) => paths.join('/'));
|
|
45
|
+
});
|
|
46
|
+
it('validates successful export folder structure', () => {
|
|
47
|
+
mockFs.existsSync.mockImplementation(filePath => {
|
|
48
|
+
return [
|
|
49
|
+
'/export/path',
|
|
50
|
+
'/export/path/export',
|
|
51
|
+
'/export/path/export/export.xml',
|
|
52
|
+
].includes(filePath);
|
|
53
|
+
});
|
|
54
|
+
mockFs.statSync.mockImplementation(filePath => ({
|
|
55
|
+
isDirectory: () => filePath !== '/export/path/export/export.xml',
|
|
56
|
+
isFile: () => filePath === '/export/path/export/export.xml',
|
|
57
|
+
}));
|
|
58
|
+
expect(() => (0, _1.validateExportFolder)('/export/path')).not.toThrow();
|
|
59
|
+
});
|
|
60
|
+
it('throws error when export folder does not exist', () => {
|
|
61
|
+
mockFs.existsSync.mockReturnValue(false);
|
|
62
|
+
expect(() => (0, _1.validateExportFolder)('/nonexistent')).toThrow('Export folder does not exist: /nonexistent');
|
|
63
|
+
});
|
|
64
|
+
it('throws error when export path is not a directory', () => {
|
|
65
|
+
mockFs.existsSync.mockReturnValue(true);
|
|
66
|
+
mockFs.statSync.mockReturnValue({
|
|
67
|
+
isDirectory: () => false,
|
|
68
|
+
isFile: () => true,
|
|
69
|
+
});
|
|
70
|
+
expect(() => (0, _1.validateExportFolder)('/export/file.txt')).toThrow('Export path is not a directory: /export/file.txt');
|
|
71
|
+
});
|
|
72
|
+
it('throws error when nested export folder does not exist', () => {
|
|
73
|
+
mockFs.existsSync.mockImplementation(filePath => filePath === '/export/path');
|
|
74
|
+
mockFs.statSync.mockReturnValue({
|
|
75
|
+
isDirectory: () => true,
|
|
76
|
+
});
|
|
77
|
+
expect(() => (0, _1.validateExportFolder)('/export/path')).toThrow('Nested export folder does not exist: /export/path/export');
|
|
78
|
+
});
|
|
79
|
+
it('throws error when export.xml does not exist', () => {
|
|
80
|
+
mockFs.existsSync.mockImplementation(filePath => {
|
|
81
|
+
return ['/export/path', '/export/path/export'].includes(filePath);
|
|
82
|
+
});
|
|
83
|
+
mockFs.statSync.mockReturnValue({
|
|
84
|
+
isDirectory: () => true,
|
|
85
|
+
});
|
|
86
|
+
expect(() => (0, _1.validateExportFolder)('/export/path')).toThrow('export.xml file does not exist in: /export/path/export');
|
|
87
|
+
});
|
|
88
|
+
it('throws error when export.xml is not a file', () => {
|
|
89
|
+
mockFs.existsSync.mockReturnValue(true);
|
|
90
|
+
mockFs.statSync.mockImplementation(filePath => ({
|
|
91
|
+
isDirectory: () => filePath !== '/export/path/export/export.xml',
|
|
92
|
+
isFile: () => false,
|
|
93
|
+
}));
|
|
94
|
+
expect(() => (0, _1.validateExportFolder)('/export/path')).toThrow('export.xml is not a valid file: /export/path/export/export.xml');
|
|
95
|
+
});
|
|
96
|
+
it('throws error when nested export path is not a directory', () => {
|
|
97
|
+
mockFs.existsSync.mockReturnValue(true);
|
|
98
|
+
mockFs.statSync.mockImplementation(filePath => {
|
|
99
|
+
if (filePath === '/export/path') {
|
|
100
|
+
return { isDirectory: () => true };
|
|
101
|
+
}
|
|
102
|
+
else if (filePath === '/export/path/export') {
|
|
103
|
+
return { isDirectory: () => false, isFile: () => true };
|
|
104
|
+
}
|
|
105
|
+
return { isDirectory: () => false, isFile: () => false };
|
|
106
|
+
});
|
|
107
|
+
expect(() => (0, _1.validateExportFolder)('/export/path')).toThrow('Nested export path is not a directory: /export/path/export');
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
describe('createTarFile', () => {
|
|
111
|
+
let mockChildProcess;
|
|
112
|
+
beforeEach(() => {
|
|
113
|
+
mockChildProcess = {
|
|
114
|
+
on: jest.fn(),
|
|
115
|
+
};
|
|
116
|
+
mockSpawn.mockReturnValue(mockChildProcess);
|
|
117
|
+
mockPath.join.mockImplementation((...paths) => paths.join('/'));
|
|
118
|
+
mockPath.dirname.mockReturnValue('/parent');
|
|
119
|
+
mockPath.basename.mockReturnValue('export');
|
|
120
|
+
// Mock Date.now() to return consistent timestamp
|
|
121
|
+
jest.spyOn(Date, 'now').mockReturnValue(1234567890);
|
|
122
|
+
});
|
|
123
|
+
afterEach(() => {
|
|
124
|
+
jest.restoreAllMocks();
|
|
125
|
+
});
|
|
126
|
+
describe('createMigration', () => {
|
|
127
|
+
let mockApiServiceInstance;
|
|
128
|
+
let mockOptions;
|
|
129
|
+
beforeEach(() => {
|
|
130
|
+
mockApiServiceInstance = {
|
|
131
|
+
client: {
|
|
132
|
+
post: jest.fn(),
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
mockApiService.mockImplementation(() => mockApiServiceInstance);
|
|
136
|
+
mockOptions = {
|
|
137
|
+
assetId: 'asset-123',
|
|
138
|
+
previewAssetId: 'preview-456',
|
|
139
|
+
matrixUrl: 'https://matrix.example.com',
|
|
140
|
+
tenant: 'test-tenant',
|
|
141
|
+
};
|
|
142
|
+
mockFetchApplicationConfig.mockResolvedValue({
|
|
143
|
+
tenant: 'test-tenant',
|
|
144
|
+
baseUrl: 'https://example.com',
|
|
145
|
+
region: 'au',
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
it('creates migration successfully', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
149
|
+
const mockResponse = {
|
|
150
|
+
status: 201,
|
|
151
|
+
data: {
|
|
152
|
+
assetMigration: {
|
|
153
|
+
migrationId: 'migration-123',
|
|
154
|
+
assetId: 'asset-123',
|
|
155
|
+
stage: 'pending',
|
|
156
|
+
status: 'created',
|
|
157
|
+
xmlFilePath: '/path/to/xml',
|
|
158
|
+
matrixUrl: 'https://matrix.example.com',
|
|
159
|
+
previewAssetId: 'preview-456',
|
|
160
|
+
created: 1234567890,
|
|
161
|
+
updated: 1234567890,
|
|
162
|
+
migrationIdAssetId: 'migration-123-asset-123',
|
|
163
|
+
},
|
|
164
|
+
uploadUrl: 'https://upload.s3.amazonaws.com',
|
|
165
|
+
},
|
|
166
|
+
};
|
|
167
|
+
mockApiServiceInstance.client.post.mockResolvedValue(mockResponse);
|
|
168
|
+
const result = yield (0, _1.createMigration)(mockOptions);
|
|
169
|
+
expect(result).toEqual(mockResponse.data);
|
|
170
|
+
expect(mockApiServiceInstance.client.post).toHaveBeenCalledWith('https://example.com/__dxp/service/aiapps/migration/migrations', {
|
|
171
|
+
assetId: 'asset-123',
|
|
172
|
+
previewAssetId: 'preview-456',
|
|
173
|
+
matrixUrl: 'https://matrix.example.com',
|
|
174
|
+
}, {
|
|
175
|
+
headers: {
|
|
176
|
+
'Content-Type': 'application/json',
|
|
177
|
+
'x-dxp-tenant': 'test-tenant',
|
|
178
|
+
},
|
|
179
|
+
});
|
|
180
|
+
}));
|
|
181
|
+
it('handles non-success status codes', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
182
|
+
const mockResponse = {
|
|
183
|
+
status: 400,
|
|
184
|
+
data: {},
|
|
185
|
+
};
|
|
186
|
+
mockApiServiceInstance.client.post.mockResolvedValue(mockResponse);
|
|
187
|
+
yield expect((0, _1.createMigration)(mockOptions)).rejects.toThrow('Migration creation failed with status: 400');
|
|
188
|
+
}));
|
|
189
|
+
it('handles invalid response format - missing migrationId', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
190
|
+
const mockResponse = {
|
|
191
|
+
status: 200,
|
|
192
|
+
data: {
|
|
193
|
+
assetMigration: {
|
|
194
|
+
assetId: 'asset-123',
|
|
195
|
+
stage: 'pending',
|
|
196
|
+
status: 'created',
|
|
197
|
+
},
|
|
198
|
+
uploadUrl: 'https://upload.s3.amazonaws.com',
|
|
199
|
+
},
|
|
200
|
+
};
|
|
201
|
+
mockApiServiceInstance.client.post.mockResolvedValue(mockResponse);
|
|
202
|
+
yield expect((0, _1.createMigration)(mockOptions)).rejects.toThrow('Invalid response format from migration service');
|
|
203
|
+
}));
|
|
204
|
+
it('handles missing upload URL', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
205
|
+
const mockResponse = {
|
|
206
|
+
status: 200,
|
|
207
|
+
data: {
|
|
208
|
+
assetMigration: {
|
|
209
|
+
migrationId: 'migration-123',
|
|
210
|
+
assetId: 'asset-123',
|
|
211
|
+
stage: 'pending',
|
|
212
|
+
status: 'created',
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
};
|
|
216
|
+
mockApiServiceInstance.client.post.mockResolvedValue(mockResponse);
|
|
217
|
+
yield expect((0, _1.createMigration)(mockOptions)).rejects.toThrow('Upload URL not found in response');
|
|
218
|
+
}));
|
|
219
|
+
it('handles API service errors', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
220
|
+
const error = new Error('Network error');
|
|
221
|
+
mockApiServiceInstance.client.post.mockRejectedValue(error);
|
|
222
|
+
yield expect((0, _1.createMigration)(mockOptions)).rejects.toThrow('Network error');
|
|
223
|
+
}));
|
|
224
|
+
it('handles unknown errors', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
225
|
+
mockApiServiceInstance.client.post.mockRejectedValue('Unknown error');
|
|
226
|
+
yield expect((0, _1.createMigration)(mockOptions)).rejects.toThrow('Failed to create migration: Unknown error');
|
|
227
|
+
}));
|
|
228
|
+
});
|
|
229
|
+
describe('createTarFile', () => {
|
|
230
|
+
let mockChildProcess;
|
|
231
|
+
beforeEach(() => {
|
|
232
|
+
mockChildProcess = {
|
|
233
|
+
on: jest.fn(),
|
|
234
|
+
};
|
|
235
|
+
mockSpawn.mockReturnValue(mockChildProcess);
|
|
236
|
+
mockPath.join.mockImplementation((...paths) => paths.join('/'));
|
|
237
|
+
mockPath.dirname.mockReturnValue('/parent');
|
|
238
|
+
mockPath.basename.mockReturnValue('export');
|
|
239
|
+
// Mock Date.now() to return consistent timestamp
|
|
240
|
+
jest.spyOn(Date, 'now').mockReturnValue(1234567890);
|
|
241
|
+
});
|
|
242
|
+
afterEach(() => {
|
|
243
|
+
jest.restoreAllMocks();
|
|
244
|
+
});
|
|
245
|
+
it('creates tar file successfully', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
246
|
+
const promise = (0, _1.createTarFile)('/parent/export');
|
|
247
|
+
// Simulate successful tar creation
|
|
248
|
+
const closeCallback = mockChildProcess.on.mock.calls.find((call) => call[0] === 'close')[1];
|
|
249
|
+
closeCallback(0);
|
|
250
|
+
const result = yield promise;
|
|
251
|
+
expect(result).toBe(`${process.cwd()}/export_1234567890.tar.gz`);
|
|
252
|
+
expect(mockSpawn).toHaveBeenCalledWith('tar', [
|
|
253
|
+
'-czf',
|
|
254
|
+
`${process.cwd()}/export_1234567890.tar.gz`,
|
|
255
|
+
'-C',
|
|
256
|
+
'/parent',
|
|
257
|
+
'export',
|
|
258
|
+
]);
|
|
259
|
+
}));
|
|
260
|
+
it('handles tar command failure', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
261
|
+
const promise = (0, _1.createTarFile)('/parent/export');
|
|
262
|
+
// Simulate tar command failure
|
|
263
|
+
const closeCallback = mockChildProcess.on.mock.calls.find((call) => call[0] === 'close')[1];
|
|
264
|
+
closeCallback(1);
|
|
265
|
+
yield expect(promise).rejects.toThrow('tar command failed with exit code 1');
|
|
266
|
+
}));
|
|
267
|
+
it('handles spawn error', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
268
|
+
const promise = (0, _1.createTarFile)('/parent/export');
|
|
269
|
+
// Simulate spawn error
|
|
270
|
+
const errorCallback = mockChildProcess.on.mock.calls.find((call) => call[0] === 'error')[1];
|
|
271
|
+
errorCallback(new Error('Spawn failed'));
|
|
272
|
+
yield expect(promise).rejects.toThrow('Failed to create tar file: Spawn failed');
|
|
273
|
+
}));
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.getMigration = void 0;
|
|
13
|
+
const ApiService_1 = require("../../ApiService");
|
|
14
|
+
const _1 = require(".");
|
|
15
|
+
function getMigration(options) {
|
|
16
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
17
|
+
const apiService = new ApiService_1.ApiService({
|
|
18
|
+
validateStatus: _1.validateAxiosStatus,
|
|
19
|
+
});
|
|
20
|
+
const migrationUrl = yield (0, _1.buildMigrationUrl)(options.tenant, options.overrideUrl);
|
|
21
|
+
try {
|
|
22
|
+
const response = yield apiService.client.get(`${migrationUrl}/${options.migrationId}/assets/${options.assetId}`, {
|
|
23
|
+
headers: yield (0, _1.getMigrationHeaders)(options.tenant),
|
|
24
|
+
});
|
|
25
|
+
if (response.status !== 200) {
|
|
26
|
+
throw new Error(`Failed to get migration: ${response.status}`);
|
|
27
|
+
}
|
|
28
|
+
if (!(response === null || response === void 0 ? void 0 : response.data)) {
|
|
29
|
+
throw new Error('No data returned from migration service');
|
|
30
|
+
}
|
|
31
|
+
return response.data;
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
if (error instanceof Error) {
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
throw new Error(`Failed to get migration: ${error}`);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
exports.getMigration = getMigration;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,156 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const ApiService_1 = require("../../ApiService");
|
|
13
|
+
const ApplicationConfig_1 = require("../../ApplicationConfig");
|
|
14
|
+
const getMigration_1 = require("./getMigration");
|
|
15
|
+
jest.mock('path');
|
|
16
|
+
jest.mock('child_process');
|
|
17
|
+
jest.mock('axios');
|
|
18
|
+
jest.mock('../../ApplicationConfig');
|
|
19
|
+
jest.mock('../../ApiService');
|
|
20
|
+
// Mock global fetch
|
|
21
|
+
const mockFetch = jest.fn();
|
|
22
|
+
global.fetch = mockFetch;
|
|
23
|
+
describe('getMigration', () => {
|
|
24
|
+
let mockApiServiceInstance;
|
|
25
|
+
let mockOptions;
|
|
26
|
+
const mockApiService = ApiService_1.ApiService;
|
|
27
|
+
const mockFetchApplicationConfig = ApplicationConfig_1.fetchApplicationConfig;
|
|
28
|
+
beforeEach(() => {
|
|
29
|
+
mockApiServiceInstance = {
|
|
30
|
+
client: {
|
|
31
|
+
get: jest.fn(),
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
mockApiService.mockImplementation(() => mockApiServiceInstance);
|
|
35
|
+
mockOptions = {
|
|
36
|
+
migrationId: 'migration-123',
|
|
37
|
+
assetId: 'asset-456',
|
|
38
|
+
tenant: 'test-tenant',
|
|
39
|
+
};
|
|
40
|
+
mockFetchApplicationConfig.mockResolvedValue({
|
|
41
|
+
tenant: 'test-tenant',
|
|
42
|
+
baseUrl: 'https://example.com',
|
|
43
|
+
region: 'au',
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
it('gets migration successfully', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
47
|
+
const mockResponse = {
|
|
48
|
+
status: 200,
|
|
49
|
+
data: {
|
|
50
|
+
migrationId: 'migration-123',
|
|
51
|
+
assetId: 'asset-456',
|
|
52
|
+
stage: 'completed',
|
|
53
|
+
status: 'success',
|
|
54
|
+
stageDetails: 'Migration completed successfully',
|
|
55
|
+
previewPageAssetId: 'preview-789',
|
|
56
|
+
componentsTarDownloadUrl: 'https://download.example.com/components.zip',
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
mockApiServiceInstance.client.get.mockResolvedValue(mockResponse);
|
|
60
|
+
const result = yield (0, getMigration_1.getMigration)(mockOptions);
|
|
61
|
+
expect(result).toEqual({
|
|
62
|
+
migrationId: 'migration-123',
|
|
63
|
+
assetId: 'asset-456',
|
|
64
|
+
stage: 'completed',
|
|
65
|
+
status: 'success',
|
|
66
|
+
stageDetails: 'Migration completed successfully',
|
|
67
|
+
previewPageAssetId: 'preview-789',
|
|
68
|
+
componentsTarDownloadUrl: 'https://download.example.com/components.zip',
|
|
69
|
+
});
|
|
70
|
+
expect(mockApiServiceInstance.client.get).toHaveBeenCalledWith('https://example.com/__dxp/service/aiapps/migration/migrations/migration-123/assets/asset-456', {
|
|
71
|
+
headers: {
|
|
72
|
+
'Content-Type': 'application/json',
|
|
73
|
+
'x-dxp-tenant': 'test-tenant',
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
}));
|
|
77
|
+
it('gets migration with override URL', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
78
|
+
const optionsWithOverride = Object.assign(Object.assign({}, mockOptions), { overrideUrl: 'https://custom.migration.url' });
|
|
79
|
+
const mockResponse = {
|
|
80
|
+
status: 200,
|
|
81
|
+
data: {
|
|
82
|
+
migrationId: 'migration-123',
|
|
83
|
+
assetId: 'asset-456',
|
|
84
|
+
stage: 'pending',
|
|
85
|
+
status: 'processing',
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
mockApiServiceInstance.client.get.mockResolvedValue(mockResponse);
|
|
89
|
+
const result = yield (0, getMigration_1.getMigration)(optionsWithOverride);
|
|
90
|
+
expect(result.migrationId).toBe('migration-123');
|
|
91
|
+
expect(result.assetId).toBe('asset-456');
|
|
92
|
+
expect(mockApiServiceInstance.client.get).toHaveBeenCalledWith('https://custom.migration.url/migrations/migration-123/assets/asset-456', expect.any(Object));
|
|
93
|
+
}));
|
|
94
|
+
it('handles non-success status codes', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
95
|
+
const mockResponse = {
|
|
96
|
+
status: 404,
|
|
97
|
+
data: {},
|
|
98
|
+
};
|
|
99
|
+
mockApiServiceInstance.client.get.mockResolvedValue(mockResponse);
|
|
100
|
+
yield expect((0, getMigration_1.getMigration)(mockOptions)).rejects.toThrow('Failed to get migration: 404');
|
|
101
|
+
}));
|
|
102
|
+
it('handles missing response data', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
103
|
+
const mockResponse = {
|
|
104
|
+
status: 200,
|
|
105
|
+
data: null,
|
|
106
|
+
};
|
|
107
|
+
mockApiServiceInstance.client.get.mockResolvedValue(mockResponse);
|
|
108
|
+
yield expect((0, getMigration_1.getMigration)(mockOptions)).rejects.toThrow('No data returned from migration service');
|
|
109
|
+
}));
|
|
110
|
+
it('handles API service errors', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
111
|
+
const error = new Error('Network error');
|
|
112
|
+
mockApiServiceInstance.client.get.mockRejectedValue(error);
|
|
113
|
+
yield expect((0, getMigration_1.getMigration)(mockOptions)).rejects.toThrow('Network error');
|
|
114
|
+
}));
|
|
115
|
+
it('handles unknown errors', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
116
|
+
mockApiServiceInstance.client.get.mockRejectedValue('Unknown error');
|
|
117
|
+
yield expect((0, getMigration_1.getMigration)(mockOptions)).rejects.toThrow('Failed to get migration: Unknown error');
|
|
118
|
+
}));
|
|
119
|
+
it('works without optional fields in response', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
120
|
+
const mockResponse = {
|
|
121
|
+
status: 200,
|
|
122
|
+
data: {
|
|
123
|
+
migrationId: 'migration-123',
|
|
124
|
+
assetId: 'asset-456',
|
|
125
|
+
stage: 'pending',
|
|
126
|
+
status: 'processing',
|
|
127
|
+
// No optional fields: stageDetails, previewPageAssetId, componentsTarDownloadUrl
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
mockApiServiceInstance.client.get.mockResolvedValue(mockResponse);
|
|
131
|
+
const result = yield (0, getMigration_1.getMigration)(mockOptions);
|
|
132
|
+
expect(result).toEqual({
|
|
133
|
+
migrationId: 'migration-123',
|
|
134
|
+
assetId: 'asset-456',
|
|
135
|
+
stage: 'pending',
|
|
136
|
+
status: 'processing',
|
|
137
|
+
stageDetails: undefined,
|
|
138
|
+
previewPageAssetId: undefined,
|
|
139
|
+
componentsTarDownloadUrl: undefined,
|
|
140
|
+
});
|
|
141
|
+
}));
|
|
142
|
+
it('constructs correct URL path', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
143
|
+
const mockResponse = {
|
|
144
|
+
status: 200,
|
|
145
|
+
data: {
|
|
146
|
+
migrationId: 'migration-123',
|
|
147
|
+
assetId: 'asset-456',
|
|
148
|
+
stage: 'completed',
|
|
149
|
+
status: 'success',
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
mockApiServiceInstance.client.get.mockResolvedValue(mockResponse);
|
|
153
|
+
yield (0, getMigration_1.getMigration)(mockOptions);
|
|
154
|
+
expect(mockApiServiceInstance.client.get).toHaveBeenCalledWith('https://example.com/__dxp/service/aiapps/migration/migrations/migration-123/assets/asset-456', expect.any(Object));
|
|
155
|
+
}));
|
|
156
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./common"), exports);
|
|
18
|
+
__exportStar(require("./options"), exports);
|
|
19
|
+
__exportStar(require("./createMigration"), exports);
|
|
20
|
+
__exportStar(require("./getMigration"), exports);
|
|
21
|
+
__exportStar(require("./nextStage"), exports);
|
|
22
|
+
__exportStar(require("./setMigrationSettings"), exports);
|
|
23
|
+
__exportStar(require("./revertMigration"), exports);
|
|
@@ -0,0 +1,44 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.nextStage = void 0;
|
|
13
|
+
const ApiService_1 = require("../../ApiService");
|
|
14
|
+
const _1 = require(".");
|
|
15
|
+
function nextStage(options) {
|
|
16
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
17
|
+
const apiService = new ApiService_1.ApiService({
|
|
18
|
+
validateStatus: _1.validateAxiosStatus,
|
|
19
|
+
});
|
|
20
|
+
const migrationUrl = yield (0, _1.buildMigrationUrl)(options.tenant, options.overrideUrl);
|
|
21
|
+
try {
|
|
22
|
+
const response = yield apiService.client.post(`${migrationUrl}/${options.migrationId}/assets/${options.assetId}/next`, {}, {
|
|
23
|
+
headers: yield (0, _1.getMigrationHeaders)(options.tenant),
|
|
24
|
+
});
|
|
25
|
+
if (response.status !== 202) {
|
|
26
|
+
throw new Error(`Next stage failed with status: ${response.status}`);
|
|
27
|
+
}
|
|
28
|
+
const { message } = response.data || {};
|
|
29
|
+
if (!message) {
|
|
30
|
+
throw new Error('Invalid response format from next stage');
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
message,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
if (error instanceof Error) {
|
|
38
|
+
throw error;
|
|
39
|
+
}
|
|
40
|
+
throw new Error(`Failed to start next stage: ${error}`);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
exports.nextStage = nextStage;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|