diff --git a/package-lock.json b/package-lock.json index c2af8b3cfc..656e6a8591 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23533,7 +23533,7 @@ "@contentstack/cli-cm-clone": "~1.9.0", "@contentstack/cli-cm-export": "~1.10.2", "@contentstack/cli-cm-export-to-csv": "~1.6.2", - "@contentstack/cli-cm-import": "~1.13.0", + "@contentstack/cli-cm-import": "~1.13.1", "@contentstack/cli-cm-migrate-rte": "~1.4.15", "@contentstack/cli-cm-seed": "~1.7.1", "@contentstack/cli-command": "~1.2.17", @@ -24249,7 +24249,7 @@ "dependencies": { "@colors/colors": "^1.5.0", "@contentstack/cli-cm-export": "~1.10.2", - "@contentstack/cli-cm-import": "~1.13.0", + "@contentstack/cli-cm-import": "~1.13.1", "@contentstack/cli-command": "~1.2.16", "@contentstack/cli-utilities": "~1.5.10", "async": "^3.2.4", @@ -25306,7 +25306,7 @@ }, "packages/contentstack-import": { "name": "@contentstack/cli-cm-import", - "version": "1.13.0", + "version": "1.13.1", "license": "MIT", "dependencies": { "@contentstack/cli-audit": "^1.3.2", @@ -25881,7 +25881,7 @@ "version": "1.7.1", "license": "MIT", "dependencies": { - "@contentstack/cli-cm-import": "~1.13.0", + "@contentstack/cli-cm-import": "~1.13.1", "@contentstack/cli-command": "~1.2.16", "@contentstack/cli-utilities": "~1.5.10", "inquirer": "8.2.4", diff --git a/packages/contentstack-clone/package.json b/packages/contentstack-clone/package.json index 46e1791133..fe7fda0654 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.2", - "@contentstack/cli-cm-import": "~1.13.0", + "@contentstack/cli-cm-import": "~1.13.1", "@contentstack/cli-command": "~1.2.16", "@contentstack/cli-utilities": "~1.5.10", "@colors/colors": "^1.5.0", diff --git a/packages/contentstack-import/package.json b/packages/contentstack-import/package.json index 185e5a6515..d407057776 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.0", + "version": "1.13.1", "author": "Contentstack", "bugs": "https://github.com/contentstack/cli/issues", "dependencies": { diff --git a/packages/contentstack-import/src/import/modules/content-types.ts b/packages/contentstack-import/src/import/modules/content-types.ts index 0ca255da31..d668138056 100644 --- a/packages/contentstack-import/src/import/modules/content-types.ts +++ b/packages/contentstack-import/src/import/modules/content-types.ts @@ -11,6 +11,7 @@ import { fsUtil, log, formatError, schemaTemplate, lookupExtension, lookUpTaxono import { ImportConfig, ModuleClassParams } from '../../types'; import BaseClass, { ApiOptions } from './base-class'; import { updateFieldRules } from '../../utils/content-type-helper'; +import { getAllContentTypesFromStack } from './../../utils/common-helper' export default class ContentTypesImport extends BaseClass { private cTsMapperPath: string; @@ -51,6 +52,9 @@ export default class ContentTypesImport extends BaseClass { }; private taxonomiesPath: string; public taxonomies: Record; + private extScopePath: string; + private extUidMapperPath: string; + private extSuccessPath: string; constructor({ importConfig, stackAPIClient }: ModuleClassParams) { super({ importConfig, stackAPIClient }); @@ -78,6 +82,10 @@ export default class ContentTypesImport extends BaseClass { this.createdGFs = []; this.pendingGFs = []; this.taxonomiesPath = path.join(importConfig.data, 'mapper/taxonomies', 'success.json'); + this.stackAPIClient = stackAPIClient; + this.extScopePath = path.join(this.importConfig.backupDir,importConfig.modules.extensions.dirName,'scope.json') + this.extUidMapperPath = path.join(this.importConfig.backupDir, 'mapper', 'extensions','uid-mapping.json'); + this.extSuccessPath = path.join(this.importConfig.backupDir, 'mapper', 'extensions','success.json') } async start(): Promise { @@ -111,6 +119,8 @@ export default class ContentTypesImport extends BaseClass { }); log(this.importConfig, 'Updated pending global fields with content type with references', 'success'); log(this.importConfig, 'Content types have been imported successfully!', 'success'); + const contentTypeTitle = await getAllContentTypesFromStack(this.stackAPIClient); + await this.lookupExtensionScope(contentTypeTitle) } async seedCTs(): Promise { @@ -250,4 +260,73 @@ export default class ContentTypesImport extends BaseClass { apiOptions.apiData = globalFieldPayload; return apiOptions; } + + async lookupExtensionScope(contentTypeTitles:any,) { + const extension = await fsUtil.readFile(this.extScopePath); + const extensionToBeCreated: any = [] + if(Array.isArray(extension)){ + extension.forEach((ext:any)=>{ + let isAllCtPresent:boolean = true; + ext?.scope?.content_types.forEach((ct:string)=>{ + if(!contentTypeTitles.includes(ct)){ + isAllCtPresent = false; + log(this.importConfig,`For Extension '${ext.title}' content type '${ct}' is not present. Skipping this extension creation`,'error'); + } + }) + if(isAllCtPresent) { + extensionToBeCreated.push(ext); + } + }) + } + if(extensionToBeCreated.length===0){ + log(this.importConfig,`No extension found to be dependent on Content types`,'info'); + } else { + const apiContent = extensionToBeCreated + const extSuccess:any = fsUtil.readFile(this.extSuccessPath); + const extUidMapper:any = fsUtil.readFile(this.extUidMapperPath); + const existingExtensions = []; + const extFailed = []; + + const onSuccess = ({ response, apiData: { uid, title } = { uid: null, title: '' } }: any) => { + extSuccess.push(response); + extUidMapper[uid] = response.uid; + log(this.importConfig, `Extension '${title}' imported successfully`, 'success'); + fsUtil.writeFile(this.extUidMapperPath, extUidMapper); + }; + + const onReject = ({ error, apiData }: any) => { + const { title } = apiData; + if (error?.errors?.title) { + if (this.importConfig.replaceExisting) { + existingExtensions.push(apiData); + } + if (!this.importConfig.skipExisting) { + log(this.importConfig, `Extension '${title}' already exists`, 'info'); + } + } else { + extFailed.push(apiData); + log(this.importConfig, `Extension '${title}' failed to be import ${formatError(error)}`, 'error'); + log(this.importConfig, error, 'error'); + } + }; + + await this.makeConcurrentCall( + { + apiContent, + processName: 'import extensions', + apiParams: { + reject: onReject.bind(this), + resolve: onSuccess.bind(this), + entity: 'create-extensions', + includeParamOnCompletion: true, + }, + concurrencyLimit: this.importConfig.concurrency || this.importConfig.fetchConcurrency || 1, + }, + undefined, + false, + ); + fsUtil.writeFile(this.extSuccessPath, extSuccess); + } + + } } diff --git a/packages/contentstack-import/src/import/modules/extensions.ts b/packages/contentstack-import/src/import/modules/extensions.ts index 22ce73dbb9..4fe0f5a3e3 100644 --- a/packages/contentstack-import/src/import/modules/extensions.ts +++ b/packages/contentstack-import/src/import/modules/extensions.ts @@ -19,6 +19,7 @@ export default class ImportExtensions extends BaseClass { private extSuccess: Record[]; private extFailed: Record[]; private existingExtensions: Record[]; + private extScopePath: string; constructor({ importConfig, stackAPIClient }: ModuleClassParams) { super({ importConfig, stackAPIClient }); @@ -28,6 +29,7 @@ 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.extScopePath = join(this.extensionsFolderPath,'scope.json') this.extFailed = []; this.extSuccess = []; this.existingExtensions = []; @@ -56,7 +58,7 @@ export default class ImportExtensions extends BaseClass { this.extUidMapper = fileHelper.fileExistsSync(this.extUidMapperPath) ? (fsUtil.readFile(join(this.extUidMapperPath), true) as Record) : {}; - + await this.getContentTypesInScope(); await this.importExtensions(); // Note: if any extensions present, then update it @@ -209,4 +211,24 @@ export default class ImportExtensions extends BaseClass { } }); } + + async getContentTypesInScope(){ + const extension = values(this.extensions); + const extensionObject:{string:Record}[] = [] + type extType = { + uid: string, + scope: Record + } + extension.forEach((ext:any)=>{ + let ct:any = ext?.scope?.content_types || []; + if(ct.length===1 && (ct[0]!=='$all')){ + extensionObject.push(ext) + delete this.extensions[ext.uid] + } else if(ct?.length>1) { + extensionObject.push(ext) + delete this.extensions[ext.uid] + } + }) + fsUtil.writeFile(this.extScopePath, extensionObject); + } } diff --git a/packages/contentstack-import/src/utils/common-helper.ts b/packages/contentstack-import/src/utils/common-helper.ts index ad8a471f52..0d70dd44ba 100644 --- a/packages/contentstack-import/src/utils/common-helper.ts +++ b/packages/contentstack-import/src/utils/common-helper.ts @@ -249,3 +249,49 @@ export const formatDate = (date: Date = new Date()) => { return formattedDate; }; + +// Get all the content types to validate whether all the content types are present in scope for the given extension +export const getAllContentTypesFromStack:any = async (stackAPIClient:any) => { + try{ + let contentTypes:any[] = [] + const contentTypeCount:number = await getContentTypeCount(stackAPIClient); + for (let index = 0; index <= contentTypeCount / 100; index++) { + const contentTypesMap = await getContentTypes(stackAPIClient, index); + contentTypes = contentTypes.concat((Object.keys(contentTypesMap))); // prompt for content Type + } + return contentTypes + } catch (err) { + return err; + } +} + +function getContentTypeCount(stackAPIClient:any):number|any { + return new Promise((resolve, reject) => { + stackAPIClient + .contentType() + .query() + .count() + .then((contentTypes:any) => resolve(contentTypes.content_types)) + .catch((error:any) => reject(error)); + }); +} + + +function getContentTypes(stackAPIClient:any, skip:any) { + return new Promise((resolve, reject) => { + let result:any = {}; + stackAPIClient + .contentType() + .query({ skip: skip * 100, include_branch: true }) + .find() + .then((contentTypes:any) => { + contentTypes.items.forEach((contentType:any) => { + result[contentType.title] = contentType.uid; + }); + resolve(result); + }) + .catch((error:any) => { + reject(error); + }); + }); +} \ No newline at end of file diff --git a/packages/contentstack-seed/package.json b/packages/contentstack-seed/package.json index a5998b0e1f..911afc2dd4 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.0", + "@contentstack/cli-cm-import": "~1.13.1", "@contentstack/cli-command": "~1.2.16", "@contentstack/cli-utilities": "~1.5.10", "inquirer": "8.2.4", diff --git a/packages/contentstack/package.json b/packages/contentstack/package.json index 9e4921c8d7..5ea3c68974 100755 --- a/packages/contentstack/package.json +++ b/packages/contentstack/package.json @@ -30,7 +30,7 @@ "@contentstack/cli-cm-clone": "~1.9.0", "@contentstack/cli-cm-export": "~1.10.2", "@contentstack/cli-cm-export-to-csv": "~1.6.2", - "@contentstack/cli-cm-import": "~1.13.0", + "@contentstack/cli-cm-import": "~1.13.1", "@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 7f1ff7b9ab..41e42c05f9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,7 +18,7 @@ importers: '@contentstack/cli-cm-clone': ~1.9.0 '@contentstack/cli-cm-export': ~1.10.2 '@contentstack/cli-cm-export-to-csv': ~1.6.2 - '@contentstack/cli-cm-import': ~1.13.0 + '@contentstack/cli-cm-import': ~1.13.1 '@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.2 - '@contentstack/cli-cm-import': ~1.13.0 + '@contentstack/cli-cm-import': ~1.13.1 '@contentstack/cli-command': ~1.2.16 '@contentstack/cli-utilities': ~1.5.10 '@oclif/test': ^1.2.7 @@ -986,7 +986,7 @@ importers: packages/contentstack-seed: specifiers: - '@contentstack/cli-cm-import': ~1.13.0 + '@contentstack/cli-cm-import': ~1.13.1 '@contentstack/cli-command': ~1.2.16 '@contentstack/cli-utilities': ~1.5.10 '@oclif/plugin-help': ^5.1.19