@contentstack/cli-cm-branches 1.0.18 → 1.0.20
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/LICENSE +1 -1
- package/README.md +1 -1
- package/lib/branch/merge-handler.js +10 -3
- package/lib/utils/create-merge-scripts.js +3 -1
- package/lib/utils/entry-create-script.js +157 -62
- package/lib/utils/entry-create-update-script.js +220 -122
- package/lib/utils/entry-update-script.js +189 -90
- package/oclif.manifest.json +1 -1
- package/package.json +3 -3
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -37,7 +37,7 @@ $ npm install -g @contentstack/cli-cm-branches
|
|
|
37
37
|
$ csdx COMMAND
|
|
38
38
|
running command...
|
|
39
39
|
$ csdx (--version)
|
|
40
|
-
@contentstack/cli-cm-branches/1.0.
|
|
40
|
+
@contentstack/cli-cm-branches/1.0.20 linux-x64 node-v18.19.0
|
|
41
41
|
$ csdx --help [COMMAND]
|
|
42
42
|
USAGE
|
|
43
43
|
$ csdx COMMAND
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
|
+
const os_1 = tslib_1.__importDefault(require("os"));
|
|
4
5
|
const path_1 = tslib_1.__importDefault(require("path"));
|
|
5
6
|
const forEach_1 = tslib_1.__importDefault(require("lodash/forEach"));
|
|
6
7
|
const cli_utilities_1 = require("@contentstack/cli-utilities");
|
|
@@ -246,7 +247,7 @@ class MergeHandler {
|
|
|
246
247
|
modified: [],
|
|
247
248
|
deleted: [],
|
|
248
249
|
};
|
|
249
|
-
selectedMergeItems.forEach((item) => {
|
|
250
|
+
selectedMergeItems === null || selectedMergeItems === void 0 ? void 0 : selectedMergeItems.forEach((item) => {
|
|
250
251
|
mergeContent.content_types[item.status].push(item.value);
|
|
251
252
|
});
|
|
252
253
|
break;
|
|
@@ -258,8 +259,14 @@ class MergeHandler {
|
|
|
258
259
|
if (scriptFolderPath !== undefined) {
|
|
259
260
|
cli_utilities_1.cliux.success(`\nSuccess! We have generated entry migration files in the folder ${scriptFolderPath}`);
|
|
260
261
|
cli_utilities_1.cliux.print('\nWARNING!!! Migration is not intended to be run more than once. Migrated(entries/assets) will be duplicated if run more than once', { color: 'yellow' });
|
|
261
|
-
|
|
262
|
-
|
|
262
|
+
let migrationCommand;
|
|
263
|
+
if (os_1.default.platform() === 'win32') {
|
|
264
|
+
migrationCommand = `csdx cm:stacks:migration --multiple --file-path ./${scriptFolderPath} --config compare-branch:${mergePayload.compare_branch},file-path:./${scriptFolderPath} --branch ${mergePayload.base_branch} --stack-api-key ${this.stackAPIKey}`;
|
|
265
|
+
}
|
|
266
|
+
else {
|
|
267
|
+
migrationCommand = `csdx cm:stacks:migration --multiple --file-path ./${scriptFolderPath} --config {compare-branch:${mergePayload.compare_branch},file-path:./${scriptFolderPath}} --branch ${mergePayload.base_branch} --stack-api-key ${this.stackAPIKey}`;
|
|
268
|
+
}
|
|
269
|
+
cli_utilities_1.cliux.print(`\nKindly follow the steps in the guide "https://www.contentstack.com/docs/developers/cli/entry-migration" to update the migration scripts, and then run the command:\n\n${migrationCommand}`, { color: 'blue' });
|
|
263
270
|
}
|
|
264
271
|
}
|
|
265
272
|
async restartMergeProcess() {
|
|
@@ -26,7 +26,6 @@ function generateMergeScripts(mergeSummary, mergeJobUID) {
|
|
|
26
26
|
merge_existing_new: entry_create_update_script_1.entryCreateUpdateScript,
|
|
27
27
|
merge_existing: entry_update_script_1.entryUpdateScript,
|
|
28
28
|
merge_new: entry_create_script_1.entryCreateScript,
|
|
29
|
-
ignore: entry_create_update_script_1.entryCreateUpdateScript,
|
|
30
29
|
};
|
|
31
30
|
const processContentTypes = (contentTypes, messageType) => {
|
|
32
31
|
if (contentTypes && contentTypes.length > 0) {
|
|
@@ -61,6 +60,9 @@ function getContentTypeMergeStatus(status) {
|
|
|
61
60
|
else if (status === 'merge_existing_new') {
|
|
62
61
|
return 'created_updated';
|
|
63
62
|
}
|
|
63
|
+
else if (status === 'ignore') {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
64
66
|
else {
|
|
65
67
|
return '';
|
|
66
68
|
}
|
|
@@ -5,6 +5,14 @@ function entryCreateScript(contentType) {
|
|
|
5
5
|
return `
|
|
6
6
|
const fs = require('fs');
|
|
7
7
|
const path = require('path');
|
|
8
|
+
const { marked } = require('marked');
|
|
9
|
+
const has = require('lodash/has');
|
|
10
|
+
const isArray = require('lodash/isArray');
|
|
11
|
+
const isObject = require('lodash/isObject');
|
|
12
|
+
const omit = require('lodash/omit');
|
|
13
|
+
const compact = require('lodash/compact')
|
|
14
|
+
const isPlainObject = require('lodash/isPlainObject');
|
|
15
|
+
const {cliux, LoggerService} = require('@contentstack/cli-utilities')
|
|
8
16
|
module.exports = async ({ migration, stackSDKInstance, managementAPIClient, config, branch, apiKey }) => {
|
|
9
17
|
const keysToRemove = [
|
|
10
18
|
'content_type_uid',
|
|
@@ -34,20 +42,18 @@ function entryCreateScript(contentType) {
|
|
|
34
42
|
let assetUIDMapper = {};
|
|
35
43
|
let assetUrlMapper = {};
|
|
36
44
|
let assetRefPath = {};
|
|
37
|
-
let
|
|
45
|
+
let downloadedAssets = [];
|
|
46
|
+
let parent=[];
|
|
47
|
+
let logger;
|
|
38
48
|
|
|
39
49
|
function getValueByPath(obj, path) {
|
|
40
50
|
return path.split('[').reduce((o, key) => o && o[key.replace(/\]$/, '')], obj);
|
|
41
51
|
}
|
|
42
52
|
|
|
43
|
-
function updateValueByPath(obj, path, newValue
|
|
53
|
+
function updateValueByPath(obj, path, newValue) {
|
|
44
54
|
path.split('[').reduce((o, key, index, arr) => {
|
|
45
55
|
if (index === arr.length - 1) {
|
|
46
|
-
if (type === 'file') {
|
|
47
|
-
o[key.replace(/]$/, '')][fileIndex] = newValue;
|
|
48
|
-
} else {
|
|
49
56
|
o[key.replace(/]$/, '')][0].uid = newValue;
|
|
50
|
-
}
|
|
51
57
|
} else {
|
|
52
58
|
return o[key.replace(/\]$/, '')];
|
|
53
59
|
}
|
|
@@ -80,35 +86,52 @@ function entryCreateScript(contentType) {
|
|
|
80
86
|
return references;
|
|
81
87
|
};
|
|
82
88
|
|
|
83
|
-
const findAssets = function (schema, entry
|
|
89
|
+
const findAssets = function (schema, entry) {
|
|
84
90
|
for (const i in schema) {
|
|
85
|
-
const currentPath = path ? path + '[' + schema[i].uid : schema[i].uid;
|
|
86
91
|
if (schema[i].data_type === 'group' || schema[i].data_type === 'global_field') {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
92
|
+
parent.push(schema[i].uid);
|
|
93
|
+
findAssets(schema[i].schema, entry);
|
|
94
|
+
parent.pop();
|
|
95
|
+
}
|
|
96
|
+
if (schema[i].data_type === 'blocks') {
|
|
97
|
+
for (const j = 0; j < schema[i].blocks; j++) {
|
|
90
98
|
{
|
|
91
|
-
if (schema[i].blocks[
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
);
|
|
99
|
+
if (schema[i].blocks[j].schema) {
|
|
100
|
+
parent.push(schema[i].uid);
|
|
101
|
+
parent.push(j);
|
|
102
|
+
parent.push(schema[i].blocks[j].uid);
|
|
103
|
+
findAssets(schema[i].blocks[j].schema, entry);
|
|
104
|
+
parent.pop();
|
|
105
|
+
parent.pop();
|
|
106
|
+
parent.pop();
|
|
98
107
|
}
|
|
99
108
|
}
|
|
100
109
|
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
|
|
110
|
+
}
|
|
111
|
+
if (schema[i].data_type === 'json' && schema[i].field_metadata.rich_text_type) {
|
|
112
|
+
parent.push(schema[i].uid);
|
|
113
|
+
findAssetIdsFromJsonRte(entry, schema);
|
|
114
|
+
parent.pop();
|
|
115
|
+
}
|
|
116
|
+
if (
|
|
104
117
|
schema[i].data_type === 'text' &&
|
|
105
118
|
schema[i].field_metadata &&
|
|
106
119
|
(schema[i].field_metadata.markdown || schema[i].field_metadata.rich_text_type)
|
|
107
120
|
) {
|
|
121
|
+
parent.push(schema[i].uid);
|
|
108
122
|
findFileUrls(schema[i], entry);
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
123
|
+
if (schema[i].field_metadata.rich_text_type) {
|
|
124
|
+
findAssetIdsFromHtmlRte(entry, schema[i]);
|
|
125
|
+
}
|
|
126
|
+
parent.pop();
|
|
127
|
+
}
|
|
128
|
+
if (schema[i].data_type === 'file') {
|
|
129
|
+
parent.push(schema[i].uid);
|
|
130
|
+
let updatedEntry = entry;
|
|
131
|
+
for (let i = 0; i < parent.length; i++) {
|
|
132
|
+
updatedEntry = updatedEntry[parent[i]];
|
|
133
|
+
}
|
|
134
|
+
const imgDetails = updatedEntry;
|
|
112
135
|
if (schema[i].multiple) {
|
|
113
136
|
if (imgDetails && imgDetails.length) {
|
|
114
137
|
imgDetails.forEach((img) => {
|
|
@@ -136,10 +159,21 @@ function entryCreateScript(contentType) {
|
|
|
136
159
|
cAssetDetails.push(obj);
|
|
137
160
|
}
|
|
138
161
|
}
|
|
162
|
+
parent.pop();
|
|
139
163
|
}
|
|
140
164
|
}
|
|
141
165
|
};
|
|
142
166
|
|
|
167
|
+
function findAssetIdsFromHtmlRte(entryObj, ctSchema) {
|
|
168
|
+
const regex = /<img asset_uid=\\"([^"]+)\\"/g;
|
|
169
|
+
let match;
|
|
170
|
+
const entry = JSON.stringify(entryObj);
|
|
171
|
+
while ((match = regex.exec(entry)) !== null) {
|
|
172
|
+
//insert into asset details
|
|
173
|
+
cAssetDetails.push({uid: match[1]});
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
143
177
|
function findFileUrls(schema, _entry) {
|
|
144
178
|
let markdownRegEx;
|
|
145
179
|
let markdownMatch;
|
|
@@ -259,31 +293,8 @@ function entryCreateScript(contentType) {
|
|
|
259
293
|
}
|
|
260
294
|
|
|
261
295
|
const updateAssetDetailsInEntries = function (entry) {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
if (imgDetails !== undefined) {
|
|
265
|
-
if (imgDetails && !Array.isArray(imgDetails)) {
|
|
266
|
-
entry[refPath] = assetUIDMapper[imgDetails.uid];
|
|
267
|
-
} else if (imgDetails && Array.isArray(imgDetails)) {
|
|
268
|
-
for (let i = 0; i < imgDetails.length; i++) {
|
|
269
|
-
const img = imgDetails[i];
|
|
270
|
-
entry[refPath][i] = assetUIDMapper[img.uid];
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
} else {
|
|
274
|
-
imgDetails = getValueByPath(entry, refPath);
|
|
275
|
-
if (imgDetails && !Array.isArray(imgDetails)) {
|
|
276
|
-
const imgUID = imgDetails?.uid;
|
|
277
|
-
updateValueByPath(entry, refPath, assetUIDMapper[imgUID], 'file', 0);
|
|
278
|
-
} else if (imgDetails && Array.isArray(imgDetails)) {
|
|
279
|
-
for (let i = 0; i < imgDetails.length; i++) {
|
|
280
|
-
const img = imgDetails[i];
|
|
281
|
-
const imgUID = img?.uid;
|
|
282
|
-
updateValueByPath(entry, refPath, assetUIDMapper[imgUID], 'file', i);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
});
|
|
296
|
+
let updatedEntry = Object.assign({},entry);
|
|
297
|
+
entry = updateFileFields(updatedEntry, entry, null)
|
|
287
298
|
entry = JSON.stringify(entry);
|
|
288
299
|
const assetUrls = cAssetDetails.map((asset) => asset.url);
|
|
289
300
|
const assetUIDs = cAssetDetails.map((asset) => asset.uid);
|
|
@@ -302,6 +313,65 @@ function entryCreateScript(contentType) {
|
|
|
302
313
|
});
|
|
303
314
|
return JSON.parse(entry);
|
|
304
315
|
};
|
|
316
|
+
|
|
317
|
+
function updateFileFields(
|
|
318
|
+
object,
|
|
319
|
+
parent,
|
|
320
|
+
pos
|
|
321
|
+
) {
|
|
322
|
+
if (isPlainObject(object) && has(object, 'filename') && has(object, 'uid')) {
|
|
323
|
+
if (typeof pos !== 'undefined') {
|
|
324
|
+
if (typeof pos === 'number' || typeof pos === 'string') {
|
|
325
|
+
const replacer = () => {
|
|
326
|
+
if (assetUIDMapper.hasOwnProperty(object.uid)) {
|
|
327
|
+
parent[pos] = assetUIDMapper[object.uid];
|
|
328
|
+
} else {
|
|
329
|
+
parent[pos] = '';
|
|
330
|
+
}
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
if (parent.uid && assetUIDMapper[parent.uid]) {
|
|
334
|
+
parent.uid = assetUIDMapper[parent.uid];
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (
|
|
338
|
+
object &&
|
|
339
|
+
isObject(parent[pos]) &&
|
|
340
|
+
parent[pos].uid &&
|
|
341
|
+
parent[pos].url &&
|
|
342
|
+
has(parent, 'asset') &&
|
|
343
|
+
has(parent, '_content_type_uid') &&
|
|
344
|
+
parent._content_type_uid === 'sys_assets'
|
|
345
|
+
) {
|
|
346
|
+
if (
|
|
347
|
+
has(parent, 'asset') &&
|
|
348
|
+
has(parent, '_content_type_uid') &&
|
|
349
|
+
parent._content_type_uid === 'sys_assets'
|
|
350
|
+
) {
|
|
351
|
+
parent = omit(parent, ['asset']);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if (object.uid && assetUIDMapper[object.uid]) {
|
|
355
|
+
object.uid = assetUIDMapper[object.uid];
|
|
356
|
+
}
|
|
357
|
+
if (object.url && assetUrlMapper[object.url]) {
|
|
358
|
+
object.url = assetUrlMapper[object.url];
|
|
359
|
+
}
|
|
360
|
+
} else {
|
|
361
|
+
replacer();
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
} else if (isPlainObject(object)) {
|
|
366
|
+
for (let key in object) updateFileFields(object[key], object, key);
|
|
367
|
+
} else if (isArray(object) && object.length) {
|
|
368
|
+
for (let i = 0; i <= object.length; i++){
|
|
369
|
+
updateFileFields(object[i], object, i);
|
|
370
|
+
}
|
|
371
|
+
parent[pos] = compact(object);
|
|
372
|
+
}
|
|
373
|
+
return object;
|
|
374
|
+
}
|
|
305
375
|
|
|
306
376
|
const checkAndDownloadAsset = async function (cAsset) {
|
|
307
377
|
const assetUID = cAsset?.uid;
|
|
@@ -318,7 +388,6 @@ function entryCreateScript(contentType) {
|
|
|
318
388
|
return false;
|
|
319
389
|
}
|
|
320
390
|
else {
|
|
321
|
-
isAssetDownload = true;
|
|
322
391
|
const cAssetDetail = await managementAPIClient
|
|
323
392
|
.stack({ api_key: stackSDKInstance.api_key, branch_uid: compareBranch })
|
|
324
393
|
.asset(assetUID)
|
|
@@ -360,8 +429,8 @@ function entryCreateScript(contentType) {
|
|
|
360
429
|
const uploadAssets = async function () {
|
|
361
430
|
const assetFolderMap = JSON.parse(fs.readFileSync(path.resolve(filePath, 'folder-mapper.json'), 'utf8'));
|
|
362
431
|
const stackAPIClient = managementAPIClient.stack({ api_key: stackSDKInstance.api_key, branch_uid: branch });
|
|
363
|
-
for (let i = 0; i <
|
|
364
|
-
const asset =
|
|
432
|
+
for (let i = 0; i < downloadedAssets?.length; i++) {
|
|
433
|
+
const asset = downloadedAssets[i];
|
|
365
434
|
let requestOption = {};
|
|
366
435
|
|
|
367
436
|
requestOption.parent_uid = assetFolderMap[asset.parent_uid] || asset.parent_uid;
|
|
@@ -404,6 +473,11 @@ function entryCreateScript(contentType) {
|
|
|
404
473
|
successTitle: 'Entries Created Successfully',
|
|
405
474
|
failedTitle: 'Failed to create entries',
|
|
406
475
|
task: async () => {
|
|
476
|
+
//logger file
|
|
477
|
+
if(!fs.existsSync(path.join(filePath, 'entry-migration'))){
|
|
478
|
+
logger = new LoggerService(filePath, 'entry-migration');
|
|
479
|
+
}
|
|
480
|
+
|
|
407
481
|
const compareBranchEntries = await managementAPIClient
|
|
408
482
|
.stack({ api_key: stackSDKInstance.api_key, branch_uid: compareBranch })
|
|
409
483
|
.contentType('${contentType}')
|
|
@@ -435,9 +509,10 @@ function entryCreateScript(contentType) {
|
|
|
435
509
|
const updatedCAsset = await checkAndDownloadAsset(asset);
|
|
436
510
|
if (updatedCAsset) {
|
|
437
511
|
cAssetDetails[i] = updatedCAsset;
|
|
512
|
+
downloadedAssets.push(updatedCAsset)
|
|
438
513
|
}
|
|
439
514
|
}
|
|
440
|
-
if (
|
|
515
|
+
if (downloadedAssets?.length) await uploadAssets();
|
|
441
516
|
}
|
|
442
517
|
|
|
443
518
|
let flag = {
|
|
@@ -448,7 +523,17 @@ function entryCreateScript(contentType) {
|
|
|
448
523
|
|
|
449
524
|
async function updateEntry(entry, entryDetails) {
|
|
450
525
|
Object.assign(entry, { ...entryDetails });
|
|
451
|
-
await entry.update()
|
|
526
|
+
await entry.update().catch(err => {
|
|
527
|
+
let errorMsg = 'Entry update failed for uid: ' + entry?.uid + ', title: ' + entry?.title + '. ';
|
|
528
|
+
if(err?.errors?.title){
|
|
529
|
+
errorMsg += 'title'+ err?.errors?.title;
|
|
530
|
+
}else if(err?.errors?.entry){
|
|
531
|
+
errorMsg += err?.errors?.entry;
|
|
532
|
+
}else{
|
|
533
|
+
errorMsg += (err?.entry?.errorMessage || err?.errorMessage || err?.message) ?? 'Something went wrong!';
|
|
534
|
+
}
|
|
535
|
+
logger.error(errorMsg)
|
|
536
|
+
});
|
|
452
537
|
}
|
|
453
538
|
|
|
454
539
|
async function updateReferences(entryDetails, baseEntry, references) {
|
|
@@ -478,15 +563,25 @@ function entryCreateScript(contentType) {
|
|
|
478
563
|
try {
|
|
479
564
|
compareFilteredProperties.length !== 0 &&
|
|
480
565
|
compareFilteredProperties.forEach(async (entryDetails) => {
|
|
481
|
-
entryDetails
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
566
|
+
if(entryDetails !== undefined){
|
|
567
|
+
entryDetails = updateAssetDetailsInEntries(entryDetails);
|
|
568
|
+
let createdEntry = await stackSDKInstance.contentType('${contentType}').entry().create({ entry: entryDetails }).catch(err => {
|
|
569
|
+
let errorMsg = 'Entry creation failed for contentType: ' + contentType + ', title: ' + entryDetails?.title + '. ';
|
|
570
|
+
if(err?.errors?.title){
|
|
571
|
+
errorMsg += err?.errors?.title;
|
|
572
|
+
}else if(err?.errors?.entry){
|
|
573
|
+
errorMsg += err?.errors?.entry;
|
|
574
|
+
}else{
|
|
575
|
+
errorMsg += (err?.entry?.errorMessage || err?.errorMessage || err?.message) ?? 'Something went wrong!';
|
|
576
|
+
}
|
|
577
|
+
logger.error(errorMsg)
|
|
578
|
+
});
|
|
579
|
+
if(createdEntry){
|
|
580
|
+
if (flag.references) {
|
|
581
|
+
await updateReferences(entryDetails, createdEntry, references);
|
|
582
|
+
}
|
|
583
|
+
await updateEntry(createdEntry, entryDetails);
|
|
488
584
|
}
|
|
489
|
-
await updateEntry(createdEntry, entryDetails);
|
|
490
585
|
}
|
|
491
586
|
});
|
|
492
587
|
} catch (error) {
|
|
@@ -5,6 +5,14 @@ function entryCreateUpdateScript(contentType) {
|
|
|
5
5
|
return `
|
|
6
6
|
const fs = require('fs');
|
|
7
7
|
const path = require('path');
|
|
8
|
+
const { marked } = require('marked');
|
|
9
|
+
const has = require('lodash/has');
|
|
10
|
+
const isArray = require('lodash/isArray');
|
|
11
|
+
const isObject = require('lodash/isObject');
|
|
12
|
+
const omit = require('lodash/omit');
|
|
13
|
+
const compact = require('lodash/compact')
|
|
14
|
+
const isPlainObject = require('lodash/isPlainObject');
|
|
15
|
+
const {cliux, LoggerService} = require('@contentstack/cli-utilities')
|
|
8
16
|
module.exports = async ({ migration, stackSDKInstance, managementAPIClient, config, branch, apiKey }) => {
|
|
9
17
|
const keysToRemove = [
|
|
10
18
|
'content_type_uid',
|
|
@@ -32,10 +40,12 @@ function entryCreateUpdateScript(contentType) {
|
|
|
32
40
|
let assetDirPath = path.resolve(filePath, 'assets');
|
|
33
41
|
let assetDetails = [];
|
|
34
42
|
let newAssetDetails = [];
|
|
43
|
+
let downloadedAssets = [];
|
|
35
44
|
let assetUIDMapper = {};
|
|
36
45
|
let assetUrlMapper = {};
|
|
37
46
|
let assetRefPath = {};
|
|
38
|
-
let
|
|
47
|
+
let parent=[];
|
|
48
|
+
let logger;
|
|
39
49
|
|
|
40
50
|
function converter(data) {
|
|
41
51
|
let arr = [];
|
|
@@ -62,14 +72,10 @@ function entryCreateUpdateScript(contentType) {
|
|
|
62
72
|
return path.split('[').reduce((o, key) => o && o[key.replace(/\]$/, '')], obj);
|
|
63
73
|
}
|
|
64
74
|
|
|
65
|
-
function updateValueByPath(obj, path, newValue
|
|
75
|
+
function updateValueByPath(obj, path, newValue) {
|
|
66
76
|
path.split('[').reduce((o, key, index, arr) => {
|
|
67
77
|
if (index === arr.length - 1) {
|
|
68
|
-
if (type === 'file') {
|
|
69
|
-
o[key.replace(/]$/, '')][fileIndex] = newValue;
|
|
70
|
-
} else {
|
|
71
78
|
o[key.replace(/]$/, '')][0].uid = newValue;
|
|
72
|
-
}
|
|
73
79
|
} else {
|
|
74
80
|
return o[key.replace(/\]$/, '')];
|
|
75
81
|
}
|
|
@@ -102,65 +108,93 @@ function entryCreateUpdateScript(contentType) {
|
|
|
102
108
|
return references;
|
|
103
109
|
};
|
|
104
110
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
111
|
+
const findAssets = function (schema, entry) {
|
|
112
|
+
for (const i in schema) {
|
|
113
|
+
if (schema[i].data_type === 'group' || schema[i].data_type === 'global_field') {
|
|
114
|
+
parent.push(schema[i].uid);
|
|
115
|
+
findAssets(schema[i].schema, entry);
|
|
116
|
+
parent.pop();
|
|
117
|
+
}
|
|
118
|
+
if (schema[i].data_type === 'blocks') {
|
|
119
|
+
for (const j = 0; j < schema[i].blocks; j++) {
|
|
120
|
+
{
|
|
121
|
+
if (schema[i].blocks[j].schema) {
|
|
122
|
+
parent.push(schema[i].uid);
|
|
123
|
+
parent.push(j);
|
|
124
|
+
parent.push(schema[i].blocks[j].uid);
|
|
125
|
+
findAssets(schema[i].blocks[j].schema, entry);
|
|
126
|
+
parent.pop();
|
|
127
|
+
parent.pop();
|
|
128
|
+
parent.pop();
|
|
129
|
+
}
|
|
120
130
|
}
|
|
121
131
|
}
|
|
122
132
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
(
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
if (
|
|
136
|
-
|
|
133
|
+
if (schema[i].data_type === 'json' && schema[i].field_metadata.rich_text_type) {
|
|
134
|
+
parent.push(schema[i].uid);
|
|
135
|
+
findAssetIdsFromJsonRte(entry, schema);
|
|
136
|
+
parent.pop();
|
|
137
|
+
}
|
|
138
|
+
if (
|
|
139
|
+
schema[i].data_type === 'text' &&
|
|
140
|
+
schema[i].field_metadata &&
|
|
141
|
+
(schema[i].field_metadata.markdown || schema[i].field_metadata.rich_text_type)
|
|
142
|
+
) {
|
|
143
|
+
parent.push(schema[i].uid);
|
|
144
|
+
findFileUrls(schema[i], entry);
|
|
145
|
+
if (schema[i].field_metadata.rich_text_type) {
|
|
146
|
+
findAssetIdsFromHtmlRte(entry, schema[i]);
|
|
147
|
+
}
|
|
148
|
+
parent.pop();
|
|
149
|
+
}
|
|
150
|
+
if (schema[i].data_type === 'file') {
|
|
151
|
+
parent.push(schema[i].uid);
|
|
152
|
+
let updatedEntry = entry;
|
|
153
|
+
for (let i = 0; i < parent.length; i++) {
|
|
154
|
+
updatedEntry = updatedEntry[parent[i]];
|
|
155
|
+
}
|
|
156
|
+
const imgDetails = updatedEntry;
|
|
157
|
+
if (schema[i].multiple) {
|
|
158
|
+
if (imgDetails && imgDetails.length) {
|
|
159
|
+
imgDetails.forEach((img) => {
|
|
160
|
+
const obj = {
|
|
161
|
+
uid: img.uid,
|
|
162
|
+
parent_uid: img.parent_uid,
|
|
163
|
+
description: img.description,
|
|
164
|
+
title: img.title,
|
|
165
|
+
filename: img.filename,
|
|
166
|
+
url: img.url,
|
|
167
|
+
};
|
|
168
|
+
assetDetails.push(obj);
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
} else {
|
|
172
|
+
if (imgDetails) {
|
|
137
173
|
const obj = {
|
|
138
|
-
uid:
|
|
139
|
-
parent_uid:
|
|
140
|
-
description:
|
|
141
|
-
title:
|
|
142
|
-
filename:
|
|
143
|
-
url:
|
|
174
|
+
uid: imgDetails.uid,
|
|
175
|
+
parent_uid: imgDetails.parent_uid,
|
|
176
|
+
description: imgDetails.description,
|
|
177
|
+
title: imgDetails.title,
|
|
178
|
+
filename: imgDetails.filename,
|
|
179
|
+
url: imgDetails.url,
|
|
144
180
|
};
|
|
145
181
|
assetDetails.push(obj);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
} else {
|
|
149
|
-
if (imgDetails) {
|
|
150
|
-
const obj = {
|
|
151
|
-
uid: imgDetails.uid,
|
|
152
|
-
parent_uid: imgDetails.parent_uid,
|
|
153
|
-
description: imgDetails.description,
|
|
154
|
-
title: imgDetails.title,
|
|
155
|
-
filename: imgDetails.filename,
|
|
156
|
-
url: imgDetails.url,
|
|
157
|
-
};
|
|
158
|
-
assetDetails.push(obj);
|
|
182
|
+
}
|
|
159
183
|
}
|
|
184
|
+
parent.pop();
|
|
160
185
|
}
|
|
161
186
|
}
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
function findAssetIdsFromHtmlRte(entryObj, ctSchema) {
|
|
190
|
+
const regex = /<img asset_uid=\\"([^"]+)\\"/g;
|
|
191
|
+
let match;
|
|
192
|
+
const entry = JSON.stringify(entryObj);
|
|
193
|
+
while ((match = regex.exec(entry)) !== null) {
|
|
194
|
+
//insert into asset details
|
|
195
|
+
assetDetails.push({uid: match[1]});
|
|
196
|
+
}
|
|
162
197
|
}
|
|
163
|
-
};
|
|
164
198
|
|
|
165
199
|
function findFileUrls(schema, _entry) {
|
|
166
200
|
let markdownRegEx;
|
|
@@ -281,31 +315,8 @@ function entryCreateUpdateScript(contentType) {
|
|
|
281
315
|
}
|
|
282
316
|
|
|
283
317
|
const updateAssetDetailsInEntries = function (entry) {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
if (imgDetails !== undefined) {
|
|
287
|
-
if (imgDetails && !Array.isArray(imgDetails)) {
|
|
288
|
-
entry[refPath] = assetUIDMapper[imgDetails.uid];
|
|
289
|
-
} else if (imgDetails && Array.isArray(imgDetails)) {
|
|
290
|
-
for (let i = 0; i < imgDetails.length; i++) {
|
|
291
|
-
const img = imgDetails[i];
|
|
292
|
-
entry[refPath][i] = assetUIDMapper[img.uid];
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
} else {
|
|
296
|
-
imgDetails = getValueByPath(entry, refPath);
|
|
297
|
-
if (imgDetails && !Array.isArray(imgDetails)) {
|
|
298
|
-
const imgUID = imgDetails?.uid;
|
|
299
|
-
updateValueByPath(entry, refPath, assetUIDMapper[imgUID], 'file', 0);
|
|
300
|
-
} else if (imgDetails && Array.isArray(imgDetails)) {
|
|
301
|
-
for (let i = 0; i < imgDetails.length; i++) {
|
|
302
|
-
const img = imgDetails[i];
|
|
303
|
-
const imgUID = img?.uid;
|
|
304
|
-
updateValueByPath(entry, refPath, assetUIDMapper[imgUID], 'file', i);
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
});
|
|
318
|
+
let updatedEntry = Object.assign({},entry);
|
|
319
|
+
entry = updateFileFields(updatedEntry, entry, null)
|
|
309
320
|
entry = JSON.stringify(entry);
|
|
310
321
|
const assetUrls = assetDetails.map((asset) => asset.url);
|
|
311
322
|
const assetUIDs = assetDetails.map((asset) => asset.uid);
|
|
@@ -324,6 +335,65 @@ function entryCreateUpdateScript(contentType) {
|
|
|
324
335
|
});
|
|
325
336
|
return JSON.parse(entry);
|
|
326
337
|
};
|
|
338
|
+
|
|
339
|
+
function updateFileFields(
|
|
340
|
+
object,
|
|
341
|
+
parent,
|
|
342
|
+
pos
|
|
343
|
+
) {
|
|
344
|
+
if (isPlainObject(object) && has(object, 'filename') && has(object, 'uid')) {
|
|
345
|
+
if (typeof pos !== 'undefined') {
|
|
346
|
+
if (typeof pos === 'number' || typeof pos === 'string') {
|
|
347
|
+
const replacer = () => {
|
|
348
|
+
if (assetUIDMapper.hasOwnProperty(object.uid)) {
|
|
349
|
+
parent[pos] = assetUIDMapper[object.uid];
|
|
350
|
+
} else {
|
|
351
|
+
parent[pos] = '';
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
if (parent.uid && assetUIDMapper[parent.uid]) {
|
|
356
|
+
parent.uid = assetUIDMapper[parent.uid];
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
if (
|
|
360
|
+
object &&
|
|
361
|
+
isObject(parent[pos]) &&
|
|
362
|
+
parent[pos].uid &&
|
|
363
|
+
parent[pos].url &&
|
|
364
|
+
has(parent, 'asset') &&
|
|
365
|
+
has(parent, '_content_type_uid') &&
|
|
366
|
+
parent._content_type_uid === 'sys_assets'
|
|
367
|
+
) {
|
|
368
|
+
if (
|
|
369
|
+
has(parent, 'asset') &&
|
|
370
|
+
has(parent, '_content_type_uid') &&
|
|
371
|
+
parent._content_type_uid === 'sys_assets'
|
|
372
|
+
) {
|
|
373
|
+
parent = omit(parent, ['asset']);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
if (object.uid && assetUIDMapper[object.uid]) {
|
|
377
|
+
object.uid = assetUIDMapper[object.uid];
|
|
378
|
+
}
|
|
379
|
+
if (object.url && assetUrlMapper[object.url]) {
|
|
380
|
+
object.url = assetUrlMapper[object.url];
|
|
381
|
+
}
|
|
382
|
+
} else {
|
|
383
|
+
replacer();
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
} else if (isPlainObject(object)) {
|
|
388
|
+
for (let key in object) updateFileFields(object[key], object, key);
|
|
389
|
+
} else if (isArray(object) && object.length) {
|
|
390
|
+
for (let i = 0; i <= object.length; i++){
|
|
391
|
+
updateFileFields(object[i], object, i);
|
|
392
|
+
}
|
|
393
|
+
parent[pos] = compact(object);
|
|
394
|
+
}
|
|
395
|
+
return object;
|
|
396
|
+
}
|
|
327
397
|
|
|
328
398
|
const checkAndDownloadAsset = async function (cAsset) {
|
|
329
399
|
if (cAsset) {
|
|
@@ -340,7 +410,6 @@ function entryCreateUpdateScript(contentType) {
|
|
|
340
410
|
return false;
|
|
341
411
|
}
|
|
342
412
|
else {
|
|
343
|
-
isAssetDownload = true;
|
|
344
413
|
const cAssetDetail = await managementAPIClient
|
|
345
414
|
.stack({ api_key: stackSDKInstance.api_key, branch_uid: compareBranch })
|
|
346
415
|
.asset(assetUID)
|
|
@@ -382,8 +451,8 @@ function entryCreateUpdateScript(contentType) {
|
|
|
382
451
|
const uploadAssets = async function () {
|
|
383
452
|
const assetFolderMap = JSON.parse(fs.readFileSync(path.resolve(filePath, 'folder-mapper.json'), 'utf8'));
|
|
384
453
|
const stackAPIClient = managementAPIClient.stack({ api_key: stackSDKInstance.api_key, branch_uid: branch });
|
|
385
|
-
for (let i = 0; i <
|
|
386
|
-
const asset =
|
|
454
|
+
for (let i = 0; i < downloadedAssets?.length; i++) {
|
|
455
|
+
const asset = downloadedAssets[i];
|
|
387
456
|
let requestOption = {};
|
|
388
457
|
|
|
389
458
|
requestOption.parent_uid = assetFolderMap[asset.parent_uid] || asset.parent_uid;
|
|
@@ -419,6 +488,10 @@ function entryCreateUpdateScript(contentType) {
|
|
|
419
488
|
successMessage: 'Entries Updated Successfully',
|
|
420
489
|
failedMessage: 'Failed to update entries',
|
|
421
490
|
task: async () => {
|
|
491
|
+
//logger file
|
|
492
|
+
if(!fs.existsSync(path.join(filePath, 'entry-migration'))){
|
|
493
|
+
logger = new LoggerService(filePath, 'entry-migration');
|
|
494
|
+
}
|
|
422
495
|
let compareBranchEntries = await managementAPIClient
|
|
423
496
|
.stack({ api_key: stackSDKInstance.api_key, branch_uid: compareBranch })
|
|
424
497
|
.contentType('${contentType}')
|
|
@@ -454,9 +527,10 @@ function entryCreateUpdateScript(contentType) {
|
|
|
454
527
|
const updatedCAsset = await checkAndDownloadAsset(asset);
|
|
455
528
|
if(updatedCAsset){
|
|
456
529
|
newAssetDetails[i] = updatedCAsset;
|
|
530
|
+
downloadedAssets.push(updatedCAsset)
|
|
457
531
|
}
|
|
458
532
|
}
|
|
459
|
-
if (
|
|
533
|
+
if (downloadedAssets?.length) await uploadAssets();
|
|
460
534
|
}
|
|
461
535
|
|
|
462
536
|
let flag = {
|
|
@@ -468,7 +542,17 @@ function entryCreateUpdateScript(contentType) {
|
|
|
468
542
|
async function updateEntry(entry, entryDetails) {
|
|
469
543
|
if (entry) {
|
|
470
544
|
Object.assign(entry, { ...entryDetails });
|
|
471
|
-
await entry.update()
|
|
545
|
+
await entry.update().catch(err => {
|
|
546
|
+
let errorMsg = 'Entry update failed for uid: ' + entry?.uid + ', title: ' + entry?.title + '.';
|
|
547
|
+
if(err?.errors?.title){
|
|
548
|
+
errorMsg += err?.errors?.title;
|
|
549
|
+
}else if(err?.errors?.entry){
|
|
550
|
+
errorMsg += err?.errors?.entry;
|
|
551
|
+
}else{
|
|
552
|
+
errorMsg += (err?.entry?.errorMessage || err?.errorMessage || err?.message) ?? 'Something went wrong!';
|
|
553
|
+
}
|
|
554
|
+
logger.error(errorMsg)
|
|
555
|
+
});
|
|
472
556
|
}
|
|
473
557
|
}
|
|
474
558
|
|
|
@@ -497,56 +581,70 @@ function entryCreateUpdateScript(contentType) {
|
|
|
497
581
|
}
|
|
498
582
|
|
|
499
583
|
try {
|
|
500
|
-
if (contentType
|
|
501
|
-
compareBranchEntries
|
|
584
|
+
if (contentType?.options?.singleton) {
|
|
585
|
+
compareBranchEntries?.items?.map(async (el) => {
|
|
502
586
|
let entryDetails = deleteUnwantedKeysFromObject(el, keysToRemove);
|
|
503
|
-
entryDetails
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
587
|
+
if(entryDetails !== undefined){
|
|
588
|
+
entryDetails = updateAssetDetailsInEntries(entryDetails);
|
|
589
|
+
|
|
590
|
+
if (baseBranchEntries && baseBranchEntries.items.length) {
|
|
591
|
+
let baseEntryUid = baseBranchEntries.items[0].uid;
|
|
592
|
+
let entry = await stackSDKInstance.contentType('${contentType}').entry(baseEntryUid);
|
|
593
|
+
|
|
594
|
+
if (flag.references) {
|
|
595
|
+
await updateReferences(entryDetails, baseBranchEntries.items[0], references);
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
await updateEntry(entry, entryDetails);
|
|
599
|
+
} else {
|
|
600
|
+
let createdEntry = await stackSDKInstance.contentType('${contentType}').entry().create({ entry: entryDetails });
|
|
508
601
|
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
} else {
|
|
515
|
-
let createdEntry = await stackSDKInstance.contentType('${contentType}').entry().create({ entry: entryDetails });
|
|
516
|
-
|
|
517
|
-
if (flag.references) {
|
|
518
|
-
await updateReferences(entryDetails, createdEntry, references);
|
|
602
|
+
if (flag.references) {
|
|
603
|
+
await updateReferences(entryDetails, createdEntry, references);
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
await updateEntry(createdEntry, entryDetails);
|
|
519
607
|
}
|
|
520
|
-
|
|
521
|
-
await updateEntry(createdEntry, entryDetails);
|
|
522
608
|
}
|
|
523
609
|
});
|
|
524
610
|
} else {
|
|
525
611
|
let compareMap = new Map(converter(compareBranchEntries.items));
|
|
526
612
|
let baseMap = new Map(converter(baseBranchEntries.items));
|
|
527
|
-
|
|
613
|
+
|
|
614
|
+
//NOTE: Filter distinct entries from the base and compare branches according to their titles.
|
|
615
|
+
//TODO: Need to discuss this approach and replace it with uid condition
|
|
528
616
|
let arr = uniquelyConcatenateArrays(Array.from(compareMap.keys()), Array.from(baseMap.keys()));
|
|
529
|
-
|
|
617
|
+
|
|
530
618
|
arr.map(async (el) => {
|
|
531
619
|
let entryDetails = deleteUnwantedKeysFromObject(compareMap.get(el), keysToRemove);
|
|
532
|
-
|
|
533
|
-
if
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
620
|
+
//NOTE: In the compare branch, entry must exist. Condition of deleted entry not handled
|
|
621
|
+
if(entryDetails !== undefined){
|
|
622
|
+
entryDetails = updateAssetDetailsInEntries(entryDetails);
|
|
623
|
+
if (compareMap.get(el) && !baseMap.get(el)) {
|
|
624
|
+
let createdEntry = await stackSDKInstance
|
|
625
|
+
.contentType('${contentType}')
|
|
626
|
+
.entry()
|
|
627
|
+
.create({ entry: entryDetails })
|
|
628
|
+
.catch(err => {
|
|
629
|
+
(err?.errorMessage || err?.message) ? err?.errorMessage || err?.message : 'Something went wrong!'
|
|
630
|
+
})
|
|
631
|
+
|
|
632
|
+
if(createdEntry){
|
|
633
|
+
if (flag.references) {
|
|
634
|
+
await updateReferences(entryDetails, createdEntry, references);
|
|
635
|
+
}
|
|
636
|
+
await updateEntry(createdEntry, entryDetails);
|
|
637
|
+
}
|
|
638
|
+
} else if (compareMap.get(el) && baseMap.get(el)) {
|
|
639
|
+
let baseEntry = baseMap.get(el);
|
|
640
|
+
let entry = await stackSDKInstance.contentType('${contentType}').entry(baseEntry.uid);
|
|
641
|
+
|
|
642
|
+
if (flag.references) {
|
|
643
|
+
await updateReferences(entryDetails, baseEntry, references);
|
|
644
|
+
}
|
|
539
645
|
|
|
540
|
-
|
|
541
|
-
} else if (compareMap.get(el) && baseMap.get(el)) {
|
|
542
|
-
let baseEntry = baseMap.get(el);
|
|
543
|
-
let entry = await stackSDKInstance.contentType('${contentType}').entry(baseEntry.uid);
|
|
544
|
-
|
|
545
|
-
if (flag.references) {
|
|
546
|
-
await updateReferences(entryDetails, baseEntry, references);
|
|
646
|
+
await updateEntry(entry, entryDetails);
|
|
547
647
|
}
|
|
548
|
-
|
|
549
|
-
await updateEntry(entry, entryDetails);
|
|
550
648
|
}
|
|
551
649
|
});
|
|
552
650
|
}
|
|
@@ -5,6 +5,14 @@ function entryUpdateScript(contentType) {
|
|
|
5
5
|
return `
|
|
6
6
|
const fs = require('fs');
|
|
7
7
|
const path = require('path');
|
|
8
|
+
const { marked } = require('marked');
|
|
9
|
+
const has = require('lodash/has');
|
|
10
|
+
const isArray = require('lodash/isArray');
|
|
11
|
+
const isObject = require('lodash/isObject');
|
|
12
|
+
const omit = require('lodash/omit');
|
|
13
|
+
const compact = require('lodash/compact')
|
|
14
|
+
const isPlainObject = require('lodash/isPlainObject');
|
|
15
|
+
const {cliux, LoggerService} = require('@contentstack/cli-utilities')
|
|
8
16
|
module.exports = async ({ migration, stackSDKInstance, managementAPIClient, config, branch, apiKey }) => {
|
|
9
17
|
const keysToRemove = [
|
|
10
18
|
'content_type_uid',
|
|
@@ -32,10 +40,12 @@ function entryUpdateScript(contentType) {
|
|
|
32
40
|
let assetDirPath = path.resolve(filePath, 'assets');
|
|
33
41
|
let assetDetails = [];
|
|
34
42
|
let newAssetDetails = [];
|
|
43
|
+
let downloadedAssets = [];
|
|
35
44
|
let assetUIDMapper = {};
|
|
36
45
|
let assetUrlMapper = {};
|
|
37
46
|
let assetRefPath = {};
|
|
38
|
-
let
|
|
47
|
+
let parent=[];
|
|
48
|
+
let logger;
|
|
39
49
|
|
|
40
50
|
function converter(data) {
|
|
41
51
|
let arr = [];
|
|
@@ -62,14 +72,10 @@ function entryUpdateScript(contentType) {
|
|
|
62
72
|
return path.split('[').reduce((o, key) => o && o[key.replace(/\]$/, '')], obj);
|
|
63
73
|
}
|
|
64
74
|
|
|
65
|
-
function updateValueByPath(obj, path, newValue
|
|
75
|
+
function updateValueByPath(obj, path, newValue) {
|
|
66
76
|
path.split('[').reduce((o, key, index, arr) => {
|
|
67
77
|
if (index === arr.length - 1) {
|
|
68
|
-
if (type === 'file') {
|
|
69
|
-
o[key.replace(/]$/, '')][fileIndex] = newValue;
|
|
70
|
-
} else {
|
|
71
78
|
o[key.replace(/]$/, '')][0].uid = newValue;
|
|
72
|
-
}
|
|
73
79
|
} else {
|
|
74
80
|
return o[key.replace(/\]$/, '')];
|
|
75
81
|
}
|
|
@@ -102,35 +108,52 @@ function entryUpdateScript(contentType) {
|
|
|
102
108
|
return references;
|
|
103
109
|
};
|
|
104
110
|
|
|
105
|
-
const findAssets = function (schema, entry
|
|
111
|
+
const findAssets = function (schema, entry) {
|
|
106
112
|
for (const i in schema) {
|
|
107
|
-
const currentPath = path ? path + '[' + schema[i].uid : schema[i].uid;
|
|
108
113
|
if (schema[i].data_type === 'group' || schema[i].data_type === 'global_field') {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
114
|
+
parent.push(schema[i].uid);
|
|
115
|
+
findAssets(schema[i].schema, entry);
|
|
116
|
+
parent.pop();
|
|
117
|
+
}
|
|
118
|
+
if (schema[i].data_type === 'blocks') {
|
|
119
|
+
for (const j = 0; j < schema[i].blocks; j++) {
|
|
112
120
|
{
|
|
113
|
-
if (schema[i].blocks[
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
);
|
|
121
|
+
if (schema[i].blocks[j].schema) {
|
|
122
|
+
parent.push(schema[i].uid);
|
|
123
|
+
parent.push(j);
|
|
124
|
+
parent.push(schema[i].blocks[j].uid);
|
|
125
|
+
findAssets(schema[i].blocks[j].schema, entry);
|
|
126
|
+
parent.pop();
|
|
127
|
+
parent.pop();
|
|
128
|
+
parent.pop();
|
|
120
129
|
}
|
|
121
130
|
}
|
|
122
131
|
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
|
|
132
|
+
}
|
|
133
|
+
if (schema[i].data_type === 'json' && schema[i].field_metadata.rich_text_type) {
|
|
134
|
+
parent.push(schema[i].uid);
|
|
135
|
+
findAssetIdsFromJsonRte(entry, schema);
|
|
136
|
+
parent.pop();
|
|
137
|
+
}
|
|
138
|
+
if (
|
|
126
139
|
schema[i].data_type === 'text' &&
|
|
127
140
|
schema[i].field_metadata &&
|
|
128
141
|
(schema[i].field_metadata.markdown || schema[i].field_metadata.rich_text_type)
|
|
129
142
|
) {
|
|
143
|
+
parent.push(schema[i].uid);
|
|
130
144
|
findFileUrls(schema[i], entry);
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
145
|
+
if (schema[i].field_metadata.rich_text_type) {
|
|
146
|
+
findAssetIdsFromHtmlRte(entry, schema[i]);
|
|
147
|
+
}
|
|
148
|
+
parent.pop();
|
|
149
|
+
}
|
|
150
|
+
if (schema[i].data_type === 'file') {
|
|
151
|
+
parent.push(schema[i].uid);
|
|
152
|
+
let updatedEntry = entry;
|
|
153
|
+
for (let i = 0; i < parent.length; i++) {
|
|
154
|
+
updatedEntry = updatedEntry[parent[i]];
|
|
155
|
+
}
|
|
156
|
+
const imgDetails = updatedEntry;
|
|
134
157
|
if (schema[i].multiple) {
|
|
135
158
|
if (imgDetails && imgDetails.length) {
|
|
136
159
|
imgDetails.forEach((img) => {
|
|
@@ -158,10 +181,21 @@ function entryUpdateScript(contentType) {
|
|
|
158
181
|
assetDetails.push(obj);
|
|
159
182
|
}
|
|
160
183
|
}
|
|
184
|
+
parent.pop();
|
|
161
185
|
}
|
|
162
186
|
}
|
|
163
187
|
};
|
|
164
188
|
|
|
189
|
+
function findAssetIdsFromHtmlRte(entryObj, ctSchema) {
|
|
190
|
+
const regex = /<img asset_uid=\\"([^"]+)\\"/g;
|
|
191
|
+
let match;
|
|
192
|
+
const entry = JSON.stringify(entryObj);
|
|
193
|
+
while ((match = regex.exec(entry)) !== null) {
|
|
194
|
+
//insert into asset details
|
|
195
|
+
assetDetails.push({uid: match[1]});
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
165
199
|
function findFileUrls(schema, _entry) {
|
|
166
200
|
let markdownRegEx;
|
|
167
201
|
let markdownMatch;
|
|
@@ -281,31 +315,8 @@ function entryUpdateScript(contentType) {
|
|
|
281
315
|
}
|
|
282
316
|
|
|
283
317
|
const updateAssetDetailsInEntries = function (entry) {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
if (imgDetails !== undefined) {
|
|
287
|
-
if (imgDetails && !Array.isArray(imgDetails)) {
|
|
288
|
-
entry[refPath] = assetUIDMapper[imgDetails.uid];
|
|
289
|
-
} else if (imgDetails && Array.isArray(imgDetails)) {
|
|
290
|
-
for (let i = 0; i < imgDetails.length; i++) {
|
|
291
|
-
const img = imgDetails[i];
|
|
292
|
-
entry[refPath][i] = assetUIDMapper[img.uid];
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
} else {
|
|
296
|
-
imgDetails = getValueByPath(entry, refPath);
|
|
297
|
-
if (imgDetails && !Array.isArray(imgDetails)) {
|
|
298
|
-
const imgUID = imgDetails?.uid;
|
|
299
|
-
updateValueByPath(entry, refPath, assetUIDMapper[imgUID], 'file', 0);
|
|
300
|
-
} else if (imgDetails && Array.isArray(imgDetails)) {
|
|
301
|
-
for (let i = 0; i < imgDetails.length; i++) {
|
|
302
|
-
const img = imgDetails[i];
|
|
303
|
-
const imgUID = img?.uid;
|
|
304
|
-
updateValueByPath(entry, refPath, assetUIDMapper[imgUID], 'file', i);
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
});
|
|
318
|
+
let updatedEntry = Object.assign({},entry);
|
|
319
|
+
entry = updateFileFields(updatedEntry, entry, null)
|
|
309
320
|
entry = JSON.stringify(entry);
|
|
310
321
|
const assetUrls = assetDetails.map((asset) => asset.url);
|
|
311
322
|
const assetUIDs = assetDetails.map((asset) => asset.uid);
|
|
@@ -324,6 +335,65 @@ function entryUpdateScript(contentType) {
|
|
|
324
335
|
});
|
|
325
336
|
return JSON.parse(entry);
|
|
326
337
|
};
|
|
338
|
+
|
|
339
|
+
function updateFileFields(
|
|
340
|
+
object,
|
|
341
|
+
parent,
|
|
342
|
+
pos
|
|
343
|
+
) {
|
|
344
|
+
if (isPlainObject(object) && has(object, 'filename') && has(object, 'uid')) {
|
|
345
|
+
if (typeof pos !== 'undefined') {
|
|
346
|
+
if (typeof pos === 'number' || typeof pos === 'string') {
|
|
347
|
+
const replacer = () => {
|
|
348
|
+
if (assetUIDMapper.hasOwnProperty(object.uid)) {
|
|
349
|
+
parent[pos] = assetUIDMapper[object.uid];
|
|
350
|
+
} else {
|
|
351
|
+
parent[pos] = '';
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
if (parent.uid && assetUIDMapper[parent.uid]) {
|
|
356
|
+
parent.uid = assetUIDMapper[parent.uid];
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
if (
|
|
360
|
+
object &&
|
|
361
|
+
isObject(parent[pos]) &&
|
|
362
|
+
parent[pos].uid &&
|
|
363
|
+
parent[pos].url &&
|
|
364
|
+
has(parent, 'asset') &&
|
|
365
|
+
has(parent, '_content_type_uid') &&
|
|
366
|
+
parent._content_type_uid === 'sys_assets'
|
|
367
|
+
) {
|
|
368
|
+
if (
|
|
369
|
+
has(parent, 'asset') &&
|
|
370
|
+
has(parent, '_content_type_uid') &&
|
|
371
|
+
parent._content_type_uid === 'sys_assets'
|
|
372
|
+
) {
|
|
373
|
+
parent = omit(parent, ['asset']);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
if (object.uid && assetUIDMapper[object.uid]) {
|
|
377
|
+
object.uid = assetUIDMapper[object.uid];
|
|
378
|
+
}
|
|
379
|
+
if (object.url && assetUrlMapper[object.url]) {
|
|
380
|
+
object.url = assetUrlMapper[object.url];
|
|
381
|
+
}
|
|
382
|
+
} else {
|
|
383
|
+
replacer();
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
} else if (isPlainObject(object)) {
|
|
388
|
+
for (let key in object) updateFileFields(object[key], object, key);
|
|
389
|
+
} else if (isArray(object) && object.length) {
|
|
390
|
+
for (let i = 0; i <= object.length; i++){
|
|
391
|
+
updateFileFields(object[i], object, i);
|
|
392
|
+
}
|
|
393
|
+
parent[pos] = compact(object);
|
|
394
|
+
}
|
|
395
|
+
return object;
|
|
396
|
+
}
|
|
327
397
|
|
|
328
398
|
const checkAndDownloadAsset = async function (cAsset) {
|
|
329
399
|
if (cAsset) {
|
|
@@ -340,7 +410,6 @@ function entryUpdateScript(contentType) {
|
|
|
340
410
|
return false;
|
|
341
411
|
}
|
|
342
412
|
else {
|
|
343
|
-
isAssetDownload = true;
|
|
344
413
|
const cAssetDetail = await managementAPIClient
|
|
345
414
|
.stack({ api_key: stackSDKInstance.api_key, branch_uid: compareBranch })
|
|
346
415
|
.asset(assetUID)
|
|
@@ -382,8 +451,8 @@ function entryUpdateScript(contentType) {
|
|
|
382
451
|
const uploadAssets = async function () {
|
|
383
452
|
const assetFolderMap = JSON.parse(fs.readFileSync(path.resolve(filePath, 'folder-mapper.json'), 'utf8'));
|
|
384
453
|
const stackAPIClient = managementAPIClient.stack({ api_key: stackSDKInstance.api_key, branch_uid: branch });
|
|
385
|
-
for (let i = 0; i <
|
|
386
|
-
const asset =
|
|
454
|
+
for (let i = 0; i < downloadedAssets?.length; i++) {
|
|
455
|
+
const asset = downloadedAssets[i];
|
|
387
456
|
let requestOption = {};
|
|
388
457
|
|
|
389
458
|
requestOption.parent_uid = assetFolderMap[asset.parent_uid] || asset.parent_uid;
|
|
@@ -418,6 +487,11 @@ function entryUpdateScript(contentType) {
|
|
|
418
487
|
successMessage: 'Entries Updated Successfully',
|
|
419
488
|
failedMessage: 'Failed to update entries',
|
|
420
489
|
task: async () => {
|
|
490
|
+
//logger file
|
|
491
|
+
if(!fs.existsSync(path.join(filePath, 'entry-migration'))){
|
|
492
|
+
logger = new LoggerService(filePath, 'entry-migration');
|
|
493
|
+
}
|
|
494
|
+
|
|
421
495
|
let compareBranchEntries = await managementAPIClient
|
|
422
496
|
.stack({ api_key: stackSDKInstance.api_key, branch_uid: compareBranch })
|
|
423
497
|
.contentType('${contentType}')
|
|
@@ -453,9 +527,10 @@ function entryUpdateScript(contentType) {
|
|
|
453
527
|
const updatedCAsset = await checkAndDownloadAsset(asset);
|
|
454
528
|
if(updatedCAsset){
|
|
455
529
|
newAssetDetails[i] = updatedCAsset;
|
|
530
|
+
downloadedAssets.push(updatedCAsset);
|
|
456
531
|
}
|
|
457
532
|
}
|
|
458
|
-
if (
|
|
533
|
+
if (downloadedAssets?.length) await uploadAssets();
|
|
459
534
|
}
|
|
460
535
|
|
|
461
536
|
let flag = {
|
|
@@ -466,7 +541,17 @@ function entryUpdateScript(contentType) {
|
|
|
466
541
|
|
|
467
542
|
async function updateEntry(entry, entryDetails) {
|
|
468
543
|
Object.assign(entry, { ...entryDetails });
|
|
469
|
-
await entry.update()
|
|
544
|
+
await entry.update().catch(err => {
|
|
545
|
+
let errorMsg = 'Entry update failed for uid: ' + entry?.uid + ', title: ' + entry?.title + '.';
|
|
546
|
+
if(err?.errors?.title){
|
|
547
|
+
errorMsg += err?.errors?.title;
|
|
548
|
+
}else if(err?.errors?.entry){
|
|
549
|
+
errorMsg += err?.errors?.entry;
|
|
550
|
+
}else{
|
|
551
|
+
errorMsg += (err?.entry?.errorMessage || err?.errorMessage || err?.message) ?? 'Something went wrong!';
|
|
552
|
+
}
|
|
553
|
+
logger.error(errorMsg)
|
|
554
|
+
});
|
|
470
555
|
}
|
|
471
556
|
|
|
472
557
|
async function updateReferences(entryDetails, baseEntry, references) {
|
|
@@ -494,56 +579,70 @@ function entryUpdateScript(contentType) {
|
|
|
494
579
|
}
|
|
495
580
|
|
|
496
581
|
try {
|
|
497
|
-
if (contentType
|
|
498
|
-
compareBranchEntries
|
|
582
|
+
if (contentType?.options?.singleton) {
|
|
583
|
+
compareBranchEntries?.items?.map(async (el) => {
|
|
499
584
|
let entryDetails = deleteUnwantedKeysFromObject(el, keysToRemove);
|
|
500
|
-
entryDetails
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
585
|
+
if(entryDetails !== undefined){
|
|
586
|
+
entryDetails = updateAssetDetailsInEntries(entryDetails);
|
|
587
|
+
if (baseBranchEntries && baseBranchEntries.items.length) {
|
|
588
|
+
let baseEntryUid = baseBranchEntries.items[0].uid;
|
|
589
|
+
let entry = await stackSDKInstance.contentType('${contentType}').entry(baseEntryUid);
|
|
590
|
+
|
|
591
|
+
if (flag.references) {
|
|
592
|
+
await updateReferences(entryDetails, baseBranchEntries.items[0], references);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
await updateEntry(entry, entryDetails);
|
|
596
|
+
} else {
|
|
597
|
+
let createdEntry = await stackSDKInstance.contentType('${contentType}').entry().create({ entry: entryDetails });
|
|
505
598
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
} else {
|
|
512
|
-
let createdEntry = await stackSDKInstance.contentType('${contentType}').entry().create({ entry: entryDetails });
|
|
513
|
-
|
|
514
|
-
if (flag.references) {
|
|
515
|
-
await updateReferences(entryDetails, createdEntry, references);
|
|
599
|
+
if (flag.references) {
|
|
600
|
+
await updateReferences(entryDetails, createdEntry, references);
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
await updateEntry(createdEntry, entryDetails);
|
|
516
604
|
}
|
|
517
|
-
|
|
518
|
-
await updateEntry(createdEntry, entryDetails);
|
|
519
605
|
}
|
|
520
606
|
});
|
|
521
607
|
} else {
|
|
522
608
|
let compareMap = new Map(converter(compareBranchEntries.items));
|
|
523
609
|
let baseMap = new Map(converter(baseBranchEntries.items));
|
|
524
|
-
|
|
610
|
+
|
|
611
|
+
//NOTE: Filter distinct entries from the base and compare branches according to their titles.
|
|
612
|
+
//TODO: Need to discuss this approach and replace it with uid approach
|
|
525
613
|
let arr = uniquelyConcatenateArrays(Array.from(compareMap.keys()), Array.from(baseMap.keys()));
|
|
526
614
|
|
|
527
615
|
arr.map(async (el) => {
|
|
528
616
|
let entryDetails = deleteUnwantedKeysFromObject(compareMap.get(el), keysToRemove);
|
|
529
|
-
|
|
530
|
-
if
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
let entry = await stackSDKInstance.contentType('${contentType}').entry(baseEntry.uid);
|
|
617
|
+
//NOTE: In the compare branch, entry must exist. Condition of deleted entry not handled
|
|
618
|
+
if(entryDetails !== undefined){
|
|
619
|
+
entryDetails = updateAssetDetailsInEntries(entryDetails);
|
|
620
|
+
if (compareMap.get(el) && !baseMap.get(el)) {
|
|
621
|
+
let createdEntry = await stackSDKInstance
|
|
622
|
+
.contentType('${contentType}')
|
|
623
|
+
.entry()
|
|
624
|
+
.create({ entry: entryDetails })
|
|
625
|
+
.catch(err => {
|
|
626
|
+
(err?.errorMessage || err?.message) ? err?.errorMessage || err?.message : 'Something went wrong!'
|
|
627
|
+
})
|
|
541
628
|
|
|
542
|
-
|
|
543
|
-
|
|
629
|
+
if(createdEntry){
|
|
630
|
+
if (flag.references) {
|
|
631
|
+
await updateReferences(entryDetails, createdEntry, references);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
await updateEntry(createdEntry, entryDetails);
|
|
635
|
+
}
|
|
636
|
+
} else if (compareMap.get(el) && baseMap.get(el)) {
|
|
637
|
+
let baseEntry = baseMap.get(el);
|
|
638
|
+
let entry = await stackSDKInstance.contentType('${contentType}').entry(baseEntry.uid);
|
|
639
|
+
|
|
640
|
+
if (flag.references) {
|
|
641
|
+
await updateReferences(entryDetails, baseEntry, references);
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
await updateEntry(entry, entryDetails);
|
|
544
645
|
}
|
|
545
|
-
|
|
546
|
-
await updateEntry(entry, entryDetails);
|
|
547
646
|
}
|
|
548
647
|
});
|
|
549
648
|
}
|
package/oclif.manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contentstack/cli-cm-branches",
|
|
3
3
|
"description": "Contentstack CLI plugin to do branches operations",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.20",
|
|
5
5
|
"author": "Contentstack",
|
|
6
6
|
"bugs": "https://github.com/contentstack/cli/issues",
|
|
7
7
|
"dependencies": {
|
|
8
8
|
"@contentstack/cli-command": "~1.2.16",
|
|
9
|
-
"@contentstack/cli-utilities": "~1.5.
|
|
9
|
+
"@contentstack/cli-utilities": "~1.5.10",
|
|
10
10
|
"@oclif/core": "^2.9.3",
|
|
11
11
|
"async": "^3.2.4",
|
|
12
12
|
"big-json": "^3.2.0",
|
|
@@ -95,4 +95,4 @@
|
|
|
95
95
|
}
|
|
96
96
|
},
|
|
97
97
|
"repository": "https://github.com/contentstack/cli"
|
|
98
|
-
}
|
|
98
|
+
}
|