diff --git a/.talismanrc b/.talismanrc index 758cb4dca1..245e755049 100644 --- a/.talismanrc +++ b/.talismanrc @@ -1,6 +1,6 @@ fileignoreconfig: - filename: package-lock.json - checksum: 5e64367e6f00c41d8fec66e335f66202d97a0e75006c9ecd331ce8f5856e296a + checksum: 40f1c53aad40a1f8d711c5ccdde7d1c147d371618c237e1fec2d313af51edb97 - filename: pnpm-lock.yaml checksum: aa6177859aaa87caf2892e8034657fd485c3abe7c13a833fd28449a1d33fa950 - filename: packages/contentstack-import-setup/test/unit/backup-handler.test.ts @@ -102,13 +102,13 @@ fileignoreconfig: - filename: packages/contentstack-audit/src/modules/workflows.ts checksum: 20d1f1985ea2657d3f9fc41b565a44000cbda47e2a60a576fee2aaff06f49352 - filename: packages/contentstack-audit/src/modules/field_rules.ts - checksum: 3eaca968126c9e0e12115491f7942341124c9962d5285dd1cfb355d9e60c6106 + checksum: f3ec8f44f8dd73601aa8da1207a72335faf0a12d52e792c1da90ba1bdeef38a7 - filename: packages/contentstack-audit/src/modules/entries.ts - checksum: 305af34194771343fee4e1d4bef60d065f1b8d1d8c1059a332f5d6c52e637ff1 + checksum: d8b6aa896aef2a9846f4dbde066d74d5b1e7b5cdbb8b548989616f9af7a8d26b - filename: packages/contentstack-audit/test/unit/base-command.test.ts checksum: b0fa8088fcbb17510fa275bd0dde3f6f4246f2525741c30426f07dd62fe497b0 - filename: packages/contentstack-audit/src/modules/content-types.ts - checksum: ddf7b08e6a80af09c6a7019a637c26089fb76572c7c3d079a8af244b02985f16 + checksum: e325a50db567abc5d0de758767037dbc10bb76501aadda32999bc96e17595d1b - filename: packages/contentstack-import/test/unit/commands/cm/stacks/import.test.ts checksum: b11e57f1b824d405f86438e9e7c59183f8c59b66b42d8d16dbeaf76195a30548 - filename: packages/contentstack-import/test/unit/utils/asset-helper.test.ts diff --git a/LICENSE b/LICENSE index 25403cd591..aff1142eed 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2025 Contentstack +Copyright (c) 2026 Contentstack Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/package-lock.json b/package-lock.json index fd0ab74499..3a6f68dfa4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7676,6 +7676,20 @@ "ieee754": "^1.1.13" } }, + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -8415,6 +8429,15 @@ "node": ">=0.10.0" } }, + "node_modules/cli-truncate/node_modules/slice-ansi": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "integrity": "sha512-up04hB2hR92PgjpyU3y/eg91yIBILyjVY26NvvciY3EVVPjybkMszMpXQ9QAkcS3I5rtJBDLoTxxg+qvW8c7rw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/cli-truncate/node_modules/string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", @@ -8751,6 +8774,20 @@ "typedarray": "^0.0.6" } }, + "node_modules/concat-stream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/conf": { "version": "10.2.0", "resolved": "https://registry.npmjs.org/conf/-/conf-10.2.0.tgz", @@ -12451,42 +12488,6 @@ "readable-stream": "^2.0.0" } }, - "node_modules/from2/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "license": "MIT" - }, - "node_modules/from2/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/from2/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/from2/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/fromentries": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", @@ -14066,66 +14067,6 @@ "url": "https://opencollective.com/express" } }, - "node_modules/inquirer/node_modules/is-interactive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/inquirer/node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/inquirer/node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "license": "MIT", - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/inquirer/node_modules/ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", - "license": "MIT", - "dependencies": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/inquirer/node_modules/rxjs": { "version": "7.8.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", @@ -14484,15 +14425,12 @@ } }, "node_modules/is-interactive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", - "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", "license": "MIT", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, "node_modules/is-map": { @@ -14758,12 +14696,12 @@ "license": "MIT" }, "node_modules/is-unicode-supported": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", - "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -14835,9 +14773,9 @@ } }, "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "license": "MIT" }, "node_modules/isexe": { @@ -14913,19 +14851,6 @@ "node": ">=8" } }, - "node_modules/istanbul-lib-processinfo/node_modules/p-map": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", - "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/istanbul-lib-processinfo/node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -16503,6 +16428,18 @@ "node": ">=4" } }, + "node_modules/listr-update-renderer/node_modules/log-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", + "integrity": "sha512-mmPrW0Fh2fxOzdBbFv4g1m6pR72haFLPJ2G5SJEELf1y+iaQrDG6cWCPjy54RHYbZAt7X+ls690Kw62AdWXBzQ==", + "license": "MIT", + "dependencies": { + "chalk": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/listr-update-renderer/node_modules/strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", @@ -16677,6 +16614,15 @@ "node": ">=0.10.0" } }, + "node_modules/listr/node_modules/p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/localStorage": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/localStorage/-/localStorage-1.0.4.tgz", @@ -16800,79 +16746,19 @@ "license": "MIT" }, "node_modules/log-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", - "integrity": "sha512-mmPrW0Fh2fxOzdBbFv4g1m6pR72haFLPJ2G5SJEELf1y+iaQrDG6cWCPjy54RHYbZAt7X+ls690Kw62AdWXBzQ==", - "license": "MIT", - "dependencies": { - "chalk": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/log-symbols/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/log-symbols/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/log-symbols/node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "license": "MIT", "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/log-symbols/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/log-symbols/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^2.0.0" + "node": ">=10" }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/log-symbols/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", - "license": "MIT", - "engines": { - "node": ">=0.8.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/log-update": { @@ -17495,40 +17381,10 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/mocha/node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "node_modules/mocha/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, "license": "ISC", "dependencies": { @@ -20463,19 +20319,6 @@ "node": ">=8" } }, - "node_modules/nyc/node_modules/p-map": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", - "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/nyc/node_modules/resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -20900,176 +20743,28 @@ "license": "MIT" }, "node_modules/ora": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz", - "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==", - "license": "MIT", - "dependencies": { - "chalk": "^5.3.0", - "cli-cursor": "^5.0.0", - "cli-spinners": "^2.9.2", - "is-interactive": "^2.0.0", - "is-unicode-supported": "^2.0.0", - "log-symbols": "^6.0.0", - "stdin-discarder": "^0.2.2", - "string-width": "^7.2.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/ora/node_modules/chalk": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", - "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/ora/node_modules/cli-cursor": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", - "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", - "license": "MIT", - "dependencies": { - "restore-cursor": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/node_modules/emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "license": "MIT" - }, - "node_modules/ora/node_modules/log-symbols": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", - "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", - "license": "MIT", - "dependencies": { - "chalk": "^5.3.0", - "is-unicode-supported": "^1.3.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/node_modules/log-symbols/node_modules/is-unicode-supported": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", - "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/node_modules/onetime": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", - "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", - "license": "MIT", - "dependencies": { - "mimic-function": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/node_modules/restore-cursor": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", - "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", - "license": "MIT", - "dependencies": { - "onetime": "^7.0.0", - "signal-exit": "^4.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/ora/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", "license": "MIT", "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" }, "engines": { - "node": ">=18" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ora/node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", @@ -21169,12 +20864,16 @@ } }, "node_modules/p-map": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", - "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, "engines": { - "node": ">=6" + "node": ">=8" } }, "node_modules/p-try": { @@ -21710,42 +21409,6 @@ "through2": "~2.0.3" } }, - "node_modules/progress-stream/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "license": "MIT" - }, - "node_modules/progress-stream/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/progress-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/progress-stream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/progress-stream/node_modules/through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", @@ -22176,19 +21839,26 @@ } }, "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -23101,6 +22771,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-array-concat/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "license": "MIT" + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -23137,6 +22813,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-push-apply/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "license": "MIT" + }, "node_modules/safe-regex-test": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", @@ -23691,12 +23373,21 @@ } }, "node_modules/slice-ansi": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", - "integrity": "sha512-up04hB2hR92PgjpyU3y/eg91yIBILyjVY26NvvciY3EVVPjybkMszMpXQ9QAkcS3I5rtJBDLoTxxg+qvW8c7rw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, "node_modules/smartwrap": { @@ -24191,6 +23882,20 @@ "readable-stream": "^3.5.0" } }, + "node_modules/stream-browserify/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/stream-connect": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/stream-connect/-/stream-connect-1.0.2.tgz", @@ -24238,14 +23943,20 @@ } }, "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "license": "MIT", "dependencies": { - "safe-buffer": "~5.2.0" + "safe-buffer": "~5.1.0" } }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, "node_modules/string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", @@ -24522,24 +24233,6 @@ "node": ">=4" } }, - "node_modules/table/node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, "node_modules/tapable": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", @@ -25898,6 +25591,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/which-builtin-type/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "license": "MIT" + }, "node_modules/which-collection": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", @@ -25991,6 +25690,34 @@ "node": ">= 12.0.0" } }, + "node_modules/winston-transport/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/winston/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -26292,7 +26019,7 @@ "version": "2.0.0-beta.2", "license": "MIT", "dependencies": { - "@contentstack/cli-audit": "~1.16.0", + "@contentstack/cli-audit": "~2.0.0-beta.0", "@contentstack/cli-auth": "~1.6.2", "@contentstack/cli-cm-bootstrap": "~2.0.0-beta.2", "@contentstack/cli-cm-branches": "~1.6.1", @@ -26362,7 +26089,7 @@ }, "packages/contentstack-audit": { "name": "@contentstack/cli-audit", - "version": "1.16.0", + "version": "2.0.0-beta.0", "license": "MIT", "dependencies": { "@contentstack/cli-command": "~1.6.1", @@ -26781,66 +26508,6 @@ "node": ">=12.0.0" } }, - "packages/contentstack-clone/node_modules/is-interactive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "packages/contentstack-clone/node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "packages/contentstack-clone/node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "license": "MIT", - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "packages/contentstack-clone/node_modules/ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", - "license": "MIT", - "dependencies": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "packages/contentstack-clone/node_modules/rxjs": { "version": "7.8.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", @@ -27817,6 +27484,46 @@ "node": ">=14.0.0" } }, + "packages/contentstack-import/node_modules/@contentstack/cli-audit": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@contentstack/cli-audit/-/cli-audit-1.16.1.tgz", + "integrity": "sha512-CRe92i7op3RlD5JQu+PY+KelITaTAb3lX22M//Cz7GzW356HyDTNtWydO5MOkPCTt6OkLNz0I9zYY2SPNCRAsw==", + "license": "MIT", + "dependencies": { + "@contentstack/cli-command": "~1.7.0", + "@contentstack/cli-utilities": "~1.15.0", + "@oclif/core": "^4.3.0", + "@oclif/plugin-help": "^6.2.28", + "@oclif/plugin-plugins": "^5.4.54", + "chalk": "^4.1.2", + "fast-csv": "^4.3.6", + "fs-extra": "^11.3.0", + "lodash": "^4.17.21", + "uuid": "^9.0.1", + "winston": "^3.17.0" + }, + "bin": { + "audit": "bin/run.js" + }, + "engines": { + "node": ">=16" + } + }, + "packages/contentstack-import/node_modules/@contentstack/cli-audit/node_modules/@contentstack/cli-command": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@contentstack/cli-command/-/cli-command-1.7.0.tgz", + "integrity": "sha512-hhsGGa6wFcvHwkapu0vXB1yvOaOmJ1LaV2imyjUREVxvHYC5O4JS2H5VeXLq137Q/dOk5q6o9MjVS+9W4Ri4sw==", + "license": "MIT", + "dependencies": { + "@contentstack/cli-utilities": "~1.15.0", + "@oclif/core": "^4.3.0", + "@oclif/plugin-help": "^6.2.28", + "contentstack": "^3.25.3" + }, + "engines": { + "node": ">=14.0.0" + } + }, "packages/contentstack-migration": { "name": "@contentstack/cli-migration", "version": "2.0.0-beta", @@ -28001,66 +27708,6 @@ "dev": true, "license": "MIT" }, - "packages/contentstack-utilities/node_modules/is-interactive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "packages/contentstack-utilities/node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "packages/contentstack-utilities/node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "license": "MIT", - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "packages/contentstack-utilities/node_modules/ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", - "license": "MIT", - "dependencies": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "packages/contentstack-variants": { "name": "@contentstack/cli-variants", "version": "2.0.0-beta.2", @@ -28107,6 +27754,213 @@ "engines": { "node": ">=14.17" } + }, + "packages/contentstack/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "packages/contentstack/node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/contentstack/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "license": "MIT" + }, + "packages/contentstack/node_modules/is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/contentstack/node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/contentstack/node_modules/log-symbols": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", + "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "is-unicode-supported": "^1.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/contentstack/node_modules/log-symbols/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "packages/contentstack/node_modules/log-symbols/node_modules/is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/contentstack/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/contentstack/node_modules/ora": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz", + "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==", + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "cli-cursor": "^5.0.0", + "cli-spinners": "^2.9.2", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^2.0.0", + "log-symbols": "^6.0.0", + "stdin-discarder": "^0.2.2", + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/contentstack/node_modules/ora/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "packages/contentstack/node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/contentstack/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "packages/contentstack/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/contentstack/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } } } } diff --git a/packages/contentstack-audit/README.md b/packages/contentstack-audit/README.md index 327e843014..562275eb58 100644 --- a/packages/contentstack-audit/README.md +++ b/packages/contentstack-audit/README.md @@ -19,7 +19,7 @@ $ npm install -g @contentstack/cli-audit $ csdx COMMAND running command... $ csdx (--version|-v) -@contentstack/cli-audit/1.14.2 darwin-arm64 node-v22.14.0 +@contentstack/cli-audit/2.0.0-beta.0 darwin-arm64 node-v22.14.0 $ csdx --help [COMMAND] USAGE $ csdx COMMAND @@ -273,7 +273,7 @@ USAGE $ csdx help [COMMAND...] [-n] ARGUMENTS - COMMAND... Command to show help for. + [COMMAND...] Command to show help for. FLAGS -n, --nested-commands Include all nested commands in the output. @@ -282,8 +282,7 @@ DESCRIPTION Display help for csdx. ``` -_See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v6.2.33/src/commands/help.ts)_ -_See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v6.2.33/src/commands/help.ts)_ +_See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v6.2.36/src/commands/help.ts)_ ## `csdx plugins` @@ -306,7 +305,7 @@ EXAMPLES $ csdx plugins ``` -_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.49/src/commands/plugins/index.ts)_ +_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.54/src/commands/plugins/index.ts)_ ## `csdx plugins:add PLUGIN` @@ -380,7 +379,7 @@ EXAMPLES $ csdx plugins:inspect myplugin ``` -_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.49/src/commands/plugins/inspect.ts)_ +_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.54/src/commands/plugins/inspect.ts)_ ## `csdx plugins:install PLUGIN` @@ -429,7 +428,7 @@ EXAMPLES $ csdx plugins:install someuser/someplugin ``` -_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.49/src/commands/plugins/install.ts)_ +_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.54/src/commands/plugins/install.ts)_ ## `csdx plugins:link PATH` @@ -460,7 +459,7 @@ EXAMPLES $ csdx plugins:link myplugin ``` -_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.49/src/commands/plugins/link.ts)_ +_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.54/src/commands/plugins/link.ts)_ ## `csdx plugins:remove [PLUGIN]` @@ -471,7 +470,7 @@ USAGE $ csdx plugins:remove [PLUGIN...] [-h] [-v] ARGUMENTS - PLUGIN... plugin to uninstall + [PLUGIN...] plugin to uninstall FLAGS -h, --help Show CLI help. @@ -501,7 +500,7 @@ FLAGS --reinstall Reinstall all plugins after uninstalling. ``` -_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.49/src/commands/plugins/reset.ts)_ +_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.54/src/commands/plugins/reset.ts)_ ## `csdx plugins:uninstall [PLUGIN]` @@ -512,7 +511,7 @@ USAGE $ csdx plugins:uninstall [PLUGIN...] [-h] [-v] ARGUMENTS - PLUGIN... plugin to uninstall + [PLUGIN...] plugin to uninstall FLAGS -h, --help Show CLI help. @@ -529,7 +528,7 @@ EXAMPLES $ csdx plugins:uninstall myplugin ``` -_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.49/src/commands/plugins/uninstall.ts)_ +_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.54/src/commands/plugins/uninstall.ts)_ ## `csdx plugins:unlink [PLUGIN]` @@ -540,7 +539,7 @@ USAGE $ csdx plugins:unlink [PLUGIN...] [-h] [-v] ARGUMENTS - PLUGIN... plugin to uninstall + [PLUGIN...] plugin to uninstall FLAGS -h, --help Show CLI help. @@ -573,5 +572,5 @@ DESCRIPTION Update installed plugins. ``` -_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.49/src/commands/plugins/update.ts)_ +_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.54/src/commands/plugins/update.ts)_ diff --git a/packages/contentstack-audit/package.json b/packages/contentstack-audit/package.json index f8d0eff690..34012b5ff6 100644 --- a/packages/contentstack-audit/package.json +++ b/packages/contentstack-audit/package.json @@ -1,6 +1,6 @@ { "name": "@contentstack/cli-audit", - "version": "1.16.0", + "version": "2.0.0-beta.0", "description": "Contentstack audit plugin", "author": "Contentstack CLI", "homepage": "https://github.com/contentstack/cli", diff --git a/packages/contentstack-audit/src/audit-base-command.ts b/packages/contentstack-audit/src/audit-base-command.ts index c588581241..1eb63cfd49 100644 --- a/packages/contentstack-audit/src/audit-base-command.ts +++ b/packages/contentstack-audit/src/audit-base-command.ts @@ -5,7 +5,7 @@ import { v4 as uuid } from 'uuid'; import isEmpty from 'lodash/isEmpty'; import { join, resolve } from 'path'; import cloneDeep from 'lodash/cloneDeep'; -import { cliux, sanitizePath, TableFlags, TableHeader, log, configHandler } from '@contentstack/cli-utilities'; +import { cliux, sanitizePath, TableFlags, TableHeader, log, configHandler, CLIProgressManager, clearProgressModuleSetting } from '@contentstack/cli-utilities'; import { createWriteStream, existsSync, mkdirSync, readFileSync, writeFileSync, rmSync } from 'fs'; import config from './config'; import { print } from './util/log'; @@ -71,11 +71,23 @@ export abstract class AuditBaseCommand extends BaseCommand { this.currentCommand = command; + + // Set progress supported module and console logs setting BEFORE any log calls + // This ensures the logger respects the setting when it's initialized + const logConfig = configHandler.get('log') || {}; + // Default to false so progress bars are shown instead of console logs + if (logConfig.showConsoleLogs === undefined) { + configHandler.set('log.showConsoleLogs', false); + } + configHandler.set('log.progressSupportedModule', 'audit'); + // Initialize audit context this.auditContext = this.createAuditContext(); log.debug(`Starting audit command: ${command}`, this.auditContext); log.info(`Starting audit command: ${command}`, this.auditContext); - + + // Initialize global summary for progress tracking + CLIProgressManager.initializeGlobalSummary('AUDIT', '', 'Auditing content...'); await this.promptQueue(); await this.createBackUp(); @@ -163,6 +175,12 @@ export abstract class AuditBaseCommand extends BaseCommand = await new ModuleDataReader(cloneDeep(constructorParam)).run(); log.debug(`Data module wise: ${JSON.stringify(dataModuleWise)}`, this.auditContext); + + // Extract logConfig and showConsoleLogs once before the loop to reuse throughout + const logConfig = configHandler.get('log') || {}; + const showConsoleLogs = logConfig.showConsoleLogs ?? true; + for (const module of this.sharedConfig.flags.modules || this.sharedConfig.modules) { // Update audit context with current module this.auditContext = this.createAuditContext(module); log.debug(`Starting audit for module: ${module}`, this.auditContext); log.info(`Starting audit for module: ${module}`, this.auditContext); - print([ - { - bold: true, - color: 'whiteBright', - message: this.$t(this.messages.AUDIT_START_SPINNER, { module }), - }, - ]); + // Only show spinner message if console logs are enabled (compatible with line-by-line logs) + if (showConsoleLogs) { + print([ + { + bold: true, + color: 'whiteBright', + message: this.$t(this.messages.AUDIT_START_SPINNER, { module }), + }, + ]); + } constructorParam['moduleName'] = module; switch (module) { case 'assets': log.info('Executing assets audit', this.auditContext); - missingEnvLocalesInAssets = await new Assets(cloneDeep(constructorParam)).run(); + const assetsTotalCount = dataModuleWise['assets']?.Total || 0; + missingEnvLocalesInAssets = await new Assets(cloneDeep(constructorParam)).run(false, assetsTotalCount); await this.prepareReport(module, missingEnvLocalesInAssets); this.getAffectedData('assets', dataModuleWise['assets'], missingEnvLocalesInAssets); log.success(`Assets audit completed. Found ${Object.keys(missingEnvLocalesInAssets || {}).length} issues`, this.auditContext); break; case 'content-types': log.info('Executing content-types audit', this.auditContext); - missingCtRefs = await new ContentType(cloneDeep(constructorParam)).run(); + const contentTypesTotalCount = dataModuleWise['content-types']?.Total || 0; + missingCtRefs = await new ContentType(cloneDeep(constructorParam)).run(false, contentTypesTotalCount); await this.prepareReport(module, missingCtRefs); this.getAffectedData('content-types', dataModuleWise['content-types'], missingCtRefs); log.success(`Content-types audit completed. Found ${Object.keys(missingCtRefs || {}).length} issues`, this.auditContext); break; case 'global-fields': log.info('Executing global-fields audit', this.auditContext); - missingGfRefs = await new GlobalField(cloneDeep(constructorParam)).run(); + const globalFieldsTotalCount = dataModuleWise['global-fields']?.Total || 0; + missingGfRefs = await new GlobalField(cloneDeep(constructorParam)).run(false, globalFieldsTotalCount); await this.prepareReport(module, missingGfRefs); this.getAffectedData('global-fields', dataModuleWise['global-fields'], missingGfRefs); log.success(`Global-fields audit completed. Found ${Object.keys(missingGfRefs || {}).length} issues`, this.auditContext); break; case 'entries': log.info('Executing entries audit', this.auditContext); - missingEntry = await new Entries(cloneDeep(constructorParam)).run(); + const entriesTotalCount = dataModuleWise['entries']?.Total || 0; + missingEntry = await new Entries(cloneDeep(constructorParam)).run(entriesTotalCount); missingEntryRefs = missingEntry.missingEntryRefs ?? {}; missingSelectFeild = missingEntry.missingSelectFeild ?? {}; missingMandatoryFields = missingEntry.missingMandatoryFields ?? {}; @@ -286,12 +316,13 @@ export abstract class AuditBaseCommand extends BaseCommand { + await this.prerequisiteData(); + }); + + // Create progress manager if we have a total count + if (totalCount && totalCount > 0) { + const progress = this.createSimpleProgress(this.moduleName, totalCount); + progress.updateStatus('Validating asset references...'); + } - log.debug('Starting asset Reference, Environment and Locale validation', this.config.auditContext); - await this.lookForReference(); + log.debug('Starting asset Reference, Environment and Locale validation', this.config.auditContext); + await this.lookForReference(); if (returnFixSchema) { log.debug(`Returning fixed schema with ${this.schema?.length || 0} items`, this.config.auditContext); @@ -86,9 +96,15 @@ export default class Assets { } } - const totalIssues = Object.keys(this.missingEnvLocales).length; - log.debug(`${this.moduleName} audit completed. Found ${totalIssues} assets with missing environment/locale references`, this.config.auditContext); - return this.missingEnvLocales; + const totalIssues = Object.keys(this.missingEnvLocales).length; + log.debug(`${this.moduleName} audit completed. Found ${totalIssues} assets with missing environment/locale references`, this.config.auditContext); + + this.completeProgress(true); + return this.missingEnvLocales; + } catch (error: any) { + this.completeProgress(false, error?.message || 'Assets audit failed'); + throw error; + } } /** @@ -227,6 +243,11 @@ export default class Assets { const remainingPublishDetails = this.assets[assetUid].publish_details?.length || 0; log.debug(`Asset ${assetUid} now has ${remainingPublishDetails} valid publish details`, this.config.auditContext); + // Track progress for each asset processed + if (this.progressManager) { + this.progressManager.tick(true, `asset: ${assetUid}`, null); + } + if (this.fix) { log.debug(`Fixing asset ${assetUid}`, this.config.auditContext); log.info($t(auditFixMsg.ASSET_FIX, { uid: assetUid }), this.config.auditContext); diff --git a/packages/contentstack-audit/src/modules/base-class.ts b/packages/contentstack-audit/src/modules/base-class.ts new file mode 100644 index 0000000000..d1a8329cf1 --- /dev/null +++ b/packages/contentstack-audit/src/modules/base-class.ts @@ -0,0 +1,57 @@ +import { CLIProgressManager, configHandler } from '@contentstack/cli-utilities'; +import { ConfigType, ModuleConstructorParam } from '../types'; + +export default abstract class BaseClass { + protected progressManager: CLIProgressManager | null = null; + protected currentModuleName: string = ''; + public config: ConfigType; + + constructor({ config }: ModuleConstructorParam) { + this.config = config; + } + + /** + * Create simple progress manager + */ + protected createSimpleProgress(moduleName: string, total?: number): CLIProgressManager { + this.currentModuleName = moduleName; + const logConfig = configHandler.get('log') || {}; + const showConsoleLogs = logConfig.showConsoleLogs ?? false; + this.progressManager = CLIProgressManager.createSimple(moduleName, total, showConsoleLogs); + return this.progressManager; + } + + /** + * Create nested progress manager + */ + protected createNestedProgress(moduleName: string): CLIProgressManager { + this.currentModuleName = moduleName; + const logConfig = configHandler.get('log') || {}; + const showConsoleLogs = logConfig.showConsoleLogs ?? false; + this.progressManager = CLIProgressManager.createNested(moduleName, showConsoleLogs); + return this.progressManager; + } + + /** + * Complete progress manager + */ + protected completeProgress(success: boolean = true, error?: string): void { + this.progressManager?.complete(success, error); + this.progressManager = null; + } + + /** + * Execute action with loading spinner (if console logs are disabled) + */ + protected async withLoadingSpinner(message: string, action: () => Promise): Promise { + const logConfig = configHandler.get('log') || {}; + const showConsoleLogs = logConfig.showConsoleLogs ?? false; + + if (showConsoleLogs) { + // If console logs are enabled, don't show spinner, just execute the action + return await action(); + } + return await CLIProgressManager.withLoadingSpinner(message, action); + } +} + diff --git a/packages/contentstack-audit/src/modules/content-types.ts b/packages/contentstack-audit/src/modules/content-types.ts index a4dd07edc2..479a1c19f9 100644 --- a/packages/contentstack-audit/src/modules/content-types.ts +++ b/packages/contentstack-audit/src/modules/content-types.ts @@ -7,7 +7,6 @@ import { existsSync, readFileSync, writeFileSync } from 'fs'; import { sanitizePath, cliux, log } from '@contentstack/cli-utilities'; import { - ConfigType, ModularBlockType, ContentTypeStruct, GroupFieldDataType, @@ -25,14 +24,14 @@ import { import auditConfig from '../config'; import { $t, auditFixMsg, auditMsg, commonMsg } from '../messages'; import { MarketplaceAppsInstallationData } from '../types/extension'; +import BaseClass from './base-class'; /* The `ContentType` class is responsible for scanning content types, looking for references, and generating a report in JSON and CSV formats. */ -export default class ContentType { +export default class ContentType extends BaseClass { protected fix: boolean; public fileName: string; - public config: ConfigType; public folderPath: string; public currentUid!: string; public currentTitle!: string; @@ -44,7 +43,7 @@ export default class ContentType { protected missingRefs: Record = {}; public moduleName: keyof typeof auditConfig.moduleConfig; constructor({ fix, config, moduleName, ctSchema, gfSchema }: ModuleConstructorParam & CtConstructorParam) { - this.config = config; + super({ config }); this.fix = fix ?? false; this.ctSchema = ctSchema; this.gfSchema = gfSchema; @@ -76,61 +75,84 @@ export default class ContentType { /** * The `run` function checks if a folder path exists, sets the schema based on the module name, * iterates over the schema and looks for references, and returns a list of missing references. + * @param returnFixSchema - If true, returns the fixed schema instead of missing references + * @param totalCount - Total number of items to process (for progress tracking) * @returns the `missingRefs` object. */ - async run(returnFixSchema = false) { - this.inMemoryFix = returnFixSchema; + async run(returnFixSchema = false, totalCount?: number) { + try { + this.inMemoryFix = returnFixSchema; + + if (!existsSync(this.folderPath)) { + log.warn(`Skipping ${this.moduleName} audit`, this.config.auditContext); + cliux.print($t(auditMsg.NOT_VALID_PATH, { path: this.folderPath }), { color: 'yellow' }); + return returnFixSchema ? [] : {}; + } - if (!existsSync(this.folderPath)) { - log.warn(`Skipping ${this.moduleName} audit`, this.config.auditContext); - cliux.print($t(auditMsg.NOT_VALID_PATH, { path: this.folderPath }), { color: 'yellow' }); - return returnFixSchema ? [] : {}; - } + this.schema = this.moduleName === 'content-types' ? this.ctSchema : this.gfSchema; + log.debug(`Found ${this.schema?.length || 0} ${this.moduleName} schemas to audit`, this.config.auditContext); - this.schema = this.moduleName === 'content-types' ? this.ctSchema : this.gfSchema; - log.debug(`Found ${this.schema?.length || 0} ${this.moduleName} schemas to audit`, this.config.auditContext); - - await this.prerequisiteData(); - - for (const schema of this.schema ?? []) { - this.currentUid = schema.uid; - this.currentTitle = schema.title; - this.missingRefs[this.currentUid] = []; - const { uid, title } = schema; - log.debug(`Auditing ${this.moduleName}: ${title} (${uid})`, this.config.auditContext); - await this.lookForReference([{ uid, name: title }], schema); - log.debug( - $t(auditMsg.SCAN_CT_SUCCESS_MSG, { title, module: this.config.moduleConfig[this.moduleName].name }), - this.config.auditContext, - ); - } + // Load prerequisite data with loading spinner + await this.withLoadingSpinner(`${this.moduleName.toUpperCase()}: Loading prerequisite data...`, async () => { + await this.prerequisiteData(); + }); - if (returnFixSchema) { - log.debug(`Returning fixed schema with ${this.schema?.length || 0} items`, this.config.auditContext); - return this.schema; - } + // Create progress manager if we have a total count + if (totalCount && totalCount > 0) { + const progress = this.createSimpleProgress(this.moduleName, totalCount); + progress.updateStatus('Validating references...'); + } - if (this.fix) { - log.debug('Writing fix content to files', this.config.auditContext); - await this.writeFixContent(); - } + for (const schema of this.schema ?? []) { + this.currentUid = schema.uid; + this.currentTitle = schema.title; + this.missingRefs[this.currentUid] = []; + const { uid, title } = schema; + log.debug(`Auditing ${this.moduleName}: ${title} (${uid})`, this.config.auditContext); + await this.lookForReference([{ uid, name: title }], schema); + log.debug( + $t(auditMsg.SCAN_CT_SUCCESS_MSG, { title, module: this.config.moduleConfig[this.moduleName].name }), + this.config.auditContext, + ); + + // Track progress for each schema processed + if (this.progressManager) { + this.progressManager.tick(true, `${this.moduleName}: ${title}`, null); + } + } - log.debug('Cleaning up empty missing references', this.config.auditContext); - log.debug(`Total missing reference properties: ${Object.keys(this.missingRefs).length}`, this.config.auditContext); - - for (let propName in this.missingRefs) { - const refCount = this.missingRefs[propName].length; - log.debug(`Property ${propName}: ${refCount} missing references`, this.config.auditContext); + if (returnFixSchema) { + log.debug(`Returning fixed schema with ${this.schema?.length || 0} items`, this.config.auditContext); + return this.schema; + } + + if (this.fix) { + log.debug('Writing fix content to files', this.config.auditContext); + await this.writeFixContent(); + } + + log.debug('Cleaning up empty missing references', this.config.auditContext); + log.debug(`Total missing reference properties: ${Object.keys(this.missingRefs).length}`, this.config.auditContext); - if (!refCount) { - log.debug(`Removing empty property: ${propName}`, this.config.auditContext); - delete this.missingRefs[propName]; + for (let propName in this.missingRefs) { + const refCount = this.missingRefs[propName].length; + log.debug(`Property ${propName}: ${refCount} missing references`, this.config.auditContext); + + if (!refCount) { + log.debug(`Removing empty property: ${propName}`, this.config.auditContext); + delete this.missingRefs[propName]; + } } - } - const totalIssues = Object.keys(this.missingRefs).length; - log.debug(`${this.moduleName} audit completed. Found ${totalIssues} schemas with issues`, this.config.auditContext); - return this.missingRefs; + const totalIssues = Object.keys(this.missingRefs).length; + log.debug(`${this.moduleName} audit completed. Found ${totalIssues} schemas with issues`, this.config.auditContext); + + this.completeProgress(true); + return this.missingRefs; + } catch (error: any) { + this.completeProgress(false, error?.message || `${this.moduleName} audit failed`); + throw error; + } } /** diff --git a/packages/contentstack-audit/src/modules/custom-roles.ts b/packages/contentstack-audit/src/modules/custom-roles.ts index 8dfe08b878..8ae7a3cbf4 100644 --- a/packages/contentstack-audit/src/modules/custom-roles.ts +++ b/packages/contentstack-audit/src/modules/custom-roles.ts @@ -1,17 +1,17 @@ import { join, resolve } from 'path'; import { existsSync, readFileSync, writeFileSync } from 'fs'; import { cloneDeep } from 'lodash'; -import { ConfigType, CtConstructorParam, ModuleConstructorParam, CustomRole, Rule } from '../types'; +import { CtConstructorParam, ModuleConstructorParam, CustomRole, Rule } from '../types'; import { cliux, sanitizePath, log } from '@contentstack/cli-utilities'; import auditConfig from '../config'; import { $t, auditMsg, commonMsg } from '../messages'; import { values } from 'lodash'; +import BaseClass from './base-class'; -export default class CustomRoles { +export default class CustomRoles extends BaseClass { protected fix: boolean; public fileName: any; - public config: ConfigType; public folderPath: string; public customRoleSchema: CustomRole[]; public moduleName: keyof typeof auditConfig.moduleConfig; @@ -20,7 +20,7 @@ export default class CustomRoles { public isBranchFixDone: boolean; constructor({ fix, config, moduleName }: ModuleConstructorParam & Pick) { - this.config = config; + super({ config }); log.debug(`Initializing Custom Roles module`, this.config.auditContext); this.fix = fix ?? false; this.customRoleSchema = []; @@ -61,25 +61,34 @@ export default class CustomRoles { * From the ctSchema add all the content type UID into ctUidSet to check whether the content-type is present or not * @returns Array of object containing the custom role name, uid and content_types that are missing */ - async run() { - - if (!existsSync(this.folderPath)) { - log.debug(`Skipping ${this.moduleName} audit - path does not exist`, this.config.auditContext); - log.warn(`Skipping ${this.moduleName} audit`, this.config.auditContext); - cliux.print($t(auditMsg.NOT_VALID_PATH, { path: this.folderPath }), { color: 'yellow' }); - return {}; - } + async run(totalCount?: number) { + try { + if (!existsSync(this.folderPath)) { + log.debug(`Skipping ${this.moduleName} audit - path does not exist`, this.config.auditContext); + log.warn(`Skipping ${this.moduleName} audit`, this.config.auditContext); + cliux.print($t(auditMsg.NOT_VALID_PATH, { path: this.folderPath }), { color: 'yellow' }); + return {}; + } - this.customRolePath = join(this.folderPath, this.fileName); - log.debug(`Custom roles file path: ${this.customRolePath}`, this.config.auditContext); - - this.customRoleSchema = existsSync(this.customRolePath) - ? values(JSON.parse(readFileSync(this.customRolePath, 'utf8')) as CustomRole[]) - : []; - - log.debug(`Found ${this.customRoleSchema.length} custom roles to audit`, this.config.auditContext); + this.customRolePath = join(this.folderPath, this.fileName); + log.debug(`Custom roles file path: ${this.customRolePath}`, this.config.auditContext); + + // Load custom roles schema with loading spinner + await this.withLoadingSpinner('CUSTOM-ROLES: Loading custom roles schema...', async () => { + this.customRoleSchema = existsSync(this.customRolePath) + ? values(JSON.parse(readFileSync(this.customRolePath, 'utf8')) as CustomRole[]) + : []; + }); + + log.debug(`Found ${this.customRoleSchema.length} custom roles to audit`, this.config.auditContext); - for (let index = 0; index < this.customRoleSchema?.length; index++) { + // Create progress manager if we have a total count + if (totalCount && totalCount > 0) { + const progress = this.createSimpleProgress(this.moduleName, totalCount); + progress.updateStatus('Validating custom roles...'); + } + + for (let index = 0; index < this.customRoleSchema?.length; index++) { const customRole = this.customRoleSchema[index]; log.debug(`Processing custom role: ${customRole.name} (${customRole.uid})`, this.config.auditContext); @@ -126,6 +135,11 @@ export default class CustomRoles { }), this.config.auditContext ); + + // Track progress for each custom role processed + if (this.progressManager) { + this.progressManager.tick(true, `custom-role: ${customRole.name}`, null); + } } log.debug(`Found ${this.missingFieldsInCustomRoles.length} custom roles with issues`, this.config.auditContext); @@ -141,7 +155,12 @@ export default class CustomRoles { } log.debug(`${this.moduleName} audit completed. Found ${this.missingFieldsInCustomRoles.length} custom roles with issues`, this.config.auditContext); - return this.missingFieldsInCustomRoles; + this.completeProgress(true); + return this.missingFieldsInCustomRoles; + } catch (error: any) { + this.completeProgress(false, error?.message || 'Custom roles audit failed'); + throw error; + } } async fixCustomRoleSchema() { diff --git a/packages/contentstack-audit/src/modules/entries.ts b/packages/contentstack-audit/src/modules/entries.ts index 8b19434ea0..cb8e248c5c 100644 --- a/packages/contentstack-audit/src/modules/entries.ts +++ b/packages/contentstack-audit/src/modules/entries.ts @@ -9,9 +9,9 @@ import { existsSync, readFileSync, writeFileSync } from 'fs'; import auditConfig from '../config'; import ContentType from './content-types'; import { $t, auditFixMsg, auditMsg, commonMsg } from '../messages'; +import BaseClass from './base-class'; import { Locale, - ConfigType, EntryStruct, EntryFieldType, ModularBlockType, @@ -40,11 +40,10 @@ import GlobalField from './global-fields'; import { MarketplaceAppsInstallationData } from '../types/extension'; import { keys } from 'lodash'; -export default class Entries { +export default class Entries extends BaseClass { protected fix: boolean; public fileName: string; public locales!: Locale[]; - public config: ConfigType; public folderPath: string; public currentUid!: string; public currentTitle!: string; @@ -63,8 +62,7 @@ export default class Entries { public moduleName: keyof typeof auditConfig.moduleConfig = 'entries'; constructor({ fix, config, moduleName, ctSchema, gfSchema }: ModuleConstructorParam & CtConstructorParam) { - - this.config = config; + super({ config }); log.debug(`Initializing Entries module`, this.config.auditContext); this.fix = fix ?? false; this.ctSchema = ctSchema; @@ -96,27 +94,38 @@ export default class Entries { /** * The `run` function checks if a folder path exists, sets the schema based on the module name, * iterates over the schema and looks for references, and returns a list of missing references. + * @param totalCount - Total number of entries to process (for progress tracking) * @returns the `missingRefs` object. */ - async run() { - - if (!existsSync(this.folderPath)) { - log.debug(`Skipping ${this.moduleName} audit - path does not exist`, this.config.auditContext); - log.warn(`Skipping ${this.moduleName} audit`, this.config.auditContext); - cliux.print($t(auditMsg.NOT_VALID_PATH, { path: this.folderPath }), { color: 'yellow' }); - return {}; - } + async run(totalCount?: number) { + try { + if (!existsSync(this.folderPath)) { + log.debug(`Skipping ${this.moduleName} audit - path does not exist`, this.config.auditContext); + log.warn(`Skipping ${this.moduleName} audit`, this.config.auditContext); + cliux.print($t(auditMsg.NOT_VALID_PATH, { path: this.folderPath }), { color: 'yellow' }); + return {}; + } - log.debug(`Found ${this.ctSchema?.length || 0} content types to audit`, this.config.auditContext); - log.debug(`Found ${this.locales?.length || 0} locales to process`, this.config.auditContext); + log.debug(`Found ${this.ctSchema?.length || 0} content types to audit`, this.config.auditContext); + log.debug(`Found ${this.locales?.length || 0} locales to process`, this.config.auditContext); - log.debug('Preparing entry metadata', this.config.auditContext); - await this.prepareEntryMetaData(); - log.debug(`Entry metadata prepared: ${this.entryMetaData.length} entries found`, this.config.auditContext); + // Prepare entry metadata with loading spinner + await this.withLoadingSpinner('ENTRIES: Preparing entry metadata...', async () => { + await this.prepareEntryMetaData(); + }); + log.debug(`Entry metadata prepared: ${this.entryMetaData.length} entries found`, this.config.auditContext); + + // Fix prerequisite data with loading spinner + await this.withLoadingSpinner('ENTRIES: Fixing prerequisite data...', async () => { + await this.fixPrerequisiteData(); + }); + log.debug('Prerequisite data fix completed', this.config.auditContext); - log.debug('Fixing prerequisite data', this.config.auditContext); - await this.fixPrerequisiteData(); - log.debug('Prerequisite data fix completed', this.config.auditContext); + // Create progress manager if we have a total count + if (totalCount && totalCount > 0) { + const progress = this.createSimpleProgress(this.moduleName, totalCount); + progress.updateStatus('Validating entries...'); + } log.debug(`Processing ${this.locales.length} locales and ${this.ctSchema.length} content types`, this.config.auditContext); for (const { code } of this.locales) { @@ -282,6 +291,11 @@ export default class Entries { }); log.debug(message, this.config.auditContext); log.info(message, this.config.auditContext); + + // Track progress for each entry processed + if (this.progressManager) { + this.progressManager.tick(true, `entry: ${title || uid}`, null); + } } if (this.fix) { @@ -305,15 +319,20 @@ export default class Entries { missingMultipleFields: this.missingMultipleField, }; - log.debug(`Entries audit completed. Found issues:`, this.config.auditContext); - log.debug(`- Missing references: ${Object.keys(this.missingRefs).length}`, this.config.auditContext); - log.debug(`- Missing select fields: ${Object.keys(this.missingSelectFeild).length}`, this.config.auditContext); - log.debug(`- Missing mandatory fields: ${Object.keys(this.missingMandatoryFields).length}`, this.config.auditContext); - log.debug(`- Missing title fields: ${Object.keys(this.missingTitleFields).length}`, this.config.auditContext); - log.debug(`- Missing environment/locale: ${Object.keys(this.missingEnvLocale).length}`, this.config.auditContext); - log.debug(`- Missing multiple fields: ${Object.keys(this.missingMultipleField).length}`, this.config.auditContext); - - return result; + log.debug(`Entries audit completed. Found issues:`, this.config.auditContext); + log.debug(`- Missing references: ${Object.keys(this.missingRefs).length}`, this.config.auditContext); + log.debug(`- Missing select fields: ${Object.keys(this.missingSelectFeild).length}`, this.config.auditContext); + log.debug(`- Missing mandatory fields: ${Object.keys(this.missingMandatoryFields).length}`, this.config.auditContext); + log.debug(`- Missing title fields: ${Object.keys(this.missingTitleFields).length}`, this.config.auditContext); + log.debug(`- Missing environment/locale: ${Object.keys(this.missingEnvLocale).length}`, this.config.auditContext); + log.debug(`- Missing multiple fields: ${Object.keys(this.missingMultipleField).length}`, this.config.auditContext); + + this.completeProgress(true); + return result; + } catch (error: any) { + this.completeProgress(false, error?.message || 'Entries audit failed'); + throw error; + } } /** diff --git a/packages/contentstack-audit/src/modules/extensions.ts b/packages/contentstack-audit/src/modules/extensions.ts index 072036c358..3d25e8581a 100644 --- a/packages/contentstack-audit/src/modules/extensions.ts +++ b/packages/contentstack-audit/src/modules/extensions.ts @@ -1,17 +1,17 @@ import path, { join, resolve } from 'path'; import { existsSync, readFileSync, writeFileSync } from 'fs'; import { cloneDeep } from 'lodash'; -import { ConfigType, ContentTypeStruct, CtConstructorParam, ModuleConstructorParam, Extension } from '../types'; +import { ContentTypeStruct, CtConstructorParam, ModuleConstructorParam, Extension } from '../types'; import { sanitizePath, cliux, log } from '@contentstack/cli-utilities'; import auditConfig from '../config'; import { $t, auditMsg, commonMsg } from '../messages'; import { values } from 'lodash'; +import BaseClass from './base-class'; -export default class Extensions { +export default class Extensions extends BaseClass { protected fix: boolean; public fileName: any; - public config: ConfigType; public folderPath: string; public extensionsSchema: Extension[]; public ctSchema: ContentTypeStruct[]; @@ -27,7 +27,7 @@ export default class Extensions { moduleName, ctSchema, }: ModuleConstructorParam & Pick) { - this.config = config; + super({ config }); this.fix = fix ?? false; this.ctSchema = ctSchema; this.extensionsSchema = []; @@ -70,33 +70,42 @@ export default class Extensions { return 'extensions'; } - async run() { - log.debug(`Starting ${this.moduleName} audit process`, this.config.auditContext); - log.debug(`Extensions folder path: ${this.folderPath}`, this.config.auditContext); - log.debug(`Fix mode: ${this.fix}`, this.config.auditContext); - - if (!existsSync(this.folderPath)) { - log.debug(`Skipping ${this.moduleName} audit - path does not exist`, this.config.auditContext); - log.warn(`Skipping ${this.moduleName} audit`, this.config.auditContext); - cliux.print($t(auditMsg.NOT_VALID_PATH, { path: this.folderPath }), { color: 'yellow' }); - return {}; - } + async run(totalCount?: number) { + try { + log.debug(`Starting ${this.moduleName} audit process`, this.config.auditContext); + log.debug(`Extensions folder path: ${this.folderPath}`, this.config.auditContext); + log.debug(`Fix mode: ${this.fix}`, this.config.auditContext); + + if (!existsSync(this.folderPath)) { + log.debug(`Skipping ${this.moduleName} audit - path does not exist`, this.config.auditContext); + log.warn(`Skipping ${this.moduleName} audit`, this.config.auditContext); + cliux.print($t(auditMsg.NOT_VALID_PATH, { path: this.folderPath }), { color: 'yellow' }); + return {}; + } + + this.extensionsPath = path.join(this.folderPath, this.fileName); + log.debug(`Extensions file path: ${this.extensionsPath}`, this.config.auditContext); - this.extensionsPath = path.join(this.folderPath, this.fileName); - log.debug(`Extensions file path: ${this.extensionsPath}`, this.config.auditContext); + // Load extensions schema with loading spinner + await this.withLoadingSpinner('EXTENSIONS: Loading extensions schema...', async () => { + this.extensionsSchema = existsSync(this.extensionsPath) + ? values(JSON.parse(readFileSync(this.extensionsPath, 'utf-8')) as Extension[]) + : []; + }); + log.debug(`Loaded ${this.extensionsSchema.length} extensions`, this.config.auditContext); - log.debug(`Loading extensions schema from file`, this.config.auditContext); - this.extensionsSchema = existsSync(this.extensionsPath) - ? values(JSON.parse(readFileSync(this.extensionsPath, 'utf-8')) as Extension[]) - : []; - log.debug(`Loaded ${this.extensionsSchema.length} extensions`, this.config.auditContext); + log.debug(`Building content type UID set from ${this.ctSchema.length} content types`, this.config.auditContext); + this.ctSchema.map((ct) => this.ctUidSet.add(ct.uid)); + log.debug(`Content type UID set contains: ${Array.from(this.ctUidSet).join(', ')}`, this.config.auditContext); - log.debug(`Building content type UID set from ${this.ctSchema.length} content types`, this.config.auditContext); - this.ctSchema.map((ct) => this.ctUidSet.add(ct.uid)); - log.debug(`Content type UID set contains: ${Array.from(this.ctUidSet).join(', ')}`, this.config.auditContext); + // Create progress manager if we have a total count + if (totalCount && totalCount > 0) { + const progress = this.createSimpleProgress(this.moduleName, totalCount); + progress.updateStatus('Validating extensions...'); + } - log.debug(`Processing ${this.extensionsSchema.length} extensions`, this.config.auditContext); - for (const ext of this.extensionsSchema) { + log.debug(`Processing ${this.extensionsSchema.length} extensions`, this.config.auditContext); + for (const ext of this.extensionsSchema) { const { title, uid, scope } = ext; log.debug(`Processing extension: ${title} (${uid})`, this.config.auditContext); log.debug(`Extension scope content types: ${scope?.content_types?.join(', ') || 'none'}`, this.config.auditContext); @@ -124,24 +133,35 @@ export default class Extensions { }), this.config.auditContext ); + + // Track progress for each extension processed + if (this.progressManager) { + this.progressManager.tick(true, `extension: ${title}`, null); + } } - log.debug(`Extensions audit completed. Found ${this.missingCtInExtensions.length} extensions with missing content types`, this.config.auditContext); - log.debug(`Total missing content types: ${this.missingCts.size}`, this.config.auditContext); + log.debug(`Extensions audit completed. Found ${this.missingCtInExtensions.length} extensions with missing content types`, this.config.auditContext); + log.debug(`Total missing content types: ${this.missingCts.size}`, this.config.auditContext); - if (this.fix && this.missingCtInExtensions.length) { - log.debug(`Fix mode enabled, fixing ${this.missingCtInExtensions.length} extensions`, this.config.auditContext); - await this.fixExtensionsScope(cloneDeep(this.missingCtInExtensions)); - this.missingCtInExtensions.forEach((ext) => { - log.debug(`Marking extension ${ext.title} as fixed`, this.config.auditContext); - ext.fixStatus = 'Fixed'; - }); - log.debug(`Extensions fix completed`, this.config.auditContext); + if (this.fix && this.missingCtInExtensions.length) { + log.debug(`Fix mode enabled, fixing ${this.missingCtInExtensions.length} extensions`, this.config.auditContext); + await this.fixExtensionsScope(cloneDeep(this.missingCtInExtensions)); + this.missingCtInExtensions.forEach((ext) => { + log.debug(`Marking extension ${ext.title} as fixed`, this.config.auditContext); + ext.fixStatus = 'Fixed'; + }); + log.debug(`Extensions fix completed`, this.config.auditContext); + this.completeProgress(true); + return this.missingCtInExtensions; + } + + log.debug(`Extensions audit completed without fixes`, this.config.auditContext); + this.completeProgress(true); return this.missingCtInExtensions; + } catch (error: any) { + this.completeProgress(false, error?.message || 'Extensions audit failed'); + throw error; } - - log.debug(`Extensions audit completed without fixes`, this.config.auditContext); - return this.missingCtInExtensions; } async fixExtensionsScope(missingCtInExtensions: Extension[]) { diff --git a/packages/contentstack-audit/src/modules/field_rules.ts b/packages/contentstack-audit/src/modules/field_rules.ts index 07e52de0dc..f56e4f1e8c 100644 --- a/packages/contentstack-audit/src/modules/field_rules.ts +++ b/packages/contentstack-audit/src/modules/field_rules.ts @@ -5,7 +5,6 @@ import { existsSync, readFileSync, writeFileSync } from 'fs'; import { FsUtility, Locale, sanitizePath, cliux, log } from '@contentstack/cli-utilities'; import { - ConfigType, ModularBlockType, ContentTypeStruct, GroupFieldDataType, @@ -20,13 +19,13 @@ import auditConfig from '../config'; import { $t, auditFixMsg, auditMsg, commonMsg } from '../messages'; import { MarketplaceAppsInstallationData } from '../types/extension'; import { values } from 'lodash'; +import BaseClass from './base-class'; -/* The `ContentType` class is responsible for scanning content types, looking for references, and +/* The `FieldRule` class is responsible for scanning field rules, looking for references, and generating a report in JSON and CSV formats. */ -export default class FieldRule { +export default class FieldRule extends BaseClass { protected fix: boolean; public fileName: string; - public config: ConfigType; public folderPath: string; public currentUid!: string; public currentTitle!: string; @@ -46,7 +45,7 @@ export default class FieldRule { public entryMetaData: Record[] = []; public action: string[] = ['show', 'hide']; constructor({ fix, config, moduleName, ctSchema, gfSchema }: ModuleConstructorParam & CtConstructorParam) { - this.config = config; + super({ config }); this.fix = fix ?? false; this.ctSchema = ctSchema; this.gfSchema = gfSchema; @@ -90,31 +89,42 @@ export default class FieldRule { * iterates over the schema and looks for references, and returns a list of missing references. * @returns the `missingRefs` object. */ - async run() { - log.debug(`Starting ${this.moduleName} field rules audit process`, this.config.auditContext); - log.debug(`Field rules folder path: ${this.folderPath}`, this.config.auditContext); - log.debug(`Fix mode: ${this.fix}`, this.config.auditContext); - - if (!existsSync(this.folderPath)) { - log.debug(`Skipping ${this.moduleName} audit - path does not exist`, this.config.auditContext); - log.warn(`Skipping ${this.moduleName} audit`, this.config.auditContext); - cliux.print($t(auditMsg.NOT_VALID_PATH, { path: this.folderPath }), { color: 'yellow' }); - return {}; - } + async run(totalCount?: number) { + try { + log.debug(`Starting ${this.moduleName} field rules audit process`, this.config.auditContext); + log.debug(`Field rules folder path: ${this.folderPath}`, this.config.auditContext); + log.debug(`Fix mode: ${this.fix}`, this.config.auditContext); + + if (!existsSync(this.folderPath)) { + log.debug(`Skipping ${this.moduleName} audit - path does not exist`, this.config.auditContext); + log.warn(`Skipping ${this.moduleName} audit`, this.config.auditContext); + cliux.print($t(auditMsg.NOT_VALID_PATH, { path: this.folderPath }), { color: 'yellow' }); + return {}; + } - this.schema = this.moduleName === 'content-types' ? this.ctSchema : this.gfSchema; - log.debug(`Using ${this.moduleName} schema with ${this.schema?.length || 0} items`, this.config.auditContext); - - log.debug(`Loading prerequisite data`, this.config.auditContext); - await this.prerequisiteData(); - log.debug(`Loaded ${this.extensions.length} extensions`, this.config.auditContext); - - log.debug(`Preparing entry metadata`, this.config.auditContext); - await this.prepareEntryMetaData(); - log.debug(`Prepared metadata for ${this.entryMetaData.length} entries`, this.config.auditContext); - - log.debug(`Processing ${this.schema?.length || 0} schemas for field rules`, this.config.auditContext); - for (const schema of this.schema ?? []) { + this.schema = this.moduleName === 'content-types' ? this.ctSchema : this.gfSchema; + log.debug(`Using ${this.moduleName} schema with ${this.schema?.length || 0} items`, this.config.auditContext); + + // Load prerequisite data with loading spinner + await this.withLoadingSpinner('FIELD-RULES: Loading prerequisite data...', async () => { + await this.prerequisiteData(); + }); + log.debug(`Loaded ${this.extensions.length} extensions`, this.config.auditContext); + + // Prepare entry metadata with loading spinner + await this.withLoadingSpinner('FIELD-RULES: Preparing entry metadata...', async () => { + await this.prepareEntryMetaData(); + }); + log.debug(`Prepared metadata for ${this.entryMetaData.length} entries`, this.config.auditContext); + + // Create progress manager if we have a total count + if (totalCount && totalCount > 0) { + const progress = this.createSimpleProgress(this.moduleName, totalCount); + progress.updateStatus('Validating field rules...'); + } + + log.debug(`Processing ${this.schema?.length || 0} schemas for field rules`, this.config.auditContext); + for (const schema of this.schema ?? []) { this.currentUid = schema.uid; this.currentTitle = schema.title; this.missingRefs[this.currentUid] = []; @@ -144,21 +154,27 @@ export default class FieldRule { ); } - if (this.fix) { - log.debug(`Fix mode enabled, writing fix content`, this.config.auditContext); - await this.writeFixContent(); - } + if (this.fix) { + log.debug(`Fix mode enabled, writing fix content`, this.config.auditContext); + await this.writeFixContent(); + } - log.debug(`Cleaning up empty missing references`, this.config.auditContext); - for (let propName in this.missingRefs) { - if (!this.missingRefs[propName].length) { - log.debug(`Removing empty missing references for: ${propName}`, this.config.auditContext); - delete this.missingRefs[propName]; + log.debug(`Cleaning up empty missing references`, this.config.auditContext); + for (let propName in this.missingRefs) { + if (!this.missingRefs[propName].length) { + log.debug(`Removing empty missing references for: ${propName}`, this.config.auditContext); + delete this.missingRefs[propName]; + } } - } - log.debug(`Field rules audit completed. Found ${Object.keys(this.missingRefs).length} schemas with issues`, this.config.auditContext); - return this.missingRefs; + log.debug(`Field rules audit completed. Found ${Object.keys(this.missingRefs).length} schemas with issues`, this.config.auditContext); + + this.completeProgress(true); + return this.missingRefs; + } catch (error: any) { + this.completeProgress(false, error?.message || 'Field rules audit failed'); + throw error; + } } validateFieldRules(schema: Record): void { diff --git a/packages/contentstack-audit/src/modules/global-fields.ts b/packages/contentstack-audit/src/modules/global-fields.ts index 75ec2c24cf..71d3e5b553 100644 --- a/packages/contentstack-audit/src/modules/global-fields.ts +++ b/packages/contentstack-audit/src/modules/global-fields.ts @@ -6,15 +6,17 @@ export default class GlobalField extends ContentType { /** * The above function is an asynchronous function that runs a validation and returns any missing * references. + * @param returnFixSchema - If true, returns the fixed schema instead of missing references + * @param totalCount - Total number of items to process (for progress tracking) * @returns the value of the variable `missingRefs`. */ - async run(returnFixSchema = false) { + async run(returnFixSchema = false, totalCount?: number) { log.debug(`Starting GlobalField audit process`, this.config.auditContext); log.debug(`Return fix schema: ${returnFixSchema}`, this.config.auditContext); // NOTE add any validation if required log.debug(`Calling parent ContentType.run() method`, this.config.auditContext); - const missingRefs = await super.run(returnFixSchema); + const missingRefs = await super.run(returnFixSchema, totalCount); log.debug(`Parent method completed, found ${Object.keys(missingRefs || {}).length} missing references`, this.config.auditContext); log.debug(`GlobalField audit completed`, this.config.auditContext); diff --git a/packages/contentstack-audit/src/modules/index.ts b/packages/contentstack-audit/src/modules/index.ts index c76eca4a72..b9665abad7 100644 --- a/packages/contentstack-audit/src/modules/index.ts +++ b/packages/contentstack-audit/src/modules/index.ts @@ -7,5 +7,6 @@ import CustomRoles from './custom-roles'; import Assets from './assets'; import FieldRule from './field_rules'; import ModuleDataReader from './modulesData'; +import BaseClass from './base-class'; -export { Entries, GlobalField, ContentType, Workflows, Extensions, Assets, CustomRoles, FieldRule, ModuleDataReader }; +export { Entries, GlobalField, ContentType, Workflows, Extensions, Assets, CustomRoles, FieldRule, ModuleDataReader, BaseClass }; diff --git a/packages/contentstack-audit/src/modules/workflows.ts b/packages/contentstack-audit/src/modules/workflows.ts index f38783699a..69ebda0af7 100644 --- a/packages/contentstack-audit/src/modules/workflows.ts +++ b/packages/contentstack-audit/src/modules/workflows.ts @@ -1,17 +1,17 @@ import { join, resolve } from 'path'; import { existsSync, readFileSync, writeFileSync } from 'fs'; import { cloneDeep } from 'lodash'; -import { ConfigType, ContentTypeStruct, CtConstructorParam, ModuleConstructorParam, Workflow } from '../types'; +import { ContentTypeStruct, CtConstructorParam, ModuleConstructorParam, Workflow } from '../types'; import { cliux, sanitizePath, log } from '@contentstack/cli-utilities'; import auditConfig from '../config'; import { $t, auditMsg, commonMsg } from '../messages'; import { values } from 'lodash'; +import BaseClass from './base-class'; -export default class Workflows { +export default class Workflows extends BaseClass { protected fix: boolean; public fileName: any; - public config: ConfigType; public folderPath: string; public workflowSchema: Workflow[]; public ctSchema: ContentTypeStruct[]; @@ -28,7 +28,7 @@ export default class Workflows { moduleName, ctSchema, }: ModuleConstructorParam & Pick) { - this.config = config; + super({ config }); this.fix = fix ?? false; this.ctSchema = ctSchema; this.workflowSchema = []; @@ -78,30 +78,38 @@ export default class Workflows { * From the ctSchema add all the content type UID into ctUidSet to check whether the content-type is present or not * @returns Array of object containing the workflow name, uid and content_types that are missing */ - async run() { - - if (!existsSync(this.folderPath)) { - log.debug(`Skipping ${this.moduleName} audit - path does not exist`, this.config.auditContext); - log.warn(`Skipping ${this.moduleName} audit`, this.config.auditContext); - cliux.print($t(auditMsg.NOT_VALID_PATH, { path: this.folderPath }), { color: 'yellow' }); - return {}; - } + async run(totalCount?: number) { + try { + if (!existsSync(this.folderPath)) { + log.debug(`Skipping ${this.moduleName} audit - path does not exist`, this.config.auditContext); + log.warn(`Skipping ${this.moduleName} audit`, this.config.auditContext); + cliux.print($t(auditMsg.NOT_VALID_PATH, { path: this.folderPath }), { color: 'yellow' }); + return {}; + } - this.workflowPath = join(this.folderPath, this.fileName); - log.debug(`Workflows file path: ${this.workflowPath}`, this.config.auditContext); + this.workflowPath = join(this.folderPath, this.fileName); + log.debug(`Workflows file path: ${this.workflowPath}`, this.config.auditContext); - log.debug(`Loading workflows schema from file`, this.config.auditContext); - this.workflowSchema = existsSync(this.workflowPath) - ? values(JSON.parse(readFileSync(this.workflowPath, 'utf8')) as Workflow[]) - : []; - log.debug(`Loaded ${this.workflowSchema.length} workflows`, this.config.auditContext); + // Load workflows schema with loading spinner + await this.withLoadingSpinner('WORKFLOWS: Loading workflows schema...', async () => { + this.workflowSchema = existsSync(this.workflowPath) + ? values(JSON.parse(readFileSync(this.workflowPath, 'utf8')) as Workflow[]) + : []; + }); + log.debug(`Loaded ${this.workflowSchema.length} workflows`, this.config.auditContext); + + log.debug(`Building content type UID set from ${this.ctSchema.length} content types`, this.config.auditContext); + this.ctSchema.forEach((ct) => this.ctUidSet.add(ct.uid)); + log.debug(`Content type UID set contains: ${Array.from(this.ctUidSet).join(', ')}`, this.config.auditContext); - log.debug(`Building content type UID set from ${this.ctSchema.length} content types`, this.config.auditContext); - this.ctSchema.forEach((ct) => this.ctUidSet.add(ct.uid)); - log.debug(`Content type UID set contains: ${Array.from(this.ctUidSet).join(', ')}`, this.config.auditContext); + // Create progress manager if we have a total count + if (totalCount && totalCount > 0) { + const progress = this.createSimpleProgress(this.moduleName, totalCount); + progress.updateStatus('Validating workflows...'); + } - log.debug(`Processing ${this.workflowSchema.length} workflows`, this.config.auditContext); - for (const workflow of this.workflowSchema) { + log.debug(`Processing ${this.workflowSchema.length} workflows`, this.config.auditContext); + for (const workflow of this.workflowSchema) { const { name, uid } = workflow; log.debug(`Processing workflow: ${name} (${uid})`, this.config.auditContext); log.debug(`Workflow content types: ${workflow.content_types?.join(', ') || 'none'}`, this.config.auditContext); @@ -152,23 +160,29 @@ export default class Workflows { ); } - log.debug(`Workflows audit completed. Found ${this.missingCtInWorkflows.length} workflows with issues`, this.config.auditContext); - log.debug(`Total missing content types: ${this.missingCts.size}`, this.config.auditContext); - log.debug(`Branch fix needed: ${this.isBranchFixDone}`, this.config.auditContext); + log.debug(`Workflows audit completed. Found ${this.missingCtInWorkflows.length} workflows with issues`, this.config.auditContext); + log.debug(`Total missing content types: ${this.missingCts.size}`, this.config.auditContext); + log.debug(`Branch fix needed: ${this.isBranchFixDone}`, this.config.auditContext); - if (this.fix && (this.missingCtInWorkflows.length || this.isBranchFixDone)) { - log.debug(`Fix mode enabled, fixing ${this.missingCtInWorkflows.length} workflows`, this.config.auditContext); - await this.fixWorkflowSchema(); - this.missingCtInWorkflows.forEach((wf) => { - log.debug(`Marking workflow ${wf.name} as fixed`, this.config.auditContext); - wf.fixStatus = 'Fixed'; - }); - log.debug(`Workflows fix completed`, this.config.auditContext); + if (this.fix && (this.missingCtInWorkflows.length || this.isBranchFixDone)) { + log.debug(`Fix mode enabled, fixing ${this.missingCtInWorkflows.length} workflows`, this.config.auditContext); + await this.fixWorkflowSchema(); + this.missingCtInWorkflows.forEach((wf) => { + log.debug(`Marking workflow ${wf.name} as fixed`, this.config.auditContext); + wf.fixStatus = 'Fixed'; + }); + log.debug(`Workflows fix completed`, this.config.auditContext); + this.completeProgress(true); + return this.missingCtInWorkflows; + } + + log.debug(`Workflows audit completed without fixes`, this.config.auditContext); + this.completeProgress(true); return this.missingCtInWorkflows; + } catch (error: any) { + this.completeProgress(false, error?.message || 'Workflows audit failed'); + throw error; } - - log.debug(`Workflows audit completed without fixes`, this.config.auditContext); - return this.missingCtInWorkflows; } async fixWorkflowSchema() { 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 255d47f02b..bffaf1bfd2 100644 --- a/packages/contentstack-audit/test/unit/audit-base-command.test.ts +++ b/packages/contentstack-audit/test/unit/audit-base-command.test.ts @@ -5,7 +5,7 @@ import { resolve } from 'path'; import { fancy } from 'fancy-test'; import { PassThrough } from 'stream'; import { expect } from 'chai'; -import { ux, cliux } from '@contentstack/cli-utilities'; +import { ux, cliux, CLIProgressManager, configHandler, clearProgressModuleSetting } from '@contentstack/cli-utilities'; import { AuditBaseCommand } from '../../src/audit-base-command'; import { @@ -370,4 +370,246 @@ describe('AuditBaseCommand class', () => { }); }); }); + + describe('Progress Manager Integration', () => { + let configHandlerStub: sinon.SinonStub; + let initializeGlobalSummarySpy: sinon.SinonSpy; + let printGlobalSummarySpy: sinon.SinonSpy; + + beforeEach(() => { + // Mock CLIProgressManager static methods + initializeGlobalSummarySpy = sinon.spy(CLIProgressManager, 'initializeGlobalSummary'); + printGlobalSummarySpy = sinon.spy(CLIProgressManager, 'printGlobalSummary'); + + // Mock configHandler + configHandlerStub = sinon.stub(configHandler, 'get').returns({}); + sinon.stub(configHandler, 'set'); + }); + + afterEach(() => { + try { + if (initializeGlobalSummarySpy && typeof initializeGlobalSummarySpy.restore === 'function') { + initializeGlobalSummarySpy.restore(); + } + } catch (e) { + // Ignore + } + + try { + if (printGlobalSummarySpy && typeof printGlobalSummarySpy.restore === 'function') { + printGlobalSummarySpy.restore(); + } + } catch (e) { + // Ignore + } + + try { + if (configHandlerStub && typeof configHandlerStub.restore === 'function') { + configHandlerStub.restore(); + } + } catch (e) { + // Ignore + } + + try { + CLIProgressManager.clearGlobalSummary(); + clearProgressModuleSetting(); + } catch (e) { + // Ignore + } + + try { + sinon.restore(); + } catch (e) { + // Ignore + } + }); + + fancy + .stdout({ print: process.env.PRINT === 'true' || false }) + .stub(winston.transports, 'File', () => fsTransport) + .stub(winston, 'createLogger', createMockWinstonLogger) + .stub(fs, 'mkdirSync', () => {}) + .stub(fs, 'writeFileSync', () => {}) + .stub(cliux, 'table', () => {}) + .stub(ux.action, 'stop', () => {}) + .stub(ux.action, 'start', () => {}) + .stub(cliux, 'inquire', () => resolve(__dirname, 'mock', 'contents')) + .stub(AuditBaseCommand.prototype, 'scanAndFix', () => ({ + missingCtRefs: {}, + missingGfRefs: {}, + missingEntryRefs: {}, + missingCtRefsInExtensions: {}, + missingCtRefsInWorkflow: {}, + missingSelectFeild: {}, + missingMandatoryFields: {}, + missingTitleFields: {}, + missingRefInCustomRoles: {}, + missingEnvLocalesInAssets: {}, + missingEnvLocalesInEntries: {}, + missingFieldRules: {}, + missingMultipleFields: {}, + })) + .stub(AuditBaseCommand.prototype, 'showOutputOnScreenWorkflowsAndExtension', () => {}) + .stub(fs, 'createWriteStream', () => new PassThrough()) + .it('should initialize global summary when start is called', async () => { + await AuditCMD.run(['--data-dir', resolve(__dirname, 'mock', 'contents')]); + + expect(initializeGlobalSummarySpy.calledOnce).to.be.true; + expect(initializeGlobalSummarySpy.calledWith('AUDIT', '', 'Auditing content...')).to.be.true; + }); + + fancy + .stdout({ print: process.env.PRINT === 'true' || false }) + .stub(winston.transports, 'File', () => fsTransport) + .stub(winston, 'createLogger', createMockWinstonLogger) + .stub(fs, 'mkdirSync', () => {}) + .stub(fs, 'writeFileSync', () => {}) + .stub(cliux, 'table', () => {}) + .stub(ux.action, 'stop', () => {}) + .stub(ux.action, 'start', () => {}) + .stub(cliux, 'inquire', () => resolve(__dirname, 'mock', 'contents')) + .stub(AuditBaseCommand.prototype, 'scanAndFix', () => ({ + missingCtRefs: {}, + missingGfRefs: {}, + missingEntryRefs: {}, + missingCtRefsInExtensions: {}, + missingCtRefsInWorkflow: {}, + missingSelectFeild: {}, + missingMandatoryFields: {}, + missingTitleFields: {}, + missingRefInCustomRoles: {}, + missingEnvLocalesInAssets: {}, + missingEnvLocalesInEntries: {}, + missingFieldRules: {}, + missingMultipleFields: {}, + })) + .stub(AuditBaseCommand.prototype, 'showOutputOnScreenWorkflowsAndExtension', () => {}) + .stub(fs, 'createWriteStream', () => new PassThrough()) + .it('should print global summary at the end of start method', async () => { + await AuditCMD.run(['--data-dir', resolve(__dirname, 'mock', 'contents')]); + + expect(printGlobalSummarySpy.calledOnce).to.be.true; + }); + + }); + + describe('Spinner Message Conditional Display', () => { + let printSpy: sinon.SinonSpy | undefined; + let configHandlerGetStub: sinon.SinonStub | undefined; + + beforeEach(() => { + // Clear any existing global summary + CLIProgressManager.clearGlobalSummary(); + + // Import print function from the correct path + const logModule = require('../../src/util/log'); + printSpy = sinon.spy(logModule, 'print'); + configHandlerGetStub = sinon.stub(configHandler, 'get'); + }); + + afterEach(() => { + try { + // Clear global summary first + CLIProgressManager.clearGlobalSummary(); + } catch (e) { + // Ignore errors + } + + try { + if (printSpy) { + printSpy.restore(); + } + } catch (e) { + // Ignore errors + } + + try { + if (configHandlerGetStub) { + configHandlerGetStub.restore(); + } + } catch (e) { + // Ignore errors + } + + try { + // Restore all sinon stubs + sinon.restore(); + } catch (e) { + // Ignore errors + } + }); + + fancy + .stdout({ print: process.env.PRINT === 'true' || false }) + .stub(winston.transports, 'File', () => fsTransport) + .stub(winston, 'createLogger', createMockWinstonLogger) + .stub(fs, 'mkdirSync', () => {}) + .stub(fs, 'writeFileSync', () => {}) + .stub(cliux, 'table', () => {}) + .stub(ux.action, 'stop', () => {}) + .stub(ux.action, 'start', () => {}) + .stub(cliux, 'inquire', () => resolve(__dirname, 'mock', 'contents')) + .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(Workflows.prototype, 'run', () => ({ wf_1: {} })) + .stub(CustomRoles.prototype, 'run', () => ({ cr_1: {} })) + .stub(Assets.prototype, 'run', () => ({ assets_1: {} })) + .stub(FieldRule.prototype, 'run', () => ({ fr_1: {} })) + .stub(AuditBaseCommand.prototype, 'showOutputOnScreenWorkflowsAndExtension', () => {}) + .stub(fs, 'createWriteStream', () => new PassThrough()) + .it('should hide spinner messages when showConsoleLogs is false', async function() { + this.timeout(5000); // Set timeout to 5 seconds + if (!configHandlerGetStub || !printSpy) { + throw new Error('Spies not initialized'); + } + configHandlerGetStub.returns({ showConsoleLogs: false }); + await AuditCMD.run(['--data-dir', resolve(__dirname, 'mock', 'contents')]); + + // Print should not be called for spinner messages when showConsoleLogs is false + const printCalls = printSpy.getCalls(); + const spinnerCalls = printCalls.filter((call: any) => + call.args[0]?.[0]?.message?.includes('scanning') + ); + expect(spinnerCalls.length).to.equal(0); + }); + + fancy + .stdout({ print: process.env.PRINT === 'true' || false }) + .stub(winston.transports, 'File', () => fsTransport) + .stub(winston, 'createLogger', createMockWinstonLogger) + .stub(fs, 'mkdirSync', () => {}) + .stub(fs, 'writeFileSync', () => {}) + .stub(cliux, 'table', () => {}) + .stub(ux.action, 'stop', () => {}) + .stub(ux.action, 'start', () => {}) + .stub(cliux, 'inquire', () => resolve(__dirname, 'mock', 'contents')) + .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(Workflows.prototype, 'run', () => ({ wf_1: {} })) + .stub(CustomRoles.prototype, 'run', () => ({ cr_1: {} })) + .stub(Assets.prototype, 'run', () => ({ assets_1: {} })) + .stub(FieldRule.prototype, 'run', () => ({ fr_1: {} })) + .stub(AuditBaseCommand.prototype, 'showOutputOnScreenWorkflowsAndExtension', () => {}) + .stub(fs, 'createWriteStream', () => new PassThrough()) + .it('should show spinner messages when showConsoleLogs is true', async function() { + this.timeout(5000); // Set timeout to 5 seconds + if (!configHandlerGetStub || !printSpy) { + throw new Error('Spies not initialized'); + } + configHandlerGetStub.returns({ showConsoleLogs: true }); + await AuditCMD.run(['--data-dir', resolve(__dirname, 'mock', 'contents')]); + + // Print should be called for spinner messages when showConsoleLogs is true + const printCalls = printSpy.getCalls(); + const spinnerCalls = printCalls.filter((call: any) => + call.args[0]?.[0]?.message?.includes('scanning') + ); + expect(spinnerCalls.length).to.be.greaterThan(0); + }); + }); }); diff --git a/packages/contentstack-audit/test/unit/modules/base-class.test.ts b/packages/contentstack-audit/test/unit/modules/base-class.test.ts new file mode 100644 index 0000000000..dc0b5563c8 --- /dev/null +++ b/packages/contentstack-audit/test/unit/modules/base-class.test.ts @@ -0,0 +1,328 @@ +import { expect } from 'chai'; +import { fancy } from 'fancy-test'; +import sinon from 'sinon'; +import { resolve } from 'node:path'; +import { CLIProgressManager, configHandler } from '@contentstack/cli-utilities'; + +import config from '../../../src/config'; +import BaseClass from '../../../src/modules/base-class'; +import { ModuleConstructorParam } from '../../../src/types'; +import { mockLogger } from '../mock-logger'; + +// Mock ora and cli-progress to prevent real spinners/progress bars +const mockOraInstance = { + start: sinon.stub().returnsThis(), + stop: sinon.stub().returnsThis(), + succeed: sinon.stub().returnsThis(), + fail: sinon.stub().returnsThis(), + text: '', + color: 'cyan', + isSpinning: false, +}; + +const mockOra = sinon.stub().returns(mockOraInstance); +(mockOra as any).promise = sinon.stub().returns(mockOraInstance); + +const mockProgressBar = { + start: sinon.stub(), + stop: sinon.stub(), + increment: sinon.stub(), + update: sinon.stub(), +}; + +const mockMultiBar = { + create: sinon.stub().returns(mockProgressBar), + stop: sinon.stub(), +}; + +// Mock require to intercept ora and cli-progress +const Module = require('node:module'); +const originalRequire = Module.prototype.require; +Module.prototype.require = function (id: string) { + if (id === 'ora') { + return mockOra; + } + if (id === 'cli-progress') { + return { + SingleBar: function() { return mockProgressBar; }, + MultiBar: function() { return mockMultiBar; }, + Presets: { shades_classic: {} } + }; + } + return originalRequire.apply(this, arguments); +}; + +describe('BaseClass Progress Manager', () => { + class TestBaseClass extends BaseClass { + public testCreateSimpleProgress(moduleName: string, total?: number) { + return this.createSimpleProgress(moduleName, total); + } + + public testCreateNestedProgress(moduleName: string) { + return this.createNestedProgress(moduleName); + } + + public async testWithLoadingSpinner(message: string, action: () => Promise): Promise { + return this.withLoadingSpinner(message, action); + } + + public testCompleteProgress(success: boolean = true, error?: string) { + return this.completeProgress(success, error); + } + } + + let testInstance: TestBaseClass; + let constructorParam: ModuleConstructorParam; + + beforeEach(() => { + constructorParam = { + config: Object.assign(config, { + basePath: resolve(__dirname, '..', 'mock', 'contents'), + flags: {}, + auditContext: { + command: 'cm:stacks:audit', + module: 'test', + email: '', + sessionId: '', + authenticationMethod: '', + } + }), + }; + + // Mock the logger + sinon.stub(require('@contentstack/cli-utilities'), 'log').value(mockLogger); + + // Reset config + configHandler.set('log', {}); + + testInstance = new TestBaseClass(constructorParam); + }); + + afterEach(() => { + try { + // Complete any running progress managers + if (testInstance && testInstance['progressManager']) { + testInstance['progressManager'].stop(); + testInstance['progressManager'] = null; + } + } catch (e) { + // Ignore + } + + try { + // Stop mock ora instance + if (mockOraInstance.stop) { + mockOraInstance.stop(); + } + + // Quick console cleanup + if (process.stdout && process.stdout.clearLine) { + process.stdout.clearLine(0); + process.stdout.cursorTo(0); + process.stdout.write('\x1b[?25h\x1b[0m'); + } + } catch (e) { + // Ignore + } + + try { + CLIProgressManager.clearGlobalSummary(); + } catch (e) { + // Ignore + } + + sinon.restore(); + Module.prototype.require = originalRequire; + }); + + describe('createSimpleProgress', () => { + fancy.it('should create simple progress manager with total count', () => { + const progress = testInstance.testCreateSimpleProgress('test-module', 100); + expect(progress).to.be.instanceOf(CLIProgressManager); + expect(testInstance['progressManager']).to.equal(progress); + expect(testInstance['currentModuleName']).to.equal('test-module'); + + // Clean up + try { + progress.stop(); + testInstance['progressManager'] = null; + } catch (e) { + // Ignore + } + }); + + fancy.it('should create simple progress manager without total count', () => { + const progress = testInstance.testCreateSimpleProgress('test-module'); + expect(progress).to.be.instanceOf(CLIProgressManager); + expect(testInstance['progressManager']).to.equal(progress); + + // Clean up + try { + progress.stop(); + testInstance['progressManager'] = null; + } catch (e) { + // Ignore + } + }); + + fancy.it('should respect showConsoleLogs setting from config', () => { + configHandler.set('log.showConsoleLogs', true); + const progress1 = testInstance.testCreateSimpleProgress('test-module', 100); + expect(progress1).to.be.instanceOf(CLIProgressManager); + + configHandler.set('log.showConsoleLogs', false); + const progress2 = testInstance.testCreateSimpleProgress('test-module-2', 100); + expect(progress2).to.be.instanceOf(CLIProgressManager); + + // Clean up + try { + progress1.stop(); + progress2.stop(); + testInstance['progressManager'] = null; + } catch (e) { + // Ignore + } + }); + + fancy.it('should default showConsoleLogs to false when not set', () => { + configHandler.set('log', {}); + const progress = testInstance.testCreateSimpleProgress('test-module', 100); + expect(progress).to.be.instanceOf(CLIProgressManager); + + // Clean up + try { + progress.stop(); + testInstance['progressManager'] = null; + } catch (e) { + // Ignore + } + }); + }); + + describe('createNestedProgress', () => { + fancy.it('should create nested progress manager', () => { + const progress = testInstance.testCreateNestedProgress('test-module'); + expect(progress).to.be.instanceOf(CLIProgressManager); + expect(testInstance['progressManager']).to.equal(progress); + expect(testInstance['currentModuleName']).to.equal('test-module'); + + // Clean up + try { + progress.stop(); + testInstance['progressManager'] = null; + } catch (e) { + // Ignore + } + }); + + fancy.it('should respect showConsoleLogs setting from config', () => { + configHandler.set('log.showConsoleLogs', false); + const progress = testInstance.testCreateNestedProgress('test-module'); + expect(progress).to.be.instanceOf(CLIProgressManager); + + // Clean up + try { + progress.stop(); + testInstance['progressManager'] = null; + } catch (e) { + // Ignore + } + }); + }); + + describe('withLoadingSpinner', () => { + fancy.it('should execute action directly when showConsoleLogs is true', async () => { + configHandler.set('log.showConsoleLogs', true); + const action = sinon.stub().resolves('result'); + + const result = await testInstance.testWithLoadingSpinner('Loading...', action); + + expect(result).to.equal('result'); + expect(action.calledOnce).to.be.true; + expect(mockOra.called).to.be.false; + }); + + fancy.it('should use spinner when showConsoleLogs is false', async () => { + configHandler.set('log.showConsoleLogs', false); + const action = sinon.stub().resolves('result'); + + const result = await testInstance.testWithLoadingSpinner('Loading...', action); + + expect(result).to.equal('result'); + expect(action.calledOnce).to.be.true; + }); + + fancy.it('should handle errors in action', async () => { + configHandler.set('log.showConsoleLogs', true); + const error = new Error('Test error'); + const action = sinon.stub().rejects(error); + + try { + await testInstance.testWithLoadingSpinner('Loading...', action); + expect.fail('Should have thrown error'); + } catch (e: any) { + expect(e).to.equal(error); + } + }); + }); + + describe('completeProgress', () => { + fancy.it('should complete progress successfully', () => { + const progress = testInstance.testCreateSimpleProgress('test-module', 100); + const completeSpy = sinon.spy(progress, 'complete'); + + testInstance.testCompleteProgress(true); + + expect(completeSpy.calledOnce).to.be.true; + expect(completeSpy.calledWith(true)).to.be.true; + expect(testInstance['progressManager']).to.be.null; + + // Ensure progress is stopped + try { + progress.stop(); + } catch (e) { + // Ignore + } + }); + + fancy.it('should complete progress with error', () => { + const progress = testInstance.testCreateSimpleProgress('test-module', 100); + const completeSpy = sinon.spy(progress, 'complete'); + + testInstance.testCompleteProgress(false, 'Test error'); + + expect(completeSpy.calledOnce).to.be.true; + expect(completeSpy.calledWith(false, 'Test error')).to.be.true; + expect(testInstance['progressManager']).to.be.null; + + // Ensure progress is stopped + try { + progress.stop(); + } catch (e) { + // Ignore + } + }); + + fancy.it('should handle completion when no progress manager exists', () => { + expect(() => testInstance.testCompleteProgress(true)).to.not.throw(); + }); + }); + + // Global after hook to ensure all spinners are cleaned up + after(() => { + try { + CLIProgressManager.clearGlobalSummary(); + if (mockOraInstance.stop) { + mockOraInstance.stop(); + } + if (process.stdout && process.stdout.clearLine) { + process.stdout.clearLine(0); + process.stdout.cursorTo(0); + process.stdout.write('\x1b[?25h\x1b[0m'); + } + } catch (e) { + // Ignore cleanup errors + } + }); +}); + diff --git a/packages/contentstack-utilities/src/constants/logging.ts b/packages/contentstack-utilities/src/constants/logging.ts index ac2e09eecc..f3bfb3267f 100644 --- a/packages/contentstack-utilities/src/constants/logging.ts +++ b/packages/contentstack-utilities/src/constants/logging.ts @@ -16,4 +16,4 @@ export const levelColors = { debug: 'blue', }; -export const PROGRESS_SUPPORTED_MODULES = ['export', 'import','import-setup'] as const; +export const PROGRESS_SUPPORTED_MODULES = ['export', 'import', 'audit', 'import-setup'] as const; diff --git a/packages/contentstack/package.json b/packages/contentstack/package.json index 0444c16c4e..8bdcb9b553 100755 --- a/packages/contentstack/package.json +++ b/packages/contentstack/package.json @@ -22,7 +22,7 @@ "prepack": "pnpm compile && oclif manifest && oclif readme" }, "dependencies": { - "@contentstack/cli-audit": "~1.16.0", + "@contentstack/cli-audit": "~2.0.0-beta.0", "@contentstack/cli-auth": "~1.6.2", "@contentstack/cli-cm-bootstrap": "~2.0.0-beta.2", "@contentstack/cli-cm-branches": "~1.6.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9f99a14628..7d12817fdd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,7 +12,7 @@ importers: packages/contentstack: specifiers: - '@contentstack/cli-audit': ~1.16.0 + '@contentstack/cli-audit': ~2.0.0-beta.0 '@contentstack/cli-auth': ~1.6.2 '@contentstack/cli-cm-bootstrap': ~2.0.0-beta.2 '@contentstack/cli-cm-branches': ~1.6.1 @@ -71,7 +71,7 @@ importers: uuid: ^9.0.1 winston: ^3.17.0 dependencies: - '@contentstack/cli-audit': 1.16.1_debug@4.4.3 + '@contentstack/cli-audit': link:../contentstack-audit '@contentstack/cli-auth': link:../contentstack-auth '@contentstack/cli-cm-bootstrap': link:../contentstack-bootstrap '@contentstack/cli-cm-branches': link:../contentstack-branches