@zohodesk/codestandard-validator 1.2.4-exp-1 → 1.2.4-exp-3
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 +6 -1
- package/build/ai/run-review.js +1 -1
- package/build/chunk/chunk_Restriction.js +12 -2
- package/build/hooks/Precommit/pre-commit-default.js +155 -140
- package/build/hooks/hook.js +5 -3
- 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/ConfigFileUtils/getLintConfiguration.js +21 -10
- package/build/utils/FileAndFolderOperations/filterFiles.js +8 -6
- package/build/utils/FileAndFolderOperations/removeFolder.js +2 -2
- package/build/utils/General/Config.js +23 -2
- package/jsonUtils/MandatoryListRules.js +1 -1
- package/package.json +2 -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
package/bin/cliCI.js
CHANGED
|
@@ -5,4 +5,9 @@
|
|
|
5
5
|
* @fileoverview This script is a Node.js executable that imports and runs the module `runner` from the `../build/lib/` directory.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
(async function () {
|
|
9
|
+
const { initConfig, getConfigPathExecute } = require('../build/utils/General/Config');
|
|
10
|
+
await initConfig(getConfigPathExecute());
|
|
11
|
+
await require('../build/chunk/chunk_Restriction');
|
|
12
|
+
require('@zohodesk/codestandard-analytics/build/lib/runner');
|
|
13
|
+
})();
|
package/build/ai/run-review.js
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
// const PROMPT_FOLDER = path.resolve(__dirname, 'prompts');
|
|
15
15
|
|
|
16
|
-
// const REVIEW_FOLDER = '/Users/raja-17710/deskApp/linter_tools/codestandard-validator/src/
|
|
16
|
+
// const REVIEW_FOLDER = '/Users/raja-17710/deskApp/linter_tools/codestandard-validator/src/mutation';
|
|
17
17
|
|
|
18
18
|
// const FOLDER_EXTENSIONS = ['.js', '.ts'];
|
|
19
19
|
|
|
@@ -12,7 +12,16 @@ const {
|
|
|
12
12
|
} = require('../utils/GitActions/gitActions');
|
|
13
13
|
const Logger = console;
|
|
14
14
|
const path = require('path');
|
|
15
|
-
const
|
|
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';
|
|
16
25
|
const compareBranch = ((_process = process) === null || _process === void 0 || (_process = _process.env) === null || _process === void 0 ? void 0 : _process.CHUNK_BRANCH) || 'release';
|
|
17
26
|
const configPath = path.resolve(process.cwd(), 'lint.config.js');
|
|
18
27
|
function getGitProjectId() {
|
|
@@ -168,7 +177,7 @@ if (shouldEnable) {
|
|
|
168
177
|
const GREEN = '\x1b[32m';
|
|
169
178
|
const RESET = '\x1b[0m';
|
|
170
179
|
(async function () {
|
|
171
|
-
Logger.log(
|
|
180
|
+
Logger.log(`****************************** Calculation Chunk Size *******************************`);
|
|
172
181
|
if (!(globalThis !== null && globalThis !== void 0 && globalThis.chunkSize)) {
|
|
173
182
|
globalThis.chunkSize = {
|
|
174
183
|
$modifieldLines: 0,
|
|
@@ -176,6 +185,7 @@ if (shouldEnable) {
|
|
|
176
185
|
};
|
|
177
186
|
try {
|
|
178
187
|
await getGitChangesets(myCurrentBranch, targetRelease, remoteName);
|
|
188
|
+
process.env.CHUNK_SIZE = JSON.stringify(chunkSize);
|
|
179
189
|
if (chunkSize.$modifieldLines <= chunk_size_env) {
|
|
180
190
|
Logger.log(`${GREEN}Your Chunk was ${chunkSize.$modifieldLines} and remaining size ${chunk_size_env - chunkSize.$modifieldLines}${RESET}`);
|
|
181
191
|
} else {
|
|
@@ -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,12 @@ 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: process.env
|
|
133
135
|
});
|
|
134
136
|
});
|
|
135
137
|
} else {
|
|
@@ -141,8 +143,8 @@ function findEslintErrors(file) {
|
|
|
141
143
|
}
|
|
142
144
|
|
|
143
145
|
/**
|
|
144
|
-
*
|
|
145
|
-
* @param {*} params
|
|
146
|
+
*
|
|
147
|
+
* @param {*} params
|
|
146
148
|
*/
|
|
147
149
|
function findStyleLintErrors(filePath) {
|
|
148
150
|
const configFilePath = path.resolve(getNodeModulesPath(), '.stylelintrc.js');
|
|
@@ -156,7 +158,7 @@ function findStyleLintErrors(filePath) {
|
|
|
156
158
|
resolve(stdout.trim().split('\n'));
|
|
157
159
|
} else if (error) {
|
|
158
160
|
Logger.log(Logger.FAILURE_TYPE, error);
|
|
159
|
-
reject(
|
|
161
|
+
reject('Error executing stylelint command');
|
|
160
162
|
} else {
|
|
161
163
|
resolve([]);
|
|
162
164
|
}
|
|
@@ -172,7 +174,7 @@ function findStyleLintErrors(filePath) {
|
|
|
172
174
|
* @function {calculateGitDiffForFile} - method calculate diff of file
|
|
173
175
|
* @param {*} branch_name - branch name
|
|
174
176
|
* @param {*} file - path of file
|
|
175
|
-
* @returns {Promise<Array<string>>} - array of command line report as a string
|
|
177
|
+
* @returns {Promise<Array<string>>} - array of command line report as a string
|
|
176
178
|
*/
|
|
177
179
|
async function calculateGitDiffForFile(branch_name, file) {
|
|
178
180
|
let gitDiffCommand = `git diff -U0 ${branch_name.trim()} ${path.resolve(getRootDirectory(), file)}`;
|
|
@@ -194,13 +196,115 @@ async function calculateGitDiffForFile(branch_name, file) {
|
|
|
194
196
|
function isOnlyWarningsPresentInFile(eslintErrorsPresent) {
|
|
195
197
|
let severityOfEachErrorInFile = [];
|
|
196
198
|
eslintErrorsPresent.map(error => {
|
|
197
|
-
let partsInString = error.split(
|
|
199
|
+
let partsInString = error.split(' ');
|
|
198
200
|
let severityOfError = partsInString.find(word => word === 'error' || word === 'warning' || word === '✖');
|
|
199
201
|
severityOfEachErrorInFile.push(severityOfError);
|
|
200
202
|
});
|
|
201
203
|
return !(severityOfEachErrorInFile.includes('✖') || severityOfEachErrorInFile.includes('error'));
|
|
202
204
|
}
|
|
203
205
|
|
|
206
|
+
/**
|
|
207
|
+
* Parse git diff hunk headers into changed line ranges.
|
|
208
|
+
* @param {string[]} diffLines - raw git diff output lines
|
|
209
|
+
* @returns {Array<{start: number, end: number}>}
|
|
210
|
+
*/
|
|
211
|
+
function getChangedLineRanges(diffLines) {
|
|
212
|
+
return diffLines.filter(line => line.startsWith('@@')).map(line => {
|
|
213
|
+
const [startStr, countStr] = line.split(' ')[2].split(',');
|
|
214
|
+
const start = parseInt(startStr, 10);
|
|
215
|
+
const end = countStr !== undefined ? start + parseInt(countStr, 10) - 1 : start;
|
|
216
|
+
return {
|
|
217
|
+
start,
|
|
218
|
+
end
|
|
219
|
+
};
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Extract only error/warning lines from eslint output (strip header & summary).
|
|
225
|
+
* @param {string[]} rawOutput
|
|
226
|
+
* @returns {string[]}
|
|
227
|
+
*/
|
|
228
|
+
function extractLintErrors(rawOutput) {
|
|
229
|
+
if (!rawOutput || rawOutput.length <= 2) return [];
|
|
230
|
+
return rawOutput.slice(1, rawOutput.length - 2);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Filter lint errors to those on changed lines or matching mandatory rules.
|
|
235
|
+
* @param {string[]} lintErrors - extracted error lines
|
|
236
|
+
* @param {Array<{start: number, end: number}>} ranges - changed line ranges
|
|
237
|
+
* @returns {string[]}
|
|
238
|
+
*/
|
|
239
|
+
function filterErrorsByChangedLines(lintErrors, ranges) {
|
|
240
|
+
const result = new Set();
|
|
241
|
+
for (const errorLine of lintErrors) {
|
|
242
|
+
const lineNum = parseInt(errorLine.trim().split(' ')[0].split(':')[0], 10);
|
|
243
|
+
if (MandatoryListRules.some(ruleId => errorLine.trim().includes(ruleId))) {
|
|
244
|
+
result.add(errorLine);
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
for (const {
|
|
248
|
+
start,
|
|
249
|
+
end
|
|
250
|
+
} of ranges) {
|
|
251
|
+
if (lineNum >= start && lineNum <= end) {
|
|
252
|
+
result.add(errorLine);
|
|
253
|
+
break;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
return Array.from(result);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Determine whether errors should abort the commit.
|
|
262
|
+
* @param {string[]} errors
|
|
263
|
+
* @returns {boolean}
|
|
264
|
+
*/
|
|
265
|
+
function shouldErrorsAbortCommit(errors) {
|
|
266
|
+
if (errors.length === 0) return false;
|
|
267
|
+
if (shouldWarningsAbortCommit) return true;
|
|
268
|
+
return !isOnlyWarningsPresentInFile(errors);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Log lint errors for a file.
|
|
273
|
+
* @param {string} fileName
|
|
274
|
+
* @param {string[]} errors
|
|
275
|
+
*/
|
|
276
|
+
function logFileErrors(fileName, errors) {
|
|
277
|
+
Logger.log(Logger.FAILURE_TYPE, `\x1b[1m${fileName}\x1b[0m`);
|
|
278
|
+
for (const error of errors) {
|
|
279
|
+
Logger.log(Logger.FAILURE_TYPE, `\x1b[37m${error.trimEnd()}\x1b[0m`);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Process a single staged file: lint it, optionally filter by changed lines, and return whether to abort.
|
|
285
|
+
* @param {string} file - relative file path
|
|
286
|
+
* @param {string} currentBranch
|
|
287
|
+
* @returns {Promise<boolean>} - true if this file should cause an abort
|
|
288
|
+
*/
|
|
289
|
+
async function processFile(file, currentBranch) {
|
|
290
|
+
if (!getSupportedLanguage().includes(path.extname(file))) return false;
|
|
291
|
+
const rawErrors = await lintFiles(file);
|
|
292
|
+
if (!rawErrors || !file || typeof file !== 'string') return false;
|
|
293
|
+
const lintErrors = extractLintErrors(rawErrors);
|
|
294
|
+
if (lintErrors.length === 0) return false;
|
|
295
|
+
let relevantErrors;
|
|
296
|
+
if (impactBasedPrecommit) {
|
|
297
|
+
const diffLines = await calculateGitDiffForFile(currentBranch, file);
|
|
298
|
+
const ranges = getChangedLineRanges(diffLines);
|
|
299
|
+
relevantErrors = filterErrorsByChangedLines(lintErrors, ranges);
|
|
300
|
+
} else {
|
|
301
|
+
relevantErrors = lintErrors;
|
|
302
|
+
}
|
|
303
|
+
if (relevantErrors.length === 0) return false;
|
|
304
|
+
logFileErrors(file, relevantErrors);
|
|
305
|
+
return shouldErrorsAbortCommit(relevantErrors);
|
|
306
|
+
}
|
|
307
|
+
|
|
204
308
|
/**
|
|
205
309
|
* @function {preCommitHook} - method execute pre commit hook
|
|
206
310
|
* @returns {void}
|
|
@@ -209,142 +313,53 @@ function isOnlyWarningsPresentInFile(eslintErrorsPresent) {
|
|
|
209
313
|
async function preCommitHook_default() {
|
|
210
314
|
Logger.log(Logger.INFO_TYPE, '\n Executing pre commit hook...');
|
|
211
315
|
Logger.log(Logger.INFO_TYPE, `working dir : ${process.cwd()}`);
|
|
316
|
+
|
|
317
|
+
// Skip merge commits
|
|
212
318
|
try {
|
|
213
|
-
|
|
319
|
+
await isMergeCommit();
|
|
214
320
|
Logger.log(Logger.INFO_TYPE, 'Looks like you have merged. So skipping pre commit check');
|
|
215
321
|
process.exit(0);
|
|
216
|
-
} catch
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
322
|
+
} catch {
|
|
323
|
+
// Not a merge commit — continue
|
|
324
|
+
}
|
|
325
|
+
let currentBranch = '';
|
|
326
|
+
try {
|
|
327
|
+
currentBranch = await getBranchName();
|
|
328
|
+
} catch {
|
|
329
|
+
Logger.log(Logger.INFO_TYPE, 'Error fetching current branch');
|
|
330
|
+
}
|
|
331
|
+
let stagedFiles = [];
|
|
332
|
+
try {
|
|
333
|
+
stagedFiles = await getStagedFiles();
|
|
334
|
+
} catch {
|
|
335
|
+
Logger.log(Logger.INFO_TYPE, 'Error executing pre commit hook');
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
if (!stagedFiles || stagedFiles.length === 0) {
|
|
339
|
+
Logger.log(Logger.INFO_TYPE, 'No files have been staged. Stage your files before committing');
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
const {
|
|
343
|
+
JsFiles,
|
|
344
|
+
CssFiles
|
|
345
|
+
} = filterFiles(stagedFiles, ['.eslintrc.js'], true);
|
|
346
|
+
const filesToLint = [...JsFiles, ...CssFiles];
|
|
347
|
+
let shouldAbortCommit = false;
|
|
348
|
+
for (const file of filesToLint) {
|
|
230
349
|
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, ...CssFiles];
|
|
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);
|
|
350
|
+
const shouldAbort = await processFile(file, currentBranch);
|
|
351
|
+
if (shouldAbort) shouldAbortCommit = true;
|
|
352
|
+
} catch (err) {
|
|
353
|
+
Logger.log(Logger.FAILURE_TYPE, err);
|
|
354
|
+
Logger.log(Logger.FAILURE_TYPE, 'Error in executing lint command');
|
|
347
355
|
}
|
|
348
356
|
}
|
|
357
|
+
if (shouldAbortCommit) {
|
|
358
|
+
Logger.log(Logger.FAILURE_TYPE, 'There are linter errors/warnings present. So commit is aborted.');
|
|
359
|
+
process.exit(1);
|
|
360
|
+
} else {
|
|
361
|
+
Logger.log(Logger.SUCCESS_TYPE, 'Commit Successful');
|
|
362
|
+
process.exit(0);
|
|
363
|
+
}
|
|
349
364
|
}
|
|
350
365
|
preCommitHook_default();
|
package/build/hooks/hook.js
CHANGED
|
@@ -28,8 +28,6 @@ const {
|
|
|
28
28
|
initConfig,
|
|
29
29
|
getConfigPathExecute
|
|
30
30
|
} = require('../utils/General/Config');
|
|
31
|
-
require("../chunk/chunk_Restriction");
|
|
32
|
-
initConfig(getConfigPathExecute());
|
|
33
31
|
async function hooks() {
|
|
34
32
|
var jsonFilePath = path.join(__dirname, '..', '..', 'jsonUtils', 'fsUtils.json');
|
|
35
33
|
let latestCommit = getLastCommitHash();
|
|
@@ -54,4 +52,8 @@ async function hooks() {
|
|
|
54
52
|
require('./Precommit/pre-commit-default');
|
|
55
53
|
}
|
|
56
54
|
}
|
|
57
|
-
|
|
55
|
+
(async function () {
|
|
56
|
+
await initConfig(getConfigPathExecute());
|
|
57
|
+
await require("../chunk/chunk_Restriction");
|
|
58
|
+
hooks();
|
|
59
|
+
})();
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
execSync
|
|
5
|
+
} = require('child_process');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
class BranchDiff {
|
|
8
|
+
constructor(options = {}) {
|
|
9
|
+
this._cwd = options.cwd || process.cwd();
|
|
10
|
+
this._api = options.api || null;
|
|
11
|
+
this._patToken = options.patToken || null;
|
|
12
|
+
this._sourceExtensions = options.sourceExtensions || ['.js', '.ts', '.jsx', '.tsx', '.mjs', '.cjs'];
|
|
13
|
+
this._testPattern = options.testPattern || /\.(test)\.(js|ts|jsx|tsx|mjs|cjs)$/;
|
|
14
|
+
}
|
|
15
|
+
_getCurrentBranch() {
|
|
16
|
+
try {
|
|
17
|
+
return execSync('git rev-parse --abbrev-ref HEAD', {
|
|
18
|
+
cwd: this._cwd,
|
|
19
|
+
encoding: 'utf-8'
|
|
20
|
+
}).trim();
|
|
21
|
+
} catch (err) {
|
|
22
|
+
throw new Error(`Failed to get current branch: ${err.message}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
_fetchBranch(branch) {
|
|
26
|
+
try {
|
|
27
|
+
execSync(`git fetch origin ${branch}`, {
|
|
28
|
+
cwd: this._cwd,
|
|
29
|
+
encoding: 'utf-8',
|
|
30
|
+
stdio: 'pipe'
|
|
31
|
+
});
|
|
32
|
+
} catch (err) {
|
|
33
|
+
// Branch might already be available locally
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
_resolveBranchRef(branch) {
|
|
37
|
+
// Check if the ref exists locally
|
|
38
|
+
const candidates = [branch, `origin/${branch}`];
|
|
39
|
+
for (const ref of candidates) {
|
|
40
|
+
try {
|
|
41
|
+
execSync(`git rev-parse --verify ${ref}`, {
|
|
42
|
+
cwd: this._cwd,
|
|
43
|
+
encoding: 'utf-8',
|
|
44
|
+
stdio: 'pipe'
|
|
45
|
+
});
|
|
46
|
+
return ref;
|
|
47
|
+
} catch {
|
|
48
|
+
// try next
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
throw new Error(`Branch '${branch}' not found locally or as 'origin/${branch}'. ` + `Run 'git fetch origin ${branch}' or check the branch name.`);
|
|
52
|
+
}
|
|
53
|
+
_getDiffFiles(targetBranch) {
|
|
54
|
+
const currentBranch = this._getCurrentBranch();
|
|
55
|
+
this._fetchBranch(targetBranch);
|
|
56
|
+
const resolvedRef = this._resolveBranchRef(targetBranch);
|
|
57
|
+
let diffRef;
|
|
58
|
+
try {
|
|
59
|
+
const mergeBase = execSync(`git merge-base ${resolvedRef} ${currentBranch}`, {
|
|
60
|
+
cwd: this._cwd,
|
|
61
|
+
encoding: 'utf-8'
|
|
62
|
+
}).trim();
|
|
63
|
+
diffRef = mergeBase;
|
|
64
|
+
} catch {
|
|
65
|
+
diffRef = resolvedRef;
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
const output = execSync(`git diff --name-only --diff-filter=ACMR ${diffRef}`, {
|
|
69
|
+
cwd: this._cwd,
|
|
70
|
+
encoding: 'utf-8'
|
|
71
|
+
});
|
|
72
|
+
return output.split('\n').map(f => f.trim()).filter(f => f.length > 0);
|
|
73
|
+
} catch (err) {
|
|
74
|
+
throw new Error(`Failed to get diff files against branch '${targetBranch}': ${err.message}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
_getDiffFilesFromApi(targetBranch) {
|
|
78
|
+
if (!this._api || !this._patToken) {
|
|
79
|
+
throw new Error('API and PAT token are required for API-based diff');
|
|
80
|
+
}
|
|
81
|
+
// Placeholder for API-based diff (e.g., Azure DevOps, GitHub, etc.)
|
|
82
|
+
// Consumers can pass in their own api object that implements `getChangedFiles(targetBranch, patToken)`
|
|
83
|
+
if (typeof this._api.getChangedFiles === 'function') {
|
|
84
|
+
return this._api.getChangedFiles(targetBranch, this._patToken);
|
|
85
|
+
}
|
|
86
|
+
throw new Error('API object must implement getChangedFiles(targetBranch, patToken)');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Fetches branch diff from GitLab compare API via HTTPS
|
|
91
|
+
* @param {string} hostname - GitLab host (e.g. 'gitlab.example.com')
|
|
92
|
+
* @param {string} branch - Target branch to compare against
|
|
93
|
+
* @returns {Promise<string[]>} - Array of changed file paths
|
|
94
|
+
*/
|
|
95
|
+
_fetchBranchDiffFromApi(hostname, branch, projectId) {
|
|
96
|
+
const currentBranch = this._getCurrentBranch();
|
|
97
|
+
const patToken = this._patToken || process.env.ZGIT_TOKEN;
|
|
98
|
+
if (!patToken) {
|
|
99
|
+
return reject(new Error('PAT token is required. Set it via options.patToken or ZGIT_TOKEN env var'));
|
|
100
|
+
}
|
|
101
|
+
if (!projectId) {
|
|
102
|
+
return reject(new Error('GitLab projectId is required for API-based diff'));
|
|
103
|
+
}
|
|
104
|
+
const createBranchDiffChunk = (resolve, reject) => {
|
|
105
|
+
// code duplicate need find solution
|
|
106
|
+
var command;
|
|
107
|
+
const endPoint = `${hostname}/api/v4/projects/${encodeURIComponent(projectId)}/repository/compare?from=${branch}&to=${currentBranch}`;
|
|
108
|
+
try {
|
|
109
|
+
command = `curl --header "PRIVATE-TOKEN:${patToken}" "${endPoint}"`;
|
|
110
|
+
return resolve(parserReleaseDiffRemoteAPI(JSON.parse(execSync(command, {
|
|
111
|
+
cwd: this._cwd
|
|
112
|
+
}))));
|
|
113
|
+
} catch (error) {
|
|
114
|
+
Logger.log(error);
|
|
115
|
+
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.`);
|
|
116
|
+
Logger.log(`\n Make sure that you have access to this repository`);
|
|
117
|
+
reject(error);
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
function parserReleaseDiffRemoteAPI(rawresponse) {
|
|
121
|
+
var formatted = [];
|
|
122
|
+
if (rawresponse !== null && rawresponse !== void 0 && rawresponse.diffs) {
|
|
123
|
+
formatted = rawresponse.diffs.map(changeset => {
|
|
124
|
+
return changeset === null || changeset === void 0 ? void 0 : changeset.new_path;
|
|
125
|
+
}).filter(Boolean);
|
|
126
|
+
}
|
|
127
|
+
return formatted;
|
|
128
|
+
}
|
|
129
|
+
return new Promise((resolve, reject) => {
|
|
130
|
+
return createBranchDiffChunk(resolve, reject);
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
async getStagedFiles() {
|
|
134
|
+
try {
|
|
135
|
+
const stdout = await execSync("git diff --staged --name-only").toString();
|
|
136
|
+
const files = stdout.trim().split("\n").filter(Boolean);
|
|
137
|
+
return files;
|
|
138
|
+
} catch (error) {
|
|
139
|
+
console.log(error);
|
|
140
|
+
throw new Error("Couldn't fetch staged files");
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
async getChangedFiles(targetBranch, options = {}) {
|
|
144
|
+
let allFiles;
|
|
145
|
+
if (options.useApi && options.hostname && options.projectId) {
|
|
146
|
+
allFiles = await this._fetchBranchDiffFromApi(options.hostname, targetBranch, options.projectId).concat(await this.getStagedFiles());
|
|
147
|
+
} else {
|
|
148
|
+
allFiles = this._getDiffFiles(targetBranch);
|
|
149
|
+
}
|
|
150
|
+
return this._categorizeFiles(allFiles);
|
|
151
|
+
}
|
|
152
|
+
_isSourceFile(filePath) {
|
|
153
|
+
const ext = path.extname(filePath);
|
|
154
|
+
if (!this._sourceExtensions.includes(ext)) {
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
return !this._testPattern.test(filePath);
|
|
158
|
+
}
|
|
159
|
+
_isTestFile(filePath) {
|
|
160
|
+
return this._testPattern.test(filePath);
|
|
161
|
+
}
|
|
162
|
+
_categorizeFiles(files) {
|
|
163
|
+
const sourceFiles = [];
|
|
164
|
+
const testFiles = [];
|
|
165
|
+
for (const file of files) {
|
|
166
|
+
if (this._isTestFile(file)) {
|
|
167
|
+
testFiles.push(file);
|
|
168
|
+
} else if (this._isSourceFile(file)) {
|
|
169
|
+
sourceFiles.push(file);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return {
|
|
173
|
+
sourceFiles,
|
|
174
|
+
testFiles
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
module.exports = BranchDiff;
|