@contentstack/cli-audit 1.6.5 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -19,7 +19,7 @@ $ npm install -g @contentstack/cli-audit
19
19
  $ csdx COMMAND
20
20
  running command...
21
21
  $ csdx (--version|-v)
22
- @contentstack/cli-audit/1.6.5 linux-x64 node-v18.20.4
22
+ @contentstack/cli-audit/1.7.1 linux-x64 node-v18.20.4
23
23
  $ csdx --help [COMMAND]
24
24
  USAGE
25
25
  $ csdx COMMAND
@@ -52,12 +52,13 @@ Perform audits and find possible errors in the exported Contentstack data
52
52
 
53
53
  ```
54
54
  USAGE
55
- $ csdx audit [--report-path <value>] [--modules content-types|global-fields|entries|extensions|workflows]
56
- [--columns <value> | ] [--sort <value>] [--filter <value>] [--csv | --no-truncate]
55
+ $ csdx audit [--report-path <value>] [--modules
56
+ content-types|global-fields|entries|extensions|workflows|custom-roles] [--columns <value> | ] [--sort <value>]
57
+ [--filter <value>] [--csv | --no-truncate]
57
58
 
58
59
  FLAGS
59
60
  --modules=<option>... Provide the list of modules to be audited
60
- <options: content-types|global-fields|entries|extensions|workflows>
61
+ <options: content-types|global-fields|entries|extensions|workflows|custom-roles>
61
62
  --report-path=<value> Path to store the audit reports
62
63
 
63
64
  TABLE FLAGS
@@ -92,8 +93,8 @@ Perform audits and fix possible errors in the exported Contentstack data.
92
93
 
93
94
  ```
94
95
  USAGE
95
- $ csdx audit:fix [--report-path <value>] [--modules content-types|global-fields|entries|extensions|workflows]
96
- [--copy-path <value> --copy-dir] [--fix-only
96
+ $ csdx audit:fix [--report-path <value>] [--modules
97
+ content-types|global-fields|entries|extensions|workflows|custom-roles] [--copy-path <value> --copy-dir] [--fix-only
97
98
  reference|global_field|json:rte|json:extension|blocks|group|content_types] [--columns <value> | ] [--sort <value>]
98
99
  [--filter <value>] [--csv | --no-truncate]
99
100
 
@@ -103,7 +104,7 @@ FLAGS
103
104
  --fix-only=<option>... Provide the list of fix options
104
105
  <options: reference|global_field|json:rte|json:extension|blocks|group|content_types>
105
106
  --modules=<option>... Provide the list of modules to be audited
106
- <options: content-types|global-fields|entries|extensions|workflows>
107
+ <options: content-types|global-fields|entries|extensions|workflows|custom-roles>
107
108
  --report-path=<value> Path to store the audit reports
108
109
 
109
110
  TABLE FLAGS
@@ -140,12 +141,13 @@ Perform audits and find possible errors in the exported Contentstack data
140
141
 
141
142
  ```
142
143
  USAGE
143
- $ csdx cm:stacks:audit [--report-path <value>] [--modules content-types|global-fields|entries|extensions|workflows]
144
- [--columns <value> | ] [--sort <value>] [--filter <value>] [--csv | --no-truncate]
144
+ $ csdx cm:stacks:audit [--report-path <value>] [--modules
145
+ content-types|global-fields|entries|extensions|workflows|custom-roles] [--columns <value> | ] [--sort <value>]
146
+ [--filter <value>] [--csv | --no-truncate]
145
147
 
146
148
  FLAGS
147
149
  --modules=<option>... Provide the list of modules to be audited
148
- <options: content-types|global-fields|entries|extensions|workflows>
150
+ <options: content-types|global-fields|entries|extensions|workflows|custom-roles>
149
151
  --report-path=<value> Path to store the audit reports
150
152
 
151
153
  TABLE FLAGS
@@ -182,8 +184,8 @@ Perform audits and fix possible errors in the exported Contentstack data.
182
184
 
183
185
  ```
184
186
  USAGE
185
- $ csdx cm:stacks:audit:fix [--report-path <value>] [--modules content-types|global-fields|entries|extensions|workflows]
186
- [--copy-path <value> --copy-dir] [--fix-only
187
+ $ csdx cm:stacks:audit:fix [--report-path <value>] [--modules
188
+ content-types|global-fields|entries|extensions|workflows|custom-roles] [--copy-path <value> --copy-dir] [--fix-only
187
189
  reference|global_field|json:rte|json:extension|blocks|group|content_types] [--columns <value> | ] [--sort <value>]
188
190
  [--filter <value>] [--csv | --no-truncate]
189
191
 
@@ -193,7 +195,7 @@ FLAGS
193
195
  --fix-only=<option>... Provide the list of fix options
194
196
  <options: reference|global_field|json:rte|json:extension|blocks|group|content_types>
195
197
  --modules=<option>... Provide the list of modules to be audited
196
- <options: content-types|global-fields|entries|extensions|workflows>
198
+ <options: content-types|global-fields|entries|extensions|workflows|custom-roles>
197
199
  --report-path=<value> Path to store the audit reports
198
200
 
199
201
  TABLE FLAGS
@@ -267,7 +269,7 @@ EXAMPLES
267
269
  $ csdx plugins
268
270
  ```
269
271
 
270
- _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.2/src/commands/plugins/index.ts)_
272
+ _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.9/src/commands/plugins/index.ts)_
271
273
 
272
274
  ## `csdx plugins:add PLUGIN`
273
275
 
@@ -341,7 +343,7 @@ EXAMPLES
341
343
  $ csdx plugins:inspect myplugin
342
344
  ```
343
345
 
344
- _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.2/src/commands/plugins/inspect.ts)_
346
+ _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.9/src/commands/plugins/inspect.ts)_
345
347
 
