@contentstack/cli-audit 1.0.0 → 1.2.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 +108 -25
- package/lib/audit-base-command.d.ts +83 -0
- package/lib/audit-base-command.js +263 -0
- package/lib/commands/cm/stacks/audit/fix.d.ts +9 -4
- package/lib/commands/cm/stacks/audit/fix.js +51 -7
- package/lib/commands/cm/stacks/audit/index.d.ts +2 -51
- package/lib/commands/cm/stacks/audit/index.js +5 -201
- package/lib/messages/index.d.ts +12 -6
- package/lib/messages/index.js +17 -10
- package/lib/modules/content-types.d.ts +59 -4
- package/lib/modules/content-types.js +241 -33
- package/lib/modules/entries.d.ts +128 -7
- package/lib/modules/entries.js +376 -60
- package/lib/types/content-types.d.ts +11 -4
- package/lib/types/entries.d.ts +6 -3
- package/oclif.manifest.json +102 -10
- package/package.json +9 -10
package/README.md
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
<!-- Insert Audit version here -->
|
|
3
3
|
|
|
4
4
|
# @contentstack/cli-audit
|
|
5
|
+
|
|
5
6
|
Audit plugin
|
|
6
7
|
|
|
7
8
|
## How to install this plugin
|
|
@@ -12,15 +13,13 @@ $ csdx plugins:install @contentstack/cli-audit
|
|
|
12
13
|
|
|
13
14
|
## How to use this plugin
|
|
14
15
|
|
|
15
|
-
This plugin requires you to be authenticated using [csdx auth:login](https://www.contentstack.com/docs/developers/cli/authenticate-with-the-cli/).
|
|
16
|
-
|
|
17
16
|
<!-- usage -->
|
|
18
17
|
```sh-session
|
|
19
18
|
$ npm install -g @contentstack/cli-audit
|
|
20
19
|
$ csdx COMMAND
|
|
21
20
|
running command...
|
|
22
21
|
$ csdx (--version|-v)
|
|
23
|
-
@contentstack/cli-audit/1.
|
|
22
|
+
@contentstack/cli-audit/1.2.1 linux-x64 node-v18.18.2
|
|
24
23
|
$ csdx --help [COMMAND]
|
|
25
24
|
USAGE
|
|
26
25
|
$ csdx COMMAND
|
|
@@ -29,10 +28,12 @@ USAGE
|
|
|
29
28
|
<!-- usagestop -->
|
|
30
29
|
|
|
31
30
|
# Commands
|
|
31
|
+
|
|
32
32
|
<!-- commands -->
|
|
33
|
-
* [`csdx
|
|
33
|
+
* [`csdx audit`](#csdx-audit)
|
|
34
|
+
* [`csdx audit:fix`](#csdx-auditfix)
|
|
34
35
|
* [`csdx cm:stacks:audit`](#csdx-cmstacksaudit)
|
|
35
|
-
* [`csdx cm:stacks:audit:fix`](#csdx-cmstacksauditfix
|
|
36
|
+
* [`csdx cm:stacks:audit:fix`](#csdx-cmstacksauditfix)
|
|
36
37
|
* [`csdx help [COMMANDS]`](#csdx-help-commands)
|
|
37
38
|
* [`csdx plugins`](#csdx-plugins)
|
|
38
39
|
* [`csdx plugins:install PLUGIN...`](#csdx-pluginsinstall-plugin)
|
|
@@ -44,29 +45,89 @@ USAGE
|
|
|
44
45
|
* [`csdx plugins:uninstall PLUGIN...`](#csdx-pluginsuninstall-plugin-2)
|
|
45
46
|
* [`csdx plugins:update`](#csdx-pluginsupdate)
|
|
46
47
|
|
|
47
|
-
## `csdx
|
|
48
|
+
## `csdx audit`
|
|
48
49
|
|
|
49
|
-
|
|
50
|
+
Perform audits and find possible errors in the exported Contentstack data
|
|
50
51
|
|
|
51
52
|
```
|
|
52
53
|
USAGE
|
|
53
|
-
$ csdx
|
|
54
|
+
$ csdx audit [-c <value>] [-d <value>] [--report-path <value>] [--modules
|
|
55
|
+
content-types|global-fields|entries] [--columns <value> | ] [--sort <value>] [--filter <value>] [--csv |
|
|
56
|
+
--no-truncate]
|
|
54
57
|
|
|
55
58
|
FLAGS
|
|
56
|
-
-c, --config=<value> Path of the external config
|
|
57
|
-
-d, --data-dir=<value> Path where the data is stored
|
|
59
|
+
-c, --config=<value> Path of the external config
|
|
60
|
+
-d, --data-dir=<value> Path where the data is stored
|
|
61
|
+
--columns=<value> only show provided columns (comma-separated)
|
|
62
|
+
--csv output is csv format [alias: --output=csv]
|
|
63
|
+
--filter=<value> filter property by partial string matching, ex: name=foo
|
|
64
|
+
--modules=<option>... Provide the list of modules to be audited
|
|
65
|
+
<options: content-types|global-fields|entries>
|
|
66
|
+
--no-truncate do not truncate output to fit screen
|
|
67
|
+
--report-path=<value> Path to store the audit reports
|
|
68
|
+
--sort=<value> property to sort by (prepend '-' for descending)
|
|
58
69
|
|
|
59
70
|
DESCRIPTION
|
|
60
|
-
|
|
71
|
+
Perform audits and find possible errors in the exported Contentstack data
|
|
61
72
|
|
|
62
73
|
ALIASES
|
|
63
|
-
$ csdx
|
|
74
|
+
$ csdx audit
|
|
75
|
+
$ csdx cm:stacks:audit
|
|
64
76
|
|
|
65
77
|
EXAMPLES
|
|
66
|
-
$ csdx
|
|
78
|
+
$ csdx audit
|
|
79
|
+
|
|
80
|
+
$ csdx audit --report-path=<path>
|
|
81
|
+
|
|
82
|
+
$ csdx audit --report-path=<path> --csv
|
|
83
|
+
|
|
84
|
+
$ csdx audit --report-path=<path> --filter="name=<filter-value>"
|
|
85
|
+
|
|
86
|
+
$ csdx audit --report-path=<path> --modules=content-types --filter="name="<filter-value>"
|
|
67
87
|
```
|
|
68
88
|
|
|
69
|
-
|
|
89
|
+
## `csdx audit:fix`
|
|
90
|
+
|
|
91
|
+
Perform audits and fix possible errors in the exported Contentstack data.
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
USAGE
|
|
95
|
+
$ csdx audit:fix [-c <value>] [-d <value>] [--report-path <value>] [--modules
|
|
96
|
+
content-types|global-fields|entries] [--copy-path <value> --copy-dir] [--columns <value> | ] [--sort <value>]
|
|
97
|
+
[--filter <value>] [--csv | --no-truncate]
|
|
98
|
+
|
|
99
|
+
FLAGS
|
|
100
|
+
-c, --config=<value> Path of the external config
|
|
101
|
+
-d, --data-dir=<value> Path where the data is stored
|
|
102
|
+
--columns=<value> only show provided columns (comma-separated)
|
|
103
|
+
--copy-dir Create backup from the original data.
|
|
104
|
+
--copy-path=<value> Provide the path to backup the copied data
|
|
105
|
+
--csv output is csv format [alias: --output=csv]
|
|
106
|
+
--filter=<value> filter property by partial string matching, ex: name=foo
|
|
107
|
+
--modules=<option>... Provide the list of modules to be audited
|
|
108
|
+
<options: content-types|global-fields|entries>
|
|
109
|
+
--no-truncate do not truncate output to fit screen
|
|
110
|
+
--report-path=<value> Path to store the audit reports
|
|
111
|
+
--sort=<value> property to sort by (prepend '-' for descending)
|
|
112
|
+
|
|
113
|
+
DESCRIPTION
|
|
114
|
+
Perform audits and fix possible errors in the exported Contentstack data.
|
|
115
|
+
|
|
116
|
+
ALIASES
|
|
117
|
+
$ csdx audit:fix
|
|
118
|
+
$ csdx cm:stacks:audit:fix
|
|
119
|
+
|
|
120
|
+
EXAMPLES
|
|
121
|
+
$ csdx audit:fix --copy-dir
|
|
122
|
+
|
|
123
|
+
$ csdx audit:fix --report-path=<path> --copy-dir
|
|
124
|
+
|
|
125
|
+
$ csdx audit:fix --report-path=<path> --copy-dir --csv
|
|
126
|
+
|
|
127
|
+
$ csdx audit:fix --report-path=<path> --filter="name=<filter-value>"
|
|
128
|
+
|
|
129
|
+
$ csdx audit:fix --report-path=<path> --modules=content-types --filter="name="<filter-value>" --copy-dir --copy-path=<path>
|
|
130
|
+
```
|
|
70
131
|
|
|
71
132
|
## `csdx cm:stacks:audit`
|
|
72
133
|
|
|
@@ -79,21 +140,22 @@ USAGE
|
|
|
79
140
|
--no-truncate]
|
|
80
141
|
|
|
81
142
|
FLAGS
|
|
82
|
-
-c, --config=<value> Path of the external config
|
|
83
|
-
-d, --data-dir=<value> Path where the data is stored
|
|
143
|
+
-c, --config=<value> Path of the external config
|
|
144
|
+
-d, --data-dir=<value> Path where the data is stored
|
|
84
145
|
--columns=<value> only show provided columns (comma-separated)
|
|
85
146
|
--csv output is csv format [alias: --output=csv]
|
|
86
147
|
--filter=<value> filter property by partial string matching, ex: name=foo
|
|
87
|
-
--modules=<option>... Provide the list of modules to be audited
|
|
148
|
+
--modules=<option>... Provide the list of modules to be audited
|
|
88
149
|
<options: content-types|global-fields|entries>
|
|
89
150
|
--no-truncate do not truncate output to fit screen
|
|
90
|
-
--report-path=<value> Path to store the audit reports
|
|
151
|
+
--report-path=<value> Path to store the audit reports
|
|
91
152
|
--sort=<value> property to sort by (prepend '-' for descending)
|
|
92
153
|
|
|
93
154
|
DESCRIPTION
|
|
94
155
|
Perform audits and find possible errors in the exported Contentstack data
|
|
95
156
|
|
|
96
157
|
ALIASES
|
|
158
|
+
$ csdx audit
|
|
97
159
|
$ csdx cm:stacks:audit
|
|
98
160
|
|
|
99
161
|
EXAMPLES
|
|
@@ -112,24 +174,45 @@ _See code: [src/commands/cm/stacks/audit/index.ts](https://github.com/contentsta
|
|
|
112
174
|
|
|
113
175
|
## `csdx cm:stacks:audit:fix`
|
|
114
176
|
|
|
115
|
-
|
|
177
|
+
Perform audits and fix possible errors in the exported Contentstack data.
|
|
116
178
|
|
|
117
179
|
```
|
|
118
180
|
USAGE
|
|
119
|
-
$ csdx cm:stacks:audit:fix [-c <value>] [-d <value>]
|
|
181
|
+
$ csdx cm:stacks:audit:fix [-c <value>] [-d <value>] [--report-path <value>] [--modules
|
|
182
|
+
content-types|global-fields|entries] [--copy-path <value> --copy-dir] [--columns <value> | ] [--sort <value>]
|
|
183
|
+
[--filter <value>] [--csv | --no-truncate]
|
|
120
184
|
|
|
121
185
|
FLAGS
|
|
122
|
-
-c, --config=<value> Path of the external config
|
|
123
|
-
-d, --data-dir=<value> Path where the data is stored
|
|
186
|
+
-c, --config=<value> Path of the external config
|
|
187
|
+
-d, --data-dir=<value> Path where the data is stored
|
|
188
|
+
--columns=<value> only show provided columns (comma-separated)
|
|
189
|
+
--copy-dir Create backup from the original data.
|
|
190
|
+
--copy-path=<value> Provide the path to backup the copied data
|
|
191
|
+
--csv output is csv format [alias: --output=csv]
|
|
192
|
+
--filter=<value> filter property by partial string matching, ex: name=foo
|
|
193
|
+
--modules=<option>... Provide the list of modules to be audited
|
|
194
|
+
<options: content-types|global-fields|entries>
|
|
195
|
+
--no-truncate do not truncate output to fit screen
|
|
196
|
+
--report-path=<value> Path to store the audit reports
|
|
197
|
+
--sort=<value> property to sort by (prepend '-' for descending)
|
|
124
198
|
|
|
125
199
|
DESCRIPTION
|
|
126
|
-
|
|
200
|
+
Perform audits and fix possible errors in the exported Contentstack data.
|
|
127
201
|
|
|
128
202
|
ALIASES
|
|
129
|
-
$ csdx
|
|
203
|
+
$ csdx audit:fix
|
|
204
|
+
$ csdx cm:stacks:audit:fix
|
|
130
205
|
|
|
131
206
|
EXAMPLES
|
|
132
|
-
$ csdx cm:stacks:audit:fix
|
|
207
|
+
$ csdx cm:stacks:audit:fix --copy-dir
|
|
208
|
+
|
|
209
|
+
$ csdx cm:stacks:audit:fix --report-path=<path> --copy-dir
|
|
210
|
+
|
|
211
|
+
$ csdx cm:stacks:audit:fix --report-path=<path> --copy-dir --csv
|
|
212
|
+
|
|
213
|
+
$ csdx cm:stacks:audit:fix --report-path=<path> --filter="name=<filter-value>"
|
|
214
|
+
|
|
215
|
+
$ csdx cm:stacks:audit:fix --report-path=<path> --modules=content-types --filter="name="<filter-value>" --copy-dir --copy-path=<path>
|
|
133
216
|
```
|
|
134
217
|
|
|
135
218
|
_See code: [src/commands/cm/stacks/audit/fix.ts](https://github.com/contentstack/audit/blob/main/packages/contentstack-audit/src/commands/cm/stacks/audit/fix.ts)_
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import config from './config';
|
|
2
|
+
import { BaseCommand } from './base-command';
|
|
3
|
+
import { ContentTypeStruct } from './types';
|
|
4
|
+
export declare abstract class AuditBaseCommand extends BaseCommand<typeof AuditBaseCommand> {
|
|
5
|
+
private currentCommand;
|
|
6
|
+
get fixStatus(): {
|
|
7
|
+
fixStatus: {
|
|
8
|
+
minWidth: number;
|
|
9
|
+
header: string;
|
|
10
|
+
get: (row: any) => string;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* The `start` function performs an audit on content types, global fields, and entries, and displays
|
|
15
|
+
* any missing references.
|
|
16
|
+
* @param {string} command - The `command` parameter is a string that represents the current command
|
|
17
|
+
* being executed.
|
|
18
|
+
*/
|
|
19
|
+
start(command: string): Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* The `scan` function performs an audit on different modules (content-types, global-fields, and
|
|
22
|
+
* entries) and returns the missing references for each module.
|
|
23
|
+
* @returns The function `scan()` returns an object with properties `missingCtRefs`, `missingGfRefs`,
|
|
24
|
+
* and `missingEntryRefs`.
|
|
25
|
+
*/
|
|
26
|
+
scanAndFix(): Promise<{
|
|
27
|
+
missingCtRefs: Record<string, any> | undefined;
|
|
28
|
+
missingGfRefs: Record<string, any> | undefined;
|
|
29
|
+
missingEntryRefs: Record<string, any> | undefined;
|
|
30
|
+
}>;
|
|
31
|
+
/**
|
|
32
|
+
* The `promptQueue` function prompts the user to enter a data directory path if the `data-dir` flag
|
|
33
|
+
* is missing, and sets the `basePath` property of the `sharedConfig` object to the entered path.
|
|
34
|
+
*/
|
|
35
|
+
promptQueue(): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* The function `createBackUp` creates a backup of data if the `copy-dir` flag is set, and throws
|
|
38
|
+
* an error if the specified path does not exist.
|
|
39
|
+
*/
|
|
40
|
+
createBackUp(): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* The function `getCtAndGfSchema` reads and parses JSON files containing content type and global
|
|
43
|
+
* field schemas, and returns them as an object.
|
|
44
|
+
* @returns The function `getCtAndGfSchema()` returns an object with two properties: `ctSchema` and
|
|
45
|
+
* `gfSchema`. The values of these properties are the parsed JSON data from two different files.
|
|
46
|
+
*/
|
|
47
|
+
getCtAndGfSchema(): {
|
|
48
|
+
ctSchema: ContentTypeStruct[];
|
|
49
|
+
gfSchema: ContentTypeStruct[];
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* The function `showOutputOnScreen` displays missing references on the terminal screen if the
|
|
53
|
+
* `showTerminalOutput` flag is set to true.
|
|
54
|
+
* @param {{ module: string; missingRefs?: Record<string, any> }[]} allMissingRefs - An array of
|
|
55
|
+
* objects, where each object has two properties:
|
|
56
|
+
*/
|
|
57
|
+
showOutputOnScreen(allMissingRefs: {
|
|
58
|
+
module: string;
|
|
59
|
+
missingRefs?: Record<string, any>;
|
|
60
|
+
}[]): void;
|
|
61
|
+
/**
|
|
62
|
+
* The function prepares a report by writing a JSON file and a CSV file with a list of missing
|
|
63
|
+
* references for a given module.
|
|
64
|
+
* @param moduleName - The `moduleName` parameter is a string that represents the name of a module.
|
|
65
|
+
* It is used to generate the filename for the report.
|
|
66
|
+
* @param listOfMissingRefs - The `listOfMissingRefs` parameter is a record object that contains
|
|
67
|
+
* information about missing references. It is a key-value pair where the key represents the
|
|
68
|
+
* reference name and the value represents additional information about the missing reference.
|
|
69
|
+
* @returns The function `prepareReport` returns a Promise that resolves to `void`.
|
|
70
|
+
*/
|
|
71
|
+
prepareReport(moduleName: keyof typeof config.moduleConfig, listOfMissingRefs: Record<string, any>): Promise<void>;
|
|
72
|
+
/**
|
|
73
|
+
* The function `prepareCSV` takes a module name and a list of missing references, and generates a
|
|
74
|
+
* CSV file with the specified columns and filtered rows.
|
|
75
|
+
* @param moduleName - The `moduleName` parameter is a string that represents the name of a module.
|
|
76
|
+
* It is used to generate the name of the CSV file that will be created.
|
|
77
|
+
* @param listOfMissingRefs - The `listOfMissingRefs` parameter is a record object that contains
|
|
78
|
+
* information about missing references. Each key in the record represents a reference, and the
|
|
79
|
+
* corresponding value is an array of objects that contain details about the missing reference.
|
|
80
|
+
* @returns The function `prepareCSV` returns a Promise that resolves to `void`.
|
|
81
|
+
*/
|
|
82
|
+
prepareCSV(moduleName: keyof typeof config.moduleConfig, listOfMissingRefs: Record<string, any>): Promise<void>;
|
|
83
|
+
}
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AuditBaseCommand = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
6
|
+
const csv = tslib_1.__importStar(require("fast-csv"));
|
|
7
|
+
const fs_extra_1 = require("fs-extra");
|
|
8
|
+
const uuid_1 = require("uuid");
|
|
9
|
+
const isEmpty_1 = tslib_1.__importDefault(require("lodash/isEmpty"));
|
|
10
|
+
const path_1 = require("path");
|
|
11
|
+
const cloneDeep_1 = tslib_1.__importDefault(require("lodash/cloneDeep"));
|
|
12
|
+
const cli_utilities_1 = require("@contentstack/cli-utilities");
|
|
13
|
+
const fs_1 = require("fs");
|
|
14
|
+
const log_1 = require("./util/log");
|
|
15
|
+
const messages_1 = require("./messages");
|
|
16
|
+
const base_command_1 = require("./base-command");
|
|
17
|
+
const modules_1 = require("./modules");
|
|
18
|
+
const types_1 = require("./types");
|
|
19
|
+
class AuditBaseCommand extends base_command_1.BaseCommand {
|
|
20
|
+
get fixStatus() {
|
|
21
|
+
return {
|
|
22
|
+
fixStatus: {
|
|
23
|
+
minWidth: 7,
|
|
24
|
+
header: 'Fix Status',
|
|
25
|
+
get: (row) => {
|
|
26
|
+
return row.fixStatus === 'Fixed' ? chalk_1.default.greenBright(row.fixStatus) : chalk_1.default.redBright(row.fixStatus);
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The `start` function performs an audit on content types, global fields, and entries, and displays
|
|
33
|
+
* any missing references.
|
|
34
|
+
* @param {string} command - The `command` parameter is a string that represents the current command
|
|
35
|
+
* being executed.
|
|
36
|
+
*/
|
|
37
|
+
async start(command) {
|
|
38
|
+
this.currentCommand = command;
|
|
39
|
+
await this.promptQueue();
|
|
40
|
+
await this.createBackUp();
|
|
41
|
+
this.sharedConfig.reportPath = (0, path_1.resolve)(this.flags['report-path'] || process.cwd(), 'audit-report');
|
|
42
|
+
const { missingCtRefs, missingGfRefs, missingEntryRefs } = await this.scanAndFix();
|
|
43
|
+
this.showOutputOnScreen([
|
|
44
|
+
{ module: 'Content types', missingRefs: missingCtRefs },
|
|
45
|
+
{ module: 'Global Fields', missingRefs: missingGfRefs },
|
|
46
|
+
{ module: 'Entries', missingRefs: missingEntryRefs },
|
|
47
|
+
]);
|
|
48
|
+
if (!(0, isEmpty_1.default)(missingCtRefs) || !(0, isEmpty_1.default)(missingGfRefs) || !(0, isEmpty_1.default)(missingEntryRefs)) {
|
|
49
|
+
if (this.currentCommand === 'cm:stacks:audit') {
|
|
50
|
+
this.log(this.$t(messages_1.auditMsg.FINAL_REPORT_PATH, { path: this.sharedConfig.reportPath }), 'warn');
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
this.log(this.$t(this.messages.FIXED_CONTENT_PATH_MAG, { path: this.sharedConfig.basePath }), 'warn');
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
this.log(this.messages.NO_MISSING_REF_FOUND, 'info');
|
|
58
|
+
this.log('');
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The `scan` function performs an audit on different modules (content-types, global-fields, and
|
|
63
|
+
* entries) and returns the missing references for each module.
|
|
64
|
+
* @returns The function `scan()` returns an object with properties `missingCtRefs`, `missingGfRefs`,
|
|
65
|
+
* and `missingEntryRefs`.
|
|
66
|
+
*/
|
|
67
|
+
async scanAndFix() {
|
|
68
|
+
let { ctSchema, gfSchema } = this.getCtAndGfSchema();
|
|
69
|
+
let missingCtRefs, missingGfRefs, missingEntryRefs;
|
|
70
|
+
for (const module of this.sharedConfig.flags.modules || this.sharedConfig.modules) {
|
|
71
|
+
cli_utilities_1.ux.action.start(this.$t(this.messages.AUDIT_START_SPINNER, { module }));
|
|
72
|
+
const constructorParam = {
|
|
73
|
+
ctSchema,
|
|
74
|
+
gfSchema,
|
|
75
|
+
log: this.log,
|
|
76
|
+
moduleName: module,
|
|
77
|
+
config: this.sharedConfig,
|
|
78
|
+
fix: this.currentCommand === 'cm:stacks:audit:fix',
|
|
79
|
+
};
|
|
80
|
+
switch (module) {
|
|
81
|
+
case 'content-types':
|
|
82
|
+
missingCtRefs = await new modules_1.ContentType((0, cloneDeep_1.default)(constructorParam)).run();
|
|
83
|
+
await this.prepareReport(module, missingCtRefs);
|
|
84
|
+
break;
|
|
85
|
+
case 'global-fields':
|
|
86
|
+
missingGfRefs = await new modules_1.GlobalField((0, cloneDeep_1.default)(constructorParam)).run();
|
|
87
|
+
await this.prepareReport(module, missingGfRefs);
|
|
88
|
+
break;
|
|
89
|
+
case 'entries':
|
|
90
|
+
missingEntryRefs = await new modules_1.Entries((0, cloneDeep_1.default)(constructorParam)).run();
|
|
91
|
+
await this.prepareReport(module, missingEntryRefs);
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
cli_utilities_1.ux.action.stop();
|
|
95
|
+
}
|
|
96
|
+
return { missingCtRefs, missingGfRefs, missingEntryRefs };
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* The `promptQueue` function prompts the user to enter a data directory path if the `data-dir` flag
|
|
100
|
+
* is missing, and sets the `basePath` property of the `sharedConfig` object to the entered path.
|
|
101
|
+
*/
|
|
102
|
+
async promptQueue() {
|
|
103
|
+
// NOTE get content path if data-dir flag is missing
|
|
104
|
+
this.sharedConfig.basePath =
|
|
105
|
+
this.flags['data-dir'] ||
|
|
106
|
+
(await cli_utilities_1.cliux.inquire({
|
|
107
|
+
type: 'input',
|
|
108
|
+
name: 'data-dir',
|
|
109
|
+
message: this.messages.DATA_DIR,
|
|
110
|
+
}));
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* The function `createBackUp` creates a backup of data if the `copy-dir` flag is set, and throws
|
|
114
|
+
* an error if the specified path does not exist.
|
|
115
|
+
*/
|
|
116
|
+
async createBackUp() {
|
|
117
|
+
if (this.currentCommand === 'cm:stacks:audit:fix' && this.flags['copy-dir']) {
|
|
118
|
+
if (!(0, fs_1.existsSync)(this.sharedConfig.basePath)) {
|
|
119
|
+
throw Error(this.$t(this.messages.NOT_VALID_PATH, { path: this.sharedConfig.basePath }));
|
|
120
|
+
}
|
|
121
|
+
// NOTE create bkp directory
|
|
122
|
+
const backupDirPath = `${(this.flags['copy-path'] || this.flags['data-dir']).replace(/\/+$/, '')}_backup_${(0, uuid_1.v4)()}`;
|
|
123
|
+
if (!(0, fs_1.existsSync)(backupDirPath)) {
|
|
124
|
+
(0, fs_1.mkdirSync)(backupDirPath, { recursive: true });
|
|
125
|
+
}
|
|
126
|
+
await (0, fs_extra_1.copy)(this.sharedConfig.basePath, backupDirPath);
|
|
127
|
+
this.sharedConfig.basePath = backupDirPath;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* The function `getCtAndGfSchema` reads and parses JSON files containing content type and global
|
|
132
|
+
* field schemas, and returns them as an object.
|
|
133
|
+
* @returns The function `getCtAndGfSchema()` returns an object with two properties: `ctSchema` and
|
|
134
|
+
* `gfSchema`. The values of these properties are the parsed JSON data from two different files.
|
|
135
|
+
*/
|
|
136
|
+
getCtAndGfSchema() {
|
|
137
|
+
const modules = this.sharedConfig.flags.modules || this.sharedConfig.modules;
|
|
138
|
+
const ctPath = (0, path_1.join)(this.sharedConfig.basePath, this.sharedConfig.moduleConfig['content-types'].dirName, this.sharedConfig.moduleConfig['content-types'].fileName);
|
|
139
|
+
const gfPath = (0, path_1.join)(this.sharedConfig.basePath, this.sharedConfig.moduleConfig['global-fields'].dirName, this.sharedConfig.moduleConfig['global-fields'].fileName);
|
|
140
|
+
if (modules.includes('content-types')) {
|
|
141
|
+
if (!(0, fs_1.existsSync)(ctPath)) {
|
|
142
|
+
this.log(this.$t(messages_1.auditMsg.NOT_VALID_PATH, { path: ctPath }), 'error');
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (modules.includes('global-fields')) {
|
|
146
|
+
if (!(0, fs_1.existsSync)(gfPath)) {
|
|
147
|
+
this.log(this.$t(messages_1.auditMsg.NOT_VALID_PATH, { path: ctPath }), 'error');
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
const gfSchema = (0, fs_1.existsSync)(gfPath) ? JSON.parse((0, fs_1.readFileSync)(gfPath, 'utf8')) : [];
|
|
151
|
+
const ctSchema = (0, fs_1.existsSync)(ctPath) ? JSON.parse((0, fs_1.readFileSync)(ctPath, 'utf8')) : [];
|
|
152
|
+
return { ctSchema, gfSchema };
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* The function `showOutputOnScreen` displays missing references on the terminal screen if the
|
|
156
|
+
* `showTerminalOutput` flag is set to true.
|
|
157
|
+
* @param {{ module: string; missingRefs?: Record<string, any> }[]} allMissingRefs - An array of
|
|
158
|
+
* objects, where each object has two properties:
|
|
159
|
+
*/
|
|
160
|
+
showOutputOnScreen(allMissingRefs) {
|
|
161
|
+
var _a;
|
|
162
|
+
if (this.sharedConfig.showTerminalOutput) {
|
|
163
|
+
this.log(''); // NOTE adding new line
|
|
164
|
+
for (const { module, missingRefs } of allMissingRefs) {
|
|
165
|
+
if (!(0, isEmpty_1.default)(missingRefs)) {
|
|
166
|
+
(0, log_1.print)([
|
|
167
|
+
{
|
|
168
|
+
bold: true,
|
|
169
|
+
color: 'cyan',
|
|
170
|
+
message: ` ${module}`,
|
|
171
|
+
},
|
|
172
|
+
]);
|
|
173
|
+
const tableValues = Object.values(missingRefs).flat();
|
|
174
|
+
cli_utilities_1.ux.table(tableValues, Object.assign(Object.assign({ name: {
|
|
175
|
+
minWidth: 7,
|
|
176
|
+
header: 'Title',
|
|
177
|
+
}, display_name: {
|
|
178
|
+
minWidth: 7,
|
|
179
|
+
header: 'Field name',
|
|
180
|
+
}, data_type: {
|
|
181
|
+
minWidth: 7,
|
|
182
|
+
header: 'Field type',
|
|
183
|
+
}, missingRefs: {
|
|
184
|
+
minWidth: 7,
|
|
185
|
+
header: 'Missing references',
|
|
186
|
+
get: (row) => {
|
|
187
|
+
return chalk_1.default.red(typeof row.missingRefs === 'object' ? JSON.stringify(row.missingRefs) : row.missingRefs);
|
|
188
|
+
},
|
|
189
|
+
} }, (((_a = tableValues[0]) === null || _a === void 0 ? void 0 : _a.fixStatus) ? this.fixStatus : {})), { treeStr: {
|
|
190
|
+
minWidth: 7,
|
|
191
|
+
header: 'Path',
|
|
192
|
+
} }), Object.assign({}, this.flags));
|
|
193
|
+
this.log(''); // NOTE adding new line
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* The function prepares a report by writing a JSON file and a CSV file with a list of missing
|
|
200
|
+
* references for a given module.
|
|
201
|
+
* @param moduleName - The `moduleName` parameter is a string that represents the name of a module.
|
|
202
|
+
* It is used to generate the filename for the report.
|
|
203
|
+
* @param listOfMissingRefs - The `listOfMissingRefs` parameter is a record object that contains
|
|
204
|
+
* information about missing references. It is a key-value pair where the key represents the
|
|
205
|
+
* reference name and the value represents additional information about the missing reference.
|
|
206
|
+
* @returns The function `prepareReport` returns a Promise that resolves to `void`.
|
|
207
|
+
*/
|
|
208
|
+
prepareReport(moduleName, listOfMissingRefs) {
|
|
209
|
+
if ((0, isEmpty_1.default)(listOfMissingRefs))
|
|
210
|
+
return Promise.resolve(void 0);
|
|
211
|
+
if (!(0, fs_1.existsSync)(this.sharedConfig.reportPath)) {
|
|
212
|
+
(0, fs_1.mkdirSync)(this.sharedConfig.reportPath, { recursive: true });
|
|
213
|
+
}
|
|
214
|
+
// NOTE write int json
|
|
215
|
+
(0, fs_1.writeFileSync)((0, path_1.join)(this.sharedConfig.reportPath, `${moduleName}.json`), JSON.stringify(listOfMissingRefs));
|
|
216
|
+
// NOTE write into CSV
|
|
217
|
+
return this.prepareCSV(moduleName, listOfMissingRefs);
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* The function `prepareCSV` takes a module name and a list of missing references, and generates a
|
|
221
|
+
* CSV file with the specified columns and filtered rows.
|
|
222
|
+
* @param moduleName - The `moduleName` parameter is a string that represents the name of a module.
|
|
223
|
+
* It is used to generate the name of the CSV file that will be created.
|
|
224
|
+
* @param listOfMissingRefs - The `listOfMissingRefs` parameter is a record object that contains
|
|
225
|
+
* information about missing references. Each key in the record represents a reference, and the
|
|
226
|
+
* corresponding value is an array of objects that contain details about the missing reference.
|
|
227
|
+
* @returns The function `prepareCSV` returns a Promise that resolves to `void`.
|
|
228
|
+
*/
|
|
229
|
+
prepareCSV(moduleName, listOfMissingRefs) {
|
|
230
|
+
const csvStream = csv.format({ headers: true });
|
|
231
|
+
const csvPath = (0, path_1.join)(this.sharedConfig.reportPath, `${moduleName}.csv`);
|
|
232
|
+
const assetFileStream = (0, fs_1.createWriteStream)(csvPath);
|
|
233
|
+
assetFileStream.on('error', (error) => {
|
|
234
|
+
throw error;
|
|
235
|
+
});
|
|
236
|
+
return new Promise((resolve, reject) => {
|
|
237
|
+
csvStream.pipe(assetFileStream).on('close', resolve).on('error', reject);
|
|
238
|
+
const defaultColumns = Object.keys(types_1.OutputColumn);
|
|
239
|
+
const userDefinedColumns = this.sharedConfig.flags.columns ? this.sharedConfig.flags.columns.split(',') : null;
|
|
240
|
+
let missingRefs = Object.values(listOfMissingRefs).flat();
|
|
241
|
+
const columns = userDefinedColumns
|
|
242
|
+
? [...userDefinedColumns, ...defaultColumns.filter((val) => !userDefinedColumns.includes(val))]
|
|
243
|
+
: defaultColumns;
|
|
244
|
+
if (this.sharedConfig.flags.filter) {
|
|
245
|
+
const [column, value] = this.sharedConfig.flags.filter.split('=');
|
|
246
|
+
missingRefs = missingRefs.filter((row) => row[types_1.OutputColumn[column]] === value);
|
|
247
|
+
}
|
|
248
|
+
for (const issue of missingRefs) {
|
|
249
|
+
let row = {};
|
|
250
|
+
for (const column of columns) {
|
|
251
|
+
row[column] = issue[types_1.OutputColumn[column]];
|
|
252
|
+
row[column] = typeof row[column] === 'object' ? JSON.stringify(row[column]) : row[column];
|
|
253
|
+
}
|
|
254
|
+
if (this.currentCommand === 'cm:stacks:audit:fix') {
|
|
255
|
+
row['Fix status'] = row.fixStatus;
|
|
256
|
+
}
|
|
257
|
+
csvStream.write(row);
|
|
258
|
+
}
|
|
259
|
+
csvStream.end();
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
exports.AuditBaseCommand = AuditBaseCommand;
|
|
@@ -1,8 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { FlagInput } from '@contentstack/cli-utilities';
|
|
2
|
+
import { AuditBaseCommand } from '../../../../audit-base-command';
|
|
3
|
+
export default class AuditFix extends AuditBaseCommand {
|
|
4
4
|
static aliases: string[];
|
|
5
|
+
static description: string;
|
|
5
6
|
static examples: string[];
|
|
6
|
-
static flags:
|
|
7
|
+
static flags: FlagInput;
|
|
8
|
+
/**
|
|
9
|
+
* The `run` function is an asynchronous function that performs an audit on different modules
|
|
10
|
+
* (content-types, global-fields, entries) and generates a report.
|
|
11
|
+
*/
|
|
7
12
|
run(): Promise<void>;
|
|
8
13
|
}
|
|
@@ -1,11 +1,55 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const cli_utilities_1 = require("@contentstack/cli-utilities");
|
|
5
|
+
const config_1 = tslib_1.__importDefault(require("../../../../config"));
|
|
6
|
+
const messages_1 = require("../../../../messages");
|
|
7
|
+
const audit_base_command_1 = require("../../../../audit-base-command");
|
|
8
|
+
class AuditFix extends audit_base_command_1.AuditBaseCommand {
|
|
9
|
+
/**
|
|
10
|
+
* The `run` function is an asynchronous function that performs an audit on different modules
|
|
11
|
+
* (content-types, global-fields, entries) and generates a report.
|
|
12
|
+
*/
|
|
13
|
+
async run() {
|
|
14
|
+
try {
|
|
15
|
+
await this.start('cm:stacks:audit:fix');
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
this.log(error instanceof Error ? error.message : error, 'error');
|
|
19
|
+
console.trace(error);
|
|
20
|
+
cli_utilities_1.ux.action.stop('Process failed.!');
|
|
21
|
+
this.exit(1);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
6
24
|
}
|
|
7
25
|
exports.default = AuditFix;
|
|
8
|
-
AuditFix.
|
|
9
|
-
AuditFix.
|
|
10
|
-
AuditFix.examples = [
|
|
11
|
-
|
|
26
|
+
AuditFix.aliases = ['audit:fix', 'cm:stacks:audit:fix'];
|
|
27
|
+
AuditFix.description = messages_1.auditFixMsg.AUDIT_FIX_CMD_DESCRIPTION;
|
|
28
|
+
AuditFix.examples = [
|
|
29
|
+
'$ <%= config.bin %> <%= command.id %> --copy-dir',
|
|
30
|
+
'$ <%= config.bin %> <%= command.id %> --report-path=<path> --copy-dir',
|
|
31
|
+
'$ <%= config.bin %> <%= command.id %> --report-path=<path> --copy-dir --csv',
|
|
32
|
+
'$ <%= config.bin %> <%= command.id %> --report-path=<path> --filter="name=<filter-value>"',
|
|
33
|
+
'$ <%= config.bin %> <%= command.id %> --report-path=<path> --modules=content-types --filter="name="<filter-value>" --copy-dir --copy-path=<path>',
|
|
34
|
+
];
|
|
35
|
+
AuditFix.flags = Object.assign({ 'report-path': cli_utilities_1.Flags.string({
|
|
36
|
+
description: messages_1.auditMsg.REPORT_PATH,
|
|
37
|
+
}), 'reference-only': cli_utilities_1.Flags.boolean({
|
|
38
|
+
hidden: true,
|
|
39
|
+
description: messages_1.auditMsg.REFERENCE_ONLY,
|
|
40
|
+
}), modules: cli_utilities_1.Flags.string({
|
|
41
|
+
multiple: true,
|
|
42
|
+
options: config_1.default.modules,
|
|
43
|
+
description: messages_1.auditMsg.MODULES,
|
|
44
|
+
}), 'copy-dir': cli_utilities_1.Flags.boolean({
|
|
45
|
+
description: messages_1.auditFixMsg.COPY_DATA,
|
|
46
|
+
}), 'copy-path': cli_utilities_1.Flags.string({
|
|
47
|
+
dependsOn: ['copy-dir'],
|
|
48
|
+
description: messages_1.auditFixMsg.BKP_PATH,
|
|
49
|
+
}), yes: cli_utilities_1.Flags.boolean({
|
|
50
|
+
char: 'y',
|
|
51
|
+
hidden: true,
|
|
52
|
+
description: 'Use this flag to skip confirmation',
|
|
53
|
+
}) }, cli_utilities_1.ux.table.flags({
|
|
54
|
+
only: ['columns', 'sort', 'filter', 'csv', 'no-truncate'],
|
|
55
|
+
}));
|