@zohodesk/codestandard-validator 1.1.4 → 1.2.4-exp-2
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/bin/cliCI.js +0 -0
- package/build/ai/config.example.json +10 -0
- package/build/ai/ollama-service.js +403 -0
- package/build/ai/prompts/CODE_REVIEW_PROMPT.md +72 -0
- package/build/ai/prompts/PROMPT1.MD +70 -0
- package/build/ai/prompts/PROMPT2.md +159 -0
- package/build/ai/prompts/PROMPT3.md +64 -0
- package/build/ai/prompts/PROMPT4.md +64 -0
- package/build/ai/provider-factory.js +19 -0
- package/build/ai/providers/OllamaProvider.js +106 -0
- package/build/ai/render.js +157 -0
- package/build/ai/run-review.js +50 -0
- package/build/chunk/chunk_Restriction.js +202 -0
- package/build/hooks/Precommit/pre-commit-default.js +158 -140
- package/build/hooks/hook.js +6 -5
- package/build/lib/postinstall.js +6 -10
- package/build/mutation/branchDiff.js +178 -0
- package/build/mutation/fileResolver.js +170 -0
- package/build/mutation/index.js +16 -0
- package/build/mutation/mutatePattern.json +3 -0
- package/build/mutation/mutationCli.js +111 -0
- package/build/mutation/mutationRunner.js +208 -0
- package/build/mutation/reportGenerator.js +72 -0
- package/build/mutation/strykerWrapper.js +180 -0
- package/build/utils/FileAndFolderOperations/filterFiles.js +8 -6
- package/build/utils/FileAndFolderOperations/removeFolder.js +2 -2
- package/build/utils/General/Config.js +25 -0
- package/build/utils/General/SonarQubeUtil.js +1 -1
- package/jest.config.js +1 -1
- package/package.json +4 -1
- package/samples/sample-branch-mode.js +34 -0
- package/samples/sample-cli-entry.js +34 -0
- package/samples/sample-components.js +63 -0
- package/samples/sample-directory-mode.js +30 -0
- package/samples/sample-runner-direct.js +32 -0
- package/samples/sample-with-api.js +44 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _process;
|
|
4
|
+
const {
|
|
5
|
+
execSync
|
|
6
|
+
} = require('child_process');
|
|
7
|
+
const {
|
|
8
|
+
getModifiedLines
|
|
9
|
+
} = require('@zohodesk/codestandard-analytics');
|
|
10
|
+
const {
|
|
11
|
+
getBranchName
|
|
12
|
+
} = require('../utils/GitActions/gitActions');
|
|
13
|
+
const Logger = console;
|
|
14
|
+
const path = require('path');
|
|
15
|
+
const {
|
|
16
|
+
getConfigPath
|
|
17
|
+
} = require('../../build/utils/General/getGeneralInfo');
|
|
18
|
+
const {
|
|
19
|
+
getConfigPathExecute
|
|
20
|
+
} = require('../utils/General/Config');
|
|
21
|
+
const {
|
|
22
|
+
gitEndPoint: _gitEndPoint
|
|
23
|
+
} = getConfigPath(getConfigPathExecute());
|
|
24
|
+
const gitEndPoint = _gitEndPoint || 'https://zgit.csez.zohocorpin.com';
|
|
25
|
+
const compareBranch = ((_process = process) === null || _process === void 0 || (_process = _process.env) === null || _process === void 0 ? void 0 : _process.CHUNK_BRANCH) || 'release';
|
|
26
|
+
const configPath = path.resolve(process.cwd(), 'lint.config.js');
|
|
27
|
+
function getGitProjectId() {
|
|
28
|
+
try {
|
|
29
|
+
const config = require(configPath);
|
|
30
|
+
return config.projectId;
|
|
31
|
+
} catch (err) {
|
|
32
|
+
Logger.log(`Failed to Fetch Chunk Details`);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const projectId = getGitProjectId();
|
|
37
|
+
const token = process.env.ZGIT_TOKEN;
|
|
38
|
+
const shouldEnable = parserBoolean(process.env.SHOULD_ENABLE_CHUNK);
|
|
39
|
+
function isTestOrUATFile(file) {
|
|
40
|
+
const f = file.replace(/\\/g, "/");
|
|
41
|
+
if (f.endsWith(".spec.js") || f.endsWith(".test.js") || f.endsWith(".spec.ts") || f.endsWith(".test.ts") || f.endsWith(".feature") || f.endsWith(".properties")) {
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// UAT folder check
|
|
46
|
+
if (f.includes("/uat/")) {
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
function parserBoolean(value) {
|
|
52
|
+
let defaultValue = false;
|
|
53
|
+
if (value == null || value == undefined) {
|
|
54
|
+
return defaultValue;
|
|
55
|
+
}
|
|
56
|
+
let AcceptedCase = new Set(["true", true]);
|
|
57
|
+
return AcceptedCase.has(value);
|
|
58
|
+
}
|
|
59
|
+
function requestUtilsCLI(command) {
|
|
60
|
+
return execSync(command, {
|
|
61
|
+
shell: true
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
function createBranchDiffChunk(branchName) {
|
|
65
|
+
var command;
|
|
66
|
+
const endPoint = `${gitEndPoint}/api/v4/projects/${projectId.toString()}/repository/compare?from=${compareBranch}&to=${branchName}`;
|
|
67
|
+
try {
|
|
68
|
+
command = `curl --header "PRIVATE-TOKEN:${token}" "${endPoint}"`;
|
|
69
|
+
return parserReleaseDiffRemoteAPI(JSON.parse(requestUtilsCLI(command).toString('utf-8')));
|
|
70
|
+
} catch (error) {
|
|
71
|
+
Logger.log(error);
|
|
72
|
+
Logger.log(`\n INFO : If you are using a VPN and encounter an SSL certification issue, ensure that the proxy is enabled for SSH and shell connections.`);
|
|
73
|
+
Logger.log(`\n Make sure that you have access to this repository`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function parserReleaseDiffRemoteAPI(rawresponse) {
|
|
77
|
+
var formatted = [];
|
|
78
|
+
if (rawresponse !== null && rawresponse !== void 0 && rawresponse.diffs) {
|
|
79
|
+
formatted = rawresponse.diffs.map(changeset => {
|
|
80
|
+
if (isTestOrUATFile(changeset.new_path)) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
const {
|
|
84
|
+
modifiedLines,
|
|
85
|
+
removedLines
|
|
86
|
+
} = getModifiedLines(changeset.diff);
|
|
87
|
+
chunkSize.$modifieldLines += modifiedLines.length;
|
|
88
|
+
chunkSize.$removedLines += removedLines.length;
|
|
89
|
+
return {
|
|
90
|
+
file: changeset.new_path,
|
|
91
|
+
diff: {
|
|
92
|
+
modifiedLines,
|
|
93
|
+
removedLines
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
}).filter(item => item !== null);
|
|
97
|
+
}
|
|
98
|
+
return formatted;
|
|
99
|
+
}
|
|
100
|
+
function parseCombinedDiff(combinedDiffString) {
|
|
101
|
+
if (!combinedDiffString) {
|
|
102
|
+
return [];
|
|
103
|
+
}
|
|
104
|
+
const fileDiffChunks = combinedDiffString.split(/(?=diff --git a\/)/g);
|
|
105
|
+
const structuredDiffs = fileDiffChunks.map(chunk => {
|
|
106
|
+
const fileHeaderMatch = chunk.match(/^diff --git a\/(.*?) b\/(.*?)\n/);
|
|
107
|
+
if (!fileHeaderMatch) {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
const filePath = fileHeaderMatch[1];
|
|
111
|
+
if (isTestOrUATFile(filePath)) {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
const {
|
|
115
|
+
modifiedLines,
|
|
116
|
+
removedLines
|
|
117
|
+
} = getModifiedLines(chunk.trim());
|
|
118
|
+
chunkSize.$modifieldLines += modifiedLines.length;
|
|
119
|
+
chunkSize.$removedLines += removedLines.length;
|
|
120
|
+
return {
|
|
121
|
+
file: filePath,
|
|
122
|
+
diff: {
|
|
123
|
+
modifiedLines,
|
|
124
|
+
removedLines
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
}).filter(item => item !== null);
|
|
128
|
+
return structuredDiffs;
|
|
129
|
+
}
|
|
130
|
+
function runGitCommand(command) {
|
|
131
|
+
try {
|
|
132
|
+
const output = execSync(command, {
|
|
133
|
+
cwd: process.cwd(),
|
|
134
|
+
encoding: 'utf8',
|
|
135
|
+
stdio: ['pipe', 'pipe', 'ignore'],
|
|
136
|
+
maxBuffer: 10 * 1024 * 1024
|
|
137
|
+
}).trim();
|
|
138
|
+
return parseCombinedDiff(output);
|
|
139
|
+
} catch (error) {
|
|
140
|
+
if (error.status === 128) {
|
|
141
|
+
return `ERROR: Git error executing command: '${command}'. Ensure you are in a Git repository and all references exist.`;
|
|
142
|
+
}
|
|
143
|
+
return undefined;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function getGitChangesets(currentBranch, releaseBranch, upstreamRemote = 'origin') {
|
|
147
|
+
const stagedDiffCommand = 'git diff --staged';
|
|
148
|
+
const stagedChangeset = {
|
|
149
|
+
git_command: stagedDiffCommand,
|
|
150
|
+
description: 'Changes staged in the index, ready to be committed.',
|
|
151
|
+
actual_output: runGitCommand(stagedDiffCommand)
|
|
152
|
+
};
|
|
153
|
+
const releaseComparison = {
|
|
154
|
+
git_command: "giff diff with release",
|
|
155
|
+
description: `Total difference between the tip of branch '${currentBranch}' and the tip of reference '${releaseBranch}'.`,
|
|
156
|
+
actual_output: createBranchDiffChunk(currentBranch)
|
|
157
|
+
};
|
|
158
|
+
const unpushedDiffCommand = `git diff ${upstreamRemote}/${currentBranch}...HEAD`;
|
|
159
|
+
const unpushedChangeset = {
|
|
160
|
+
git_command: unpushedDiffCommand,
|
|
161
|
+
description: `Changes from all local commits that have not been pushed (diff since common ancestor of HEAD and its upstream).`,
|
|
162
|
+
actual_output: runGitCommand(unpushedDiffCommand)
|
|
163
|
+
};
|
|
164
|
+
return {
|
|
165
|
+
stagedChangeset,
|
|
166
|
+
releaseComparison,
|
|
167
|
+
unpushedChangeset
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
if (shouldEnable) {
|
|
171
|
+
const myCurrentBranch = getBranchName();
|
|
172
|
+
const targetRelease = process.env.CHUNK_BRANCH || 'release';
|
|
173
|
+
const chunk_size_env = Number(process.env.CHUNK_SIZE) || 800;
|
|
174
|
+
const remoteName = 'origin';
|
|
175
|
+
const Logger = console;
|
|
176
|
+
const RED = '\x1b[31m';
|
|
177
|
+
const GREEN = '\x1b[32m';
|
|
178
|
+
const RESET = '\x1b[0m';
|
|
179
|
+
(async function () {
|
|
180
|
+
Logger.log(`****************************** Calculation Chunk Size *******************************`);
|
|
181
|
+
if (!(globalThis !== null && globalThis !== void 0 && globalThis.chunkSize)) {
|
|
182
|
+
globalThis.chunkSize = {
|
|
183
|
+
$modifieldLines: 0,
|
|
184
|
+
$removedLines: 0
|
|
185
|
+
};
|
|
186
|
+
try {
|
|
187
|
+
await getGitChangesets(myCurrentBranch, targetRelease, remoteName);
|
|
188
|
+
if (chunkSize.$modifieldLines <= chunk_size_env) {
|
|
189
|
+
Logger.log(`${GREEN}Your Chunk was ${chunkSize.$modifieldLines} and remaining size ${chunk_size_env - chunkSize.$modifieldLines}${RESET}`);
|
|
190
|
+
} else {
|
|
191
|
+
Logger.log(`${RED}Your Chunk was ${chunkSize.$modifieldLines} which exceeded the allowed limit ${chunk_size_env} ${RESET}`);
|
|
192
|
+
// process.exit(1)
|
|
193
|
+
}
|
|
194
|
+
} catch (e) {
|
|
195
|
+
console.log(e);
|
|
196
|
+
Logger.error("Execution failed. Ensure you are running this in a Node.js environment with the 'child_process' module and 'git' installed.");
|
|
197
|
+
Logger.error(e.message);
|
|
198
|
+
}
|
|
199
|
+
Logger.log(`*************************************************************************************`);
|
|
200
|
+
}
|
|
201
|
+
})();
|
|
202
|
+
}
|
|
@@ -58,7 +58,7 @@ async function isMergeCommit() {
|
|
|
58
58
|
|
|
59
59
|
async function getStagedFiles() {
|
|
60
60
|
return new Promise((resolve, reject) => {
|
|
61
|
-
exec(
|
|
61
|
+
exec('git diff --staged --name-only', (error, stderr, stdout) => {
|
|
62
62
|
if (error) {
|
|
63
63
|
if (error != null) reject("Couldn't fetch staged files");
|
|
64
64
|
} else if (stderr) {
|
|
@@ -73,7 +73,7 @@ async function getStagedFiles() {
|
|
|
73
73
|
/**
|
|
74
74
|
* @function {filterDeltedFileFromStagedFiles} - filter deleted staged files
|
|
75
75
|
* @param {Array<string>} files - staged files
|
|
76
|
-
* @returns
|
|
76
|
+
* @returns
|
|
77
77
|
*/
|
|
78
78
|
function filterDeltedFileFromStagedFiles(files) {
|
|
79
79
|
return files.filter(file => {
|
|
@@ -109,7 +109,7 @@ async function lintFiles(filePath) {
|
|
|
109
109
|
/**
|
|
110
110
|
* @function findEslintErrors - method Lint given file based on given configuration
|
|
111
111
|
* @param {*} file - path of file to lint
|
|
112
|
-
* @returns {Array<string>} - array of command line report as a string
|
|
112
|
+
* @returns {Array<string>} - array of command line report as a string
|
|
113
113
|
*/
|
|
114
114
|
|
|
115
115
|
function findEslintErrors(file) {
|
|
@@ -126,10 +126,15 @@ function findEslintErrors(file) {
|
|
|
126
126
|
resolve(stderr.trim().split('\n'));
|
|
127
127
|
} else if (error) {
|
|
128
128
|
Logger.log(Logger.FAILURE_TYPE, error);
|
|
129
|
-
reject(
|
|
129
|
+
reject('Error executing eslint command');
|
|
130
130
|
} else {
|
|
131
131
|
resolve([]);
|
|
132
132
|
}
|
|
133
|
+
}, {
|
|
134
|
+
env: {
|
|
135
|
+
...process.env,
|
|
136
|
+
CHUNK_SIZE: (globalThis === null || globalThis === void 0 ? void 0 : globalThis.chunkSize) ?? ''
|
|
137
|
+
}
|
|
133
138
|
});
|
|
134
139
|
});
|
|
135
140
|
} else {
|
|
@@ -141,8 +146,8 @@ function findEslintErrors(file) {
|
|
|
141
146
|
}
|
|
142
147
|
|
|
143
148
|
/**
|
|
144
|
-
*
|
|
145
|
-
* @param {*} params
|
|
149
|
+
*
|
|
150
|
+
* @param {*} params
|
|
146
151
|
*/
|
|
147
152
|
function findStyleLintErrors(filePath) {
|
|
148
153
|
const configFilePath = path.resolve(getNodeModulesPath(), '.stylelintrc.js');
|
|
@@ -156,7 +161,7 @@ function findStyleLintErrors(filePath) {
|
|
|
156
161
|
resolve(stdout.trim().split('\n'));
|
|
157
162
|
} else if (error) {
|
|
158
163
|
Logger.log(Logger.FAILURE_TYPE, error);
|
|
159
|
-
reject(
|
|
164
|
+
reject('Error executing stylelint command');
|
|
160
165
|
} else {
|
|
161
166
|
resolve([]);
|
|
162
167
|
}
|
|
@@ -172,7 +177,7 @@ function findStyleLintErrors(filePath) {
|
|
|
172
177
|
* @function {calculateGitDiffForFile} - method calculate diff of file
|
|
173
178
|
* @param {*} branch_name - branch name
|
|
174
179
|
* @param {*} file - path of file
|
|
175
|
-
* @returns {Promise<Array<string>>} - array of command line report as a string
|
|
180
|
+
* @returns {Promise<Array<string>>} - array of command line report as a string
|
|
176
181
|
*/
|
|
177
182
|
async function calculateGitDiffForFile(branch_name, file) {
|
|
178
183
|
let gitDiffCommand = `git diff -U0 ${branch_name.trim()} ${path.resolve(getRootDirectory(), file)}`;
|
|
@@ -194,13 +199,115 @@ async function calculateGitDiffForFile(branch_name, file) {
|
|
|
194
199
|
function isOnlyWarningsPresentInFile(eslintErrorsPresent) {
|
|
195
200
|
let severityOfEachErrorInFile = [];
|
|
196
201
|
eslintErrorsPresent.map(error => {
|
|
197
|
-
let partsInString = error.split(
|
|
202
|
+
let partsInString = error.split(' ');
|
|
198
203
|
let severityOfError = partsInString.find(word => word === 'error' || word === 'warning' || word === '✖');
|
|
199
204
|
severityOfEachErrorInFile.push(severityOfError);
|
|
200
205
|
});
|
|
201
206
|
return !(severityOfEachErrorInFile.includes('✖') || severityOfEachErrorInFile.includes('error'));
|
|
202
207
|
}
|
|
203
208
|
|
|
209
|
+
/**
|
|
210
|
+
* Parse git diff hunk headers into changed line ranges.
|
|
211
|
+
* @param {string[]} diffLines - raw git diff output lines
|
|
212
|
+
* @returns {Array<{start: number, end: number}>}
|
|
213
|
+
*/
|
|
214
|
+
function getChangedLineRanges(diffLines) {
|
|
215
|
+
return diffLines.filter(line => line.startsWith('@@')).map(line => {
|
|
216
|
+
const [startStr, countStr] = line.split(' ')[2].split(',');
|
|
217
|
+
const start = parseInt(startStr, 10);
|
|
218
|
+
const end = countStr !== undefined ? start + parseInt(countStr, 10) - 1 : start;
|
|
219
|
+
return {
|
|
220
|
+
start,
|
|
221
|
+
end
|
|
222
|
+
};
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Extract only error/warning lines from eslint output (strip header & summary).
|
|
228
|
+
* @param {string[]} rawOutput
|
|
229
|
+
* @returns {string[]}
|
|
230
|
+
*/
|
|
231
|
+
function extractLintErrors(rawOutput) {
|
|
232
|
+
if (!rawOutput || rawOutput.length <= 2) return [];
|
|
233
|
+
return rawOutput.slice(1, rawOutput.length - 2);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Filter lint errors to those on changed lines or matching mandatory rules.
|
|
238
|
+
* @param {string[]} lintErrors - extracted error lines
|
|
239
|
+
* @param {Array<{start: number, end: number}>} ranges - changed line ranges
|
|
240
|
+
* @returns {string[]}
|
|
241
|
+
*/
|
|
242
|
+
function filterErrorsByChangedLines(lintErrors, ranges) {
|
|
243
|
+
const result = new Set();
|
|
244
|
+
for (const errorLine of lintErrors) {
|
|
245
|
+
const lineNum = parseInt(errorLine.trim().split(' ')[0].split(':')[0], 10);
|
|
246
|
+
if (MandatoryListRules.some(ruleId => errorLine.trim().includes(ruleId))) {
|
|
247
|
+
result.add(errorLine);
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
for (const {
|
|
251
|
+
start,
|
|
252
|
+
end
|
|
253
|
+
} of ranges) {
|
|
254
|
+
if (lineNum >= start && lineNum <= end) {
|
|
255
|
+
result.add(errorLine);
|
|
256
|
+
break;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return Array.from(result);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Determine whether errors should abort the commit.
|
|
265
|
+
* @param {string[]} errors
|
|
266
|
+
* @returns {boolean}
|
|
267
|
+
*/
|
|
268
|
+
function shouldErrorsAbortCommit(errors) {
|
|
269
|
+
if (errors.length === 0) return false;
|
|
270
|
+
if (shouldWarningsAbortCommit) return true;
|
|
271
|
+
return !isOnlyWarningsPresentInFile(errors);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Log lint errors for a file.
|
|
276
|
+
* @param {string} fileName
|
|
277
|
+
* @param {string[]} errors
|
|
278
|
+
*/
|
|
279
|
+
function logFileErrors(fileName, errors) {
|
|
280
|
+
Logger.log(Logger.FAILURE_TYPE, `\x1b[1m${fileName}\x1b[0m`);
|
|
281
|
+
for (const error of errors) {
|
|
282
|
+
Logger.log(Logger.FAILURE_TYPE, `\x1b[37m${error.trimEnd()}\x1b[0m`);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Process a single staged file: lint it, optionally filter by changed lines, and return whether to abort.
|
|
288
|
+
* @param {string} file - relative file path
|
|
289
|
+
* @param {string} currentBranch
|
|
290
|
+
* @returns {Promise<boolean>} - true if this file should cause an abort
|
|
291
|
+
*/
|
|
292
|
+
async function processFile(file, currentBranch) {
|
|
293
|
+
if (!getSupportedLanguage().includes(path.extname(file))) return false;
|
|
294
|
+
const rawErrors = await lintFiles(file);
|
|
295
|
+
if (!rawErrors || !file || typeof file !== 'string') return false;
|
|
296
|
+
const lintErrors = extractLintErrors(rawErrors);
|
|
297
|
+
if (lintErrors.length === 0) return false;
|
|
298
|
+
let relevantErrors;
|
|
299
|
+
if (impactBasedPrecommit) {
|
|
300
|
+
const diffLines = await calculateGitDiffForFile(currentBranch, file);
|
|
301
|
+
const ranges = getChangedLineRanges(diffLines);
|
|
302
|
+
relevantErrors = filterErrorsByChangedLines(lintErrors, ranges);
|
|
303
|
+
} else {
|
|
304
|
+
relevantErrors = lintErrors;
|
|
305
|
+
}
|
|
306
|
+
if (relevantErrors.length === 0) return false;
|
|
307
|
+
logFileErrors(file, relevantErrors);
|
|
308
|
+
return shouldErrorsAbortCommit(relevantErrors);
|
|
309
|
+
}
|
|
310
|
+
|
|
204
311
|
/**
|
|
205
312
|
* @function {preCommitHook} - method execute pre commit hook
|
|
206
313
|
* @returns {void}
|
|
@@ -209,142 +316,53 @@ function isOnlyWarningsPresentInFile(eslintErrorsPresent) {
|
|
|
209
316
|
async function preCommitHook_default() {
|
|
210
317
|
Logger.log(Logger.INFO_TYPE, '\n Executing pre commit hook...');
|
|
211
318
|
Logger.log(Logger.INFO_TYPE, `working dir : ${process.cwd()}`);
|
|
319
|
+
|
|
320
|
+
// Skip merge commits
|
|
212
321
|
try {
|
|
213
|
-
|
|
322
|
+
await isMergeCommit();
|
|
214
323
|
Logger.log(Logger.INFO_TYPE, 'Looks like you have merged. So skipping pre commit check');
|
|
215
324
|
process.exit(0);
|
|
216
|
-
} catch
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
325
|
+
} catch {
|
|
326
|
+
// Not a merge commit — continue
|
|
327
|
+
}
|
|
328
|
+
let currentBranch = '';
|
|
329
|
+
try {
|
|
330
|
+
currentBranch = await getBranchName();
|
|
331
|
+
} catch {
|
|
332
|
+
Logger.log(Logger.INFO_TYPE, 'Error fetching current branch');
|
|
333
|
+
}
|
|
334
|
+
let stagedFiles = [];
|
|
335
|
+
try {
|
|
336
|
+
stagedFiles = await getStagedFiles();
|
|
337
|
+
} catch {
|
|
338
|
+
Logger.log(Logger.INFO_TYPE, 'Error executing pre commit hook');
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
if (!stagedFiles || stagedFiles.length === 0) {
|
|
342
|
+
Logger.log(Logger.INFO_TYPE, 'No files have been staged. Stage your files before committing');
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
const {
|
|
346
|
+
JsFiles,
|
|
347
|
+
CssFiles
|
|
348
|
+
} = filterFiles(stagedFiles, ['.eslintrc.js'], true);
|
|
349
|
+
const filesToLint = [...JsFiles, ...CssFiles];
|
|
350
|
+
let shouldAbortCommit = false;
|
|
351
|
+
for (const file of filesToLint) {
|
|
230
352
|
try {
|
|
231
|
-
|
|
232
|
-
if (
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
} = filterFiles(staged_files, eslintConfigFiles, true);
|
|
237
|
-
|
|
238
|
-
// staged_filesJS = filterFiles(staged_filesJS,exemptionFiles) //this is the code for giving exemption to a file during pre commit
|
|
239
|
-
// if(staged_filesJS.length === 0){
|
|
240
|
-
// Logger.log(Logger.SUCCESS_TYPE,`Commit Successful`)
|
|
241
|
-
// process.exit(0)
|
|
242
|
-
// }
|
|
243
|
-
|
|
244
|
-
// CssFiles not Enabled For while
|
|
245
|
-
areFilesStaged = true;
|
|
246
|
-
var stagedFiles = [...staged_filesJS];
|
|
247
|
-
for (let file in stagedFiles) {
|
|
248
|
-
let currentFileName = stagedFiles[file];
|
|
249
|
-
let changedLinesArray = [];
|
|
250
|
-
let eslintErrorsInChangedLines = new Set();
|
|
251
|
-
let isOnlyEslintWarningsPresentInFile = false;
|
|
252
|
-
if (getSupportedLanguage().includes(path.extname(stagedFiles[file]))) {
|
|
253
|
-
try {
|
|
254
|
-
var errorsInFile = await lintFiles(stagedFiles[file]);
|
|
255
|
-
// eslintErrorsInFile = impactBasedPrecommit == false ? filterWarningInFile(errorsInFile) : errorsInFile
|
|
256
|
-
if (stagedFiles[file] && typeof stagedFiles[file] == 'string') {
|
|
257
|
-
if (!errorsInFile.length == 0) {
|
|
258
|
-
//Calculating changed lines in a file and storing them in respective arrays
|
|
259
|
-
if (impactBasedPrecommit) {
|
|
260
|
-
//git diff is computed and stored in an array
|
|
261
|
-
let git_diff = await calculateGitDiffForFile(current_branch, stagedFiles[file]);
|
|
262
|
-
changedLinesArray = git_diff.filter(line => line.startsWith('@@'));
|
|
263
|
-
let changedLinesStartArray = [];
|
|
264
|
-
let changedLinesEndArray = [];
|
|
265
|
-
for (let number of changedLinesArray) {
|
|
266
|
-
let changesStartLine = parseInt(number.split(' ')[2].split(',')[0]);
|
|
267
|
-
changedLinesStartArray.push(changesStartLine);
|
|
268
|
-
let changesEndLine = number.split(' ')[2].split(',')[1];
|
|
269
|
-
if (changesEndLine === undefined) {
|
|
270
|
-
changedLinesEndArray.push(changesStartLine);
|
|
271
|
-
} else {
|
|
272
|
-
changedLinesEndArray.push(changesStartLine + parseInt(changesEndLine) - 1);
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
for (let error = 1; error < errorsInFile.length - 2; error++) {
|
|
276
|
-
//errorsInFile[error].trim() - 69:26 error => Do not hardcode content. Use I18N key instead no-hardcoding/no-hardcoding,
|
|
277
|
-
//errorsInFile[error].trim().split(' ')[0] => 69:26
|
|
278
|
-
//errorsInFile[error].trim().split(' ')[0].split(':')[0] => 69
|
|
279
|
-
|
|
280
|
-
let eslintErrorLineNumber = errorsInFile[error].trim().split(' ')[0].split(':')[0];
|
|
281
|
-
if (MandatoryListRules.some(ruleId => errorsInFile[error].trim().includes(ruleId))) {
|
|
282
|
-
eslintErrorsInChangedLines.add(errorsInFile[error]);
|
|
283
|
-
}
|
|
284
|
-
for (let lineNumber in changedLinesStartArray) {
|
|
285
|
-
if (eslintErrorLineNumber >= changedLinesStartArray[lineNumber] && eslintErrorLineNumber <= changedLinesEndArray[lineNumber]) {
|
|
286
|
-
eslintErrorsInChangedLines.add(errorsInFile[error]);
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
if (eslintErrorsInChangedLines.size > 0) {
|
|
291
|
-
isOnlyEslintWarningsPresentInFile = isOnlyWarningsPresentInFile(Array.from(eslintErrorsInChangedLines));
|
|
292
|
-
Logger.log(Logger.FAILURE_TYPE, `\x1b[1m${currentFileName}\x1b[0m`);
|
|
293
|
-
for (let eslintError of Array.from(eslintErrorsInChangedLines)) {
|
|
294
|
-
Logger.log(Logger.FAILURE_TYPE, `\x1b[37m${eslintError.trimEnd()}\x1b[0m`);
|
|
295
|
-
}
|
|
296
|
-
if (shouldWarningsAbortCommit) {
|
|
297
|
-
hasEslintErrorsInChangedLines = true;
|
|
298
|
-
shouldAbortCommit = true;
|
|
299
|
-
} else if (!shouldWarningsAbortCommit && isOnlyEslintWarningsPresentInFile) {
|
|
300
|
-
hasEslintErrorsInChangedLines = false;
|
|
301
|
-
} else if (!shouldWarningsAbortCommit && !isOnlyEslintWarningsPresentInFile) {
|
|
302
|
-
hasEslintErrorsInChangedLines = true;
|
|
303
|
-
shouldAbortCommit = true;
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
} else {
|
|
307
|
-
if (errorsInFile.length > 0) {
|
|
308
|
-
let startIndex = 1;
|
|
309
|
-
let endIndex = errorsInFile.length - 2;
|
|
310
|
-
let listOsEslintErrors = errorsInFile.slice(startIndex, endIndex);
|
|
311
|
-
isOnlyEslintWarningsPresentInFile = isOnlyWarningsPresentInFile(listOsEslintErrors);
|
|
312
|
-
Logger.log(Logger.FAILURE_TYPE, `\x1b[1m${currentFileName}\x1b[0m`);
|
|
313
|
-
for (let eslintError of listOsEslintErrors) {
|
|
314
|
-
Logger.log(Logger.FAILURE_TYPE, `\x1b[37m${eslintError.trimEnd()}\x1b[0m`);
|
|
315
|
-
}
|
|
316
|
-
if (shouldWarningsAbortCommit) {
|
|
317
|
-
hasEslintErrorsInFiles = true;
|
|
318
|
-
shouldAbortCommit = true;
|
|
319
|
-
} else if (!shouldWarningsAbortCommit && isOnlyEslintWarningsPresentInFile) {
|
|
320
|
-
hasEslintErrorsInFiles = false;
|
|
321
|
-
} else if (!shouldWarningsAbortCommit && !isOnlyEslintWarningsPresentInFile) {
|
|
322
|
-
hasEslintErrorsInFiles = true;
|
|
323
|
-
shouldAbortCommit = true;
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
} catch (err) {
|
|
330
|
-
Logger.log(Logger.FAILURE_TYPE, err);
|
|
331
|
-
Logger.log(Logger.FAILURE_TYPE, "Error in executing lint command");
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
} else if (staged_files.length === 0) {
|
|
336
|
-
Logger.log(Logger.INFO_TYPE, 'No files have been staged. Stage your files before committing');
|
|
337
|
-
}
|
|
338
|
-
} catch {
|
|
339
|
-
Logger.log(Logger.INFO_TYPE, 'Error executing pre commit hook');
|
|
340
|
-
}
|
|
341
|
-
if (shouldAbortCommit) {
|
|
342
|
-
Logger.log(Logger.FAILURE_TYPE, `There are linter errors/warnings present. So commit is aborted.`);
|
|
343
|
-
process.exit(1);
|
|
344
|
-
} else if (shouldAbortCommit === false && staged_files.length !== 0) {
|
|
345
|
-
Logger.log(Logger.SUCCESS_TYPE, `Commit Successful`);
|
|
346
|
-
process.exit(0);
|
|
353
|
+
const shouldAbort = await processFile(file, currentBranch);
|
|
354
|
+
if (shouldAbort) shouldAbortCommit = true;
|
|
355
|
+
} catch (err) {
|
|
356
|
+
Logger.log(Logger.FAILURE_TYPE, err);
|
|
357
|
+
Logger.log(Logger.FAILURE_TYPE, 'Error in executing lint command');
|
|
347
358
|
}
|
|
348
359
|
}
|
|
360
|
+
if (shouldAbortCommit) {
|
|
361
|
+
Logger.log(Logger.FAILURE_TYPE, 'There are linter errors/warnings present. So commit is aborted.');
|
|
362
|
+
process.exit(1);
|
|
363
|
+
} else {
|
|
364
|
+
Logger.log(Logger.SUCCESS_TYPE, 'Commit Successful');
|
|
365
|
+
process.exit(0);
|
|
366
|
+
}
|
|
349
367
|
}
|
|
350
368
|
preCommitHook_default();
|
package/build/hooks/hook.js
CHANGED
|
@@ -24,11 +24,12 @@ const {
|
|
|
24
24
|
const {
|
|
25
25
|
ensurePluginsInstalled
|
|
26
26
|
} = require('./Precommit/guard');
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
const {
|
|
28
|
+
initConfig,
|
|
29
|
+
getConfigPathExecute
|
|
30
|
+
} = require('../utils/General/Config');
|
|
31
|
+
require("../chunk/chunk_Restriction");
|
|
32
|
+
initConfig(getConfigPathExecute());
|
|
32
33
|
async function hooks() {
|
|
33
34
|
var jsonFilePath = path.join(__dirname, '..', '..', 'jsonUtils', 'fsUtils.json');
|
|
34
35
|
let latestCommit = getLastCommitHash();
|
package/build/lib/postinstall.js
CHANGED
|
@@ -15,27 +15,23 @@ const {
|
|
|
15
15
|
const {
|
|
16
16
|
executeMethodsThatReturnBooleanValue
|
|
17
17
|
} = require('../utils/General/wrapperFunctionToExecuteAFunction');
|
|
18
|
-
const {
|
|
19
|
-
arePluginsInstalled
|
|
20
|
-
} = require('../utils/PluginsInstallation/arePluginsInstalled');
|
|
21
18
|
const {
|
|
22
19
|
isGitInitialized
|
|
23
20
|
} = require('../utils/GitActions/gitActions');
|
|
24
21
|
const {
|
|
25
22
|
writeFsPaths
|
|
26
23
|
} = require('../utils/General/writeProjectDetailsToJson');
|
|
27
|
-
const
|
|
24
|
+
const {
|
|
25
|
+
initConfig,
|
|
26
|
+
getConfigPathPostInstall
|
|
27
|
+
} = require('../utils/General/Config');
|
|
28
|
+
|
|
28
29
|
/**
|
|
29
30
|
* @function {postInstall} - This methods setup husky and configuration for executing project
|
|
30
31
|
* @returns {void}
|
|
31
32
|
*/
|
|
32
33
|
async function postInstall() {
|
|
33
|
-
|
|
34
|
-
const config = require(path.join(actualNodeMoulesPath, 'lint.config.js'));
|
|
35
|
-
process.env.SONARQUBE_EXTERNAL = config.metric_token;
|
|
36
|
-
process.env.SONARQUBE = config.meticHandler_api_token;
|
|
37
|
-
process.env.ZGIT_TOKEN = config.token;
|
|
38
|
-
process.env.TOOL_TOKEN = config.toolToken;
|
|
34
|
+
initConfig(getConfigPathPostInstall());
|
|
39
35
|
try {
|
|
40
36
|
await executeMethodsThatReturnBooleanValue('Some issue in writing node_modules path to json', writeFsPaths, null);
|
|
41
37
|
isGitInitialized() ? await executeMethodsThatReturnBooleanValue('Some issue occurred in setting up husky.', setupHusky, null) : null;
|