From f33be910dee5f975198381f4311ea419cdb5b952 Mon Sep 17 00:00:00 2001 From: raj pandey Date: Wed, 28 Feb 2024 15:50:45 +0530 Subject: [PATCH 1/7] initial commit, added extensions to audit command --- .../src/audit-base-command.ts | 13 ++- .../contentstack-audit/src/config/index.ts | 7 +- .../src/modules/extensions.ts | 92 +++++++++++++++++++ .../contentstack-audit/src/modules/index.ts | 10 +- .../src/types/extensions.ts | 22 +++++ .../contentstack-audit/src/types/index.ts | 1 + 6 files changed, 135 insertions(+), 10 deletions(-) create mode 100644 packages/contentstack-audit/src/modules/extensions.ts create mode 100644 packages/contentstack-audit/src/types/extensions.ts diff --git a/packages/contentstack-audit/src/audit-base-command.ts b/packages/contentstack-audit/src/audit-base-command.ts index 2674927a53..ec6d0b9b26 100644 --- a/packages/contentstack-audit/src/audit-base-command.ts +++ b/packages/contentstack-audit/src/audit-base-command.ts @@ -12,7 +12,7 @@ import config from './config'; import { print } from './util/log'; import { auditMsg } from './messages'; import { BaseCommand } from './base-command'; -import { Entries, GlobalField, ContentType } from './modules'; +import { Entries, GlobalField, ContentType, Extensions } from './modules'; import { CommandNames, ContentTypeStruct, OutputColumn, RefErrorReturnType } from './types'; export abstract class AuditBaseCommand extends BaseCommand { @@ -42,12 +42,13 @@ export abstract class AuditBaseCommand extends BaseCommand; + public missingCtInExtensions: Extension[]; + public missingCts: Set; + public extensionsPath: string; + + constructor({ + log, + fix, + config, + moduleName, + ctSchema, + }: ModuleConstructorParam & Pick) { + this.log = log; + this.config = config; + this.fix = fix ?? false; + this.ctSchema = ctSchema; + this.extensionsSchema = []; + this.moduleName = moduleName ?? 'extensions'; + this.fileName = config.moduleConfig[this.moduleName].fileName; + this.folderPath = resolve(config.basePath, config.moduleConfig[this.moduleName].dirName); + this.ctUidSet = new Set(['$all']); + this.missingCtInExtensions = []; + this.missingCts = new Set(); + this.extensionsPath = ''; + } + + async run() { + if (!existsSync(this.folderPath)) { + this.log(`Skipping ${this.moduleName} audit`, 'warn'); + this.log($t(auditMsg.NOT_VALID_PATH, { path: this.folderPath }), { color: 'yellow' }); + return {}; + } + + this.extensionsPath = path.join(this.folderPath, this.fileName); + + this.extensionsSchema = existsSync(this.extensionsPath) + ? values(JSON.parse(readFileSync(this.extensionsPath, 'utf-8')) as Extension[]) + : []; + this.ctSchema = []; + this.ctSchema.forEach((ct) => this.ctUidSet.add(ct.uid)); + + this.extensionsSchema.forEach((ext: Extension) => { + const { title, uid, scope } = ext; + let ctNotPresent: string[] = []; + scope?.content_types.forEach((ct) => { + if (!this.ctUidSet.has(ct)) { + ctNotPresent.push(ct); + this.missingCts.add(ct); + } + }); + if (ctNotPresent.length) { + ext.scope.content_types = ctNotPresent; + this.missingCtInExtensions.push(cloneDeep(ext)); + } + this.log( + $t(auditMsg.SCAN_CT_SUCCESS_MSG, { + name: title, + module: this.config.moduleConfig[this.moduleName].name, + }), + 'info', + ); + }); + this.missingCtInExtensions.forEach((ext) => { + console.log(ext.scope); + }); + console.log(this.missingCtInExtensions); + return this.missingCtInExtensions; + } + + async fixExtensionsScope() {} + + async writeFixContent() {} +} diff --git a/packages/contentstack-audit/src/modules/index.ts b/packages/contentstack-audit/src/modules/index.ts index 81d42bc7b5..e0b1e5ac9c 100644 --- a/packages/contentstack-audit/src/modules/index.ts +++ b/packages/contentstack-audit/src/modules/index.ts @@ -1,5 +1,5 @@ -import Entries from "./entries" -import GlobalField from "./global-fields" -import ContentType from "./content-types" - -export { Entries, GlobalField, ContentType } \ No newline at end of file +import Entries from './entries'; +import GlobalField from './global-fields'; +import ContentType from './content-types'; +import Extensions from './extensions'; +export { Entries, GlobalField, ContentType, Extensions }; diff --git a/packages/contentstack-audit/src/types/extensions.ts b/packages/contentstack-audit/src/types/extensions.ts new file mode 100644 index 0000000000..b65cf890a5 --- /dev/null +++ b/packages/contentstack-audit/src/types/extensions.ts @@ -0,0 +1,22 @@ +export interface Extension { + stackHeaders: { + api_key: string; + }; + urlPath: string; + uid: string; + created_at: string; + updated_at: string; + created_by: string; + updated_by: string; + tags: []; + _version: number; + title: string; + config: {}; + type: 'field'; + data_type: string; + multiple: boolean; + srcdoc?: string; + scope: { + content_types: string[]; + }; +} diff --git a/packages/contentstack-audit/src/types/index.ts b/packages/contentstack-audit/src/types/index.ts index 9c78f7486e..a3d24f2525 100644 --- a/packages/contentstack-audit/src/types/index.ts +++ b/packages/contentstack-audit/src/types/index.ts @@ -2,3 +2,4 @@ export * from './utils'; export * from './common'; export * from './entries'; export * from './content-types'; +export * from './extensions'; \ No newline at end of file From 03f15fbfc1672fd8f0eebcbe564b220244499de9 Mon Sep 17 00:00:00 2001 From: raj pandey Date: Wed, 28 Feb 2024 18:34:28 +0530 Subject: [PATCH 2/7] audit fix for extensions --- .../contentstack-audit/src/messages/index.ts | 3 + .../src/modules/extensions.ts | 73 ++++++++++++++++--- 2 files changed, 66 insertions(+), 10 deletions(-) diff --git a/packages/contentstack-audit/src/messages/index.ts b/packages/contentstack-audit/src/messages/index.ts index 6b073217f5..2978d689d8 100644 --- a/packages/contentstack-audit/src/messages/index.ts +++ b/packages/contentstack-audit/src/messages/index.ts @@ -12,6 +12,8 @@ const commonMsg = { CONFIG: 'Path of the external config', DATA_DIR: 'Path where the data is stored', FIX_CONFIRMATION: 'Would you like to overwrite existing file.?', + EXTENSION_FIX_WARN: `Extension {uid} named '{title}' will be removed.`, + EXTENSION_FIX_CONFIRMATION: `Would you like to overwrite existing file.?`, }; const auditMsg = { @@ -25,6 +27,7 @@ const auditMsg = { FINAL_REPORT_PATH: "Reports ready. Please find the reports at '{path}'.", SCAN_CT_SUCCESS_MSG: "Successfully completed the scanning of {module} '{title}'.", SCAN_ENTRY_SUCCESS_MSG: "Successfully completed the scanning of {module} ({local}) '{title}'.", + SCAN_EXT_SUCCESS_MSG: "Successfully completed the scanning of {module} titled '{title}' having uid '{uid}'.", AUDIT_CMD_DESCRIPTION: 'Perform audits and find possible errors in the exported Contentstack data', }; diff --git a/packages/contentstack-audit/src/modules/extensions.ts b/packages/contentstack-audit/src/modules/extensions.ts index 026bc8d7e1..9d3f567776 100644 --- a/packages/contentstack-audit/src/modules/extensions.ts +++ b/packages/contentstack-audit/src/modules/extensions.ts @@ -55,38 +55,91 @@ export default class Extensions { this.extensionsSchema = existsSync(this.extensionsPath) ? values(JSON.parse(readFileSync(this.extensionsPath, 'utf-8')) as Extension[]) : []; - this.ctSchema = []; this.ctSchema.forEach((ct) => this.ctUidSet.add(ct.uid)); this.extensionsSchema.forEach((ext: Extension) => { const { title, uid, scope } = ext; let ctNotPresent: string[] = []; + scope?.content_types.forEach((ct) => { if (!this.ctUidSet.has(ct)) { ctNotPresent.push(ct); this.missingCts.add(ct); } }); - if (ctNotPresent.length) { + + if (ctNotPresent.length && ext.scope) { ext.scope.content_types = ctNotPresent; this.missingCtInExtensions.push(cloneDeep(ext)); } + this.log( - $t(auditMsg.SCAN_CT_SUCCESS_MSG, { - name: title, + $t(auditMsg.SCAN_EXT_SUCCESS_MSG, { + title: title, module: this.config.moduleConfig[this.moduleName].name, + uid: uid, }), 'info', ); }); - this.missingCtInExtensions.forEach((ext) => { - console.log(ext.scope); - }); - console.log(this.missingCtInExtensions); + + if (this.fix && this.missingCtInExtensions.length) { + await this.fixExtensionsScope(cloneDeep(this.missingCtInExtensions)); + } + return this.missingCtInExtensions; } - async fixExtensionsScope() {} + async fixExtensionsScope(missingCtInExtensions: Extension[]) { + for (let ext in missingCtInExtensions) { + if (missingCtInExtensions[ext].scope) { + missingCtInExtensions[ext].scope.content_types = missingCtInExtensions[ext].scope.content_types.filter((ct) => { + !this.missingCts.has(ct); + }); + } + } + + let newExtensionSchema: Record = existsSync(this.extensionsPath) + ? JSON.parse(readFileSync(this.extensionsPath, 'utf8')) + : {}; + + if (Object.keys(newExtensionSchema).length !== 0) { + for (let ext in missingCtInExtensions) { + let fixedCts = missingCtInExtensions[ext].scope.content_types.filter((ct) => { + !this.missingCts.has(ct); + }); + if (fixedCts.length) { + newExtensionSchema[missingCtInExtensions[ext].uid].scope.content_types = fixedCts; + } else { + this.log( + $t(commonMsg.EXTENSION_FIX_WARN, { + name: missingCtInExtensions[ext].title, + uid: missingCtInExtensions[ext].uid, + }), + { color: 'yellow' }, + ); + if (this.config.flags.yes || (await ux.confirm(commonMsg.EXTENSION_FIX_CONFIRMATION))) { + delete newExtensionSchema[missingCtInExtensions[ext].uid]; + } + } + } + } + this.writeFixContent(newExtensionSchema); + } + + async writeFixContent(fixedExtensions: Record) { + let canWrite = true; - async writeFixContent() {} + if (this.fix) { + if (!this.config.flags['copy-dir'] && !this.config.flags['external-config']?.skipConfirm) { + canWrite = this.config.flags.yes ?? (await ux.confirm(commonMsg.FIX_CONFIRMATION)); + } + if (canWrite) { + writeFileSync( + join(this.folderPath, this.config.moduleConfig[this.moduleName].fileName), + JSON.stringify(fixedExtensions), + ); + } + } + } } From 62aa368f9993d291a8367aad9ad1c6cf9e4ddaaa Mon Sep 17 00:00:00 2001 From: raj pandey Date: Thu, 29 Feb 2024 22:51:15 +0530 Subject: [PATCH 3/7] added test case and code optimization --- .../src/audit-base-command.ts | 65 ++- .../src/modules/extensions.ts | 88 ++-- .../src/types/content-types.ts | 5 + .../src/types/extensions.ts | 3 +- .../test/unit/audit-base-command.test.ts | 7 +- .../allCts/extensions/extensions.json | 44 ++ .../mock/contents/extensions/ctSchema.json | 303 ++++++++++++ .../mock/contents/extensions/extensions.json | 248 ++++++++++ .../extensions/extensions.json | 104 +++++ .../validExtensions/extensions.json | 98 ++++ .../test/unit/modules/extensions.test.ts | 431 ++++++++++++++++++ 11 files changed, 1336 insertions(+), 60 deletions(-) create mode 100644 packages/contentstack-audit/test/unit/mock/contents/extensions/allCts/extensions/extensions.json create mode 100644 packages/contentstack-audit/test/unit/mock/contents/extensions/ctSchema.json create mode 100644 packages/contentstack-audit/test/unit/mock/contents/extensions/extensions.json create mode 100644 packages/contentstack-audit/test/unit/mock/contents/extensions/invalidExtensions/extensions/extensions.json create mode 100644 packages/contentstack-audit/test/unit/mock/contents/extensions/validExtensions/extensions.json create mode 100644 packages/contentstack-audit/test/unit/modules/extensions.test.ts diff --git a/packages/contentstack-audit/src/audit-base-command.ts b/packages/contentstack-audit/src/audit-base-command.ts index ec6d0b9b26..2312e43823 100644 --- a/packages/contentstack-audit/src/audit-base-command.ts +++ b/packages/contentstack-audit/src/audit-base-command.ts @@ -48,10 +48,15 @@ export abstract class AuditBaseCommand extends BaseCommand }[]) { + if (!this.sharedConfig.showTerminalOutput || this.flags['external-config']?.noTerminalOutput) { + return; + } + + this.log(''); // Adding a new line + + for (const { module, missingRefs } of allMissingRefs) { + if (isEmpty(missingRefs)) { + continue; + } + + print([{ bold: true, color: 'cyan', message: ` ${module}` }]); + + const tableValues = Object.values(missingRefs).flat(); + + const tableKeys = Object.keys(missingRefs[0]); + + const arrayOfObjects = tableKeys.map((key) => { + if (['title', 'name', 'uid', 'content_types'].includes(key)) { + return { + [key]: { + minWidth: 7, + header: key, + get: (row: Record) => { + return chalk.red(typeof row[key] === 'object' ? JSON.stringify(row[key]) : row[key]); + }, + }, + }; + } + return {}; + }); + + const mergedObject = Object.assign({}, ...arrayOfObjects); + + ux.table(tableValues, mergedObject, { ...this.flags }); + this.log(''); // Adding a new line + } + } + /** * The function prepares a report by writing a JSON file and a CSV file with a list of missing * references for a given module. @@ -304,8 +355,10 @@ export abstract class AuditBaseCommand extends BaseCommand = {}; for (const column of columns) { - row[column] = issue[OutputColumn[column]]; - row[column] = typeof row[column] === 'object' ? JSON.stringify(row[column]) : row[column]; + if (Object.keys(issue).includes(OutputColumn[column])) { + row[column] = issue[OutputColumn[column]] as string; + row[column] = typeof row[column] === 'object' ? JSON.stringify(row[column]) : row[column]; + } } if (this.currentCommand === 'cm:stacks:audit:fix') { diff --git a/packages/contentstack-audit/src/modules/extensions.ts b/packages/contentstack-audit/src/modules/extensions.ts index 9d3f567776..273d8a40da 100644 --- a/packages/contentstack-audit/src/modules/extensions.ts +++ b/packages/contentstack-audit/src/modules/extensions.ts @@ -55,47 +55,39 @@ export default class Extensions { this.extensionsSchema = existsSync(this.extensionsPath) ? values(JSON.parse(readFileSync(this.extensionsPath, 'utf-8')) as Extension[]) : []; - this.ctSchema.forEach((ct) => this.ctUidSet.add(ct.uid)); - - this.extensionsSchema.forEach((ext: Extension) => { + this.ctSchema.map((ct) => this.ctUidSet.add(ct.uid)); + for (const ext of this.extensionsSchema) { const { title, uid, scope } = ext; - let ctNotPresent: string[] = []; - - scope?.content_types.forEach((ct) => { - if (!this.ctUidSet.has(ct)) { - ctNotPresent.push(ct); - this.missingCts.add(ct); - } - }); + const ctNotPresent = scope?.content_types.filter((ct) => !this.ctUidSet.has(ct)); - if (ctNotPresent.length && ext.scope) { + if (ctNotPresent?.length && ext.scope) { ext.scope.content_types = ctNotPresent; + ext.content_types = ctNotPresent; + ctNotPresent.forEach((ct) => this.missingCts.add(ct)); this.missingCtInExtensions.push(cloneDeep(ext)); } this.log( $t(auditMsg.SCAN_EXT_SUCCESS_MSG, { - title: title, + title, module: this.config.moduleConfig[this.moduleName].name, - uid: uid, + uid, }), 'info', ); - }); + } if (this.fix && this.missingCtInExtensions.length) { await this.fixExtensionsScope(cloneDeep(this.missingCtInExtensions)); + return {}; } - return this.missingCtInExtensions; } async fixExtensionsScope(missingCtInExtensions: Extension[]) { - for (let ext in missingCtInExtensions) { - if (missingCtInExtensions[ext].scope) { - missingCtInExtensions[ext].scope.content_types = missingCtInExtensions[ext].scope.content_types.filter((ct) => { - !this.missingCts.has(ct); - }); + for (const ext of missingCtInExtensions) { + if (ext.scope) { + ext.scope.content_types = ext.scope.content_types.filter((ct) => !this.missingCts.has(ct)); } } @@ -103,43 +95,35 @@ export default class Extensions { ? JSON.parse(readFileSync(this.extensionsPath, 'utf8')) : {}; - if (Object.keys(newExtensionSchema).length !== 0) { - for (let ext in missingCtInExtensions) { - let fixedCts = missingCtInExtensions[ext].scope.content_types.filter((ct) => { - !this.missingCts.has(ct); - }); - if (fixedCts.length) { - newExtensionSchema[missingCtInExtensions[ext].uid].scope.content_types = fixedCts; - } else { - this.log( - $t(commonMsg.EXTENSION_FIX_WARN, { - name: missingCtInExtensions[ext].title, - uid: missingCtInExtensions[ext].uid, - }), - { color: 'yellow' }, - ); - if (this.config.flags.yes || (await ux.confirm(commonMsg.EXTENSION_FIX_CONFIRMATION))) { - delete newExtensionSchema[missingCtInExtensions[ext].uid]; - } + for (const ext of missingCtInExtensions) { + const { uid, title } = ext; + const fixedCts = ext?.scope?.content_types.filter((ct) => !this.missingCts.has(ct)); + + if (fixedCts?.length) { + newExtensionSchema[uid].scope.content_types = fixedCts; + } else { + this.log($t(commonMsg.EXTENSION_FIX_WARN, { title: title, uid }), { color: 'yellow' }); + + const shouldDelete = this.config.flags.yes || (await ux.confirm(commonMsg.EXTENSION_FIX_CONFIRMATION)); + if (shouldDelete) { + delete newExtensionSchema[uid]; } } } - this.writeFixContent(newExtensionSchema); + await this.writeFixContent(newExtensionSchema); } async writeFixContent(fixedExtensions: Record) { - let canWrite = true; - - if (this.fix) { - if (!this.config.flags['copy-dir'] && !this.config.flags['external-config']?.skipConfirm) { - canWrite = this.config.flags.yes ?? (await ux.confirm(commonMsg.FIX_CONFIRMATION)); - } - if (canWrite) { - writeFileSync( - join(this.folderPath, this.config.moduleConfig[this.moduleName].fileName), - JSON.stringify(fixedExtensions), - ); - } + if ( + this.fix && + (this.config.flags['copy-dir'] || + this.config.flags['external-config']?.skipConfirm || + (await ux.confirm(commonMsg.FIX_CONFIRMATION))) + ) { + writeFileSync( + join(this.folderPath, this.config.moduleConfig[this.moduleName].fileName), + JSON.stringify(fixedExtensions), + ); } } } diff --git a/packages/contentstack-audit/src/types/content-types.ts b/packages/contentstack-audit/src/types/content-types.ts index ebd8f32ac8..835f3f63ac 100644 --- a/packages/contentstack-audit/src/types/content-types.ts +++ b/packages/contentstack-audit/src/types/content-types.ts @@ -48,6 +48,8 @@ type RefErrorReturnType = { missingRefs: string[]; display_name: string; tree: Record[]; + uid?: string; + content_types?: string[]; }; // NOTE Type 1 @@ -113,6 +115,9 @@ enum OutputColumn { 'Field type' = 'data_type', 'Missing references' = 'missingRefs', Path = 'treeStr', + content_types = 'content_types', + 'uid' = 'uid', + 'missingCts' = 'content_types', } export { diff --git a/packages/contentstack-audit/src/types/extensions.ts b/packages/contentstack-audit/src/types/extensions.ts index b65cf890a5..74e79252ab 100644 --- a/packages/contentstack-audit/src/types/extensions.ts +++ b/packages/contentstack-audit/src/types/extensions.ts @@ -8,7 +8,7 @@ export interface Extension { updated_at: string; created_by: string; updated_by: string; - tags: []; + tags?: []; _version: number; title: string; config: {}; @@ -19,4 +19,5 @@ export interface Extension { scope: { content_types: string[]; }; + content_types?: string[]; } diff --git a/packages/contentstack-audit/test/unit/audit-base-command.test.ts b/packages/contentstack-audit/test/unit/audit-base-command.test.ts index 81301e8997..f85899cb47 100644 --- a/packages/contentstack-audit/test/unit/audit-base-command.test.ts +++ b/packages/contentstack-audit/test/unit/audit-base-command.test.ts @@ -7,7 +7,7 @@ import { expect } from '@oclif/test'; import { ux, cliux } from '@contentstack/cli-utilities'; import { AuditBaseCommand } from '../../src/audit-base-command'; -import { ContentType, Entries, GlobalField } from '../../src/modules'; +import { ContentType, Entries, GlobalField, Extensions } from '../../src/modules'; import { FileTransportInstance } from 'winston/lib/winston/transports'; import { $t, auditMsg } from '../../src/messages'; @@ -41,6 +41,8 @@ describe('AuditBaseCommand class', () => { .stub(Entries.prototype, 'run', () => ({ entry_1: {} })) .stub(ContentType.prototype, 'run', () => ({ ct_1: {} })) .stub(GlobalField.prototype, 'run', () => ({ gf_1: {} })) + .stub(Extensions.prototype, 'run', () => ({ ext_1: {} })) + .stub(AuditBaseCommand.prototype, 'showOutputOnScreenWorkflowsAndExtension', () => {}) .stub(fs, 'createWriteStream', () => new PassThrough()) .it('should show audit report path', async (ctx) => { await AuditCMD.run(['--data-dir', resolve(__dirname, 'mock', 'contents')]); @@ -61,6 +63,7 @@ describe('AuditBaseCommand class', () => { .stub(Entries.prototype, 'run', () => ({ entry_1: {} })) .stub(ContentType.prototype, 'run', () => ({ ct_1: {} })) .stub(GlobalField.prototype, 'run', () => ({ gf_1: {} })) + .stub(Extensions.prototype, 'run', () => ({ ext_1: {} })) .stub(fs, 'createWriteStream', () => new PassThrough()) .it('should print info of no ref found', async (ctx) => { await AuditCMD.run([]); @@ -78,6 +81,7 @@ describe('AuditBaseCommand class', () => { .stub(ux, 'table', (...args: any) => { args[1].missingRefs.get({ missingRefs: ['gf_0'] }); }) + .stub(AuditBaseCommand.prototype, 'showOutputOnScreenWorkflowsAndExtension', () => {}) .stub(ux.action, 'stop', () => {}) .stub(ux.action, 'start', () => {}) .stub(Entries.prototype, 'run', () => ({ @@ -91,6 +95,7 @@ describe('AuditBaseCommand class', () => { })) .stub(ContentType.prototype, 'run', () => ({ ct_1: {} })) .stub(GlobalField.prototype, 'run', () => ({ gf_1: {} })) + .stub(Extensions.prototype, 'run', () => ({ ext_1: {} })) .stub(fs, 'createBackUp', () => {}) .stub(fs, 'createWriteStream', () => new PassThrough()) .stub(AuditBaseCommand.prototype, 'createBackUp', () => {}) diff --git a/packages/contentstack-audit/test/unit/mock/contents/extensions/allCts/extensions/extensions.json b/packages/contentstack-audit/test/unit/mock/contents/extensions/allCts/extensions/extensions.json new file mode 100644 index 0000000000..f9d142a39a --- /dev/null +++ b/packages/contentstack-audit/test/unit/mock/contents/extensions/allCts/extensions/extensions.json @@ -0,0 +1,44 @@ +{ + "ext1": { + "stackHeaders": { + "api_key": "apiKey" + }, + "urlPath": "/extensions/ext1", + "uid": "ext1", + "created_at": "2024-02-22T09:45:48.681Z", + "updated_at": "2024-02-22T09:45:48.681Z", + "created_by": "u1", + "updated_by": "u1", + "tags": [], + "_version": 1, + "title": "Progress Bar", + "config": {}, + "type": "field", + "data_type": "number", + "multiple": false, + "scope": { + "content_types": ["$all"] + } + }, + "ext2": { + "stackHeaders": { + "api_key": "apiKey" + }, + "urlPath": "/extensions/ext2", + "uid": "ext2", + "created_at": "2024-02-22T09:45:11.284Z", + "updated_at": "2024-02-22T09:45:11.284Z", + "created_by": "u1", + "updated_by": "u1", + "tags": [], + "_version": 1, + "title": "Color Picker", + "config": {}, + "type": "field", + "data_type": "text", + "multiple": false, + "scope": { + "content_types": ["$all"] + } + } +} diff --git a/packages/contentstack-audit/test/unit/mock/contents/extensions/ctSchema.json b/packages/contentstack-audit/test/unit/mock/contents/extensions/ctSchema.json new file mode 100644 index 0000000000..12c2324e02 --- /dev/null +++ b/packages/contentstack-audit/test/unit/mock/contents/extensions/ctSchema.json @@ -0,0 +1,303 @@ +[ + { + "title": "ct2", + "uid": "ct2", + "schema": [ + { + "data_type": "text", + "display_name": "Title", + "field_metadata": { "_default": true, "version": 3 }, + "mandatory": true, + "uid": "title", + "unique": true, + "multiple": false, + "non_localizable": false + } + ], + "description": "", + "options": { "is_page": false, "singleton": true, "sub_title": [], "title": "title" } + }, + { + "title": "ct3", + "uid": "ct3", + "schema": [ + { + "data_type": "text", + "display_name": "Title", + "field_metadata": { "_default": true, "version": 3 }, + "mandatory": true, + "uid": "title", + "unique": true, + "multiple": false, + "non_localizable": false + } + ], + "description": "", + "options": { "is_page": false, "singleton": true, "sub_title": [], "title": "title" } + }, + { + "title": "ct4", + "uid": "ct4", + "schema": [ + { + "data_type": "text", + "display_name": "Title", + "field_metadata": { "_default": true, "version": 3 }, + "mandatory": true, + "uid": "title", + "unique": true, + "multiple": false, + "non_localizable": false + } + ], + "description": "", + "options": { "is_page": false, "singleton": true, "sub_title": [], "title": "title" } + }, + { + "title": "ct5", + "uid": "ct5", + "schema": [ + { + "data_type": "text", + "display_name": "Title", + "field_metadata": { "_default": true, "version": 3 }, + "mandatory": true, + "uid": "title", + "unique": true, + "multiple": false, + "non_localizable": false + } + ], + "description": "", + "options": { "is_page": false, "singleton": true, "sub_title": [], "title": "title" } + }, + { + "title": "mpa", + "uid": "mpa", + "schema": [ + { + "data_type": "text", + "display_name": "Title", + "field_metadata": { "_default": true, "version": 3 }, + "mandatory": true, + "uid": "title", + "unique": true, + "multiple": false, + "non_localizable": false + }, + { + "display_name": "Custom", + "extension_uid": "blt1ea8d9d672fe8449", + "field_metadata": { "extension": true, "ref_multiple_content_types": true, "ref_multiple": true }, + "uid": "custom", + "mandatory": false, + "non_localizable": false, + "unique": false, + "config": {}, + "reference_to": ["mpa"], + "data_type": "reference", + "multiple": false + } + ], + "description": "", + "options": { "is_page": false, "singleton": false, "sub_title": [], "title": "title" } + }, + { + "title": "ct1", + "uid": "ct1", + "schema": [ + { + "data_type": "text", + "display_name": "Title", + "field_metadata": { "_default": true, "version": 3 }, + "mandatory": true, + "uid": "title", + "unique": true, + "multiple": false, + "non_localizable": false + }, + { + "data_type": "reference", + "display_name": "Reference", + "reference_to": ["ct1"], + "field_metadata": { "ref_multiple": false, "ref_multiple_content_types": true }, + "uid": "reference", + "mandatory": false, + "multiple": false, + "non_localizable": false, + "unique": false + }, + { + "data_type": "group", + "display_name": "Group", + "field_metadata": { "description": "", "instruction": "" }, + "schema": [ + { + "data_type": "text", + "display_name": "Rich Text Editor", + "uid": "rich_text_editor", + "field_metadata": { + "allow_rich_text": true, + "description": "", + "multiline": false, + "rich_text_type": "custom", + "options": [], + "version": 3 + }, + "mandatory": false, + "multiple": false, + "non_localizable": false, + "unique": false + }, + { + "data_type": "json", + "display_name": "JSON Rich Text Editor", + "uid": "json_rte", + "field_metadata": { + "allow_json_rte": true, + "embed_entry": true, + "description": "", + "default_value": "", + "multiline": false, + "rich_text_type": "advanced", + "options": [], + "ref_multiple_content_types": true + }, + "format": "", + "error_messages": { "format": "" }, + "reference_to": ["sys_assets", "ct3"], + "multiple": false, + "non_localizable": false, + "unique": false, + "mandatory": false + }, + { + "data_type": "group", + "display_name": "Group", + "field_metadata": { "description": "", "instruction": "" }, + "schema": [ + { + "data_type": "reference", + "display_name": "Reference", + "reference_to": ["ct3"], + "field_metadata": { "ref_multiple": false, "ref_multiple_content_types": true }, + "uid": "reference", + "mandatory": false, + "multiple": false, + "non_localizable": false, + "unique": false + } + ], + "uid": "group", + "mandatory": false, + "multiple": false, + "non_localizable": false, + "unique": false + }, + { + "data_type": "global_field", + "display_name": "Global", + "reference_to": "gf1", + "field_metadata": { "description": "" }, + "uid": "global_field", + "mandatory": false, + "multiple": false, + "non_localizable": false, + "unique": false, + "schema": [ + { + "data_type": "reference", + "display_name": "Reference", + "reference_to": ["ct1"], + "field_metadata": { "ref_multiple": false, "ref_multiple_content_types": true }, + "uid": "reference", + "mandatory": false, + "multiple": false, + "non_localizable": false, + "unique": false, + "indexed": false, + "inbuilt_model": false + } + ] + }, + { + "data_type": "reference", + "display_name": "Reference", + "reference_to": ["ct2"], + "field_metadata": { "ref_multiple": false, "ref_multiple_content_types": true }, + "uid": "reference", + "mandatory": false, + "multiple": false, + "non_localizable": false, + "unique": false + } + ], + "uid": "group", + "mandatory": false, + "multiple": false, + "non_localizable": false, + "unique": false + } + ], + "description": "", + "options": { "is_page": false, "singleton": true, "sub_title": [], "title": "title" } + }, + { + "title": "json", + "uid": "json", + "schema": [ + { + "data_type": "text", + "display_name": "Title", + "field_metadata": { "_default": true, "version": 3 }, + "mandatory": true, + "uid": "title", + "unique": true, + "multiple": false, + "non_localizable": false + }, + { + "data_type": "json", + "display_name": "JSON Rich Text Editor", + "uid": "json_rte", + "field_metadata": { + "allow_json_rte": true, + "embed_entry": true, + "description": "", + "default_value": "", + "multiline": false, + "rich_text_type": "advanced", + "options": ["widget"], + "ref_multiple_content_types": true + }, + "format": "", + "error_messages": { "format": "" }, + "reference_to": ["json", "mpa", "ct5", "ct4", "sys_assets"], + "multiple": false, + "non_localizable": false, + "unique": false, + "mandatory": false, + "plugins": [ + "blt314473f8f7e13956", + "bltc4143ac9b693fbdc", + "blt0f35138b9c17384e", + "bltcb085fe6edbb3407", + "bltc674482e12b1eb30" + ] + }, + { + "data_type": "reference", + "display_name": "Reference", + "reference_to": ["mpa", "json", "ct5", "ct4"], + "field_metadata": { "ref_multiple": false, "ref_multiple_content_types": true }, + "uid": "reference", + "mandatory": false, + "multiple": false, + "non_localizable": false, + "unique": false + } + ], + "description": "", + "options": { "is_page": false, "singleton": true, "sub_title": [], "title": "title" } + } +] diff --git a/packages/contentstack-audit/test/unit/mock/contents/extensions/extensions.json b/packages/contentstack-audit/test/unit/mock/contents/extensions/extensions.json new file mode 100644 index 0000000000..54405cb969 --- /dev/null +++ b/packages/contentstack-audit/test/unit/mock/contents/extensions/extensions.json @@ -0,0 +1,248 @@ +{ + "missingCts": { + "ext1": { + "stackHeaders": { + "api_key": "apiKey" + }, + "urlPath": "/extensions/ext1", + "uid": "ext1", + "created_at": "2024-02-22T09:45:48.681Z", + "updated_at": "2024-02-22T09:45:48.681Z", + "created_by": "u1", + "updated_by": "u1", + "tags": [], + "_version": 1, + "title": "Progress Bar", + "config": {}, + "type": "field", + "data_type": "number", + "multiple": false, + "scope": { + "content_types": ["ct6"] + } + }, + "ext2": { + "stackHeaders": { + "api_key": "apiKey" + }, + "urlPath": "/extensions/ext2", + "uid": "ext2", + "created_at": "2024-02-22T09:45:11.284Z", + "updated_at": "2024-02-22T09:45:11.284Z", + "created_by": "u1", + "updated_by": "u1", + "tags": [], + "_version": 1, + "title": "Color Picker", + "config": {}, + "type": "field", + "data_type": "text", + "multiple": false, + "scope": { + "content_types": ["ct8"] + } + }, + "ext5": { + "stackHeaders": { + "api_key": "apiKey" + }, + "urlPath": "/extensions/ext5", + "uid": "ext5", + "created_at": "2024-02-22T09:44:27.030Z", + "updated_at": "2024-02-22T09:44:27.030Z", + "created_by": "u1", + "updated_by": "u1", + "tags": [], + "_version": 1, + "title": "Text Intelligence", + "config": { + "token": "your_token_here" + }, + "type": "widget", + "scope": { + "content_types": ["ct4", "ct3", "ct2", "ct1"] + } + }, + "ext6": { + "stackHeaders": { + "api_key": "apiKey" + }, + "urlPath": "/extensions/ext6", + "uid": "ext6", + "created_at": "2024-02-22T09:44:01.784Z", + "updated_at": "2024-02-22T09:44:01.784Z", + "created_by": "u1", + "updated_by": "u1", + "tags": [], + "_version": 1, + "title": "Ace Editor", + "config": {}, + "type": "field", + "data_type": "reference", + "multiple": true + }, + "ext7": { + "stackHeaders": { + "api_key": "apiKey" + }, + "urlPath": "/extensions/ext7", + "uid": "ext7", + "created_at": "2024-02-22T09:43:35.589Z", + "updated_at": "2024-02-22T09:43:35.589Z", + "created_by": "u1", + "updated_by": "u1", + "tags": [], + "_version": 1, + "title": "Gatsby Preview", + "config": { + "siteUrl": "your_site_url" + }, + "type": "widget", + "scope": { + "content_types": ["ct3", "ct5"] + } + } + }, + "allCts": { + "ext1": { + "stackHeaders": { + "api_key": "apiKey" + }, + "urlPath": "/extensions/ext1", + "uid": "ext1", + "created_at": "2024-02-22T09:45:48.681Z", + "updated_at": "2024-02-22T09:45:48.681Z", + "created_by": "u1", + "updated_by": "u1", + "tags": [], + "_version": 1, + "title": "Progress Bar", + "config": {}, + "type": "field", + "data_type": "number", + "multiple": false, + "scope": { + "content_types": ["$all"] + } + }, + "ext2": { + "stackHeaders": { + "api_key": "apiKey" + }, + "urlPath": "/extensions/ext2", + "uid": "ext2", + "created_at": "2024-02-22T09:45:11.284Z", + "updated_at": "2024-02-22T09:45:11.284Z", + "created_by": "u1", + "updated_by": "u1", + "tags": [], + "_version": 1, + "title": "Color Picker", + "config": {}, + "type": "field", + "data_type": "text", + "multiple": false, + "scope": { + "content_types": ["$all"] + } + } + }, + "noMissingCts": { + "ext1": { + "stackHeaders": { + "api_key": "apiKey" + }, + "urlPath": "/extensions/ext1", + "uid": "ext1", + "created_at": "2024-02-22T09:45:48.681Z", + "updated_at": "2024-02-22T09:45:48.681Z", + "created_by": "u1", + "updated_by": "u1", + "tags": [], + "_version": 1, + "title": "Progress Bar", + "config": {}, + "type": "field", + "data_type": "number", + "multiple": false + }, + "ext2": { + "stackHeaders": { + "api_key": "apiKey" + }, + "urlPath": "/extensions/ext2", + "uid": "ext2", + "created_at": "2024-02-22T09:45:11.284Z", + "updated_at": "2024-02-22T09:45:11.284Z", + "created_by": "u1", + "updated_by": "u1", + "tags": [], + "_version": 1, + "title": "Color Picker", + "config": {}, + "type": "field", + "data_type": "text", + "multiple": false + }, + "ext5": { + "stackHeaders": { + "api_key": "apiKey" + }, + "urlPath": "/extensions/ext5", + "uid": "ext5", + "created_at": "2024-02-22T09:44:27.030Z", + "updated_at": "2024-02-22T09:44:27.030Z", + "created_by": "u1", + "updated_by": "u1", + "tags": [], + "_version": 1, + "title": "Text Intelligence", + "config": { + "token": "your_token_here" + }, + "type": "widget", + "scope": { + "content_types": ["ct4", "ct3", "ct2", "ct1"] + } + }, + "ext6": { + "stackHeaders": { + "api_key": "apiKey" + }, + "urlPath": "/extensions/ext6", + "uid": "ext6", + "created_at": "2024-02-22T09:44:01.784Z", + "updated_at": "2024-02-22T09:44:01.784Z", + "created_by": "u1", + "updated_by": "u1", + "tags": [], + "_version": 1, + "title": "Ace Editor", + "config": {}, + "type": "field", + "data_type": "reference", + "multiple": true + }, + "ext7": { + "stackHeaders": { + "api_key": "apiKey" + }, + "urlPath": "/extensions/ext7", + "uid": "ext7", + "created_at": "2024-02-22T09:43:35.589Z", + "updated_at": "2024-02-22T09:43:35.589Z", + "created_by": "u1", + "updated_by": "u1", + "tags": [], + "_version": 1, + "title": "Gatsby Preview", + "config": { + "siteUrl": "your_site_url" + }, + "type": "widget", + "scope": { + "content_types": ["ct3", "ct5"] + } + } + } +} diff --git a/packages/contentstack-audit/test/unit/mock/contents/extensions/invalidExtensions/extensions/extensions.json b/packages/contentstack-audit/test/unit/mock/contents/extensions/invalidExtensions/extensions/extensions.json new file mode 100644 index 0000000000..dad7460f85 --- /dev/null +++ b/packages/contentstack-audit/test/unit/mock/contents/extensions/invalidExtensions/extensions/extensions.json @@ -0,0 +1,104 @@ +{ + "ext1": { + "stackHeaders": { + "api_key": "apiKey" + }, + "urlPath": "/extensions/ext1", + "uid": "ext1", + "created_at": "2024-02-22T09:45:48.681Z", + "updated_at": "2024-02-22T09:45:48.681Z", + "created_by": "u1", + "updated_by": "u1", + "tags": [], + "_version": 1, + "title": "Progress Bar", + "config": {}, + "type": "field", + "data_type": "number", + "multiple": false, + "scope": { + "content_types": ["ct6"] + } + }, + "ext2": { + "stackHeaders": { + "api_key": "apiKey" + }, + "urlPath": "/extensions/ext2", + "uid": "ext2", + "created_at": "2024-02-22T09:45:11.284Z", + "updated_at": "2024-02-22T09:45:11.284Z", + "created_by": "u1", + "updated_by": "u1", + "tags": [], + "_version": 1, + "title": "Color Picker", + "config": {}, + "type": "field", + "data_type": "text", + "multiple": false, + "scope": { + "content_types": ["ct8"] + } + }, + "ext5": { + "stackHeaders": { + "api_key": "apiKey" + }, + "urlPath": "/extensions/ext5", + "uid": "ext5", + "created_at": "2024-02-22T09:44:27.030Z", + "updated_at": "2024-02-22T09:44:27.030Z", + "created_by": "u1", + "updated_by": "u1", + "tags": [], + "_version": 1, + "title": "Text Intelligence", + "config": { + "token": "your_token_here" + }, + "type": "widget", + "scope": { + "content_types": ["ct4", "ct3", "ct2", "ct1", "ct6"] + } + }, + "ext6": { + "stackHeaders": { + "api_key": "apiKey" + }, + "urlPath": "/extensions/ext6", + "uid": "ext6", + "created_at": "2024-02-22T09:44:01.784Z", + "updated_at": "2024-02-22T09:44:01.784Z", + "created_by": "u1", + "updated_by": "u1", + "tags": [], + "_version": 1, + "title": "Ace Editor", + "config": {}, + "type": "field", + "data_type": "reference", + "multiple": true + }, + "ext7": { + "stackHeaders": { + "api_key": "apiKey" + }, + "urlPath": "/extensions/ext7", + "uid": "ext7", + "created_at": "2024-02-22T09:43:35.589Z", + "updated_at": "2024-02-22T09:43:35.589Z", + "created_by": "u1", + "updated_by": "u1", + "tags": [], + "_version": 1, + "title": "Gatsby Preview", + "config": { + "siteUrl": "your_site_url" + }, + "type": "widget", + "scope": { + "content_types": ["ct3", "ct5"] + } + } +} diff --git a/packages/contentstack-audit/test/unit/mock/contents/extensions/validExtensions/extensions.json b/packages/contentstack-audit/test/unit/mock/contents/extensions/validExtensions/extensions.json new file mode 100644 index 0000000000..c72bd53885 --- /dev/null +++ b/packages/contentstack-audit/test/unit/mock/contents/extensions/validExtensions/extensions.json @@ -0,0 +1,98 @@ +{ + "ext1": { + "stackHeaders": { + "api_key": "apiKey" + }, + "urlPath": "/extensions/ext1", + "uid": "ext1", + "created_at": "2024-02-22T09:45:48.681Z", + "updated_at": "2024-02-22T09:45:48.681Z", + "created_by": "u1", + "updated_by": "u1", + "tags": [], + "_version": 1, + "title": "Progress Bar", + "config": {}, + "type": "field", + "data_type": "number", + "multiple": false + }, + "ext2": { + "stackHeaders": { + "api_key": "apiKey" + }, + "urlPath": "/extensions/ext2", + "uid": "ext2", + "created_at": "2024-02-22T09:45:11.284Z", + "updated_at": "2024-02-22T09:45:11.284Z", + "created_by": "u1", + "updated_by": "u1", + "tags": [], + "_version": 1, + "title": "Color Picker", + "config": {}, + "type": "field", + "data_type": "text", + "multiple": false + }, + "ext5": { + "stackHeaders": { + "api_key": "apiKey" + }, + "urlPath": "/extensions/ext5", + "uid": "ext5", + "created_at": "2024-02-22T09:44:27.030Z", + "updated_at": "2024-02-22T09:44:27.030Z", + "created_by": "u1", + "updated_by": "u1", + "tags": [], + "_version": 1, + "title": "Text Intelligence", + "config": { + "token": "your_token_here" + }, + "type": "widget", + "scope": { + "content_types": ["ct4", "ct3", "ct2", "ct1"] + } + }, + "ext6": { + "stackHeaders": { + "api_key": "apiKey" + }, + "urlPath": "/extensions/ext6", + "uid": "ext6", + "created_at": "2024-02-22T09:44:01.784Z", + "updated_at": "2024-02-22T09:44:01.784Z", + "created_by": "u1", + "updated_by": "u1", + "tags": [], + "_version": 1, + "title": "Ace Editor", + "config": {}, + "type": "field", + "data_type": "reference", + "multiple": true + }, + "ext7": { + "stackHeaders": { + "api_key": "apiKey" + }, + "urlPath": "/extensions/ext7", + "uid": "ext7", + "created_at": "2024-02-22T09:43:35.589Z", + "updated_at": "2024-02-22T09:43:35.589Z", + "created_by": "u1", + "updated_by": "u1", + "tags": [], + "_version": 1, + "title": "Gatsby Preview", + "config": { + "siteUrl": "your_site_url" + }, + "type": "widget", + "scope": { + "content_types": ["ct3", "ct5"] + } + } +} diff --git a/packages/contentstack-audit/test/unit/modules/extensions.test.ts b/packages/contentstack-audit/test/unit/modules/extensions.test.ts new file mode 100644 index 0000000000..164391dbf3 --- /dev/null +++ b/packages/contentstack-audit/test/unit/modules/extensions.test.ts @@ -0,0 +1,431 @@ +import fs from 'fs'; +import { resolve } from 'path'; +import { fancy } from 'fancy-test'; +import { expect } from '@oclif/test'; +import cloneDeep from 'lodash/cloneDeep'; +import { ux } from '@contentstack/cli-utilities'; + +import config from '../../../src/config'; +import { Extensions } from '../../../src/modules'; +import { $t, auditMsg } from '../../../src/messages'; +import { values } from 'lodash'; +// import { spy } from '@contentstack/cli-dev-dependencies'; +import sinon from 'sinon'; +// import extensionsExamples from './../mock/contents/extensions/extensions.json'; +import { Extension } from '../../../src/types'; +// import { join } from 'path'; + +describe('Extensions scope containing content_types uids', () => { + describe('run method with invalid path for extensions', () => { + const ext = new Extensions({ + log: () => {}, + moduleName: 'extensions', + ctSchema: cloneDeep(require('./../mock/contents/extensions/ctSchema.json')), + config: Object.assign(config, { basePath: resolve(__dirname, '..', 'mock', 'workflows'), flags: {} }), + }); + fancy + .stdout({ print: process.env.PRINT === 'true' || false }) + .stub(ux, 'confirm', async () => true) + .it('Should Validate the base path for workflows', async () => { + try { + await ext.run(); + } catch (error: any) { + expect(error).to.be.instanceOf(Error); + expect(error.message).to.eql($t(auditMsg.NOT_VALID_PATH, { path: ext.folderPath })); + } + }); + }); + describe('run method with valid path for extensions containing extensions with missing content types', () => { + const ext = new Extensions({ + log: () => {}, + moduleName: 'extensions', + ctSchema: cloneDeep(require('./../mock/contents/extensions/ctSchema.json')), + config: Object.assign(config, { + basePath: resolve(`./test/unit/mock/contents/extensions/invalidExtensions/`), + flags: {}, + }), + }); + fancy + .stdout({ print: process.env.PRINT === 'true' || true }) + .stub(ux, 'confirm', async () => true) + .it( + 'should expect missingRefs equal to empty array, expect entire workflow schema and empty missingCts', + async () => { + const missingRefs = await ext.run(); + expect(ext.missingCtInExtensions).eql([ + { + stackHeaders: { + api_key: 'apiKey', + }, + urlPath: '/extensions/ext1', + uid: 'ext1', + created_at: '2024-02-22T09:45:48.681Z', + updated_at: '2024-02-22T09:45:48.681Z', + created_by: 'u1', + updated_by: 'u1', + tags: [], + _version: 1, + title: 'Progress Bar', + config: {}, + type: 'field', + data_type: 'number', + content_types: ['ct6'], + multiple: false, + scope: { + content_types: ['ct6'], + }, + }, + { + stackHeaders: { + api_key: 'apiKey', + }, + urlPath: '/extensions/ext2', + uid: 'ext2', + created_at: '2024-02-22T09:45:11.284Z', + updated_at: '2024-02-22T09:45:11.284Z', + created_by: 'u1', + updated_by: 'u1', + tags: [], + _version: 1, + title: 'Color Picker', + config: {}, + type: 'field', + data_type: 'text', + multiple: false, + content_types: ['ct8'], + scope: { + content_types: ['ct8'], + }, + }, + { + stackHeaders: { + api_key: 'apiKey', + }, + urlPath: '/extensions/ext5', + uid: 'ext5', + created_at: '2024-02-22T09:44:27.030Z', + updated_at: '2024-02-22T09:44:27.030Z', + created_by: 'u1', + updated_by: 'u1', + tags: [], + _version: 1, + title: 'Text Intelligence', + config: { + token: 'your_token_here', + }, + content_types: ['ct6'], + type: 'widget', + scope: { + content_types: ['ct6'], + }, + }, + ]); + expect(ext.missingCts).eql(new Set(['ct6', 'ct8'])); + }, + ); + }); + describe('run method with valid path for extensions containing extensions with no missing content types and ct set to $all', () => { + const ext = new Extensions({ + log: () => {}, + moduleName: 'extensions', + ctSchema: cloneDeep(require('./../mock/contents/extensions/ctSchema.json')), + config: Object.assign(config, { + basePath: resolve(`./test/unit/mock/contents/extensions/allCts/`), + flags: {}, + }), + }); + fancy + .stdout({ print: process.env.PRINT === 'true' || true }) + .stub(ux, 'confirm', async () => true) + .it( + 'should expect missingRefs equal to empty array, expect entire workflow schema and empty missingCts', + async () => { + // const missingRefs = await ext.run(); + expect(ext.missingCtInExtensions).eql([]); + expect(ext.missingCts).eql(new Set([])); + }, + ); + }); + describe('run method with valid path for extensions containing extensions with no missing content types and ct set content types that are present', () => { + const ext = new Extensions({ + log: () => {}, + moduleName: 'extensions', + ctSchema: cloneDeep(require('./../mock/contents/extensions/ctSchema.json')), + config: Object.assign(config, { + basePath: resolve(`./test/unit/mock/contents/extensions/validExtensions/`), + flags: {}, + }), + }); + fancy + .stdout({ print: process.env.PRINT === 'true' || true }) + .stub(ux, 'confirm', async () => true) + .it( + 'should expect missingRefs equal to empty array, expect entire workflow schema and empty missingCts', + async () => { + const missingRefs = await ext.run(); + expect(ext.missingCtInExtensions).eql([]); + expect(ext.missingCts).eql(new Set([])); + }, + ); + }); + describe('fixSchema method with valid path for extensions containing extensions with missing content typessdfsdfdsfdsfdsfds', () => { + const ext = new (class Class extends Extensions { + public fixedExtensions!: Record; + constructor() { + super({ + log: () => {}, + moduleName: 'extensions', + ctSchema: cloneDeep(require('./../mock/contents/extensions/ctSchema.json')), + config: Object.assign(config, { + basePath: resolve(`./test/unit/mock/contents/extensions/invalidExtensions/`), + flags: {}, + }), + fix: true, + }); + } + async writeFixContent(fixedExtensions: Record) { + this.fixedExtensions = fixedExtensions; + } + })(); + + fancy + .stdout({ print: process.env.PRINT === 'true' || true }) + .stub(ux, 'confirm', async () => true) + .stub(ext, 'writeFileSync', () => {}) + .it( + 'should expect missingRefs equal to empty array, expect entire extensions schema and empty missingCts', + async () => { + const missingRefs = await ext.run(); + expect(ext.missingCtInExtensions).eql([ + { + stackHeaders: { + api_key: 'apiKey', + }, + urlPath: '/extensions/ext1', + uid: 'ext1', + created_at: '2024-02-22T09:45:48.681Z', + updated_at: '2024-02-22T09:45:48.681Z', + created_by: 'u1', + updated_by: 'u1', + tags: [], + _version: 1, + title: 'Progress Bar', + config: {}, + type: 'field', + data_type: 'number', + content_types: ['ct6'], + multiple: false, + scope: { + content_types: ['ct6'], + }, + }, + { + stackHeaders: { + api_key: 'apiKey', + }, + urlPath: '/extensions/ext2', + uid: 'ext2', + created_at: '2024-02-22T09:45:11.284Z', + updated_at: '2024-02-22T09:45:11.284Z', + created_by: 'u1', + updated_by: 'u1', + tags: [], + _version: 1, + title: 'Color Picker', + config: {}, + type: 'field', + data_type: 'text', + multiple: false, + content_types: ['ct8'], + scope: { + content_types: ['ct8'], + }, + }, + { + stackHeaders: { + api_key: 'apiKey', + }, + urlPath: '/extensions/ext5', + uid: 'ext5', + created_at: '2024-02-22T09:44:27.030Z', + updated_at: '2024-02-22T09:44:27.030Z', + created_by: 'u1', + updated_by: 'u1', + tags: [], + _version: 1, + title: 'Text Intelligence', + config: { + token: 'your_token_here', + }, + content_types: ['ct6'], + type: 'widget', + scope: { + content_types: ['ct6'], + }, + }, + ]); + expect(missingRefs).eql({}); + expect(ext.missingCts).eql(new Set(['ct6', 'ct8'])); + expect(ext.fixedExtensions).eql({ + ext6: { + stackHeaders: { + api_key: 'apiKey', + }, + urlPath: '/extensions/ext6', + uid: 'ext6', + created_at: '2024-02-22T09:44:01.784Z', + updated_at: '2024-02-22T09:44:01.784Z', + created_by: 'u1', + updated_by: 'u1', + tags: [], + _version: 1, + title: 'Ace Editor', + config: {}, + type: 'field', + data_type: 'reference', + multiple: true, + }, + ext7: { + stackHeaders: { + api_key: 'apiKey', + }, + urlPath: '/extensions/ext7', + uid: 'ext7', + created_at: '2024-02-22T09:43:35.589Z', + updated_at: '2024-02-22T09:43:35.589Z', + created_by: 'u1', + updated_by: 'u1', + tags: [], + _version: 1, + title: 'Gatsby Preview', + config: { + siteUrl: 'your_site_url', + }, + type: 'widget', + scope: { + content_types: ['ct3', 'ct5'], + }, + }, + }); + }, + ); + }); + describe('fixSchema method with valid path for extensions containing extensions with missing content types checking the fixed content', () => { + const ext = new Extensions({ + log: () => {}, + moduleName: 'extensions', + ctSchema: cloneDeep(require('./../mock/contents/extensions/ctSchema.json')), + config: Object.assign(config, { + basePath: resolve(`./test/unit/mock/contents/extensions/invalidExtensions/`), + flags: {}, + }), + fix: true, + }); + fancy + .stdout({ print: process.env.PRINT === 'true' || true }) + .stub(ux, 'confirm', async () => true) + .stub(ext, 'writeFixContent', async () => {}) + .stub(ext, 'writeFileSync', () => {}) + .it( + 'should expect missingRefs equal to empty array, expect entire extensions schema and empty missingCts', + async () => { + const missingRefs = await ext.run(); + expect(ext.missingCtInExtensions).eql([ + { + stackHeaders: { + api_key: 'apiKey', + }, + urlPath: '/extensions/ext1', + uid: 'ext1', + created_at: '2024-02-22T09:45:48.681Z', + updated_at: '2024-02-22T09:45:48.681Z', + created_by: 'u1', + updated_by: 'u1', + tags: [], + _version: 1, + title: 'Progress Bar', + config: {}, + type: 'field', + data_type: 'number', + content_types: ['ct6'], + multiple: false, + scope: { + content_types: ['ct6'], + }, + }, + { + stackHeaders: { + api_key: 'apiKey', + }, + urlPath: '/extensions/ext2', + uid: 'ext2', + created_at: '2024-02-22T09:45:11.284Z', + updated_at: '2024-02-22T09:45:11.284Z', + created_by: 'u1', + updated_by: 'u1', + tags: [], + _version: 1, + title: 'Color Picker', + config: {}, + type: 'field', + data_type: 'text', + multiple: false, + content_types: ['ct8'], + scope: { + content_types: ['ct8'], + }, + }, + { + stackHeaders: { + api_key: 'apiKey', + }, + urlPath: '/extensions/ext5', + uid: 'ext5', + created_at: '2024-02-22T09:44:27.030Z', + updated_at: '2024-02-22T09:44:27.030Z', + created_by: 'u1', + updated_by: 'u1', + tags: [], + _version: 1, + title: 'Text Intelligence', + config: { + token: 'your_token_here', + }, + content_types: ['ct6'], + type: 'widget', + scope: { + content_types: ['ct6'], + }, + }, + ]); + expect(missingRefs).eql({}); + expect(ext.missingCts).eql(new Set(['ct6', 'ct8'])); + }, + ); + }); + describe('fixSchema method with valid path for extensions containing extensions with no missing content types and ct set to $all', () => { + const ext = new Extensions({ + log: () => {}, + moduleName: 'extensions', + ctSchema: cloneDeep(require('./../mock/contents/extensions/ctSchema.json')), + config: Object.assign(config, { + basePath: resolve(`./test/unit/mock/contents/extensions/allCts/`), + flags: {}, + }), + fix: true, + }); + fancy + .stdout({ print: process.env.PRINT === 'true' || true }) + .stub(ux, 'confirm', async () => true) + .stub(ext, 'writeFileSync', () => {}) + .it( + 'should expect missingRefs equal to empty array, expect entire workflow schema and empty missingCts', + async () => { + expect(ext.missingCtInExtensions).eql([]); + expect(ext.missingCts).eql(new Set([])); + const fixExt = sinon.spy(ext, 'fixExtensionsScope'); + expect(fixExt.callCount).to.be.equals(0); + }, + ); + }); +}); From cfa546cbd7323b5e6e942683e30e660acdf828ce Mon Sep 17 00:00:00 2001 From: raj pandey Date: Fri, 1 Mar 2024 13:07:06 +0530 Subject: [PATCH 4/7] test cases fixed and csv --- packages/contentstack-audit/src/audit-base-command.ts | 2 -- packages/contentstack-audit/src/types/content-types.ts | 3 ++- .../test/unit/modules/extensions.test.ts | 9 ++------- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/packages/contentstack-audit/src/audit-base-command.ts b/packages/contentstack-audit/src/audit-base-command.ts index 2312e43823..9a27de2be0 100644 --- a/packages/contentstack-audit/src/audit-base-command.ts +++ b/packages/contentstack-audit/src/audit-base-command.ts @@ -274,7 +274,6 @@ export abstract class AuditBaseCommand extends BaseCommand { if (['title', 'name', 'uid', 'content_types'].includes(key)) { return { @@ -350,7 +349,6 @@ export abstract class AuditBaseCommand extends BaseCommand[] = []; - for (const issue of missingRefs) { let row: Record = {}; diff --git a/packages/contentstack-audit/src/types/content-types.ts b/packages/contentstack-audit/src/types/content-types.ts index 835f3f63ac..8f4d614eef 100644 --- a/packages/contentstack-audit/src/types/content-types.ts +++ b/packages/contentstack-audit/src/types/content-types.ts @@ -50,6 +50,7 @@ type RefErrorReturnType = { tree: Record[]; uid?: string; content_types?: string[]; + title?: string; }; // NOTE Type 1 @@ -115,7 +116,7 @@ enum OutputColumn { 'Field type' = 'data_type', 'Missing references' = 'missingRefs', Path = 'treeStr', - content_types = 'content_types', + title = 'title', 'uid' = 'uid', 'missingCts' = 'content_types', } diff --git a/packages/contentstack-audit/test/unit/modules/extensions.test.ts b/packages/contentstack-audit/test/unit/modules/extensions.test.ts index 164391dbf3..23ad2a15b8 100644 --- a/packages/contentstack-audit/test/unit/modules/extensions.test.ts +++ b/packages/contentstack-audit/test/unit/modules/extensions.test.ts @@ -1,4 +1,3 @@ -import fs from 'fs'; import { resolve } from 'path'; import { fancy } from 'fancy-test'; import { expect } from '@oclif/test'; @@ -8,12 +7,8 @@ import { ux } from '@contentstack/cli-utilities'; import config from '../../../src/config'; import { Extensions } from '../../../src/modules'; import { $t, auditMsg } from '../../../src/messages'; -import { values } from 'lodash'; -// import { spy } from '@contentstack/cli-dev-dependencies'; import sinon from 'sinon'; -// import extensionsExamples from './../mock/contents/extensions/extensions.json'; import { Extension } from '../../../src/types'; -// import { join } from 'path'; describe('Extensions scope containing content_types uids', () => { describe('run method with invalid path for extensions', () => { @@ -51,7 +46,7 @@ describe('Extensions scope containing content_types uids', () => { .it( 'should expect missingRefs equal to empty array, expect entire workflow schema and empty missingCts', async () => { - const missingRefs = await ext.run(); + await ext.run(); expect(ext.missingCtInExtensions).eql([ { stackHeaders: { @@ -162,7 +157,7 @@ describe('Extensions scope containing content_types uids', () => { .it( 'should expect missingRefs equal to empty array, expect entire workflow schema and empty missingCts', async () => { - const missingRefs = await ext.run(); + await ext.run(); expect(ext.missingCtInExtensions).eql([]); expect(ext.missingCts).eql(new Set([])); }, From 37959b7a89becadee74f734ed0e131ff9bd667c9 Mon Sep 17 00:00:00 2001 From: raj pandey Date: Sat, 2 Mar 2024 15:03:42 +0530 Subject: [PATCH 5/7] test case fixed, code optimisation --- .../src/audit-base-command.ts | 10 +- .../src/modules/extensions.ts | 14 +- .../src/types/extensions.ts | 1 + .../test/unit/modules/extensions.test.ts | 316 ++++++++---------- 4 files changed, 149 insertions(+), 192 deletions(-) diff --git a/packages/contentstack-audit/src/audit-base-command.ts b/packages/contentstack-audit/src/audit-base-command.ts index 9a27de2be0..770e108d0e 100644 --- a/packages/contentstack-audit/src/audit-base-command.ts +++ b/packages/contentstack-audit/src/audit-base-command.ts @@ -275,13 +275,19 @@ export abstract class AuditBaseCommand extends BaseCommand { - if (['title', 'name', 'uid', 'content_types'].includes(key)) { + if (['title', 'name', 'uid', 'content_types', 'fixStatus'].includes(key)) { return { [key]: { minWidth: 7, header: key, get: (row: Record) => { - return chalk.red(typeof row[key] === 'object' ? JSON.stringify(row[key]) : row[key]); + if(key==='fixStatus') { + return chalk.green(typeof row[key] === 'object' ? JSON.stringify(row[key]) : row[key]); + } else if(key==='content_types') { + return chalk.red(typeof row[key] === 'object' ? JSON.stringify(row[key]) : row[key]); + } else { + return chalk.white(typeof row[key] === 'object' ? JSON.stringify(row[key]) : row[key]); + } }, }, }; diff --git a/packages/contentstack-audit/src/modules/extensions.ts b/packages/contentstack-audit/src/modules/extensions.ts index 273d8a40da..09c4bf8d08 100644 --- a/packages/contentstack-audit/src/modules/extensions.ts +++ b/packages/contentstack-audit/src/modules/extensions.ts @@ -61,7 +61,6 @@ export default class Extensions { const ctNotPresent = scope?.content_types.filter((ct) => !this.ctUidSet.has(ct)); if (ctNotPresent?.length && ext.scope) { - ext.scope.content_types = ctNotPresent; ext.content_types = ctNotPresent; ctNotPresent.forEach((ct) => this.missingCts.add(ct)); this.missingCtInExtensions.push(cloneDeep(ext)); @@ -79,26 +78,19 @@ export default class Extensions { if (this.fix && this.missingCtInExtensions.length) { await this.fixExtensionsScope(cloneDeep(this.missingCtInExtensions)); - return {}; + this.missingCtInExtensions.forEach((ext) => (ext.fixStatus = 'Fixed')); + return this.missingCtInExtensions } return this.missingCtInExtensions; } async fixExtensionsScope(missingCtInExtensions: Extension[]) { - for (const ext of missingCtInExtensions) { - if (ext.scope) { - ext.scope.content_types = ext.scope.content_types.filter((ct) => !this.missingCts.has(ct)); - } - } - let newExtensionSchema: Record = existsSync(this.extensionsPath) ? JSON.parse(readFileSync(this.extensionsPath, 'utf8')) : {}; - for (const ext of missingCtInExtensions) { const { uid, title } = ext; const fixedCts = ext?.scope?.content_types.filter((ct) => !this.missingCts.has(ct)); - if (fixedCts?.length) { newExtensionSchema[uid].scope.content_types = fixedCts; } else { @@ -115,7 +107,7 @@ export default class Extensions { async writeFixContent(fixedExtensions: Record) { if ( - this.fix && + this.fix || (this.config.flags['copy-dir'] || this.config.flags['external-config']?.skipConfirm || (await ux.confirm(commonMsg.FIX_CONFIRMATION))) diff --git a/packages/contentstack-audit/src/types/extensions.ts b/packages/contentstack-audit/src/types/extensions.ts index 74e79252ab..91393bd3dd 100644 --- a/packages/contentstack-audit/src/types/extensions.ts +++ b/packages/contentstack-audit/src/types/extensions.ts @@ -20,4 +20,5 @@ export interface Extension { content_types: string[]; }; content_types?: string[]; + fixStatus?: string; } diff --git a/packages/contentstack-audit/test/unit/modules/extensions.test.ts b/packages/contentstack-audit/test/unit/modules/extensions.test.ts index 23ad2a15b8..fc279d6d08 100644 --- a/packages/contentstack-audit/test/unit/modules/extensions.test.ts +++ b/packages/contentstack-audit/test/unit/modules/extensions.test.ts @@ -10,6 +10,77 @@ import { $t, auditMsg } from '../../../src/messages'; import sinon from 'sinon'; import { Extension } from '../../../src/types'; +const fixedSchema = [ + { + stackHeaders: { + api_key: 'apiKey', + }, + urlPath: '/extensions/ext1', + uid: 'ext1', + created_at: '2024-02-22T09:45:48.681Z', + updated_at: '2024-02-22T09:45:48.681Z', + created_by: 'u1', + updated_by: 'u1', + tags: [], + _version: 1, + title: 'Progress Bar', + config: {}, + type: 'field', + data_type: 'number', + "fixStatus": "Fixed", + content_types: ['ct6'], + multiple: false, + scope: { + content_types: ['ct6'], + } + }, + { + stackHeaders: { + api_key: 'apiKey', + }, + urlPath: '/extensions/ext2', + uid: 'ext2', + created_at: '2024-02-22T09:45:11.284Z', + updated_at: '2024-02-22T09:45:11.284Z', + created_by: 'u1', + updated_by: 'u1', + tags: [], + _version: 1, + title: 'Color Picker', + config: {}, + type: 'field', + data_type: 'text', + "fixStatus": "Fixed", + multiple: false, + content_types: ['ct8'], + scope: { + content_types: ['ct8'], + } + }, + { + stackHeaders: { + api_key: 'apiKey', + }, + urlPath: '/extensions/ext5', + uid: 'ext5', + created_at: '2024-02-22T09:44:27.030Z', + updated_at: '2024-02-22T09:44:27.030Z', + created_by: 'u1', + "fixStatus": "Fixed", + updated_by: 'u1', + tags: [], + _version: 1, + title: 'Text Intelligence', + config: { + token: 'your_token_here', + }, + content_types: ['ct6'], + type: 'widget', + scope: { + content_types: ["ct4", "ct3", "ct2", "ct1",'ct6'], + }, + }, +] describe('Extensions scope containing content_types uids', () => { describe('run method with invalid path for extensions', () => { const ext = new Extensions({ @@ -44,7 +115,7 @@ describe('Extensions scope containing content_types uids', () => { .stdout({ print: process.env.PRINT === 'true' || true }) .stub(ux, 'confirm', async () => true) .it( - 'should expect missingRefs equal to empty array, expect entire workflow schema and empty missingCts', + 'should expect missing Cts to the ones that are not present in the schema, and MissingCts in extension equal to the extensions which has Cts that are not present', async () => { await ext.run(); expect(ext.missingCtInExtensions).eql([ @@ -111,7 +182,7 @@ describe('Extensions scope containing content_types uids', () => { content_types: ['ct6'], type: 'widget', scope: { - content_types: ['ct6'], + content_types: ["ct4", "ct3", "ct2", "ct1", "ct6"], }, }, ]); @@ -135,7 +206,6 @@ describe('Extensions scope containing content_types uids', () => { .it( 'should expect missingRefs equal to empty array, expect entire workflow schema and empty missingCts', async () => { - // const missingRefs = await ext.run(); expect(ext.missingCtInExtensions).eql([]); expect(ext.missingCts).eql(new Set([])); }, @@ -163,7 +233,7 @@ describe('Extensions scope containing content_types uids', () => { }, ); }); - describe('fixSchema method with valid path for extensions containing extensions with missing content typessdfsdfdsfdsfdsfds', () => { + describe('fixSchema method with valid path for extensions containing extensions with missing content types', () => { const ext = new (class Class extends Extensions { public fixedExtensions!: Record; constructor() { @@ -188,120 +258,75 @@ describe('Extensions scope containing content_types uids', () => { .stub(ux, 'confirm', async () => true) .stub(ext, 'writeFileSync', () => {}) .it( - 'should expect missingRefs equal to empty array, expect entire extensions schema and empty missingCts', + 'missingCts in extension to extensionSchema containing, extensions with fixed scope, missing Cts to the Cts that are not present in Ct Schema, And the fixed extensions that would be overwritten in the file', async () => { const missingRefs = await ext.run(); - expect(ext.missingCtInExtensions).eql([ - { - stackHeaders: { - api_key: 'apiKey', - }, - urlPath: '/extensions/ext1', - uid: 'ext1', - created_at: '2024-02-22T09:45:48.681Z', - updated_at: '2024-02-22T09:45:48.681Z', - created_by: 'u1', - updated_by: 'u1', - tags: [], - _version: 1, - title: 'Progress Bar', - config: {}, - type: 'field', - data_type: 'number', - content_types: ['ct6'], - multiple: false, - scope: { - content_types: ['ct6'], - }, - }, - { - stackHeaders: { - api_key: 'apiKey', - }, - urlPath: '/extensions/ext2', - uid: 'ext2', - created_at: '2024-02-22T09:45:11.284Z', - updated_at: '2024-02-22T09:45:11.284Z', - created_by: 'u1', - updated_by: 'u1', - tags: [], - _version: 1, - title: 'Color Picker', - config: {}, - type: 'field', - data_type: 'text', - multiple: false, - content_types: ['ct8'], - scope: { - content_types: ['ct8'], - }, - }, - { - stackHeaders: { - api_key: 'apiKey', - }, - urlPath: '/extensions/ext5', - uid: 'ext5', - created_at: '2024-02-22T09:44:27.030Z', - updated_at: '2024-02-22T09:44:27.030Z', - created_by: 'u1', - updated_by: 'u1', - tags: [], - _version: 1, - title: 'Text Intelligence', - config: { - token: 'your_token_here', - }, - content_types: ['ct6'], - type: 'widget', - scope: { - content_types: ['ct6'], - }, - }, - ]); - expect(missingRefs).eql({}); + expect(ext.missingCtInExtensions).eql(fixedSchema); + expect(missingRefs).eql(fixedSchema); expect(ext.missingCts).eql(new Set(['ct6', 'ct8'])); expect(ext.fixedExtensions).eql({ - ext6: { - stackHeaders: { - api_key: 'apiKey', + "ext5": { + "stackHeaders": { + "api_key": "apiKey" }, - urlPath: '/extensions/ext6', - uid: 'ext6', - created_at: '2024-02-22T09:44:01.784Z', - updated_at: '2024-02-22T09:44:01.784Z', - created_by: 'u1', - updated_by: 'u1', - tags: [], - _version: 1, - title: 'Ace Editor', - config: {}, - type: 'field', - data_type: 'reference', - multiple: true, + "urlPath": "/extensions/ext5", + "uid": "ext5", + "created_at": "2024-02-22T09:44:27.030Z", + "updated_at": "2024-02-22T09:44:27.030Z", + "created_by": "u1", + "updated_by": "u1", + "tags": [], + "_version": 1, + "title": "Text Intelligence", + "config": { + "token": "your_token_here" + }, + "type": "widget", + "scope": { + "content_types": ["ct4", "ct3", "ct2", "ct1"] + } }, - ext7: { - stackHeaders: { - api_key: 'apiKey', + "ext6": { + "stackHeaders": { + "api_key": "apiKey" }, - urlPath: '/extensions/ext7', - uid: 'ext7', - created_at: '2024-02-22T09:43:35.589Z', - updated_at: '2024-02-22T09:43:35.589Z', - created_by: 'u1', - updated_by: 'u1', - tags: [], - _version: 1, - title: 'Gatsby Preview', - config: { - siteUrl: 'your_site_url', + "urlPath": "/extensions/ext6", + "uid": "ext6", + "created_at": "2024-02-22T09:44:01.784Z", + "updated_at": "2024-02-22T09:44:01.784Z", + "created_by": "u1", + "updated_by": "u1", + "tags": [], + "_version": 1, + "title": "Ace Editor", + "config": {}, + "type": "field", + "data_type": "reference", + "multiple": true + }, + "ext7": { + "stackHeaders": { + "api_key": "apiKey" }, - type: 'widget', - scope: { - content_types: ['ct3', 'ct5'], + "urlPath": "/extensions/ext7", + "uid": "ext7", + "created_at": "2024-02-22T09:43:35.589Z", + "updated_at": "2024-02-22T09:43:35.589Z", + "created_by": "u1", + "updated_by": "u1", + "tags": [], + "_version": 1, + "title": "Gatsby Preview", + "config": { + "siteUrl": "your_site_url" }, - }, - }); + "type": "widget", + "scope": { + "content_types": ["ct3", "ct5"] + } + } + } + ); }, ); }); @@ -322,78 +347,11 @@ describe('Extensions scope containing content_types uids', () => { .stub(ext, 'writeFixContent', async () => {}) .stub(ext, 'writeFileSync', () => {}) .it( - 'should expect missingRefs equal to empty array, expect entire extensions schema and empty missingCts', + 'missingCts in extension to extensionSchema containing, extensions with fixed scope, missing Cts to the Cts that are not present in Ct Schema, Not overwriting to the file', async () => { const missingRefs = await ext.run(); - expect(ext.missingCtInExtensions).eql([ - { - stackHeaders: { - api_key: 'apiKey', - }, - urlPath: '/extensions/ext1', - uid: 'ext1', - created_at: '2024-02-22T09:45:48.681Z', - updated_at: '2024-02-22T09:45:48.681Z', - created_by: 'u1', - updated_by: 'u1', - tags: [], - _version: 1, - title: 'Progress Bar', - config: {}, - type: 'field', - data_type: 'number', - content_types: ['ct6'], - multiple: false, - scope: { - content_types: ['ct6'], - }, - }, - { - stackHeaders: { - api_key: 'apiKey', - }, - urlPath: '/extensions/ext2', - uid: 'ext2', - created_at: '2024-02-22T09:45:11.284Z', - updated_at: '2024-02-22T09:45:11.284Z', - created_by: 'u1', - updated_by: 'u1', - tags: [], - _version: 1, - title: 'Color Picker', - config: {}, - type: 'field', - data_type: 'text', - multiple: false, - content_types: ['ct8'], - scope: { - content_types: ['ct8'], - }, - }, - { - stackHeaders: { - api_key: 'apiKey', - }, - urlPath: '/extensions/ext5', - uid: 'ext5', - created_at: '2024-02-22T09:44:27.030Z', - updated_at: '2024-02-22T09:44:27.030Z', - created_by: 'u1', - updated_by: 'u1', - tags: [], - _version: 1, - title: 'Text Intelligence', - config: { - token: 'your_token_here', - }, - content_types: ['ct6'], - type: 'widget', - scope: { - content_types: ['ct6'], - }, - }, - ]); - expect(missingRefs).eql({}); + expect(ext.missingCtInExtensions).eql(fixedSchema); + expect(missingRefs).eql(fixedSchema); expect(ext.missingCts).eql(new Set(['ct6', 'ct8'])); }, ); From bfa80b43fdbfadaa086ed03e5805a65be082e426 Mon Sep 17 00:00:00 2001 From: raj pandey Date: Fri, 8 Mar 2024 12:26:25 +0530 Subject: [PATCH 6/7] ui text update --- packages/contentstack-audit/src/messages/index.ts | 6 +++--- packages/contentstack-audit/src/modules/extensions.ts | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/contentstack-audit/src/messages/index.ts b/packages/contentstack-audit/src/messages/index.ts index 7f2d10b847..6ae890e4c0 100644 --- a/packages/contentstack-audit/src/messages/index.ts +++ b/packages/contentstack-audit/src/messages/index.ts @@ -15,8 +15,8 @@ const commonMsg = { CONFIG: 'Path of the external config', DATA_DIR: 'Path where the data is stored', FIX_CONFIRMATION: 'Would you like to overwrite existing file.?', - EXTENSION_FIX_WARN: `Extension {uid} named '{title}' will be removed.`, - EXTENSION_FIX_CONFIRMATION: `Would you like to overwrite existing file.?`, + EXTENSION_FIX_WARN: `The extension associated with UID {uid} and title '{title}' will be removed.`, + EXTENSION_FIX_CONFIRMATION: `Would you like to overwrite existing file?`, }; const auditMsg = { @@ -30,7 +30,7 @@ const auditMsg = { FINAL_REPORT_PATH: "Reports ready. Please find the reports at '{path}'.", SCAN_CT_SUCCESS_MSG: "Successfully completed the scanning of {module} '{title}'.", SCAN_ENTRY_SUCCESS_MSG: "Successfully completed the scanning of {module} ({local}) '{title}'.", - SCAN_EXT_SUCCESS_MSG: "Successfully completed the scanning of {module} titled '{title}' having uid '{uid}'.", + SCAN_EXT_SUCCESS_MSG: "Successfully completed scanning the {module} titled '{title}' with UID '{uid}'", AUDIT_CMD_DESCRIPTION: 'Perform audits and find possible errors in the exported Contentstack data', }; diff --git a/packages/contentstack-audit/src/modules/extensions.ts b/packages/contentstack-audit/src/modules/extensions.ts index 09c4bf8d08..4b07481417 100644 --- a/packages/contentstack-audit/src/modules/extensions.ts +++ b/packages/contentstack-audit/src/modules/extensions.ts @@ -91,11 +91,10 @@ export default class Extensions { for (const ext of missingCtInExtensions) { const { uid, title } = ext; const fixedCts = ext?.scope?.content_types.filter((ct) => !this.missingCts.has(ct)); - if (fixedCts?.length) { + if (fixedCts?.length && newExtensionSchema[uid]?.scope) { newExtensionSchema[uid].scope.content_types = fixedCts; } else { this.log($t(commonMsg.EXTENSION_FIX_WARN, { title: title, uid }), { color: 'yellow' }); - const shouldDelete = this.config.flags.yes || (await ux.confirm(commonMsg.EXTENSION_FIX_CONFIRMATION)); if (shouldDelete) { delete newExtensionSchema[uid]; From f5f30833be6df8b99ec0f98d1e8d7196e6581b98 Mon Sep 17 00:00:00 2001 From: raj pandey Date: Fri, 8 Mar 2024 13:24:10 +0530 Subject: [PATCH 7/7] fixed audit during import --- packages/contentstack-import/src/import/module-importer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/contentstack-import/src/import/module-importer.ts b/packages/contentstack-import/src/import/module-importer.ts index 599e41447f..9db609b62b 100755 --- a/packages/contentstack-import/src/import/module-importer.ts +++ b/packages/contentstack-import/src/import/module-importer.ts @@ -132,7 +132,7 @@ class ModuleImporter { args.push('--modules', this.importConfig.moduleName); } else if (this.importConfig.modules.types.length) { this.importConfig.modules.types - .filter((val) => ['content-types', 'global-fields', 'entries'].includes(val)) + .filter((val) => ['content-types', 'global-fields', 'entries', 'extensions'].includes(val)) .forEach((val) => { args.push('--modules', val); });