346
348
  ## `csdx plugins:install PLUGIN`
347
349
 
@@ -390,7 +392,7 @@ EXAMPLES
390
392
  $ csdx plugins:install someuser/someplugin
391
393
  ```
392
394
 
393
- _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.2/src/commands/plugins/install.ts)_
395
+ _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.9/src/commands/plugins/install.ts)_
394
396
 
395
397
  ## `csdx plugins:link PATH`
396
398
 
@@ -420,7 +422,7 @@ EXAMPLES
420
422
  $ csdx plugins:link myplugin
421
423
  ```
422
424
 
423
- _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.2/src/commands/plugins/link.ts)_
425
+ _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.9/src/commands/plugins/link.ts)_
424
426
 
425
427
  ## `csdx plugins:remove [PLUGIN]`
426
428
 
@@ -461,7 +463,7 @@ FLAGS
461
463
  --reinstall Reinstall all plugins after uninstalling.
462
464
  ```
463
465
 
464
- _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.2/src/commands/plugins/reset.ts)_
466
+ _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.9/src/commands/plugins/reset.ts)_
465
467
 
466
468
  ## `csdx plugins:uninstall [PLUGIN]`
467
469
 
@@ -489,7 +491,7 @@ EXAMPLES
489
491
  $ csdx plugins:uninstall myplugin
490
492
  ```
491
493
 
492
- _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.2/src/commands/plugins/uninstall.ts)_
494
+ _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.9/src/commands/plugins/uninstall.ts)_
493
495
 
494
496
  ## `csdx plugins:unlink [PLUGIN]`
495
497
 
@@ -533,5 +535,5 @@ DESCRIPTION
533
535
  Update installed plugins.
