@contentstack/cli-audit 1.17.0 → 2.0.0-beta.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/LICENSE +1 -1
- package/README.md +10 -431
- package/lib/audit-base-command.d.ts +4 -1
- package/lib/audit-base-command.js +85 -54
- package/lib/commands/cm/stacks/audit/fix.d.ts +0 -1
- package/lib/commands/cm/stacks/audit/fix.js +0 -1
- package/lib/commands/cm/stacks/audit/index.d.ts +0 -1
- package/lib/commands/cm/stacks/audit/index.js +0 -1
- package/lib/config/index.d.ts +0 -5
- package/lib/config/index.js +9 -16
- package/lib/messages/index.d.ts +0 -1
- package/lib/messages/index.js +1 -2
- package/lib/modules/assets.d.ts +6 -4
- package/lib/modules/assets.js +51 -30
- package/lib/modules/base-class.d.ts +24 -0
- package/lib/modules/base-class.js +54 -0
- package/lib/modules/content-types.d.ts +6 -4
- package/lib/modules/content-types.js +62 -40
- package/lib/modules/custom-roles.d.ts +4 -4
- package/lib/modules/custom-roles.js +82 -61
- package/lib/modules/entries.d.ts +5 -4
- package/lib/modules/entries.js +190 -168
- package/lib/modules/extensions.d.ts +4 -4
- package/lib/modules/extensions.js +78 -58
- package/lib/modules/field_rules.d.ts +4 -4
- package/lib/modules/field_rules.js +69 -52
- package/lib/modules/global-fields.d.ts +3 -1
- package/lib/modules/global-fields.js +4 -2
- package/lib/modules/index.d.ts +2 -2
- package/lib/modules/index.js +3 -3
- package/lib/modules/modulesData.js +8 -17
- package/lib/modules/workflows.d.ts +4 -4
- package/lib/modules/workflows.js +85 -68
- package/lib/types/content-types.d.ts +1 -2
- package/lib/types/content-types.js +0 -1
- package/lib/types/context.d.ts +5 -0
- package/oclif.manifest.json +5 -13
- package/package.json +4 -6
- package/lib/modules/composable-studio.d.ts +0 -40
- package/lib/modules/composable-studio.js +0 -307
- package/lib/types/composable-studio.d.ts +0 -25
- package/lib/types/composable-studio.js +0 -2
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Locale } from '@contentstack/cli-utilities';
|
|
2
|
-
import {
|
|
2
|
+
import { ModularBlockType, ContentTypeStruct, GroupFieldDataType, CtConstructorParam, GlobalFieldDataType, ModularBlocksDataType, ModuleConstructorParam, EntryStruct } from '../types';
|
|
3
3
|
import auditConfig from '../config';
|
|
4
|
-
|
|
4
|
+
import BaseClass from './base-class';
|
|
5
|
+
export default class FieldRule extends BaseClass {
|
|
5
6
|
protected fix: boolean;
|
|
6
7
|
fileName: string;
|
|
7
|
-
config: ConfigType;
|
|
8
8
|
folderPath: string;
|
|
9
9
|
currentUid: string;
|
|
10
10
|
currentTitle: string;
|
|
@@ -30,7 +30,7 @@ export default class FieldRule {
|
|
|
30
30
|
* iterates over the schema and looks for references, and returns a list of missing references.
|
|
31
31
|
* @returns the `missingRefs` object.
|
|
32
32
|
*/
|
|
33
|
-
run(): Promise<Record<string, any>>;
|
|
33
|
+
run(totalCount?: number): Promise<Record<string, any>>;
|
|
34
34
|
validateFieldRules(schema: Record<string, unknown>): void;
|
|
35
35
|
fixFieldRules(schema: Record<string, unknown>): void;
|
|
36
36
|
addMissingReferences(actions: Record<string, unknown>, fixStatus?: string): void;
|
|
@@ -7,10 +7,12 @@ const fs_1 = require("fs");
|
|
|
7
7
|
const cli_utilities_1 = require("@contentstack/cli-utilities");
|
|
8
8
|
const messages_1 = require("../messages");
|
|
9
9
|
const lodash_1 = require("lodash");
|
|
10
|
-
|
|
10
|
+
const base_class_1 = tslib_1.__importDefault(require("./base-class"));
|
|
11
|
+
/* The `FieldRule` class is responsible for scanning field rules, looking for references, and
|
|
11
12
|
generating a report in JSON and CSV formats. */
|
|
12
|
-
class FieldRule {
|
|
13
|
+
class FieldRule extends base_class_1.default {
|
|
13
14
|
constructor({ fix, config, moduleName, ctSchema, gfSchema }) {
|
|
15
|
+
super({ config });
|
|
14
16
|
this.extensions = [];
|
|
15
17
|
this.inMemoryFix = false;
|
|
16
18
|
this.schema = [];
|
|
@@ -21,7 +23,6 @@ class FieldRule {
|
|
|
21
23
|
this.missingEnvLocale = {};
|
|
22
24
|
this.entryMetaData = [];
|
|
23
25
|
this.action = ['show', 'hide'];
|
|
24
|
-
this.config = config;
|
|
25
26
|
this.fix = fix !== null && fix !== void 0 ? fix : false;
|
|
26
27
|
this.ctSchema = ctSchema;
|
|
27
28
|
this.gfSchema = gfSchema;
|
|
@@ -52,61 +53,77 @@ class FieldRule {
|
|
|
52
53
|
* iterates over the schema and looks for references, and returns a list of missing references.
|
|
53
54
|
* @returns the `missingRefs` object.
|
|
54
55
|
*/
|
|
55
|
-
async run() {
|
|
56
|
+
async run(totalCount) {
|
|
56
57
|
var _a, _b, _c;
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
cli_utilities_1.log.debug(`
|
|
85
|
-
this.
|
|
58
|
+
try {
|
|
59
|
+
cli_utilities_1.log.debug(`Starting ${this.moduleName} field rules audit process`, this.config.auditContext);
|
|
60
|
+
cli_utilities_1.log.debug(`Field rules folder path: ${this.folderPath}`, this.config.auditContext);
|
|
61
|
+
cli_utilities_1.log.debug(`Fix mode: ${this.fix}`, this.config.auditContext);
|
|
62
|
+
if (!(0, fs_1.existsSync)(this.folderPath)) {
|
|
63
|
+
cli_utilities_1.log.debug(`Skipping ${this.moduleName} audit - path does not exist`, this.config.auditContext);
|
|
64
|
+
cli_utilities_1.log.warn(`Skipping ${this.moduleName} audit`, this.config.auditContext);
|
|
65
|
+
cli_utilities_1.cliux.print((0, messages_1.$t)(messages_1.auditMsg.NOT_VALID_PATH, { path: this.folderPath }), { color: 'yellow' });
|
|
66
|
+
return {};
|
|
67
|
+
}
|
|
68
|
+
this.schema = this.moduleName === 'content-types' ? this.ctSchema : this.gfSchema;
|
|
69
|
+
cli_utilities_1.log.debug(`Using ${this.moduleName} schema with ${((_a = this.schema) === null || _a === void 0 ? void 0 : _a.length) || 0} items`, this.config.auditContext);
|
|
70
|
+
// Load prerequisite data with loading spinner
|
|
71
|
+
await this.withLoadingSpinner('FIELD-RULES: Loading prerequisite data...', async () => {
|
|
72
|
+
await this.prerequisiteData();
|
|
73
|
+
});
|
|
74
|
+
cli_utilities_1.log.debug(`Loaded ${this.extensions.length} extensions`, this.config.auditContext);
|
|
75
|
+
// Prepare entry metadata with loading spinner
|
|
76
|
+
await this.withLoadingSpinner('FIELD-RULES: Preparing entry metadata...', async () => {
|
|
77
|
+
await this.prepareEntryMetaData();
|
|
78
|
+
});
|
|
79
|
+
cli_utilities_1.log.debug(`Prepared metadata for ${this.entryMetaData.length} entries`, this.config.auditContext);
|
|
80
|
+
// Create progress manager if we have a total count
|
|
81
|
+
if (totalCount && totalCount > 0) {
|
|
82
|
+
const progress = this.createSimpleProgress(this.moduleName, totalCount);
|
|
83
|
+
progress.updateStatus('Validating field rules...');
|
|
84
|
+
}
|
|
85
|
+
cli_utilities_1.log.debug(`Processing ${((_b = this.schema) === null || _b === void 0 ? void 0 : _b.length) || 0} schemas for field rules`, this.config.auditContext);
|
|
86
|
+
for (const schema of (_c = this.schema) !== null && _c !== void 0 ? _c : []) {
|
|
87
|
+
this.currentUid = schema.uid;
|
|
88
|
+
this.currentTitle = schema.title;
|
|
89
|
+
this.missingRefs[this.currentUid] = [];
|
|
90
|
+
const { uid, title } = schema;
|
|
91
|
+
cli_utilities_1.log.debug(`Processing schema: ${title} (${uid})`, this.config.auditContext);
|
|
92
|
+
cli_utilities_1.log.debug(`Field rules count: ${Array.isArray(schema.field_rules) ? schema.field_rules.length : 0}`, this.config.auditContext);
|
|
93
|
+
cli_utilities_1.log.debug(`Looking for references in schema: ${title}`, this.config.auditContext);
|
|
94
|
+
await this.lookForReference([{ uid, name: title }], schema, null);
|
|
95
|
+
cli_utilities_1.log.debug(`Schema map contains ${this.schemaMap.length} field references`, this.config.auditContext);
|
|
96
|
+
this.missingRefs[this.currentUid] = [];
|
|
97
|
+
if (this.fix) {
|
|
98
|
+
cli_utilities_1.log.debug(`Fixing field rules for schema: ${title}`, this.config.auditContext);
|
|
99
|
+
this.fixFieldRules(schema);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
cli_utilities_1.log.debug(`Validating field rules for schema: ${title}`, this.config.auditContext);
|
|
103
|
+
this.validateFieldRules(schema);
|
|
104
|
+
}
|
|
105
|
+
this.schemaMap = [];
|
|
106
|
+
cli_utilities_1.log.info((0, messages_1.$t)(messages_1.auditMsg.SCAN_CT_SUCCESS_MSG, { title, module: this.config.moduleConfig[this.moduleName].name }), this.config.auditContext);
|
|
107
|
+
}
|
|
86
108
|
if (this.fix) {
|
|
87
|
-
cli_utilities_1.log.debug(`
|
|
88
|
-
this.
|
|
109
|
+
cli_utilities_1.log.debug(`Fix mode enabled, writing fix content`, this.config.auditContext);
|
|
110
|
+
await this.writeFixContent();
|
|
89
111
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
this.
|
|
112
|
+
cli_utilities_1.log.debug(`Cleaning up empty missing references`, this.config.auditContext);
|
|
113
|
+
for (let propName in this.missingRefs) {
|
|
114
|
+
if (!this.missingRefs[propName].length) {
|
|
115
|
+
cli_utilities_1.log.debug(`Removing empty missing references for: ${propName}`, this.config.auditContext);
|
|
116
|
+
delete this.missingRefs[propName];
|
|
117
|
+
}
|
|
93
118
|
}
|
|
94
|
-
this.
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
if (this.fix) {
|
|
98
|
-
cli_utilities_1.log.debug(`Fix mode enabled, writing fix content`, this.config.auditContext);
|
|
99
|
-
await this.writeFixContent();
|
|
119
|
+
cli_utilities_1.log.debug(`Field rules audit completed. Found ${Object.keys(this.missingRefs).length} schemas with issues`, this.config.auditContext);
|
|
120
|
+
this.completeProgress(true);
|
|
121
|
+
return this.missingRefs;
|
|
100
122
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
cli_utilities_1.log.debug(`Removing empty missing references for: ${propName}`, this.config.auditContext);
|
|
105
|
-
delete this.missingRefs[propName];
|
|
106
|
-
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
this.completeProgress(false, (error === null || error === void 0 ? void 0 : error.message) || 'Field rules audit failed');
|
|
125
|
+
throw error;
|
|
107
126
|
}
|
|
108
|
-
cli_utilities_1.log.debug(`Field rules audit completed. Found ${Object.keys(this.missingRefs).length} schemas with issues`, this.config.auditContext);
|
|
109
|
-
return this.missingRefs;
|
|
110
127
|
}
|
|
111
128
|
validateFieldRules(schema) {
|
|
112
129
|
cli_utilities_1.log.debug(`Validating field rules for schema: ${schema.uid}`, this.config.auditContext);
|
|
@@ -4,9 +4,11 @@ export default class GlobalField extends ContentType {
|
|
|
4
4
|
/**
|
|
5
5
|
* The above function is an asynchronous function that runs a validation and returns any missing
|
|
6
6
|
* references.
|
|
7
|
+
* @param returnFixSchema - If true, returns the fixed schema instead of missing references
|
|
8
|
+
* @param totalCount - Total number of items to process (for progress tracking)
|
|
7
9
|
* @returns the value of the variable `missingRefs`.
|
|
8
10
|
*/
|
|
9
|
-
run(returnFixSchema?: boolean): Promise<Record<string, any> | import("../types").ContentTypeStruct[]>;
|
|
11
|
+
run(returnFixSchema?: boolean, totalCount?: number): Promise<Record<string, any> | import("../types").ContentTypeStruct[]>;
|
|
10
12
|
/**
|
|
11
13
|
* The function validates a field containing modular blocks by traversing each block and checking for
|
|
12
14
|
* references in a given tree.
|
|
@@ -7,14 +7,16 @@ class GlobalField extends content_types_1.default {
|
|
|
7
7
|
/**
|
|
8
8
|
* The above function is an asynchronous function that runs a validation and returns any missing
|
|
9
9
|
* references.
|
|
10
|
+
* @param returnFixSchema - If true, returns the fixed schema instead of missing references
|
|
11
|
+
* @param totalCount - Total number of items to process (for progress tracking)
|
|
10
12
|
* @returns the value of the variable `missingRefs`.
|
|
11
13
|
*/
|
|
12
|
-
async run(returnFixSchema = false) {
|
|
14
|
+
async run(returnFixSchema = false, totalCount) {
|
|
13
15
|
cli_utilities_1.log.debug(`Starting GlobalField audit process`, this.config.auditContext);
|
|
14
16
|
cli_utilities_1.log.debug(`Return fix schema: ${returnFixSchema}`, this.config.auditContext);
|
|
15
17
|
// NOTE add any validation if required
|
|
16
18
|
cli_utilities_1.log.debug(`Calling parent ContentType.run() method`, this.config.auditContext);
|
|
17
|
-
const missingRefs = await super.run(returnFixSchema);
|
|
19
|
+
const missingRefs = await super.run(returnFixSchema, totalCount);
|
|
18
20
|
cli_utilities_1.log.debug(`Parent method completed, found ${Object.keys(missingRefs || {}).length} missing references`, this.config.auditContext);
|
|
19
21
|
cli_utilities_1.log.debug(`GlobalField audit completed`, this.config.auditContext);
|
|
20
22
|
return missingRefs;
|
package/lib/modules/index.d.ts
CHANGED
|
@@ -7,5 +7,5 @@ import CustomRoles from './custom-roles';
|
|
|
7
7
|
import Assets from './assets';
|
|
8
8
|
import FieldRule from './field_rules';
|
|
9
9
|
import ModuleDataReader from './modulesData';
|
|
10
|
-
import
|
|
11
|
-
export { Entries, GlobalField, ContentType, Workflows, Extensions, Assets, CustomRoles, FieldRule, ModuleDataReader,
|
|
10
|
+
import BaseClass from './base-class';
|
|
11
|
+
export { Entries, GlobalField, ContentType, Workflows, Extensions, Assets, CustomRoles, FieldRule, ModuleDataReader, BaseClass };
|
package/lib/modules/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.BaseClass = exports.ModuleDataReader = exports.FieldRule = exports.CustomRoles = exports.Assets = exports.Extensions = exports.Workflows = exports.ContentType = exports.GlobalField = exports.Entries = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const entries_1 = tslib_1.__importDefault(require("./entries"));
|
|
6
6
|
exports.Entries = entries_1.default;
|
|
@@ -20,5 +20,5 @@ const field_rules_1 = tslib_1.__importDefault(require("./field_rules"));
|
|
|
20
20
|
exports.FieldRule = field_rules_1.default;
|
|
21
21
|
const modulesData_1 = tslib_1.__importDefault(require("./modulesData"));
|
|
22
22
|
exports.ModuleDataReader = modulesData_1.default;
|
|
23
|
-
const
|
|
24
|
-
exports.
|
|
23
|
+
const base_class_1 = tslib_1.__importDefault(require("./base-class"));
|
|
24
|
+
exports.BaseClass = base_class_1.default;
|
|
@@ -24,7 +24,7 @@ class ModuleDataReader {
|
|
|
24
24
|
cli_utilities_1.log.debug(`Getting item count for module: ${moduleName}`, this.config.auditContext);
|
|
25
25
|
let count = 0;
|
|
26
26
|
switch (moduleName) {
|
|
27
|
-
case
|
|
27
|
+
case "content-types":
|
|
28
28
|
cli_utilities_1.log.debug(`Counting content types`, this.config.auditContext);
|
|
29
29
|
count = this.ctSchema.length;
|
|
30
30
|
cli_utilities_1.log.debug(`Content types count: ${count}`, this.config.auditContext);
|
|
@@ -38,7 +38,7 @@ class ModuleDataReader {
|
|
|
38
38
|
cli_utilities_1.log.debug(`Counting assets`, this.config.auditContext);
|
|
39
39
|
const assetsPath = (0, path_1.join)(this.folderPath, 'assets');
|
|
40
40
|
cli_utilities_1.log.debug(`Assets path: ${assetsPath}`, this.config.auditContext);
|
|
41
|
-
count =
|
|
41
|
+
count = await this.readEntryAssetsModule(assetsPath, 'assets') || 0;
|
|
42
42
|
cli_utilities_1.log.debug(`Assets count: ${count}`, this.config.auditContext);
|
|
43
43
|
break;
|
|
44
44
|
}
|
|
@@ -53,13 +53,11 @@ class ModuleDataReader {
|
|
|
53
53
|
cli_utilities_1.log.debug(`Master locales path: ${masterLocalesPath}`, this.config.auditContext);
|
|
54
54
|
cli_utilities_1.log.debug(`Loading master locales`, this.config.auditContext);
|
|
55
55
|
this.locales = (0, lodash_1.values)(await this.readUsingFsModule(masterLocalesPath));
|
|
56
|
-
cli_utilities_1.log.debug(`Loaded ${this.locales.length} master locales: ${this.locales.map(
|
|
56
|
+
cli_utilities_1.log.debug(`Loaded ${this.locales.length} master locales: ${this.locales.map(locale => locale.code).join(', ')}`, this.config.auditContext);
|
|
57
57
|
if ((0, fs_1.existsSync)(localesPath)) {
|
|
58
58
|
cli_utilities_1.log.debug(`Loading additional locales from file`, this.config.auditContext);
|
|
59
59
|
this.locales.push(...(0, lodash_1.values)(JSON.parse((0, fs_1.readFileSync)(localesPath, 'utf8'))));
|
|
60
|
-
cli_utilities_1.log.debug(`Total locales after loading: ${this.locales.length} - ${this.locales
|
|
61
|
-
.map((locale) => locale.code)
|
|
62
|
-
.join(', ')}`, this.config.auditContext);
|
|
60
|
+
cli_utilities_1.log.debug(`Total locales after loading: ${this.locales.length} - ${this.locales.map(locale => locale.code).join(', ')}`, this.config.auditContext);
|
|
63
61
|
}
|
|
64
62
|
else {
|
|
65
63
|
cli_utilities_1.log.debug(`Additional locales file not found`, this.config.auditContext);
|
|
@@ -71,7 +69,7 @@ class ModuleDataReader {
|
|
|
71
69
|
cli_utilities_1.log.debug(`Processing content type: ${ctSchema.uid}`, this.config.auditContext);
|
|
72
70
|
const basePath = (0, path_1.join)(this.folderPath, 'entries', ctSchema.uid, code);
|
|
73
71
|
cli_utilities_1.log.debug(`Base path: ${basePath}`, this.config.auditContext);
|
|
74
|
-
const entryCount =
|
|
72
|
+
const entryCount = await this.readEntryAssetsModule(basePath, 'index') || 0;
|
|
75
73
|
cli_utilities_1.log.debug(`Found ${entryCount} entries for ${ctSchema.uid} in ${code}`, this.config.auditContext);
|
|
76
74
|
count = count + entryCount;
|
|
77
75
|
}
|
|
@@ -81,19 +79,12 @@ class ModuleDataReader {
|
|
|
81
79
|
break;
|
|
82
80
|
case 'custom-roles':
|
|
83
81
|
case 'extensions':
|
|
84
|
-
case 'workflows':
|
|
85
|
-
case 'composable-studio': {
|
|
82
|
+
case 'workflows': {
|
|
86
83
|
cli_utilities_1.log.debug(`Counting ${moduleName}`, this.config.auditContext);
|
|
87
84
|
const modulePath = (0, path_1.resolve)(this.folderPath, (0, cli_utilities_1.sanitizePath)(this.config.moduleConfig[moduleName].dirName), (0, cli_utilities_1.sanitizePath)(this.config.moduleConfig[moduleName].fileName));
|
|
88
85
|
cli_utilities_1.log.debug(`Reading module: ${moduleName} from file: ${modulePath}`, this.config.auditContext);
|
|
89
86
|
const moduleData = await this.readUsingFsModule(modulePath);
|
|
90
|
-
|
|
91
|
-
if (moduleName === 'composable-studio') {
|
|
92
|
-
count = Array.isArray(moduleData) ? moduleData.length : Object.keys(moduleData).length > 0 ? 1 : 0;
|
|
93
|
-
}
|
|
94
|
-
else {
|
|
95
|
-
count = (0, lodash_1.keys)(moduleData).length;
|
|
96
|
-
}
|
|
87
|
+
count = (0, lodash_1.keys)(moduleData).length;
|
|
97
88
|
cli_utilities_1.log.debug(`module:${moduleName} count: ${count}`, this.config.auditContext);
|
|
98
89
|
break;
|
|
99
90
|
}
|
|
@@ -103,7 +94,7 @@ class ModuleDataReader {
|
|
|
103
94
|
}
|
|
104
95
|
async readUsingFsModule(path) {
|
|
105
96
|
cli_utilities_1.log.debug(`Reading file: ${path}`, this.config.auditContext);
|
|
106
|
-
const data = (0, fs_1.existsSync)(path) ? JSON.parse((0, fs_1.readFileSync)(path, 'utf-8')) : [];
|
|
97
|
+
const data = (0, fs_1.existsSync)(path) ? (JSON.parse((0, fs_1.readFileSync)(path, 'utf-8'))) : [];
|
|
107
98
|
cli_utilities_1.log.debug(`File ${(0, fs_1.existsSync)(path) ? 'exists' : 'not found'}, data type: ${Array.isArray(data) ? 'array' : 'object'}`, this.config.auditContext);
|
|
108
99
|
if ((0, fs_1.existsSync)(path)) {
|
|
109
100
|
const dataSize = Array.isArray(data) ? data.length : Object.keys(data).length;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ContentTypeStruct, CtConstructorParam, ModuleConstructorParam, Workflow } from '../types';
|
|
2
2
|
import auditConfig from '../config';
|
|
3
|
-
|
|
3
|
+
import BaseClass from './base-class';
|
|
4
|
+
export default class Workflows extends BaseClass {
|
|
4
5
|
protected fix: boolean;
|
|
5
6
|
fileName: any;
|
|
6
|
-
config: ConfigType;
|
|
7
7
|
folderPath: string;
|
|
8
8
|
workflowSchema: Workflow[];
|
|
9
9
|
ctSchema: ContentTypeStruct[];
|
|
@@ -21,7 +21,7 @@ export default class Workflows {
|
|
|
21
21
|
* From the ctSchema add all the content type UID into ctUidSet to check whether the content-type is present or not
|
|
22
22
|
* @returns Array of object containing the workflow name, uid and content_types that are missing
|
|
23
23
|
*/
|
|
24
|
-
run(): Promise<{}>;
|
|
24
|
+
run(totalCount?: number): Promise<{}>;
|
|
25
25
|
fixWorkflowSchema(): Promise<void>;
|
|
26
26
|
writeFixContent(newWorkflowSchema: Record<string, Workflow>): Promise<void>;
|
|
27
27
|
}
|
package/lib/modules/workflows.js
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
3
4
|
const path_1 = require("path");
|
|
4
5
|
const fs_1 = require("fs");
|
|
5
6
|
const lodash_1 = require("lodash");
|
|
6
7
|
const cli_utilities_1 = require("@contentstack/cli-utilities");
|
|
7
8
|
const messages_1 = require("../messages");
|
|
8
9
|
const lodash_2 = require("lodash");
|
|
9
|
-
|
|
10
|
+
const base_class_1 = tslib_1.__importDefault(require("./base-class"));
|
|
11
|
+
class Workflows extends base_class_1.default {
|
|
10
12
|
constructor({ fix, config, moduleName, ctSchema, }) {
|
|
11
|
-
|
|
13
|
+
super({ config });
|
|
12
14
|
this.fix = fix !== null && fix !== void 0 ? fix : false;
|
|
13
15
|
this.ctSchema = ctSchema;
|
|
14
16
|
this.workflowSchema = [];
|
|
@@ -44,81 +46,96 @@ class Workflows {
|
|
|
44
46
|
* From the ctSchema add all the content type UID into ctUidSet to check whether the content-type is present or not
|
|
45
47
|
* @returns Array of object containing the workflow name, uid and content_types that are missing
|
|
46
48
|
*/
|
|
47
|
-
async run() {
|
|
49
|
+
async run(totalCount) {
|
|
48
50
|
var _a, _b, _c, _d, _e;
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
this.workflowPath = (0, path_1.join)(this.folderPath, this.fileName);
|
|
56
|
-
cli_utilities_1.log.debug(`Workflows file path: ${this.workflowPath}`, this.config.auditContext);
|
|
57
|
-
cli_utilities_1.log.debug(`Loading workflows schema from file`, this.config.auditContext);
|
|
58
|
-
this.workflowSchema = (0, fs_1.existsSync)(this.workflowPath)
|
|
59
|
-
? (0, lodash_2.values)(JSON.parse((0, fs_1.readFileSync)(this.workflowPath, 'utf8')))
|
|
60
|
-
: [];
|
|
61
|
-
cli_utilities_1.log.debug(`Loaded ${this.workflowSchema.length} workflows`, this.config.auditContext);
|
|
62
|
-
cli_utilities_1.log.debug(`Building content type UID set from ${this.ctSchema.length} content types`, this.config.auditContext);
|
|
63
|
-
this.ctSchema.forEach((ct) => this.ctUidSet.add(ct.uid));
|
|
64
|
-
cli_utilities_1.log.debug(`Content type UID set contains: ${Array.from(this.ctUidSet).join(', ')}`, this.config.auditContext);
|
|
65
|
-
cli_utilities_1.log.debug(`Processing ${this.workflowSchema.length} workflows`, this.config.auditContext);
|
|
66
|
-
for (const workflow of this.workflowSchema) {
|
|
67
|
-
const { name, uid } = workflow;
|
|
68
|
-
cli_utilities_1.log.debug(`Processing workflow: ${name} (${uid})`, this.config.auditContext);
|
|
69
|
-
cli_utilities_1.log.debug(`Workflow content types: ${((_a = workflow.content_types) === null || _a === void 0 ? void 0 : _a.join(', ')) || 'none'}`, this.config.auditContext);
|
|
70
|
-
cli_utilities_1.log.debug(`Workflow branches: ${((_b = workflow.branches) === null || _b === void 0 ? void 0 : _b.join(', ')) || 'none'}`, this.config.auditContext);
|
|
71
|
-
const ctNotPresent = workflow.content_types.filter((ct) => !this.ctUidSet.has(ct));
|
|
72
|
-
cli_utilities_1.log.debug(`Missing content types in workflow: ${(ctNotPresent === null || ctNotPresent === void 0 ? void 0 : ctNotPresent.join(', ')) || 'none'}`, this.config.auditContext);
|
|
73
|
-
cli_utilities_1.log.debug(`Config branch : ${this.config.branch}`, this.config.auditContext);
|
|
74
|
-
let branchesToBeRemoved = [];
|
|
75
|
-
if ((_c = this.config) === null || _c === void 0 ? void 0 : _c.branch) {
|
|
76
|
-
branchesToBeRemoved = ((_d = workflow === null || workflow === void 0 ? void 0 : workflow.branches) === null || _d === void 0 ? void 0 : _d.filter((branch) => { var _a; return branch !== ((_a = this.config) === null || _a === void 0 ? void 0 : _a.branch); })) || [];
|
|
77
|
-
cli_utilities_1.log.debug(`Branches to be removed: ${(branchesToBeRemoved === null || branchesToBeRemoved === void 0 ? void 0 : branchesToBeRemoved.join(', ')) || 'none'}`, this.config.auditContext);
|
|
51
|
+
try {
|
|
52
|
+
if (!(0, fs_1.existsSync)(this.folderPath)) {
|
|
53
|
+
cli_utilities_1.log.debug(`Skipping ${this.moduleName} audit - path does not exist`, this.config.auditContext);
|
|
54
|
+
cli_utilities_1.log.warn(`Skipping ${this.moduleName} audit`, this.config.auditContext);
|
|
55
|
+
cli_utilities_1.cliux.print((0, messages_1.$t)(messages_1.auditMsg.NOT_VALID_PATH, { path: this.folderPath }), { color: 'yellow' });
|
|
56
|
+
return {};
|
|
78
57
|
}
|
|
79
|
-
|
|
80
|
-
|
|
58
|
+
this.workflowPath = (0, path_1.join)(this.folderPath, this.fileName);
|
|
59
|
+
cli_utilities_1.log.debug(`Workflows file path: ${this.workflowPath}`, this.config.auditContext);
|
|
60
|
+
// Load workflows schema with loading spinner
|
|
61
|
+
await this.withLoadingSpinner('WORKFLOWS: Loading workflows schema...', async () => {
|
|
62
|
+
this.workflowSchema = (0, fs_1.existsSync)(this.workflowPath)
|
|
63
|
+
? (0, lodash_2.values)(JSON.parse((0, fs_1.readFileSync)(this.workflowPath, 'utf8')))
|
|
64
|
+
: [];
|
|
65
|
+
});
|
|
66
|
+
cli_utilities_1.log.debug(`Loaded ${this.workflowSchema.length} workflows`, this.config.auditContext);
|
|
67
|
+
cli_utilities_1.log.debug(`Building content type UID set from ${this.ctSchema.length} content types`, this.config.auditContext);
|
|
68
|
+
this.ctSchema.forEach((ct) => this.ctUidSet.add(ct.uid));
|
|
69
|
+
cli_utilities_1.log.debug(`Content type UID set contains: ${Array.from(this.ctUidSet).join(', ')}`, this.config.auditContext);
|
|
70
|
+
// Create progress manager if we have a total count
|
|
71
|
+
if (totalCount && totalCount > 0) {
|
|
72
|
+
const progress = this.createSimpleProgress(this.moduleName, totalCount);
|
|
73
|
+
progress.updateStatus('Validating workflows...');
|
|
81
74
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
75
|
+
cli_utilities_1.log.debug(`Processing ${this.workflowSchema.length} workflows`, this.config.auditContext);
|
|
76
|
+
for (const workflow of this.workflowSchema) {
|
|
77
|
+
const { name, uid } = workflow;
|
|
78
|
+
cli_utilities_1.log.debug(`Processing workflow: ${name} (${uid})`, this.config.auditContext);
|
|
79
|
+
cli_utilities_1.log.debug(`Workflow content types: ${((_a = workflow.content_types) === null || _a === void 0 ? void 0 : _a.join(', ')) || 'none'}`, this.config.auditContext);
|
|
80
|
+
cli_utilities_1.log.debug(`Workflow branches: ${((_b = workflow.branches) === null || _b === void 0 ? void 0 : _b.join(', ')) || 'none'}`, this.config.auditContext);
|
|
81
|
+
const ctNotPresent = workflow.content_types.filter((ct) => !this.ctUidSet.has(ct));
|
|
82
|
+
cli_utilities_1.log.debug(`Missing content types in workflow: ${(ctNotPresent === null || ctNotPresent === void 0 ? void 0 : ctNotPresent.join(', ')) || 'none'}`, this.config.auditContext);
|
|
83
|
+
cli_utilities_1.log.debug(`Config branch : ${this.config.branch}`, this.config.auditContext);
|
|
84
|
+
let branchesToBeRemoved = [];
|
|
85
|
+
if ((_c = this.config) === null || _c === void 0 ? void 0 : _c.branch) {
|
|
86
|
+
branchesToBeRemoved = ((_d = workflow === null || workflow === void 0 ? void 0 : workflow.branches) === null || _d === void 0 ? void 0 : _d.filter((branch) => { var _a; return branch !== ((_a = this.config) === null || _a === void 0 ? void 0 : _a.branch); })) || [];
|
|
87
|
+
cli_utilities_1.log.debug(`Branches to be removed: ${(branchesToBeRemoved === null || branchesToBeRemoved === void 0 ? void 0 : branchesToBeRemoved.join(', ')) || 'none'}`, this.config.auditContext);
|
|
88
88
|
}
|
|
89
|
-
|
|
90
|
-
cli_utilities_1.log.debug(`
|
|
91
|
-
this.isBranchFixDone = true;
|
|
89
|
+
else {
|
|
90
|
+
cli_utilities_1.log.debug(`No branch configuration found`, this.config.auditContext);
|
|
92
91
|
}
|
|
93
|
-
ctNotPresent.
|
|
94
|
-
cli_utilities_1.log.debug(`
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
92
|
+
if (ctNotPresent.length || (branchesToBeRemoved === null || branchesToBeRemoved === void 0 ? void 0 : branchesToBeRemoved.length)) {
|
|
93
|
+
cli_utilities_1.log.debug(`Workflow ${name} has issues - missing content types: ${ctNotPresent.length}, branches to remove: ${branchesToBeRemoved.length}`, this.config.auditContext);
|
|
94
|
+
const tempwf = (0, lodash_1.cloneDeep)(workflow);
|
|
95
|
+
tempwf.content_types = ctNotPresent || [];
|
|
96
|
+
if ((workflow === null || workflow === void 0 ? void 0 : workflow.branches) && ((_e = this.config) === null || _e === void 0 ? void 0 : _e.branch)) {
|
|
97
|
+
tempwf.branches = branchesToBeRemoved;
|
|
98
|
+
}
|
|
99
|
+
if (branchesToBeRemoved === null || branchesToBeRemoved === void 0 ? void 0 : branchesToBeRemoved.length) {
|
|
100
|
+
cli_utilities_1.log.debug(`Branch fix will be needed`, this.config.auditContext);
|
|
101
|
+
this.isBranchFixDone = true;
|
|
102
|
+
}
|
|
103
|
+
ctNotPresent.forEach((ct) => {
|
|
104
|
+
cli_utilities_1.log.debug(`Adding missing content type: ${ct} to the Audit report.`, this.config.auditContext);
|
|
105
|
+
this.missingCts.add(ct);
|
|
106
|
+
});
|
|
107
|
+
this.missingCtInWorkflows.push(tempwf);
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
cli_utilities_1.log.debug(`Workflow ${name} has no issues`, this.config.auditContext);
|
|
111
|
+
}
|
|
112
|
+
cli_utilities_1.log.info((0, messages_1.$t)(messages_1.auditMsg.SCAN_WF_SUCCESS_MSG, {
|
|
113
|
+
name: workflow.name,
|
|
114
|
+
uid: workflow.uid,
|
|
115
|
+
}), this.config.auditContext);
|
|
98
116
|
}
|
|
99
|
-
|
|
100
|
-
|
|
117
|
+
cli_utilities_1.log.debug(`Workflows audit completed. Found ${this.missingCtInWorkflows.length} workflows with issues`, this.config.auditContext);
|
|
118
|
+
cli_utilities_1.log.debug(`Total missing content types: ${this.missingCts.size}`, this.config.auditContext);
|
|
119
|
+
cli_utilities_1.log.debug(`Branch fix needed: ${this.isBranchFixDone}`, this.config.auditContext);
|
|
120
|
+
if (this.fix && (this.missingCtInWorkflows.length || this.isBranchFixDone)) {
|
|
121
|
+
cli_utilities_1.log.debug(`Fix mode enabled, fixing ${this.missingCtInWorkflows.length} workflows`, this.config.auditContext);
|
|
122
|
+
await this.fixWorkflowSchema();
|
|
123
|
+
this.missingCtInWorkflows.forEach((wf) => {
|
|
124
|
+
cli_utilities_1.log.debug(`Marking workflow ${wf.name} as fixed`, this.config.auditContext);
|
|
125
|
+
wf.fixStatus = 'Fixed';
|
|
126
|
+
});
|
|
127
|
+
cli_utilities_1.log.debug(`Workflows fix completed`, this.config.auditContext);
|
|
128
|
+
this.completeProgress(true);
|
|
129
|
+
return this.missingCtInWorkflows;
|
|
101
130
|
}
|
|
102
|
-
cli_utilities_1.log.
|
|
103
|
-
|
|
104
|
-
uid: workflow.uid,
|
|
105
|
-
}), this.config.auditContext);
|
|
106
|
-
}
|
|
107
|
-
cli_utilities_1.log.debug(`Workflows audit completed. Found ${this.missingCtInWorkflows.length} workflows with issues`, this.config.auditContext);
|
|
108
|
-
cli_utilities_1.log.debug(`Total missing content types: ${this.missingCts.size}`, this.config.auditContext);
|
|
109
|
-
cli_utilities_1.log.debug(`Branch fix needed: ${this.isBranchFixDone}`, this.config.auditContext);
|
|
110
|
-
if (this.fix && (this.missingCtInWorkflows.length || this.isBranchFixDone)) {
|
|
111
|
-
cli_utilities_1.log.debug(`Fix mode enabled, fixing ${this.missingCtInWorkflows.length} workflows`, this.config.auditContext);
|
|
112
|
-
await this.fixWorkflowSchema();
|
|
113
|
-
this.missingCtInWorkflows.forEach((wf) => {
|
|
114
|
-
cli_utilities_1.log.debug(`Marking workflow ${wf.name} as fixed`, this.config.auditContext);
|
|
115
|
-
wf.fixStatus = 'Fixed';
|
|
116
|
-
});
|
|
117
|
-
cli_utilities_1.log.debug(`Workflows fix completed`, this.config.auditContext);
|
|
131
|
+
cli_utilities_1.log.debug(`Workflows audit completed without fixes`, this.config.auditContext);
|
|
132
|
+
this.completeProgress(true);
|
|
118
133
|
return this.missingCtInWorkflows;
|
|
119
134
|
}
|
|
120
|
-
|
|
121
|
-
|
|
135
|
+
catch (error) {
|
|
136
|
+
this.completeProgress(false, (error === null || error === void 0 ? void 0 : error.message) || 'Workflows audit failed');
|
|
137
|
+
throw error;
|
|
138
|
+
}
|
|
122
139
|
}
|
|
123
140
|
async fixWorkflowSchema() {
|
|
124
141
|
var _a;
|
|
@@ -127,8 +127,7 @@ declare enum OutputColumn {
|
|
|
127
127
|
"Fixable" = "Fixable",
|
|
128
128
|
"Non-Fixable" = "Non-Fixable",
|
|
129
129
|
"Fixed" = "Fixed",
|
|
130
|
-
"Not-Fixed" = "Not-Fixed"
|
|
131
|
-
"Issues" = "issues"
|
|
130
|
+
"Not-Fixed" = "Not-Fixed"
|
|
132
131
|
}
|
|
133
132
|
export { CtConstructorParam, ContentTypeStruct, ModuleConstructorParam, ReferenceFieldDataType, GlobalFieldDataType, ExtensionOrAppFieldDataType, JsonRTEFieldDataType, GroupFieldDataType, ModularBlocksDataType, RefErrorReturnType, ModularBlocksSchemaTypes, ModularBlockType, OutputColumn, ContentTypeSchemaType, GlobalFieldSchemaTypes, WorkflowExtensionsRefErrorReturnType, SelectFeildStruct, FieldRuleStruct, };
|
|
134
133
|
type FieldRuleStruct = {
|
package/lib/types/context.d.ts
CHANGED
package/oclif.manifest.json
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"commands": {
|
|
3
3
|
"cm:stacks:audit:fix": {
|
|
4
|
-
"aliases": [
|
|
5
|
-
"audit:fix",
|
|
6
|
-
"cm:stacks:audit:fix"
|
|
7
|
-
],
|
|
4
|
+
"aliases": [],
|
|
8
5
|
"args": {},
|
|
9
6
|
"description": "Perform audits and fix possible errors in the exported Contentstack data.",
|
|
10
7
|
"examples": [
|
|
@@ -68,8 +65,7 @@
|
|
|
68
65
|
"workflows",
|
|
69
66
|
"custom-roles",
|
|
70
67
|
"assets",
|
|
71
|
-
"field-rules"
|
|
72
|
-
"composable-studio"
|
|
68
|
+
"field-rules"
|
|
73
69
|
],
|
|
74
70
|
"type": "option"
|
|
75
71
|
},
|
|
@@ -198,10 +194,7 @@
|
|
|
198
194
|
]
|
|
199
195
|
},
|
|
200
196
|
"cm:stacks:audit": {
|
|
201
|
-
"aliases": [
|
|
202
|
-
"audit",
|
|
203
|
-
"cm:stacks:audit"
|
|
204
|
-
],
|
|
197
|
+
"aliases": [],
|
|
205
198
|
"args": {},
|
|
206
199
|
"description": "Perform audits and find possible errors in the exported Contentstack data",
|
|
207
200
|
"examples": [
|
|
@@ -264,8 +257,7 @@
|
|
|
264
257
|
"workflows",
|
|
265
258
|
"custom-roles",
|
|
266
259
|
"assets",
|
|
267
|
-
"field-rules"
|
|
268
|
-
"composable-studio"
|
|
260
|
+
"field-rules"
|
|
269
261
|
],
|
|
270
262
|
"type": "option"
|
|
271
263
|
},
|
|
@@ -346,5 +338,5 @@
|
|
|
346
338
|
]
|
|
347
339
|
}
|
|
348
340
|
},
|
|
349
|
-
"version": "
|
|
341
|
+
"version": "2.0.0-beta.1"
|
|
350
342
|
}
|