diff --git a/package-lock.json b/package-lock.json
index 5f92539d83..e7cf5847c3 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -23496,7 +23496,7 @@
"@contentstack/cli-audit": "~1.3.2",
"@contentstack/cli-auth": "~1.3.17",
"@contentstack/cli-cm-bootstrap": "~1.7.1",
- "@contentstack/cli-cm-branches": "~1.0.19",
+ "@contentstack/cli-cm-branches": "~1.0.20",
"@contentstack/cli-cm-bulk-publish": "~1.4.0",
"@contentstack/cli-cm-clone": "~1.9.0",
"@contentstack/cli-cm-export": "~1.10.2",
@@ -23923,7 +23923,7 @@
},
"packages/contentstack-branches": {
"name": "@contentstack/cli-cm-branches",
- "version": "1.0.19",
+ "version": "1.0.20",
"license": "MIT",
"dependencies": {
"@contentstack/cli-command": "~1.2.16",
diff --git a/packages/contentstack-branches/README.md b/packages/contentstack-branches/README.md
index 2cdc9f6ddf..2ecc88b069 100755
--- a/packages/contentstack-branches/README.md
+++ b/packages/contentstack-branches/README.md
@@ -37,7 +37,7 @@ $ npm install -g @contentstack/cli-cm-branches
$ csdx COMMAND
running command...
$ csdx (--version)
-@contentstack/cli-cm-branches/1.0.19 darwin-arm64 node-v20.8.0
+@contentstack/cli-cm-branches/1.0.20 darwin-arm64 node-v20.8.0
$ csdx --help [COMMAND]
USAGE
$ csdx COMMAND
diff --git a/packages/contentstack-branches/package.json b/packages/contentstack-branches/package.json
index f9fe694229..29b95f9d6b 100644
--- a/packages/contentstack-branches/package.json
+++ b/packages/contentstack-branches/package.json
@@ -1,7 +1,7 @@
{
"name": "@contentstack/cli-cm-branches",
"description": "Contentstack CLI plugin to do branches operations",
- "version": "1.0.19",
+ "version": "1.0.20",
"author": "Contentstack",
"bugs": "https://github.com/contentstack/cli/issues",
"dependencies": {
diff --git a/packages/contentstack-branches/src/branch/merge-handler.ts b/packages/contentstack-branches/src/branch/merge-handler.ts
index 823da0743a..aa91ede899 100644
--- a/packages/contentstack-branches/src/branch/merge-handler.ts
+++ b/packages/contentstack-branches/src/branch/merge-handler.ts
@@ -1,3 +1,4 @@
+import os from 'os';
import path from 'path';
import forEach from 'lodash/forEach';
import { cliux } from '@contentstack/cli-utilities';
@@ -275,7 +276,7 @@ export default class MergeHandler {
deleted: [],
};
- selectedMergeItems.forEach((item) => {
+ selectedMergeItems?.forEach((item) => {
mergeContent.content_types[item.status].push(item.value);
});
break;
@@ -290,10 +291,16 @@ export default class MergeHandler {
if (scriptFolderPath !== undefined) {
cliux.success(`\nSuccess! We have generated entry migration files in the folder ${scriptFolderPath}`);
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'});
-
- const 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}`;
+
+ let migrationCommand: string;
+ if(os.platform() === 'win32'){
+ 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}`;
+ }else{
+ 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}`;
+ }
+
cliux.print(
- `\nKindly follow the steps in the guide "https://www.contentstack.com/docs/developers/cli/migrate-branch-entries" to update the migration scripts, and then run the command:\n\n${migrationCommand}`,
+ `\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' },
);
}
diff --git a/packages/contentstack-branches/src/utils/create-merge-scripts.ts b/packages/contentstack-branches/src/utils/create-merge-scripts.ts
index 239cb86a27..95c2cf1bbc 100644
--- a/packages/contentstack-branches/src/utils/create-merge-scripts.ts
+++ b/packages/contentstack-branches/src/utils/create-merge-scripts.ts
@@ -30,7 +30,6 @@ export function generateMergeScripts(mergeSummary, mergeJobUID) {
merge_existing_new: entryCreateUpdateScript,
merge_existing: entryUpdateScript,
merge_new: entryCreateScript,
- ignore: entryCreateUpdateScript,
};
const processContentTypes = (contentTypes, messageType) => {
@@ -66,6 +65,8 @@ export function getContentTypeMergeStatus(status) {
return 'created';
} else if (status === 'merge_existing_new') {
return 'created_updated';
+ } else if (status === 'ignore') {
+ return;
} else {
return '';
}
diff --git a/packages/contentstack-branches/src/utils/entry-create-script.ts b/packages/contentstack-branches/src/utils/entry-create-script.ts
index e40f18cb16..228202ae59 100644
--- a/packages/contentstack-branches/src/utils/entry-create-script.ts
+++ b/packages/contentstack-branches/src/utils/entry-create-script.ts
@@ -2,6 +2,14 @@ export function entryCreateScript(contentType) {
return `
const fs = require('fs');
const path = require('path');
+ const { marked } = require('marked');
+ const has = require('lodash/has');
+ const isArray = require('lodash/isArray');
+ const isObject = require('lodash/isObject');
+ const omit = require('lodash/omit');
+ const compact = require('lodash/compact')
+ const isPlainObject = require('lodash/isPlainObject');
+ const {cliux, LoggerService} = require('@contentstack/cli-utilities')
module.exports = async ({ migration, stackSDKInstance, managementAPIClient, config, branch, apiKey }) => {
const keysToRemove = [
'content_type_uid',
@@ -31,20 +39,18 @@ export function entryCreateScript(contentType) {
let assetUIDMapper = {};
let assetUrlMapper = {};
let assetRefPath = {};
- let isAssetDownload = false;
+ let downloadedAssets = [];
+ let parent=[];
+ let logger;
function getValueByPath(obj, path) {
return path.split('[').reduce((o, key) => o && o[key.replace(/\]$/, '')], obj);
}
- function updateValueByPath(obj, path, newValue, type, fileIndex) {
+ function updateValueByPath(obj, path, newValue) {
path.split('[').reduce((o, key, index, arr) => {
if (index === arr.length - 1) {
- if (type === 'file') {
- o[key.replace(/]$/, '')][fileIndex] = newValue;
- } else {
o[key.replace(/]$/, '')][0].uid = newValue;
- }
} else {
return o[key.replace(/\]$/, '')];
}
@@ -77,35 +83,52 @@ export function entryCreateScript(contentType) {
return references;
};
- const findAssets = function (schema, entry, refPath, path) {
+ const findAssets = function (schema, entry) {
for (const i in schema) {
- const currentPath = path ? path + '[' + schema[i].uid : schema[i].uid;
if (schema[i].data_type === 'group' || schema[i].data_type === 'global_field') {
- findAssets(schema[i].schema, entry, refPath, currentPath + '[0]');
- } else if (schema[i].data_type === 'blocks') {
- for (const block in schema[i].blocks) {
+ parent.push(schema[i].uid);
+ findAssets(schema[i].schema, entry);
+ parent.pop();
+ }
+ if (schema[i].data_type === 'blocks') {
+ for (const j = 0; j < schema[i].blocks; j++) {
{
- if (schema[i].blocks[block].schema) {
- findAssets(
- schema[i].blocks[block].schema,
- entry,
- refPath,
- currentPath + '[' + block + '][' + schema[i].blocks[block].uid + ']',
- );
+ if (schema[i].blocks[j].schema) {
+ parent.push(schema[i].uid);
+ parent.push(j);
+ parent.push(schema[i].blocks[j].uid);
+ findAssets(schema[i].blocks[j].schema, entry);
+ parent.pop();
+ parent.pop();
+ parent.pop();
}
}
}
- } else if (schema[i].data_type === 'json' && schema[i].field_metadata.rich_text_type) {
- findAssetIdsFromJsonRte(entry, schema, refPath, path);
- } else if (
+ }
+ if (schema[i].data_type === 'json' && schema[i].field_metadata.rich_text_type) {
+ parent.push(schema[i].uid);
+ findAssetIdsFromJsonRte(entry, schema);
+ parent.pop();
+ }
+ if (
schema[i].data_type === 'text' &&
schema[i].field_metadata &&
(schema[i].field_metadata.markdown || schema[i].field_metadata.rich_text_type)
) {
+ parent.push(schema[i].uid);
findFileUrls(schema[i], entry);
- } else if (schema[i].data_type === 'file') {
- refPath.push(currentPath)
- const imgDetails = getValueByPath(entry, currentPath);
+ if (schema[i].field_metadata.rich_text_type) {
+ findAssetIdsFromHtmlRte(entry, schema[i]);
+ }
+ parent.pop();
+ }
+ if (schema[i].data_type === 'file') {
+ parent.push(schema[i].uid);
+ let updatedEntry = entry;
+ for (let i = 0; i < parent.length; i++) {
+ updatedEntry = updatedEntry[parent[i]];
+ }
+ const imgDetails = updatedEntry;
if (schema[i].multiple) {
if (imgDetails && imgDetails.length) {
imgDetails.forEach((img) => {
@@ -133,10 +156,21 @@ export function entryCreateScript(contentType) {
cAssetDetails.push(obj);
}
}
+ parent.pop();
}
}
};
+ function findAssetIdsFromHtmlRte(entryObj, ctSchema) {
+ const regex = / {
- let imgDetails = entry[refPath];
- if (imgDetails !== undefined) {
- if (imgDetails && !Array.isArray(imgDetails)) {
- entry[refPath] = assetUIDMapper[imgDetails.uid];
- } else if (imgDetails && Array.isArray(imgDetails)) {
- for (let i = 0; i < imgDetails.length; i++) {
- const img = imgDetails[i];
- entry[refPath][i] = assetUIDMapper[img.uid];
- }
- }
- } else {
- imgDetails = getValueByPath(entry, refPath);
- if (imgDetails && !Array.isArray(imgDetails)) {
- const imgUID = imgDetails?.uid;
- updateValueByPath(entry, refPath, assetUIDMapper[imgUID], 'file', 0);
- } else if (imgDetails && Array.isArray(imgDetails)) {
- for (let i = 0; i < imgDetails.length; i++) {
- const img = imgDetails[i];
- const imgUID = img?.uid;
- updateValueByPath(entry, refPath, assetUIDMapper[imgUID], 'file', i);
- }
- }
- }
- });
+ let updatedEntry = Object.assign({},entry);
+ entry = updateFileFields(updatedEntry, entry, null)
entry = JSON.stringify(entry);
const assetUrls = cAssetDetails.map((asset) => asset.url);
const assetUIDs = cAssetDetails.map((asset) => asset.uid);
@@ -299,6 +310,65 @@ export function entryCreateScript(contentType) {
});
return JSON.parse(entry);
};
+
+ function updateFileFields(
+ object,
+ parent,
+ pos
+ ) {
+ if (isPlainObject(object) && has(object, 'filename') && has(object, 'uid')) {
+ if (typeof pos !== 'undefined') {
+ if (typeof pos === 'number' || typeof pos === 'string') {
+ const replacer = () => {
+ if (assetUIDMapper.hasOwnProperty(object.uid)) {
+ parent[pos] = assetUIDMapper[object.uid];
+ } else {
+ parent[pos] = '';
+ }
+ };
+
+ if (parent.uid && assetUIDMapper[parent.uid]) {
+ parent.uid = assetUIDMapper[parent.uid];
+ }
+
+ if (
+ object &&
+ isObject(parent[pos]) &&
+ parent[pos].uid &&
+ parent[pos].url &&
+ has(parent, 'asset') &&
+ has(parent, '_content_type_uid') &&
+ parent._content_type_uid === 'sys_assets'
+ ) {
+ if (
+ has(parent, 'asset') &&
+ has(parent, '_content_type_uid') &&
+ parent._content_type_uid === 'sys_assets'
+ ) {
+ parent = omit(parent, ['asset']);
+ }
+
+ if (object.uid && assetUIDMapper[object.uid]) {
+ object.uid = assetUIDMapper[object.uid];
+ }
+ if (object.url && assetUrlMapper[object.url]) {
+ object.url = assetUrlMapper[object.url];
+ }
+ } else {
+ replacer();
+ }
+ }
+ }
+ } else if (isPlainObject(object)) {
+ for (let key in object) updateFileFields(object[key], object, key);
+ } else if (isArray(object) && object.length) {
+ for (let i = 0; i <= object.length; i++){
+ updateFileFields(object[i], object, i);
+ }
+ parent[pos] = compact(object);
+ }
+ return object;
+ }
const checkAndDownloadAsset = async function (cAsset) {
const assetUID = cAsset?.uid;
@@ -315,7 +385,6 @@ export function entryCreateScript(contentType) {
return false;
}
else {
- isAssetDownload = true;
const cAssetDetail = await managementAPIClient
.stack({ api_key: stackSDKInstance.api_key, branch_uid: compareBranch })
.asset(assetUID)
@@ -357,8 +426,8 @@ export function entryCreateScript(contentType) {
const uploadAssets = async function () {
const assetFolderMap = JSON.parse(fs.readFileSync(path.resolve(filePath, 'folder-mapper.json'), 'utf8'));
const stackAPIClient = managementAPIClient.stack({ api_key: stackSDKInstance.api_key, branch_uid: branch });
- for (let i = 0; i < cAssetDetails?.length; i++) {
- const asset = cAssetDetails[i];
+ for (let i = 0; i < downloadedAssets?.length; i++) {
+ const asset = downloadedAssets[i];
let requestOption = {};
requestOption.parent_uid = assetFolderMap[asset.parent_uid] || asset.parent_uid;
@@ -401,6 +470,11 @@ export function entryCreateScript(contentType) {
successTitle: 'Entries Created Successfully',
failedTitle: 'Failed to create entries',
task: async () => {
+ //logger file
+ if(!fs.existsSync(path.join(filePath, 'entry-migration'))){
+ logger = new LoggerService(filePath, 'entry-migration');
+ }
+
const compareBranchEntries = await managementAPIClient
.stack({ api_key: stackSDKInstance.api_key, branch_uid: compareBranch })
.contentType('${contentType}')
@@ -432,9 +506,10 @@ export function entryCreateScript(contentType) {
const updatedCAsset = await checkAndDownloadAsset(asset);
if (updatedCAsset) {
cAssetDetails[i] = updatedCAsset;
+ downloadedAssets.push(updatedCAsset)
}
}
- if (isAssetDownload) await uploadAssets();
+ if (downloadedAssets?.length) await uploadAssets();
}
let flag = {
@@ -445,7 +520,17 @@ export function entryCreateScript(contentType) {
async function updateEntry(entry, entryDetails) {
Object.assign(entry, { ...entryDetails });
- await entry.update();
+ await entry.update().catch(err => {
+ let errorMsg = 'Entry update failed for uid: ' + entry?.uid + ', title: ' + entry?.title + '. ';
+ if(err?.errors?.title){
+ errorMsg += 'title'+ err?.errors?.title;
+ }else if(err?.errors?.entry){
+ errorMsg += err?.errors?.entry;
+ }else{
+ errorMsg += (err?.entry?.errorMessage || err?.errorMessage || err?.message) ?? 'Something went wrong!';
+ }
+ logger.error(errorMsg)
+ });
}
async function updateReferences(entryDetails, baseEntry, references) {
@@ -477,8 +562,16 @@ export function entryCreateScript(contentType) {
compareFilteredProperties.forEach(async (entryDetails) => {
if(entryDetails !== undefined){
entryDetails = updateAssetDetailsInEntries(entryDetails);
- let createdEntry = await stackSDKInstance.contentType('${contentType}').entry().create({ entry: entryDetails }).catch(error => {
- throw error;
+ let createdEntry = await stackSDKInstance.contentType('${contentType}').entry().create({ entry: entryDetails }).catch(err => {
+ let errorMsg = 'Entry creation failed for contentType: ' + contentType + ', title: ' + entryDetails?.title + '. ';
+ if(err?.errors?.title){
+ errorMsg += err?.errors?.title;
+ }else if(err?.errors?.entry){
+ errorMsg += err?.errors?.entry;
+ }else{
+ errorMsg += (err?.entry?.errorMessage || err?.errorMessage || err?.message) ?? 'Something went wrong!';
+ }
+ logger.error(errorMsg)
});
if(createdEntry){
if (flag.references) {
diff --git a/packages/contentstack-branches/src/utils/entry-create-update-script.ts b/packages/contentstack-branches/src/utils/entry-create-update-script.ts
index 194a218aad..f4e8b8048c 100644
--- a/packages/contentstack-branches/src/utils/entry-create-update-script.ts
+++ b/packages/contentstack-branches/src/utils/entry-create-update-script.ts
@@ -2,6 +2,14 @@ export function entryCreateUpdateScript(contentType) {
return `
const fs = require('fs');
const path = require('path');
+ const { marked } = require('marked');
+ const has = require('lodash/has');
+ const isArray = require('lodash/isArray');
+ const isObject = require('lodash/isObject');
+ const omit = require('lodash/omit');
+ const compact = require('lodash/compact')
+ const isPlainObject = require('lodash/isPlainObject');
+ const {cliux, LoggerService} = require('@contentstack/cli-utilities')
module.exports = async ({ migration, stackSDKInstance, managementAPIClient, config, branch, apiKey }) => {
const keysToRemove = [
'content_type_uid',
@@ -29,10 +37,12 @@ export function entryCreateUpdateScript(contentType) {
let assetDirPath = path.resolve(filePath, 'assets');
let assetDetails = [];
let newAssetDetails = [];
+ let downloadedAssets = [];
let assetUIDMapper = {};
let assetUrlMapper = {};
let assetRefPath = {};
- let isAssetDownload = false;
+ let parent=[];
+ let logger;
function converter(data) {
let arr = [];
@@ -59,14 +69,10 @@ export function entryCreateUpdateScript(contentType) {
return path.split('[').reduce((o, key) => o && o[key.replace(/\]$/, '')], obj);
}
- function updateValueByPath(obj, path, newValue, type, fileIndex) {
+ function updateValueByPath(obj, path, newValue) {
path.split('[').reduce((o, key, index, arr) => {
if (index === arr.length - 1) {
- if (type === 'file') {
- o[key.replace(/]$/, '')][fileIndex] = newValue;
- } else {
o[key.replace(/]$/, '')][0].uid = newValue;
- }
} else {
return o[key.replace(/\]$/, '')];
}
@@ -99,65 +105,93 @@ export function entryCreateUpdateScript(contentType) {
return references;
};
- const findAssets = function (schema, entry, refPath, path) {
- for (const i in schema) {
- const currentPath = path ? path + '[' + schema[i].uid : schema[i].uid;
- if (schema[i].data_type === 'group' || schema[i].data_type === 'global_field') {
- findAssets(schema[i].schema, entry, refPath, currentPath + '[0]');
- } else if (schema[i].data_type === 'blocks') {
- for (const block in schema[i].blocks) {
- {
- if (schema[i].blocks[block].schema) {
- findAssets(
- schema[i].blocks[block].schema,
- entry,
- refPath,
- currentPath + '[' + block + '][' + schema[i].blocks[block].uid + ']',
- );
+ const findAssets = function (schema, entry) {
+ for (const i in schema) {
+ if (schema[i].data_type === 'group' || schema[i].data_type === 'global_field') {
+ parent.push(schema[i].uid);
+ findAssets(schema[i].schema, entry);
+ parent.pop();
+ }
+ if (schema[i].data_type === 'blocks') {
+ for (const j = 0; j < schema[i].blocks; j++) {
+ {
+ if (schema[i].blocks[j].schema) {
+ parent.push(schema[i].uid);
+ parent.push(j);
+ parent.push(schema[i].blocks[j].uid);
+ findAssets(schema[i].blocks[j].schema, entry);
+ parent.pop();
+ parent.pop();
+ parent.pop();
+ }
}
}
}
- } else if (schema[i].data_type === 'json' && schema[i].field_metadata.rich_text_type) {
- findAssetIdsFromJsonRte(entry, schema, refPath, path);
- } else if (
- schema[i].data_type === 'text' &&
- schema[i].field_metadata &&
- (schema[i].field_metadata.markdown || schema[i].field_metadata.rich_text_type)
- ) {
- findFileUrls(schema[i], entry);
- } else if (schema[i].data_type === 'file') {
- refPath.push(currentPath)
- const imgDetails = getValueByPath(entry, currentPath);
- if (schema[i].multiple) {
- if (imgDetails && imgDetails.length) {
- imgDetails.forEach((img) => {
+ if (schema[i].data_type === 'json' && schema[i].field_metadata.rich_text_type) {
+ parent.push(schema[i].uid);
+ findAssetIdsFromJsonRte(entry, schema);
+ parent.pop();
+ }
+ if (
+ schema[i].data_type === 'text' &&
+ schema[i].field_metadata &&
+ (schema[i].field_metadata.markdown || schema[i].field_metadata.rich_text_type)
+ ) {
+ parent.push(schema[i].uid);
+ findFileUrls(schema[i], entry);
+ if (schema[i].field_metadata.rich_text_type) {
+ findAssetIdsFromHtmlRte(entry, schema[i]);
+ }
+ parent.pop();
+ }
+ if (schema[i].data_type === 'file') {
+ parent.push(schema[i].uid);
+ let updatedEntry = entry;
+ for (let i = 0; i < parent.length; i++) {
+ updatedEntry = updatedEntry[parent[i]];
+ }
+ const imgDetails = updatedEntry;
+ if (schema[i].multiple) {
+ if (imgDetails && imgDetails.length) {
+ imgDetails.forEach((img) => {
+ const obj = {
+ uid: img.uid,
+ parent_uid: img.parent_uid,
+ description: img.description,
+ title: img.title,
+ filename: img.filename,
+ url: img.url,
+ };
+ assetDetails.push(obj);
+ });
+ }
+ } else {
+ if (imgDetails) {
const obj = {
- uid: img.uid,
- parent_uid: img.parent_uid,
- description: img.description,
- title: img.title,
- filename: img.filename,
- url: img.url,
+ uid: imgDetails.uid,
+ parent_uid: imgDetails.parent_uid,
+ description: imgDetails.description,
+ title: imgDetails.title,
+ filename: imgDetails.filename,
+ url: imgDetails.url,
};
assetDetails.push(obj);
- });
- }
- } else {
- if (imgDetails) {
- const obj = {
- uid: imgDetails.uid,
- parent_uid: imgDetails.parent_uid,
- description: imgDetails.description,
- title: imgDetails.title,
- filename: imgDetails.filename,
- url: imgDetails.url,
- };
- assetDetails.push(obj);
+ }
}
+ parent.pop();
}
}
+ };
+
+ function findAssetIdsFromHtmlRte(entryObj, ctSchema) {
+ const regex = / {
- let imgDetails = entry[refPath];
- if (imgDetails !== undefined) {
- if (imgDetails && !Array.isArray(imgDetails)) {
- entry[refPath] = assetUIDMapper[imgDetails.uid];
- } else if (imgDetails && Array.isArray(imgDetails)) {
- for (let i = 0; i < imgDetails.length; i++) {
- const img = imgDetails[i];
- entry[refPath][i] = assetUIDMapper[img.uid];
- }
- }
- } else {
- imgDetails = getValueByPath(entry, refPath);
- if (imgDetails && !Array.isArray(imgDetails)) {
- const imgUID = imgDetails?.uid;
- updateValueByPath(entry, refPath, assetUIDMapper[imgUID], 'file', 0);
- } else if (imgDetails && Array.isArray(imgDetails)) {
- for (let i = 0; i < imgDetails.length; i++) {
- const img = imgDetails[i];
- const imgUID = img?.uid;
- updateValueByPath(entry, refPath, assetUIDMapper[imgUID], 'file', i);
- }
- }
- }
- });
+ let updatedEntry = Object.assign({},entry);
+ entry = updateFileFields(updatedEntry, entry, null)
entry = JSON.stringify(entry);
const assetUrls = assetDetails.map((asset) => asset.url);
const assetUIDs = assetDetails.map((asset) => asset.uid);
@@ -321,6 +332,65 @@ export function entryCreateUpdateScript(contentType) {
});
return JSON.parse(entry);
};
+
+ function updateFileFields(
+ object,
+ parent,
+ pos
+ ) {
+ if (isPlainObject(object) && has(object, 'filename') && has(object, 'uid')) {
+ if (typeof pos !== 'undefined') {
+ if (typeof pos === 'number' || typeof pos === 'string') {
+ const replacer = () => {
+ if (assetUIDMapper.hasOwnProperty(object.uid)) {
+ parent[pos] = assetUIDMapper[object.uid];
+ } else {
+ parent[pos] = '';
+ }
+ };
+
+ if (parent.uid && assetUIDMapper[parent.uid]) {
+ parent.uid = assetUIDMapper[parent.uid];
+ }
+
+ if (
+ object &&
+ isObject(parent[pos]) &&
+ parent[pos].uid &&
+ parent[pos].url &&
+ has(parent, 'asset') &&
+ has(parent, '_content_type_uid') &&
+ parent._content_type_uid === 'sys_assets'
+ ) {
+ if (
+ has(parent, 'asset') &&
+ has(parent, '_content_type_uid') &&
+ parent._content_type_uid === 'sys_assets'
+ ) {
+ parent = omit(parent, ['asset']);
+ }
+
+ if (object.uid && assetUIDMapper[object.uid]) {
+ object.uid = assetUIDMapper[object.uid];
+ }
+ if (object.url && assetUrlMapper[object.url]) {
+ object.url = assetUrlMapper[object.url];
+ }
+ } else {
+ replacer();
+ }
+ }
+ }
+ } else if (isPlainObject(object)) {
+ for (let key in object) updateFileFields(object[key], object, key);
+ } else if (isArray(object) && object.length) {
+ for (let i = 0; i <= object.length; i++){
+ updateFileFields(object[i], object, i);
+ }
+ parent[pos] = compact(object);
+ }
+ return object;
+ }
const checkAndDownloadAsset = async function (cAsset) {
if (cAsset) {
@@ -337,7 +407,6 @@ export function entryCreateUpdateScript(contentType) {
return false;
}
else {
- isAssetDownload = true;
const cAssetDetail = await managementAPIClient
.stack({ api_key: stackSDKInstance.api_key, branch_uid: compareBranch })
.asset(assetUID)
@@ -379,8 +448,8 @@ export function entryCreateUpdateScript(contentType) {
const uploadAssets = async function () {
const assetFolderMap = JSON.parse(fs.readFileSync(path.resolve(filePath, 'folder-mapper.json'), 'utf8'));
const stackAPIClient = managementAPIClient.stack({ api_key: stackSDKInstance.api_key, branch_uid: branch });
- for (let i = 0; i < assetDetails?.length; i++) {
- const asset = assetDetails[i];
+ for (let i = 0; i < downloadedAssets?.length; i++) {
+ const asset = downloadedAssets[i];
let requestOption = {};
requestOption.parent_uid = assetFolderMap[asset.parent_uid] || asset.parent_uid;
@@ -416,6 +485,10 @@ export function entryCreateUpdateScript(contentType) {
successMessage: 'Entries Updated Successfully',
failedMessage: 'Failed to update entries',
task: async () => {
+ //logger file
+ if(!fs.existsSync(path.join(filePath, 'entry-migration'))){
+ logger = new LoggerService(filePath, 'entry-migration');
+ }
let compareBranchEntries = await managementAPIClient
.stack({ api_key: stackSDKInstance.api_key, branch_uid: compareBranch })
.contentType('${contentType}')
@@ -451,9 +524,10 @@ export function entryCreateUpdateScript(contentType) {
const updatedCAsset = await checkAndDownloadAsset(asset);
if(updatedCAsset){
newAssetDetails[i] = updatedCAsset;
+ downloadedAssets.push(updatedCAsset)
}
}
- if (isAssetDownload) await uploadAssets();
+ if (downloadedAssets?.length) await uploadAssets();
}
let flag = {
@@ -465,7 +539,17 @@ export function entryCreateUpdateScript(contentType) {
async function updateEntry(entry, entryDetails) {
if (entry) {
Object.assign(entry, { ...entryDetails });
- await entry.update();
+ await entry.update().catch(err => {
+ let errorMsg = 'Entry update failed for uid: ' + entry?.uid + ', title: ' + entry?.title + '.';
+ if(err?.errors?.title){
+ errorMsg += err?.errors?.title;
+ }else if(err?.errors?.entry){
+ errorMsg += err?.errors?.entry;
+ }else{
+ errorMsg += (err?.entry?.errorMessage || err?.errorMessage || err?.message) ?? 'Something went wrong!';
+ }
+ logger.error(errorMsg)
+ });
}
}
diff --git a/packages/contentstack-branches/src/utils/entry-update-script.ts b/packages/contentstack-branches/src/utils/entry-update-script.ts
index 19b6549bda..ce6257a4d1 100644
--- a/packages/contentstack-branches/src/utils/entry-update-script.ts
+++ b/packages/contentstack-branches/src/utils/entry-update-script.ts
@@ -2,6 +2,14 @@ export function entryUpdateScript(contentType) {
return `
const fs = require('fs');
const path = require('path');
+ const { marked } = require('marked');
+ const has = require('lodash/has');
+ const isArray = require('lodash/isArray');
+ const isObject = require('lodash/isObject');
+ const omit = require('lodash/omit');
+ const compact = require('lodash/compact')
+ const isPlainObject = require('lodash/isPlainObject');
+ const {cliux, LoggerService} = require('@contentstack/cli-utilities')
module.exports = async ({ migration, stackSDKInstance, managementAPIClient, config, branch, apiKey }) => {
const keysToRemove = [
'content_type_uid',
@@ -29,10 +37,12 @@ export function entryUpdateScript(contentType) {
let assetDirPath = path.resolve(filePath, 'assets');
let assetDetails = [];
let newAssetDetails = [];
+ let downloadedAssets = [];
let assetUIDMapper = {};
let assetUrlMapper = {};
let assetRefPath = {};
- let isAssetDownload = false;
+ let parent=[];
+ let logger;
function converter(data) {
let arr = [];
@@ -59,14 +69,10 @@ export function entryUpdateScript(contentType) {
return path.split('[').reduce((o, key) => o && o[key.replace(/\]$/, '')], obj);
}
- function updateValueByPath(obj, path, newValue, type, fileIndex) {
+ function updateValueByPath(obj, path, newValue) {
path.split('[').reduce((o, key, index, arr) => {
if (index === arr.length - 1) {
- if (type === 'file') {
- o[key.replace(/]$/, '')][fileIndex] = newValue;
- } else {
o[key.replace(/]$/, '')][0].uid = newValue;
- }
} else {
return o[key.replace(/\]$/, '')];
}
@@ -99,35 +105,52 @@ export function entryUpdateScript(contentType) {
return references;
};
- const findAssets = function (schema, entry, refPath, path) {
+ const findAssets = function (schema, entry) {
for (const i in schema) {
- const currentPath = path ? path + '[' + schema[i].uid : schema[i].uid;
if (schema[i].data_type === 'group' || schema[i].data_type === 'global_field') {
- findAssets(schema[i].schema, entry, refPath, currentPath + '[0]');
- } else if (schema[i].data_type === 'blocks') {
- for (const block in schema[i].blocks) {
+ parent.push(schema[i].uid);
+ findAssets(schema[i].schema, entry);
+ parent.pop();
+ }
+ if (schema[i].data_type === 'blocks') {
+ for (const j = 0; j < schema[i].blocks; j++) {
{
- if (schema[i].blocks[block].schema) {
- findAssets(
- schema[i].blocks[block].schema,
- entry,
- refPath,
- currentPath + '[' + block + '][' + schema[i].blocks[block].uid + ']',
- );
+ if (schema[i].blocks[j].schema) {
+ parent.push(schema[i].uid);
+ parent.push(j);
+ parent.push(schema[i].blocks[j].uid);
+ findAssets(schema[i].blocks[j].schema, entry);
+ parent.pop();
+ parent.pop();
+ parent.pop();
}
}
}
- } else if (schema[i].data_type === 'json' && schema[i].field_metadata.rich_text_type) {
- findAssetIdsFromJsonRte(entry, schema, refPath, path);
- } else if (
+ }
+ if (schema[i].data_type === 'json' && schema[i].field_metadata.rich_text_type) {
+ parent.push(schema[i].uid);
+ findAssetIdsFromJsonRte(entry, schema);
+ parent.pop();
+ }
+ if (
schema[i].data_type === 'text' &&
schema[i].field_metadata &&
(schema[i].field_metadata.markdown || schema[i].field_metadata.rich_text_type)
) {
+ parent.push(schema[i].uid);
findFileUrls(schema[i], entry);
- } else if (schema[i].data_type === 'file') {
- refPath.push(currentPath)
- const imgDetails = getValueByPath(entry, currentPath);
+ if (schema[i].field_metadata.rich_text_type) {
+ findAssetIdsFromHtmlRte(entry, schema[i]);
+ }
+ parent.pop();
+ }
+ if (schema[i].data_type === 'file') {
+ parent.push(schema[i].uid);
+ let updatedEntry = entry;
+ for (let i = 0; i < parent.length; i++) {
+ updatedEntry = updatedEntry[parent[i]];
+ }
+ const imgDetails = updatedEntry;
if (schema[i].multiple) {
if (imgDetails && imgDetails.length) {
imgDetails.forEach((img) => {
@@ -155,10 +178,21 @@ export function entryUpdateScript(contentType) {
assetDetails.push(obj);
}
}
+ parent.pop();
}
}
};
+ function findAssetIdsFromHtmlRte(entryObj, ctSchema) {
+ const regex = / {
- let imgDetails = entry[refPath];
- if (imgDetails !== undefined) {
- if (imgDetails && !Array.isArray(imgDetails)) {
- entry[refPath] = assetUIDMapper[imgDetails.uid];
- } else if (imgDetails && Array.isArray(imgDetails)) {
- for (let i = 0; i < imgDetails.length; i++) {
- const img = imgDetails[i];
- entry[refPath][i] = assetUIDMapper[img.uid];
- }
- }
- } else {
- imgDetails = getValueByPath(entry, refPath);
- if (imgDetails && !Array.isArray(imgDetails)) {
- const imgUID = imgDetails?.uid;
- updateValueByPath(entry, refPath, assetUIDMapper[imgUID], 'file', 0);
- } else if (imgDetails && Array.isArray(imgDetails)) {
- for (let i = 0; i < imgDetails.length; i++) {
- const img = imgDetails[i];
- const imgUID = img?.uid;
- updateValueByPath(entry, refPath, assetUIDMapper[imgUID], 'file', i);
- }
- }
- }
- });
+ let updatedEntry = Object.assign({},entry);
+ entry = updateFileFields(updatedEntry, entry, null)
entry = JSON.stringify(entry);
const assetUrls = assetDetails.map((asset) => asset.url);
const assetUIDs = assetDetails.map((asset) => asset.uid);
@@ -321,6 +332,65 @@ export function entryUpdateScript(contentType) {
});
return JSON.parse(entry);
};
+
+ function updateFileFields(
+ object,
+ parent,
+ pos
+ ) {
+ if (isPlainObject(object) && has(object, 'filename') && has(object, 'uid')) {
+ if (typeof pos !== 'undefined') {
+ if (typeof pos === 'number' || typeof pos === 'string') {
+ const replacer = () => {
+ if (assetUIDMapper.hasOwnProperty(object.uid)) {
+ parent[pos] = assetUIDMapper[object.uid];
+ } else {
+ parent[pos] = '';
+ }
+ };
+
+ if (parent.uid && assetUIDMapper[parent.uid]) {
+ parent.uid = assetUIDMapper[parent.uid];
+ }
+
+ if (
+ object &&
+ isObject(parent[pos]) &&
+ parent[pos].uid &&
+ parent[pos].url &&
+ has(parent, 'asset') &&
+ has(parent, '_content_type_uid') &&
+ parent._content_type_uid === 'sys_assets'
+ ) {
+ if (
+ has(parent, 'asset') &&
+ has(parent, '_content_type_uid') &&
+ parent._content_type_uid === 'sys_assets'
+ ) {
+ parent = omit(parent, ['asset']);
+ }
+
+ if (object.uid && assetUIDMapper[object.uid]) {
+ object.uid = assetUIDMapper[object.uid];
+ }
+ if (object.url && assetUrlMapper[object.url]) {
+ object.url = assetUrlMapper[object.url];
+ }
+ } else {
+ replacer();
+ }
+ }
+ }
+ } else if (isPlainObject(object)) {
+ for (let key in object) updateFileFields(object[key], object, key);
+ } else if (isArray(object) && object.length) {
+ for (let i = 0; i <= object.length; i++){
+ updateFileFields(object[i], object, i);
+ }
+ parent[pos] = compact(object);
+ }
+ return object;
+ }
const checkAndDownloadAsset = async function (cAsset) {
if (cAsset) {
@@ -337,7 +407,6 @@ export function entryUpdateScript(contentType) {
return false;
}
else {
- isAssetDownload = true;
const cAssetDetail = await managementAPIClient
.stack({ api_key: stackSDKInstance.api_key, branch_uid: compareBranch })
.asset(assetUID)
@@ -379,8 +448,8 @@ export function entryUpdateScript(contentType) {
const uploadAssets = async function () {
const assetFolderMap = JSON.parse(fs.readFileSync(path.resolve(filePath, 'folder-mapper.json'), 'utf8'));
const stackAPIClient = managementAPIClient.stack({ api_key: stackSDKInstance.api_key, branch_uid: branch });
- for (let i = 0; i < assetDetails?.length; i++) {
- const asset = assetDetails[i];
+ for (let i = 0; i < downloadedAssets?.length; i++) {
+ const asset = downloadedAssets[i];
let requestOption = {};
requestOption.parent_uid = assetFolderMap[asset.parent_uid] || asset.parent_uid;
@@ -415,6 +484,11 @@ export function entryUpdateScript(contentType) {
successMessage: 'Entries Updated Successfully',
failedMessage: 'Failed to update entries',
task: async () => {
+ //logger file
+ if(!fs.existsSync(path.join(filePath, 'entry-migration'))){
+ logger = new LoggerService(filePath, 'entry-migration');
+ }
+
let compareBranchEntries = await managementAPIClient
.stack({ api_key: stackSDKInstance.api_key, branch_uid: compareBranch })
.contentType('${contentType}')
@@ -450,9 +524,10 @@ export function entryUpdateScript(contentType) {
const updatedCAsset = await checkAndDownloadAsset(asset);
if(updatedCAsset){
newAssetDetails[i] = updatedCAsset;
+ downloadedAssets.push(updatedCAsset);
}
}
- if (isAssetDownload) await uploadAssets();
+ if (downloadedAssets?.length) await uploadAssets();
}
let flag = {
@@ -463,7 +538,17 @@ export function entryUpdateScript(contentType) {
async function updateEntry(entry, entryDetails) {
Object.assign(entry, { ...entryDetails });
- await entry.update();
+ await entry.update().catch(err => {
+ let errorMsg = 'Entry update failed for uid: ' + entry?.uid + ', title: ' + entry?.title + '.';
+ if(err?.errors?.title){
+ errorMsg += err?.errors?.title;
+ }else if(err?.errors?.entry){
+ errorMsg += err?.errors?.entry;
+ }else{
+ errorMsg += (err?.entry?.errorMessage || err?.errorMessage || err?.message) ?? 'Something went wrong!';
+ }
+ logger.error(errorMsg)
+ });
}
async function updateReferences(entryDetails, baseEntry, references) {
diff --git a/packages/contentstack/package.json b/packages/contentstack/package.json
index dd83c43c56..9e4921c8d7 100755
--- a/packages/contentstack/package.json
+++ b/packages/contentstack/package.json
@@ -25,7 +25,7 @@
"@contentstack/cli-audit": "~1.3.2",
"@contentstack/cli-auth": "~1.3.17",
"@contentstack/cli-cm-bootstrap": "~1.7.1",
- "@contentstack/cli-cm-branches": "~1.0.19",
+ "@contentstack/cli-cm-branches": "~1.0.20",
"@contentstack/cli-cm-bulk-publish": "~1.4.0",
"@contentstack/cli-cm-clone": "~1.9.0",
"@contentstack/cli-cm-export": "~1.10.2",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 9332f9b940..9cfe8e1a66 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -13,7 +13,7 @@ importers:
'@contentstack/cli-audit': ~1.3.2
'@contentstack/cli-auth': ~1.3.17
'@contentstack/cli-cm-bootstrap': ~1.7.1
- '@contentstack/cli-cm-branches': ~1.0.19
+ '@contentstack/cli-cm-branches': ~1.0.20
'@contentstack/cli-cm-bulk-publish': ~1.4.0
'@contentstack/cli-cm-clone': ~1.9.0
'@contentstack/cli-cm-export': ~1.10.2