534
536
  ```
535
537
 
536
- _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.2/src/commands/plugins/update.ts)_
538
+ _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.9/src/commands/plugins/update.ts)_
537
539
  <!-- commandsstop -->
@@ -31,6 +31,8 @@ export declare abstract class AuditBaseCommand extends BaseCommand<typeof AuditB
31
31
  missingCtRefsInWorkflow: {} | undefined;
32
32
  missingSelectFeild: Record<string, any> | undefined;
33
33
  missingMandatoryFields: Record<string, any> | undefined;
34
+ missingTitleFields: Record<string, any> | undefined;
35
+ missingRefInCustomRoles: {} | undefined;
34
36
  }>;
35
37
  /**
36
38
  * The `promptQueue` function prompts the user to enter a data directory path if the `data-dir` flag
@@ -17,6 +17,7 @@ const messages_1 = require("./messages");
17
17
  const base_command_1 = require("./base-command");
18
18
  const modules_1 = require("./modules");
19
19
  const types_1 = require("./types");
20
+ const custom_roles_1 = tslib_1.__importDefault(require("./modules/custom-roles"));
20
21
  class AuditBaseCommand extends base_command_1.BaseCommand {
21
22
  get fixStatus() {
22
23
  return {
@@ -40,7 +41,7 @@ class AuditBaseCommand extends base_command_1.BaseCommand {
40
41
  await this.promptQueue();
41
42
  await this.createBackUp();
42
43
  this.sharedConfig.reportPath = (0, path_1.resolve)(this.flags['report-path'] || process.cwd(), 'audit-report');
43
- const { missingCtRefs, missingGfRefs, missingEntryRefs, missingCtRefsInExtensions, missingCtRefsInWorkflow, missingSelectFeild, missingMandatoryFields, } = await this.scanAndFix();
44
+ const { missingCtRefs, missingGfRefs, missingEntryRefs, missingCtRefsInExtensions, missingCtRefsInWorkflow, missingSelectFeild, missingMandatoryFields, missingTitleFields, missingRefInCustomRoles } = await this.scanAndFix();
44
45
  this.showOutputOnScreen([
45
46
  { module: 'Content types', missingRefs: missingCtRefs },
46
47
  { module: 'Global Fields', missingRefs: missingGfRefs },
@@ -52,12 +53,18 @@ class AuditBaseCommand extends base_command_1.BaseCommand {
52
53
  this.showOutputOnScreenWorkflowsAndExtension([
53
54
  { module: 'Entries Mandatory Field', missingRefs: missingMandatoryFields },
54
55
  ]);
56
+ this.showOutputOnScreenWorkflowsAndExtension([
57
+ { module: 'Entries Title Field', missingRefs: missingTitleFields },
58
+ ]);
59
+ this.showOutputOnScreenWorkflowsAndExtension([{ module: 'Custom Roles', missingRefs: missingRefInCustomRoles }]);
55
60
  if (!(0, isEmpty_1.default)(missingCtRefs) ||
56
61
  !(0, isEmpty_1.default)(missingGfRefs) ||
57
62
  !(0, isEmpty_1.default)(missingEntryRefs) ||
58
63
  !(0, isEmpty_1.default)(missingCtRefsInWorkflow) ||
59
64
  !(0, isEmpty_1.default)(missingCtRefsInExtensions) ||
60
- !(0, isEmpty_1.default)(missingSelectFeild)) {
65
+ !(0, isEmpty_1.default)(missingSelectFeild) ||
66
+ !(0, isEmpty_1.default)(missingTitleFields) ||
67
+ !(0, isEmpty_1.default)(missingRefInCustomRoles)) {
61
68
  if (this.currentCommand === 'cm:stacks:audit') {
62
69
  this.log(this.$t(messages_1.auditMsg.FINAL_REPORT_PATH, { path: this.sharedConfig.reportPath }), 'warn');
63
70
  }
@@ -80,7 +87,8 @@ class AuditBaseCommand extends base_command_1.BaseCommand {
80
87
  !(0, isEmpty_1.default)(missingEntryRefs) ||
81
88
  !(0, isEmpty_1.default)(missingCtRefsInWorkflow) ||
82
89
  !(0, isEmpty_1.default)(missingCtRefsInExtensions) ||
83
- !(0, isEmpty_1.default)(missingSelectFeild));
90
+ !(0, isEmpty_1.default)(missingSelectFeild) ||
91
+ !(0, isEmpty_1.default)(missingRefInCustomRoles));
84
92
  }
85
93
  /**
86
94
  * The `scan` function performs an audit on different modules (content-types, global-fields, and
@@ -89,9 +97,9 @@ class AuditBaseCommand extends base_command_1.BaseCommand {
89
97
  * and `missingEntryRefs`.
90
98
  */
91
99
  async scanAndFix() {
92
- var _a, _b, _c;
100
+ var _a, _b, _c, _d;
93
101
  let { ctSchema, gfSchema } = this.getCtAndGfSchema();
94
- let missingCtRefs, missingGfRefs, missingEntryRefs, missingCtRefsInExtensions, missingCtRefsInWorkflow, missingSelectFeild, missingEntry, missingMandatoryFields;
102
+ let missingCtRefs, missingGfRefs, missingEntryRefs, missingCtRefsInExtensions, missingCtRefsInWorkflow, missingSelectFeild, missingEntry, missingMandatoryFields, missingTitleFields, missingRefInCustomRoles;
95
103
  for (const module of this.sharedConfig.flags.modules || this.sharedConfig.modules) {
96
104
  (0, log_1.print)([
97
105
  {
@@ -122,9 +130,11 @@ class AuditBaseCommand extends base_command_1.BaseCommand {
122
130
  missingEntryRefs = (_a = missingEntry.missingEntryRefs) !== null && _a !== void 0 ? _a : {};
123
131
  missingSelectFeild = (_b = missingEntry.missingSelectFeild) !== null && _b !== void 0 ? _b : {};
124
132
  missingMandatoryFields = (_c = missingEntry.missingMandatoryFields) !== null && _c !== void 0 ? _c : {};
133
+ missingTitleFields = (_d = missingEntry.missingTitleFields) !== null && _d !== void 0 ? _d : {};
125
134
  await this.prepareReport(module, missingEntryRefs);
126
135
  await this.prepareReport(`Entries_Select_feild`, missingSelectFeild);
127
136
  await this.prepareReport('Entries_Mandatory_feild', missingMandatoryFields);
137
+ await this.prepareReport('Entries_Title_feild', missingTitleFields);
128
138
  break;
129
139
  case 'workflows':
130
140
  missingCtRefsInWorkflow = await new modules_1.Workflows({
@@ -140,6 +150,10 @@ class AuditBaseCommand extends base_command_1.BaseCommand {
140
150
  missingCtRefsInExtensions = await new modules_1.Extensions((0, cloneDeep_1.default)(constructorParam)).run();
141
151
  await this.prepareReport(module, missingCtRefsInExtensions);
142
152
  break;
153
+ case 'custom-roles':
154
+ missingRefInCustomRoles = await new custom_roles_1.default((0, cloneDeep_1.default)(constructorParam)).run();
155
+ await this.prepareReport(module, missingRefInCustomRoles);
156
+ break;
143
157
  }
144
158
  (0, log_1.print)([
145
159
  {
@@ -162,6 +176,8 @@ class AuditBaseCommand extends base_command_1.BaseCommand {
162
176
  missingCtRefsInWorkflow,
163
177
  missingSelectFeild,
164
178
  missingMandatoryFields,
179
+ missingTitleFields,
180
+ missingRefInCustomRoles,
165
181
  };
166
182
  }
167
183
  /**
@@ -332,7 +348,7 @@ class AuditBaseCommand extends base_command_1.BaseCommand {
332
348
  * @returns The function `prepareCSV` returns a Promise that resolves to `void`.
333
349
  */
334
350
  prepareCSV(moduleName, listOfMissingRefs) {
335
- if (Object.keys(config_1.default.moduleConfig).includes(moduleName)) {
351
+ if (Object.keys(config_1.default.moduleConfig).includes(moduleName) || config_1.default.feild_level_modules.includes(moduleName)) {
336
352
  const csvPath = (0, path_1.join)((0, cli_utilities_1.sanitizePath)(this.sharedConfig.reportPath), `${(0, cli_utilities_1.sanitizePath)(moduleName)}.csv`);
337
353
  return new Promise((resolve, reject) => {
338
354
  // file deepcode ignore MissingClose: Will auto close once csv stream end
@@ -35,6 +35,11 @@ declare const config: {
35
35
  dirName: string;
36
36
  fileName: string;
37
37
  };
38
+ 'custom-roles': {
39
+ name: string;
40
+ dirName: string;
41
+ fileName: string;
42
+ };
38
43
  };
39
44
  entries: {
40
45
  systemKeys: string[];
@@ -43,6 +48,8 @@ declare const config: {
43
48
  ReportTitleForEntries: {
44
49
  Entries_Select_feild: string;
45
50
  Entries_Mandatory_feild: string;
51
+ Entries_Title_feild: string;
46
52
  };
53
+ feild_level_modules: string[];
47
54
  };
48
55
  export default config;
@@ -4,7 +4,7 @@ const config = {
4
4
  showTerminalOutput: true,
5
5
  skipRefs: ['sys_assets'],
6
6
  skipFieldTypes: ['taxonomy', 'group'],
7
- modules: ['content-types', 'global-fields', 'entries', 'extensions', 'workflows'],
7
+ modules: ['content-types', 'global-fields', 'entries', 'extensions', 'workflows', 'custom-roles'],
8
8
  'fix-fields': ['reference', 'global_field', 'json:rte', 'json:extension', 'blocks', 'group', 'content_types'],
9
9
  moduleConfig: {
10
10
  'content-types': {
@@ -37,6 +37,11 @@ const config = {
37
37
  dirName: 'extensions',
38
38
  fileName: 'extensions.json',
39
39
  },
40
+ 'custom-roles': {
41
+ name: 'custom-roles',
42
+ dirName: 'custom-roles',
43
+ fileName: 'custom-roles.json',
44
+ },
40
45
  },
41
46
  entries: {
42
47
  systemKeys: [
@@ -77,6 +82,8 @@ const config = {
77
82
  ReportTitleForEntries: {
78
83
  Entries_Select_feild: 'Entries_Select_feild',
79
84
  Entries_Mandatory_feild: 'Entries_Mandatory_feild',
85
+ Entries_Title_feild: 'Entries_Title_feild',
80
86
  },
87
+ feild_level_modules: ['Entries_Title_feild', 'Entries_Mandatory_feild', 'Entries_Select_feild'],
81
88
  };
82
89
  exports.default = config;
@@ -15,6 +15,7 @@ declare const commonMsg: {
15
15
  EXTENSION_FIX_WARN: string;
16
16
  EXTENSION_FIX_CONFIRMATION: string;
17
17
  WF_BRANCH_REMOVAL: string;
18
+ CR_BRANCH_REMOVAL: string;
18
19
  };
19
20
  declare const auditMsg: {
20
21
  REPORT_PATH: string;
@@ -30,6 +31,7 @@ declare const auditMsg: {
30
31
  SCAN_EXT_SUCCESS_MSG: string;
31
32
  AUDIT_CMD_DESCRIPTION: string;
32
33
  SCAN_WF_SUCCESS_MSG: string;
34
+ SCAN_CR_SUCCESS_MSG: string;
33
35
  };
34
36
  declare const auditFixMsg: {
35
37
  COPY_DATA: string;
@@ -22,6 +22,7 @@ const commonMsg = {
22
22
  EXTENSION_FIX_WARN: `The extension associated with UID {uid} and title '{title}' will be removed.`,
23
23
  EXTENSION_FIX_CONFIRMATION: `Would you like to overwrite existing file?`,
24
24
  WF_BRANCH_REMOVAL: `Removing the branch '{branch} from workflow with UID {uid} and name {name} will be removed.'`,
25
+ CR_BRANCH_REMOVAL: `Removing the branch '{branch} from custom role with UID {uid} and name {name} will be removed.'`,
25
26
  };
26
27
  exports.commonMsg = commonMsg;
27
28
  const auditMsg = {
@@ -38,6 +39,7 @@ const auditMsg = {
38
39
  SCAN_EXT_SUCCESS_MSG: "Successfully completed scanning the {module} titled '{title}' with UID '{uid}'",
39
40
  AUDIT_CMD_DESCRIPTION: 'Perform audits and find possible errors in the exported Contentstack data',
40
41
  SCAN_WF_SUCCESS_MSG: 'Successfully completed the scanning of workflow with UID {uid} and name {name}.',
42
+ SCAN_CR_SUCCESS_MSG: 'Successfully completed the scanning of custom role with UID {uid} and name {name}.',
41
43
  };
42
44
  exports.auditMsg = auditMsg;
43
45
  const auditFixMsg = {
@@ -0,0 +1,25 @@
1
+ import { LogFn, ConfigType, CtConstructorParam, ModuleConstructorParam, CustomRole } from '../types';
2
+ import auditConfig from '../config';
3
+ export default class CustomRoles {
4
+ log: LogFn;
5
+ protected fix: boolean;
6
+ fileName: any;
7
+ config: ConfigType;
8
+ folderPath: string;
9
+ customRoleSchema: CustomRole[];
10
+ moduleName: keyof typeof auditConfig.moduleConfig;
11
+ missingFieldsInCustomRoles: CustomRole[];
12
+ customRolePath: string;
13
+ isBranchFixDone: boolean;
14
+ constructor({ log, fix, config, moduleName }: ModuleConstructorParam & Pick<CtConstructorParam, 'ctSchema'>);
15
+ validateModules(moduleName: keyof typeof auditConfig.moduleConfig, moduleConfig: Record<string, unknown>): keyof typeof auditConfig.moduleConfig;
16
+ /**
17
+ * Check whether the given path for the custom role exists or not
18
+ * If path exist read
19
+ * From the ctSchema add all the content type UID into ctUidSet to check whether the content-type is present or not
20
+ * @returns Array of object containing the custom role name, uid and content_types that are missing
21
+ */
22
+ run(): Promise<{}>;
23
+ fixCustomRoleSchema(): Promise<void>;
24
+ writeFixContent(newCustomRoleSchema: Record<string, CustomRole>): Promise<void>;
25
+ }
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const path_1 = require("path");
4
+ const fs_1 = require("fs");
5
+ const lodash_1 = require("lodash");
6
+ const cli_utilities_1 = require("@contentstack/cli-utilities");
7
+ const messages_1 = require("../messages");
8
+ const lodash_2 = require("lodash");
9
+ class CustomRoles {
10
+ constructor({ log, fix, config, moduleName }) {
11
+ this.log = log;
12
+ this.config = config;
13
+ this.fix = fix !== null && fix !== void 0 ? fix : false;
14
+ this.customRoleSchema = [];
15
+ this.moduleName = this.validateModules(moduleName, this.config.moduleConfig);
16
+ this.fileName = config.moduleConfig[this.moduleName].fileName;
17
+ this.folderPath = (0, path_1.resolve)((0, cli_utilities_1.sanitizePath)(config.basePath), (0, cli_utilities_1.sanitizePath)(config.moduleConfig[this.moduleName].dirName));
18
+ this.missingFieldsInCustomRoles = [];
19
+ this.customRolePath = '';
20
+ this.isBranchFixDone = false;
21
+ }
22
+ validateModules(moduleName, moduleConfig) {
23
+ if (Object.keys(moduleConfig).includes(moduleName)) {
24
+ return moduleName;
25
+ }
26
+ return 'custom-roles';
27
+ }
28
+ /**
29
+ * Check whether the given path for the custom role exists or not
30
+ * If path exist read
31
+ * From the ctSchema add all the content type UID into ctUidSet to check whether the content-type is present or not
32
+ * @returns Array of object containing the custom role name, uid and content_types that are missing
33
+ */
34
+ async run() {
35
+ var _a, _b, _c, _d;
36
+ if (!(0, fs_1.existsSync)(this.folderPath)) {
37
+ this.log(`Skipping ${this.moduleName} audit`, 'warn');
38
+ this.log((0, messages_1.$t)(messages_1.auditMsg.NOT_VALID_PATH, { path: this.folderPath }), { color: 'yellow' });
39
+ return {};
40
+ }
41
+ this.customRolePath = (0, path_1.join)(this.folderPath, this.fileName);
42
+ this.customRoleSchema = (0, fs_1.existsSync)(this.customRolePath)
43
+ ? (0, lodash_2.values)(JSON.parse((0, fs_1.readFileSync)(this.customRolePath, 'utf8')))
44
+ : [];
45
+ for (let index = 0; index < ((_a = this.customRoleSchema) === null || _a === void 0 ? void 0 : _a.length); index++) {
46
+ const customRole = this.customRoleSchema[index];
47
+ let branchesToBeRemoved = [];
48
+ if ((_b = this.config) === null || _b === void 0 ? void 0 : _b.branch) {
49
+ (_c = customRole === null || customRole === void 0 ? void 0 : customRole.rules) === null || _c === void 0 ? void 0 : _c.filter((rule) => {
50
+ var _a;
51
+ if (rule.module === 'branch') {
52
+ branchesToBeRemoved = ((_a = rule === null || rule === void 0 ? void 0 : rule.branches) === null || _a === void 0 ? void 0 : _a.filter((branch) => { var _a; return branch !== ((_a = this.config) === null || _a === void 0 ? void 0 : _a.branch); })) || [];
53
+ }
54
+ });
55
+ }
56
+ if (branchesToBeRemoved === null || branchesToBeRemoved === void 0 ? void 0 : branchesToBeRemoved.length) {
57
+ this.isBranchFixDone = true;
58
+ const tempCR = (0, lodash_1.cloneDeep)(customRole);
59
+ if ((customRole === null || customRole === void 0 ? void 0 : customRole.rules) && ((_d = this.config) === null || _d === void 0 ? void 0 : _d.branch)) {
60
+ tempCR.rules.forEach((rule) => {
61
+ if (rule.module === 'branch') {
62
+ rule.branches = branchesToBeRemoved;
63
+ }
64
+ });
65
+ }
66
+ this.missingFieldsInCustomRoles.push(tempCR);
67
+ }
68
+ this.log((0, messages_1.$t)(messages_1.auditMsg.SCAN_CR_SUCCESS_MSG, {
69
+ name: customRole.name,
70
+ uid: customRole.uid,
71
+ }), 'info');
72
+ }
73
+ if (this.fix && (this.missingFieldsInCustomRoles.length || this.isBranchFixDone)) {
74
+ await this.fixCustomRoleSchema();
75
+ this.missingFieldsInCustomRoles.forEach((cr) => (cr.fixStatus = 'Fixed'));
76
+ }
77
+ return this.missingFieldsInCustomRoles;
78
+ }
79
+ async fixCustomRoleSchema() {
80
+ var _a;
81
+ const newCustomRoleSchema = (0, fs_1.existsSync)(this.customRolePath)
82
+ ? JSON.parse((0, fs_1.readFileSync)(this.customRolePath, 'utf8'))
83
+ : {};
84
+ if (Object.keys(newCustomRoleSchema).length === 0 || !((_a = this.customRoleSchema) === null || _a === void 0 ? void 0 : _a.length)) {
85
+ return;
86
+ }
87
+ this.customRoleSchema.forEach((customRole) => {
88
+ var _a, _b, _c, _d;
89
+ if (!this.config.branch)
90
+ return;
91
+ const fixedBranches = (_b = (_a = customRole.rules) === null || _a === void 0 ? void 0 : _a.filter((rule) => { var _a; return rule.module === 'branch' && ((_a = rule.branches) === null || _a === void 0 ? void 0 : _a.length); })) === null || _b === void 0 ? void 0 : _b.reduce((acc, rule) => {
92
+ var _a;
93
+ const relevantBranches = ((_a = rule.branches) === null || _a === void 0 ? void 0 : _a.filter((branch) => {
94
+ if (branch !== this.config.branch) {
95
+ this.log((0, messages_1.$t)(messages_1.commonMsg.CR_BRANCH_REMOVAL, {
96
+ uid: customRole.uid,
97
+ name: customRole.name,
98
+ branch,
99
+ }), { color: 'yellow' });
100
+ return false;
101
+ }
102
+ return true;
103
+ })) || [];
104
+ return [...acc, ...relevantBranches];
105
+ }, []);
106
+ if (fixedBranches === null || fixedBranches === void 0 ? void 0 : fixedBranches.length) {
107
+ (_d = (_c = newCustomRoleSchema[customRole.uid].rules) === null || _c === void 0 ? void 0 : _c.filter((rule) => rule.module === 'branch')) === null || _d === void 0 ? void 0 : _d.forEach((rule) => {
108
+ rule.branches = fixedBranches;
109
+ });
110
+ }
111
+ });
112
+ await this.writeFixContent(newCustomRoleSchema);
113
+ }
114
+ async writeFixContent(newCustomRoleSchema) {
115
+ var _a;
116
+ if (this.fix &&
117
+ (this.config.flags['copy-dir'] ||
118
+ ((_a = this.config.flags['external-config']) === null || _a === void 0 ? void 0 : _a.skipConfirm) ||
119
+ this.config.flags.yes ||
120
+ (await cli_utilities_1.ux.confirm(messages_1.commonMsg.FIX_CONFIRMATION)))) {
121
+ (0, fs_1.writeFileSync)((0, path_1.join)(this.folderPath, this.config.moduleConfig[this.moduleName].fileName), JSON.stringify(newCustomRoleSchema));
122
+ }
123
+ }
124
+ }
125
+ exports.default = CustomRoles;
@@ -16,6 +16,7 @@ export default class Entries {
16
16
  protected missingRefs: Record<string, any>;
17
17
  protected missingSelectFeild: Record<string, any>;
18
18
  protected missingMandatoryFields: Record<string, any>;
19
+ protected missingTitleFields: Record<string, any>;
19
20
  entryMetaData: Record<string, any>[];
20
21
  moduleName: keyof typeof auditConfig.moduleConfig;
21
22
  constructor({ log, fix, config, moduleName, ctSchema, gfSchema }: ModuleConstructorParam & CtConstructorParam);
@@ -29,10 +30,12 @@ export default class Entries {
29
30
  missingEntryRefs?: undefined;
30
31
  missingSelectFeild?: undefined;
31
32
  missingMandatoryFields?: undefined;
33
+ missingTitleFields?: undefined;
32
34
  } | {
33
35
  missingEntryRefs: Record<string, any>;
34
36
  missingSelectFeild: Record<string, any>;
35
37
  missingMandatoryFields: Record<string, any>;
38
+ missingTitleFields: Record<string, any>;
36
39
  }>;
37
40
  /**
38
41
  * The function removes any properties from the `missingRefs` object that have an empty array value.
@@ -18,6 +18,7 @@ class Entries {
18
18
  this.missingRefs = {};
19
19
  this.missingSelectFeild = {};
20
20
  this.missingMandatoryFields = {};
21
+ this.missingTitleFields = {};
21
22
  this.entryMetaData = [];
22
23
  this.moduleName = 'entries';
23
24
  this.log = log;
@@ -113,6 +114,7 @@ class Entries {
113
114
  missingEntryRefs: this.missingRefs,
114
115
  missingSelectFeild: this.missingSelectFeild,
115
116
  missingMandatoryFields: this.missingMandatoryFields,
117
+ missingTitleFields: this.missingTitleFields,
116
118
  };
117
119
  }
118
120
  /**
@@ -211,7 +213,7 @@ class Entries {
211
213
  }
212
214
  for (const child of (_a = field === null || field === void 0 ? void 0 : field.schema) !== null && _a !== void 0 ? _a : []) {
213
215
  const { uid } = child;
214
- this.missingMandatoryFields[this.currentUid].push(...this.validateMandatoryFields([...tree, { uid: field.uid, name: child.display_name, field: uid }], child, entry));
216
+ this.missingMandatoryFields[this.currentUid].push(...(this.validateMandatoryFields([...tree, { uid: field.uid, name: child.display_name, field: uid }], child, entry)));
215
217
  if (!(entry === null || entry === void 0 ? void 0 : entry[uid]) && !child.hasOwnProperty('display_type')) {
216
218
  continue;
217
219
  }
@@ -527,8 +529,8 @@ class Entries {
527
529
  * Else empty array
528
530
  */
529
531
  validateSelectField(tree, fieldStructure, field) {
530
- const { display_name, enum: selectOptions, multiple, min_instance, display_type } = fieldStructure;
531
- if (field === null || field === '' || (field === null || field === void 0 ? void 0 : field.length) === 0 || !field) {
532
+ const { display_name, enum: selectOptions, multiple, min_instance, display_type, data_type } = fieldStructure;
533
+ if (field === null || field === '' || (Array.isArray(field) && field.length === 0) || (!field && data_type !== 'number')) {
532
534
  let missingCTSelectFieldValues = 'Not Selected';
533
535
  return [
534
536
  {
@@ -661,13 +663,18 @@ class Entries {
661
663
  return jsonNode === '';
662
664
  };
663
665
  const isEntryEmpty = () => {
664
- var _a;
665
- const fieldValue = multiple ? (_a = entry[uid]) === null || _a === void 0 ? void 0 : _a.length : entry[uid];
666
+ var _a, _b;
667
+ let fieldValue = multiple ? (_a = entry[uid]) === null || _a === void 0 ? void 0 : _a.length : entry;
668
+ if (data_type === 'number' && !multiple) {
669
+ fieldValue = entry[uid] || entry[uid] === 0 ? true : false;
670
+ }
671
+ if (Array.isArray(entry[uid]) && data_type === 'reference') {
672
+ fieldValue = ((_b = entry[uid]) === null || _b === void 0 ? void 0 : _b.length) ? true : false;
673
+ }
666
674
  return fieldValue === '' || !fieldValue;
667
675
  };
668
676
  if (mandatory) {
669
- if ((data_type === 'json' && field_metadata.allow_json_rte && isJsonRteEmpty()) ||
670
- (!(data_type === 'json') && isEntryEmpty())) {
677
+ if ((data_type === 'json' && field_metadata.allow_json_rte && isJsonRteEmpty()) || isEntryEmpty()) {
671
678
  return [
672
679
  {
673
680
  uid: this.currentUid,
@@ -983,6 +990,11 @@ class Entries {
983
990
  for (const entryUid in entries) {
984
991
  let { title } = entries[entryUid];
985
992
  if (entries[entryUid].hasOwnProperty('title') && !title) {
993
+ this.missingTitleFields[entryUid] = {
994
+ 'Entry UID': entryUid,
995
+ 'Content Type UID': uid,
996
+ "Locale": code,
997
+ };
986
998
  this.log(`The 'title' field in Entry with UID '${entryUid}' of Content Type '${uid}' in Locale '${code}' is empty.`, `error`);
987
999
  }
988
1000
  else if (!title) {
@@ -100,6 +100,9 @@ declare enum OutputColumn {
100
100
  'MissingValues' = "missingCTSelectFieldValues",
101
101
  'Minimum Required Instaces' = "min_instance",
102
102
  'missingFieldUid' = "missingFieldUid",
103
- 'isPublished' = "isPublished"
103
+ 'isPublished' = "isPublished",
104
+ 'Entry UID' = "Entry UID",
105
+ 'Content Type UID' = "Content Type UID",
106
+ "Locale" = "Locale"
104
107
  }
105
108
  export { CtConstructorParam, ContentTypeStruct, ModuleConstructorParam, ReferenceFieldDataType, GlobalFieldDataType, ExtensionOrAppFieldDataType, JsonRTEFieldDataType, GroupFieldDataType, ModularBlocksDataType, RefErrorReturnType, ModularBlocksSchemaTypes, ModularBlockType, OutputColumn, ContentTypeSchemaType, GlobalFieldSchemaTypes, WorkflowExtensionsRefErrorReturnType, SelectFeildStruct, };
@@ -17,5 +17,8 @@ var OutputColumn;
17
17
  OutputColumn["Minimum Required Instaces"] = "min_instance";
18
18
  OutputColumn["missingFieldUid"] = "missingFieldUid";
19
19
  OutputColumn["isPublished"] = "isPublished";
20
+ OutputColumn["Entry UID"] = "Entry UID";
21
+ OutputColumn["Content Type UID"] = "Content Type UID";
22
+ OutputColumn["Locale"] = "Locale";
20
23
  })(OutputColumn || (OutputColumn = {}));
21
24
  exports.OutputColumn = OutputColumn;
@@ -0,0 +1,76 @@
1
+ export interface CustomRole {
2
+ name: string;
3
+ description: string;
4
+ rules: Rule[];
5
+ users: string[];
6
+ uid: string;
7
+ created_by: string;
8
+ updated_by: string;
9
+ created_at: string;
10
+ updated_at: string;
11
+ owner: string;
12
+ stack: Stack;
13
+ permissions: Permissions;
14
+ SYS_ACL: Record<string, unknown>;
15
+ fixStatus?: string;
16
+ missingRefs?: any;
17
+ }
18
+ export interface Rule {
19
+ module: string;
20
+ environments?: string[];
21
+ locales?: string[];
22
+ branches?: string[];
23
+ acl: ACL;
24
+ }
25
+ interface ACL {
26
+ read: boolean;
27
+ }
28
+ interface Stack {
29
+ created_at: string;
30
+ updated_at: string;
31
+ uid: string;
32
+ name: string;
33
+ org_uid: string;
34
+ api_key: string;
35
+ master_locale: string;
36
+ is_asset_download_public: boolean;
37
+ owner_uid: string;
38
+ user_uids: string[];
39
+ settings: Settings;
40
+ master_key: string;
41
+ }
42
+ interface Settings {
43
+ version: string;
44
+ rte_version: number;
45
+ blockAuthQueryParams: boolean;
46
+ allowedCDNTokens: string[];
47
+ branches: boolean;
48
+ localesOptimization: boolean;
49
+ webhook_enabled: boolean;
50
+ stack_variables: Record<string, unknown>;
51
+ live_preview: Record<string, unknown>;
52
+ discrete_variables: DiscreteVariables;
53
+ language_fallback: boolean;
54
+ }
55
+ interface DiscreteVariables {
56
+ cms: boolean;
57
+ _version: number;
58
+ secret_key: string;
59
+ }
60
+ interface Permissions {
61
+ content_types: ContentType[];
62
+ environments: string[];
63
+ locales: Locale[];
64
+ }
65
+ interface ContentType {
66
+ uid: string;
67
+ SYS_ACL: SysACL;
68
+ }
69
+ interface SysACL {
70
+ sub_acl: Record<string, unknown>;
71
+ }
72
+ interface Locale {
73
+ uid: string;
74
+ SYS_ACL: ACL;
75
+ }
76
+ export {};
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -4,3 +4,4 @@ export * from './entries';
4
4
  export * from './content-types';
5
5
  export * from './workflow';
6
6
  export * from './extensions';
7
+ export * from './custom-role';
@@ -7,3 +7,4 @@ tslib_1.__exportStar(require("./entries"), exports);
7
7
  tslib_1.__exportStar(require("./content-types"), exports);
8
8
  tslib_1.__exportStar(require("./workflow"), exports);
9
9
  tslib_1.__exportStar(require("./extensions"), exports);
10
+ tslib_1.__exportStar(require("./custom-role"), exports);
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.6.5",
2
+ "version": "1.7.1",
3
3
  "commands": {
4
4
  "cm:stacks:audit:fix": {
5
5
  "id": "cm:stacks:audit:fix",
@@ -45,7 +45,8 @@
45
45
  "global-fields",
46
46
  "entries",
47
47
  "extensions",
48
- "workflows"
48
+ "workflows",
49
+ "custom-roles"
49
50
  ]
50
51
  },
51
52
  "copy-dir": {
@@ -183,7 +184,8 @@
183
184
  "global-fields",
184
185
  "entries",
185
186
  "extensions",
186
- "workflows"
187
+ "workflows",
188
+ "custom-roles"
187
189
  ]
188
190
  },
189
191
  "columns": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentstack/cli-audit",
3
- "version": "1.6.5",
3
+ "version": "1.7.1",
4
4
  "description": "Contentstack audit plugin",
5
5
  "author": "Contentstack CLI",
6
6
  "homepage": "https://github.com/contentstack/cli",
@@ -18,8 +18,8 @@
18
18
  "/oclif.manifest.json"
19
19
  ],
20
20
  "dependencies": {
21
- "@contentstack/cli-command": "~1.2.19",
22
- "@contentstack/cli-utilities": "~1.7.1",
21
+ "@contentstack/cli-command": "~1.3.0",
22
+ "@contentstack/cli-utilities": "~1.7.2",
23
23
  "@oclif/plugin-help": "^5",
24
24
  "@oclif/plugin-plugins": "^5.0.0",
25
25
  "chalk": "^4.1.2",
@@ -45,7 +45,7 @@
45
45
  "nyc": "^15.1.0",
46
46
  "oclif": "^3",
47
47
  "shx": "^0.3.4",
48
- "sinon": "^17.0.0",
48
+ "sinon": "^19.0.0",
49
49
  "ts-jest": "^29.1.1",
50
50
  "ts-node": "^10.9.1",
51
51
  "tslib": "^2.5.3",