diff --git a/package-lock.json b/package-lock.json index fecf852c35..1a74fab8cc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10036,10 +10036,23 @@ "node": ">=8" } }, - "node_modules/ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dev": true, + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/ip-address/node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", "dev": true }, "node_modules/ipaddr.js": { @@ -11684,6 +11697,12 @@ "xmlcreate": "^2.0.4" } }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "dev": true + }, "node_modules/jsdoc": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.2.tgz", @@ -11734,14 +11753,13 @@ } }, "node_modules/jsdoc-parse": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/jsdoc-parse/-/jsdoc-parse-6.2.0.tgz", - "integrity": "sha512-Afu1fQBEb7QHt6QWX/6eUWvYHJofB90Fjx7FuJYF7mnG9z5BkAIpms1wsnvYLytfmqpEENHs/fax9p8gvMj7dw==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsdoc-parse/-/jsdoc-parse-6.2.1.tgz", + "integrity": "sha512-9viGRUUtWOk/G4V0+nQ6rfLucz5plxh5I74WbNSNm9h9NWugCDVX4jbG8hZP9QqKGpdTPDE+qJXzaYNos3wqTA==", "dev": true, "dependencies": { "array-back": "^6.2.2", "lodash.omit": "^4.5.0", - "lodash.pick": "^4.4.0", "reduce-extract": "^1.0.0", "sort-array": "^4.1.5", "test-value": "^3.0.0" @@ -12474,12 +12492,6 @@ "integrity": "sha512-sOQs2aqGpbl27tmCS1QNZA09Uqp01ZzWfDUoD+xzTii0E7dSQfRKcRetFwa+uXaxaqL+TKm7CgD2JdKP7aZBSw==", "dev": true }, - "node_modules/lodash.pick": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", - "integrity": "sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q==", - "dev": true - }, "node_modules/lodash.template": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", @@ -20106,16 +20118,16 @@ } }, "node_modules/socks": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", - "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.3.tgz", + "integrity": "sha512-vfuYK48HXCTFD03G/1/zkIls3Ebr2YNa4qU9gHDZdblHLiqhJrJGkY3+0Nx0JpN9qBhJbVObc1CNciT1bIZJxw==", "dev": true, "dependencies": { - "ip": "^2.0.0", + "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" }, "engines": { - "node": ">= 10.13.0", + "node": ">= 10.0.0", "npm": ">= 3.0.0" } }, @@ -23551,7 +23563,7 @@ "@contentstack/cli-cm-clone": "~1.10.0", "@contentstack/cli-cm-export": "~1.10.5", "@contentstack/cli-cm-export-to-csv": "~1.6.2", - "@contentstack/cli-cm-import": "~1.13.4", + "@contentstack/cli-cm-import": "~1.13.5", "@contentstack/cli-cm-migrate-rte": "~1.4.15", "@contentstack/cli-cm-seed": "~1.7.1", "@contentstack/cli-command": "~1.2.17", @@ -24093,7 +24105,7 @@ "dependencies": { "@colors/colors": "^1.5.0", "@contentstack/cli-cm-export": "~1.10.5", - "@contentstack/cli-cm-import": "~1.13.4", + "@contentstack/cli-cm-import": "~1.13.5", "@contentstack/cli-command": "~1.2.16", "@contentstack/cli-utilities": "~1.5.13", "async": "^3.2.4", @@ -24993,7 +25005,7 @@ }, "packages/contentstack-import": { "name": "@contentstack/cli-cm-import", - "version": "1.13.4", + "version": "1.13.5", "license": "MIT", "dependencies": { "@contentstack/cli-audit": "~1.4.0", @@ -25472,7 +25484,7 @@ "version": "1.7.1", "license": "MIT", "dependencies": { - "@contentstack/cli-cm-import": "~1.13.4", + "@contentstack/cli-cm-import": "~1.13.5", "@contentstack/cli-command": "~1.2.16", "@contentstack/cli-utilities": "~1.5.13", "inquirer": "8.2.4", diff --git a/packages/contentstack-clone/package.json b/packages/contentstack-clone/package.json index 783be690cb..9fefe51e13 100644 --- a/packages/contentstack-clone/package.json +++ b/packages/contentstack-clone/package.json @@ -6,7 +6,7 @@ "bugs": "https://github.com/rohitmishra209/cli-cm-clone/issues", "dependencies": { "@contentstack/cli-cm-export": "~1.10.5", - "@contentstack/cli-cm-import": "~1.13.4", + "@contentstack/cli-cm-import": "~1.13.5", "@contentstack/cli-command": "~1.2.16", "@contentstack/cli-utilities": "~1.5.13", "@colors/colors": "^1.5.0", diff --git a/packages/contentstack-import/package.json b/packages/contentstack-import/package.json index 65ff8139dc..18c6f20bf0 100644 --- a/packages/contentstack-import/package.json +++ b/packages/contentstack-import/package.json @@ -1,7 +1,7 @@ { "name": "@contentstack/cli-cm-import", "description": "Contentstack CLI plugin to import content into stack", - "version": "1.13.4", + "version": "1.13.5", "author": "Contentstack", "bugs": "https://github.com/contentstack/cli/issues", "dependencies": { diff --git a/packages/contentstack-import/src/import/modules/base-class.ts b/packages/contentstack-import/src/import/modules/base-class.ts index d4a69296c9..72b2374897 100644 --- a/packages/contentstack-import/src/import/modules/base-class.ts +++ b/packages/contentstack-import/src/import/modules/base-class.ts @@ -251,6 +251,13 @@ export default abstract class BaseClass { apiData: includeParamOnCompletion ? apiData : undefined, }); + if ( + !apiData || + (entity === 'publish-entries' && !apiData.entryUid) || + (entity === 'update-extensions' && !apiData.uid) + ) { + return Promise.resolve(); + } switch (entity) { case 'create-assets-folder': return this.stack @@ -283,6 +290,16 @@ export default abstract class BaseClass { .create({ extension: omit(apiData, ['uid']) as ExtensionData }) .then(onSuccess) .catch(onReject); + case 'update-extensions': + return this.stack + .extension(apiData.uid) + .fetch() + .then((extension) => { + extension.scope = apiData.scope; + return extension.update(); + }) + .then(onSuccess) + .catch(onReject); case 'create-locale': return this.stack .locale() @@ -298,14 +315,8 @@ export default abstract class BaseClass { case 'create-cts': return this.stack.contentType().create(apiData).then(onSuccess).catch(onReject); case 'update-cts': - if (!apiData) { - return Promise.resolve(); - } return apiData.update().then(onSuccess).catch(onReject); case 'update-gfs': - if (!apiData) { - return Promise.resolve(); - } return apiData.update().then(onSuccess).catch(onReject); case 'create-environments': return this.stack @@ -347,9 +358,6 @@ export default abstract class BaseClass { .then(onSuccess) .catch(onReject); case 'create-entries': - if (!apiData) { - return Promise.resolve(); - } if (additionalInfo[apiData?.uid]?.isLocalized) { return apiData.update({ locale: additionalInfo.locale }).then(onSuccess).catch(onReject); } @@ -360,14 +368,8 @@ export default abstract class BaseClass { .then(onSuccess) .catch(onReject); case 'update-entries': - if (!apiData) { - return Promise.resolve(); - } return apiData.update({ locale: additionalInfo.locale }).then(onSuccess).catch(onReject); case 'publish-entries': - if (!apiData || !apiData.entryUid) { - return Promise.resolve(); - } return this.stack .contentType(additionalInfo.cTUid) .entry(apiData.entryUid) diff --git a/packages/contentstack-import/src/import/modules/content-types.ts b/packages/contentstack-import/src/import/modules/content-types.ts index 0ca255da31..9fd9f4e5c3 100644 --- a/packages/contentstack-import/src/import/modules/content-types.ts +++ b/packages/contentstack-import/src/import/modules/content-types.ts @@ -51,6 +51,7 @@ export default class ContentTypesImport extends BaseClass { }; private taxonomiesPath: string; public taxonomies: Record; + private extPendingPath: string; constructor({ importConfig, stackAPIClient }: ModuleClassParams) { super({ importConfig, stackAPIClient }); @@ -78,6 +79,7 @@ export default class ContentTypesImport extends BaseClass { this.createdGFs = []; this.pendingGFs = []; this.taxonomiesPath = path.join(importConfig.data, 'mapper/taxonomies', 'success.json'); + this.extPendingPath = path.join(importConfig.data, 'mapper', 'extensions', 'pending_extensions.js'); } async start(): Promise { @@ -106,6 +108,9 @@ export default class ContentTypesImport extends BaseClass { if (this.fieldRules.length > 0) { await fsUtil.writeFile(path.join(this.cTsFolderPath, 'field_rules_uid.json'), this.fieldRules); } + log(this.importConfig, 'Updating the extensions...', 'success'); + await this.updatePendingExtensions(); + log(this.importConfig, 'Successfully updated the extensions.', 'success'); await this.updatePendingGFs().catch((error) => { log(this.importConfig, `Error while updating pending global field ${formatError(error)}`, 'error'); }); @@ -250,4 +255,44 @@ export default class ContentTypesImport extends BaseClass { apiOptions.apiData = globalFieldPayload; return apiOptions; } + + async updatePendingExtensions(): Promise { + let apiContent = fsUtil.readFile(this.extPendingPath) as Record[]; + if (apiContent.length === 0) { + log(this.importConfig, `No extensions found to be updated.`, 'success'); + return; + } + + const onSuccess = ({ response, apiData: { uid, title } = { uid: null, title: '' } }: any) => { + log(this.importConfig, `Successfully updated the '${response.title}' extension.`, 'success'); + }; + + const onReject = ({ error, apiData }: any) => { + const { uid } = apiData; + if (error?.errors?.title) { + if (!this.importConfig.skipExisting) { + log(this.importConfig, `Extension '${uid}' already exists.`, 'info'); + } + } else { + log(this.importConfig, `Failed to update '${uid}' extension due to ${formatError(error)}.`, 'error'); + log(this.importConfig, error, 'error'); + } + }; + + return await this.makeConcurrentCall( + { + apiContent, + processName: 'update extensions', + apiParams: { + reject: onReject.bind(this), + resolve: onSuccess.bind(this), + entity: 'update-extensions', + includeParamOnCompletion: true, + }, + concurrencyLimit: this.importConfig.concurrency || this.importConfig.fetchConcurrency || 1, + }, + undefined, + false, + ); + } } diff --git a/packages/contentstack-import/src/import/modules/extensions.ts b/packages/contentstack-import/src/import/modules/extensions.ts index 22ce73dbb9..ce92433ca9 100644 --- a/packages/contentstack-import/src/import/modules/extensions.ts +++ b/packages/contentstack-import/src/import/modules/extensions.ts @@ -5,7 +5,7 @@ import { join } from 'node:path'; import { log, formatError, fsUtil, fileHelper } from '../../utils'; import BaseClass, { ApiOptions } from './base-class'; -import { ModuleClassParams, Extensions } from '../../types'; +import { ModuleClassParams, Extensions, ExtensionType } from '../../types'; export default class ImportExtensions extends BaseClass { private mapperDirPath: string; @@ -19,6 +19,8 @@ export default class ImportExtensions extends BaseClass { private extSuccess: Record[]; private extFailed: Record[]; private existingExtensions: Record[]; + private extPendingPath: string; + private extensionObject: Record[]; constructor({ importConfig, stackAPIClient }: ModuleClassParams) { super({ importConfig, stackAPIClient }); @@ -28,10 +30,12 @@ export default class ImportExtensions extends BaseClass { this.extUidMapperPath = join(this.mapperDirPath, 'uid-mapping.json'); this.extSuccessPath = join(this.mapperDirPath, 'success.json'); this.extFailsPath = join(this.mapperDirPath, 'fails.json'); + this.extPendingPath = join(this.mapperDirPath, 'pending_extensions.js'); this.extFailed = []; this.extSuccess = []; this.existingExtensions = []; this.extUidMapper = {}; + this.extensionObject = []; } /** @@ -45,7 +49,7 @@ export default class ImportExtensions extends BaseClass { if (fileHelper.fileExistsSync(this.extensionsFolderPath)) { this.extensions = fsUtil.readFile(join(this.extensionsFolderPath, 'extensions.json'), true) as Record< string, - unknown + Record >; } else { log(this.importConfig, `No such file or directory - '${this.extensionsFolderPath}'`, 'error'); @@ -57,8 +61,14 @@ export default class ImportExtensions extends BaseClass { ? (fsUtil.readFile(join(this.extUidMapperPath), true) as Record) : {}; + // Check whether the scope of an extension contains content-types in scope + // Remove the scope and store the scope with uid in pending extensions + this.getContentTypesInScope(); + await this.importExtensions(); + // Update the uid of the extension + this.updateUidExtension(); // Note: if any extensions present, then update it if (this.importConfig.replaceExisting && this.existingExtensions.length > 0) { await this.replaceExtensions().catch((error: Error) => { @@ -209,4 +219,25 @@ export default class ImportExtensions extends BaseClass { } }); } + + getContentTypesInScope() { + const extension = values(this.extensions); + extension.forEach((ext: ExtensionType) => { + let ct: any = ext?.scope?.content_types || []; + if ((ct.length === 1 && ct[0] !== '$all') || ct?.length > 1) { + log(this.importConfig, `Removing the content-types ${ct.join(',')} from the extension ${ext.title} ...`, 'info'); + const { uid, scope } = ext; + this.extensionObject.push({ uid, scope }); + delete ext.scope; + this.extensions[ext.uid] = ext; + } + }); + } + + updateUidExtension() { + for (let i in this.extensionObject) { + this.extensionObject[i].uid = this.extUidMapper[this.extensionObject[i].uid as string]; + } + fsUtil.writeFile(this.extPendingPath, this.extensionObject); + } } diff --git a/packages/contentstack-import/src/types/index.ts b/packages/contentstack-import/src/types/index.ts index 5a570afac3..16b6785a88 100644 --- a/packages/contentstack-import/src/types/index.ts +++ b/packages/contentstack-import/src/types/index.ts @@ -106,4 +106,10 @@ export { default as DefaultConfig } from './default-config'; export { default as ImportConfig } from './import-config'; export * from './entries' -export * from './marketplace-app' \ No newline at end of file +export * from './marketplace-app' + +export type ExtensionType = { + uid: string, + scope: Record, + title: string +} \ No newline at end of file diff --git a/packages/contentstack-seed/package.json b/packages/contentstack-seed/package.json index e09b96b882..0876826649 100644 --- a/packages/contentstack-seed/package.json +++ b/packages/contentstack-seed/package.json @@ -5,7 +5,7 @@ "author": "Contentstack", "bugs": "https://github.com/contentstack/cli/issues", "dependencies": { - "@contentstack/cli-cm-import": "~1.13.4", + "@contentstack/cli-cm-import": "~1.13.5", "@contentstack/cli-command": "~1.2.16", "@contentstack/cli-utilities": "~1.5.13", "inquirer": "8.2.4", diff --git a/packages/contentstack/package.json b/packages/contentstack/package.json index f48d578c82..852a3239e6 100755 --- a/packages/contentstack/package.json +++ b/packages/contentstack/package.json @@ -30,7 +30,7 @@ "@contentstack/cli-cm-export": "~1.10.5", "@contentstack/cli-cm-clone": "~1.10.0", "@contentstack/cli-cm-export-to-csv": "~1.6.2", - "@contentstack/cli-cm-import": "~1.13.4", + "@contentstack/cli-cm-import": "~1.13.5", "@contentstack/cli-cm-migrate-rte": "~1.4.15", "@contentstack/cli-cm-seed": "~1.7.1", "@contentstack/cli-command": "~1.2.17", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 09a1b708a8..43eed03e57 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,7 +18,7 @@ importers: '@contentstack/cli-cm-clone': ~1.10.0 '@contentstack/cli-cm-export': ~1.10.5 '@contentstack/cli-cm-export-to-csv': ~1.6.2 - '@contentstack/cli-cm-import': ~1.13.4 + '@contentstack/cli-cm-import': ~1.13.5 '@contentstack/cli-cm-migrate-rte': ~1.4.15 '@contentstack/cli-cm-seed': ~1.7.1 '@contentstack/cli-command': ~1.2.17 @@ -424,7 +424,7 @@ importers: specifiers: '@colors/colors': ^1.5.0 '@contentstack/cli-cm-export': ~1.10.5 - '@contentstack/cli-cm-import': ~1.13.4 + '@contentstack/cli-cm-import': ~1.13.5 '@contentstack/cli-command': ~1.2.16 '@contentstack/cli-utilities': ~1.5.13 '@oclif/test': ^2.5.6 @@ -990,7 +990,7 @@ importers: packages/contentstack-seed: specifiers: - '@contentstack/cli-cm-import': ~1.13.4 + '@contentstack/cli-cm-import': ~1.13.5 '@contentstack/cli-command': ~1.2.16 '@contentstack/cli-utilities': ~1.5.13 '@oclif/plugin-help': ^5.1.19