mirror of
https://github.com/vacp2p/linea-monorepo.git
synced 2026-01-09 04:08:01 -05:00
Feat/husky lint (#431)
* add poc husky lint script * test commit change * undo test change * test change * undo test change * test * test * test * test * do * test * test * test * test * test * test * test * test * test * test * refactor to pre-commit to NodeJS script * add logs for demo * small refactor of pre-commit.js * add shebang to pre-commit * add other folders to husky script * added postman to pre-commit * remove test md change * add comments for pre-commit.js * adjust lint:fix scripts * Update .husky/pre-commit.js Co-authored-by: The Dark Jester <thedarkjester@users.noreply.github.com> Signed-off-by: kyzooghost <73516204+kyzooghost@users.noreply.github.com> --------- Signed-off-by: kyzooghost <73516204+kyzooghost@users.noreply.github.com> Co-authored-by: The Dark Jester <thedarkjester@users.noreply.github.com>
This commit is contained in:
10
.husky/pre-commit
Executable file
10
.husky/pre-commit
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Run `npx husky` in root directory to initialize this pre-commit hook for local machine
|
||||
|
||||
# Execute NodeJS script because
|
||||
# i.) Husky requires NodeJS -> fair assumption that machine will have NodeJS
|
||||
# ii.) Cleaner syntax and abstractions than shell scripting
|
||||
node .husky/pre-commit.js
|
||||
|
||||
exit 0
|
||||
217
.husky/pre-commit.js
Normal file
217
.husky/pre-commit.js
Normal file
@@ -0,0 +1,217 @@
|
||||
/**
|
||||
* Runs as git pre-commit hook
|
||||
* Filters the list of changed files on 'git commit'
|
||||
* If *.ts files in specified projects are detected, runs the 'lint:ts:fix' package.json script for that project
|
||||
* E.g. if a *.ts file is changed in /sdk, then this script will run 'pnpm run lint:ts:fix' in the /sdk project
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const { execSync } = require('child_process');
|
||||
|
||||
/**
|
||||
* ENUMS
|
||||
*/
|
||||
|
||||
// File extensions to filter for
|
||||
const FILE_EXTENSION = {
|
||||
TYPESCRIPT: "TYPESCRIPT",
|
||||
SOLIDITY: "SOLIDITY",
|
||||
}
|
||||
|
||||
// Projects to filter for
|
||||
const FOLDER = {
|
||||
BRIDGEUI: "BRIDGEUI",
|
||||
CONTRACTS: "CONTRACTS",
|
||||
E2E: "E2E",
|
||||
OPERATIONS: "OPERATIONS",
|
||||
POSTMAN: "POSTMAN",
|
||||
SDK: "SDK",
|
||||
}
|
||||
|
||||
// Project runtimes
|
||||
const RUNTIME = {
|
||||
NODEJS: "NODEJS"
|
||||
}
|
||||
|
||||
/**
|
||||
* MAPPINGS
|
||||
*/
|
||||
|
||||
// File extension => regex
|
||||
const FILE_EXTENSION_FILTERS = {
|
||||
[FILE_EXTENSION.TYPESCRIPT]: "\.ts$",
|
||||
[FILE_EXTENSION.SOLIDITY]: "\.sol$",
|
||||
};
|
||||
|
||||
// File extension => script in package.json to run
|
||||
const FILE_EXTENSION_LINTING_COMMAND = {
|
||||
[FILE_EXTENSION.TYPESCRIPT]: "pnpm run lint:ts:fix",
|
||||
[FILE_EXTENSION.SOLIDITY]: "pnpm run lint:sol:fix",
|
||||
};
|
||||
|
||||
// Project => Path in monorepo
|
||||
const FOLDER_PATH = {
|
||||
[FOLDER.BRIDGEUI]: "bridge-ui/",
|
||||
[FOLDER.CONTRACTS]: "contracts/",
|
||||
[FOLDER.E2E]: "e2e/",
|
||||
[FOLDER.OPERATIONS]: "operations/",
|
||||
[FOLDER.POSTMAN]: "postman/",
|
||||
[FOLDER.SDK]: "sdk/",
|
||||
};
|
||||
|
||||
// Project => List of changed files
|
||||
const FOLDER_CHANGED_FILES = {
|
||||
[FOLDER.BRIDGEUI]: new Array(),
|
||||
[FOLDER.CONTRACTS]: new Array(),
|
||||
[FOLDER.E2E]: new Array(),
|
||||
[FOLDER.OPERATIONS]: new Array(),
|
||||
[FOLDER.POSTMAN]: new Array(),
|
||||
[FOLDER.SDK]: new Array(),
|
||||
};
|
||||
|
||||
// Project => Runtime
|
||||
const FOLDER_RUNTIME = {
|
||||
[FOLDER.BRIDGEUI]: RUNTIME.NODEJS,
|
||||
[FOLDER.CONTRACTS]: RUNTIME.NODEJS,
|
||||
[FOLDER.E2E]: RUNTIME.NODEJS,
|
||||
[FOLDER.OPERATIONS]: RUNTIME.NODEJS,
|
||||
[FOLDER.POSTMAN]: RUNTIME.NODEJS,
|
||||
[FOLDER.SDK]: RUNTIME.NODEJS,
|
||||
};
|
||||
|
||||
/**
|
||||
* MAIN FUNCTION
|
||||
*/
|
||||
|
||||
main();
|
||||
|
||||
function main() {
|
||||
const changedFileList = getChangedFileList();
|
||||
partitionChangedFileList(changedFileList);
|
||||
|
||||
for (const folder in FOLDER) {
|
||||
if (!isDependenciesInstalled(folder)) {
|
||||
console.error(`Dependencies not installed in ${FOLDER_PATH[folder]}, exiting...`)
|
||||
process.exit(1);
|
||||
}
|
||||
const changedFileExtensions = getChangedFileExtensions(folder);
|
||||
executeLinting(folder, changedFileExtensions);
|
||||
}
|
||||
|
||||
updateGitIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* HELPER FUNCTIONS
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets a list of changed files in the git commit
|
||||
* @returns {string[]}
|
||||
*/
|
||||
function getChangedFileList() {
|
||||
try {
|
||||
const cmd = 'git diff --name-only HEAD'
|
||||
const stdout = execSync(cmd, { encoding: 'utf8' });
|
||||
return stdout.split('\n').filter(file => file.trim() !== '');
|
||||
} catch (error) {
|
||||
console.error($`Error running ${cmd}:`, error.message);
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Partitions list of changed files from getChangedFileList() by project
|
||||
* Stores results in FOLDER_CHANGED_FILES
|
||||
* @param {string[]}
|
||||
*/
|
||||
function partitionChangedFileList(_changedFileList) {
|
||||
for (const file of _changedFileList) {
|
||||
for (const path in FOLDER) {
|
||||
if (file.match(new RegExp(`^${FOLDER_PATH[path]}`))) {
|
||||
FOLDER_CHANGED_FILES[path].push(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if runtime dependencies are installed for a project
|
||||
* @param {FOLDER}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isDependenciesInstalled(_folder) {
|
||||
const runtime = FOLDER_RUNTIME[_folder];
|
||||
const path = FOLDER_PATH[_folder];
|
||||
|
||||
switch(runtime) {
|
||||
case RUNTIME.NODEJS:
|
||||
const dependencyFolder = `${path}node_modules`
|
||||
return fs.existsSync(dependencyFolder)
|
||||
default:
|
||||
console.error(`${runtime} runtime not supported.`);
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve list of changed file extensions for a project
|
||||
* @param {FOLDER}
|
||||
* @returns {FILE_EXTENSION[]}
|
||||
*/
|
||||
function getChangedFileExtensions(_folder) {
|
||||
// Use sets to implement early exit from loop, once we have matched all configured file extensions
|
||||
const remainingFileExtensionsSet = new Set(Object.values(FILE_EXTENSION));
|
||||
const foundFileExtensionsSet = new Set();
|
||||
|
||||
for (const file of FOLDER_CHANGED_FILES[_folder]) {
|
||||
for (const fileExtension of remainingFileExtensionsSet) {
|
||||
if (file.match(new RegExp(FILE_EXTENSION_FILTERS[fileExtension]))) {
|
||||
foundFileExtensionsSet.add(fileExtension);
|
||||
remainingFileExtensionsSet.delete(fileExtension);
|
||||
}
|
||||
}
|
||||
|
||||
// No more remaining file extensions to look for
|
||||
if (remainingFileExtensionsSet.size == 0) break;
|
||||
}
|
||||
|
||||
return Array.from(foundFileExtensionsSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute linting command
|
||||
* @param {FOLDER, FILE_EXTENSION[]}
|
||||
*/
|
||||
function executeLinting(_folder, _changedFileExtensions) {
|
||||
for (const fileExtension of _changedFileExtensions) {
|
||||
const path = FOLDER_PATH[_folder];
|
||||
const cmd = FILE_EXTENSION_LINTING_COMMAND[fileExtension];
|
||||
console.log(`${fileExtension} change found in ${path}, linting...`);
|
||||
try {
|
||||
// Execute command synchronously and stream output directly to the current stdout
|
||||
execSync(`
|
||||
cd ${path};
|
||||
${cmd};
|
||||
`, { stdio: 'inherit' });
|
||||
} catch (error) {
|
||||
console.error(`Error:`, error.message);
|
||||
console.error(`Exiting...`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Redo `git add` for files updated during executeLinting(), so that they are not left out of the commit
|
||||
* The difference between 'git add .' and 'git update-index --again', is that the latter will not include untracked files
|
||||
*/
|
||||
function updateGitIndex() {
|
||||
try {
|
||||
const cmd = 'git update-index --again'
|
||||
execSync(cmd, { stdio: 'inherit' });
|
||||
} catch (error) {
|
||||
console.error($`Error running ${cmd}:`, error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,8 @@
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint",
|
||||
"lint:fix": "next lint --fix",
|
||||
"lint:fix": "pnpm run lint:ts:fix",
|
||||
"lint:ts:fix": "next lint --fix",
|
||||
"clean": "rimraf node_modules .next .next-env.d.ts",
|
||||
"install:playwright": "playwright install --with-deps",
|
||||
"build:cache": "synpress",
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
"prettier": "prettier -c '**/*.{js,ts}'",
|
||||
"prettier:fix": "prettier -w '**/*.{js,ts}'",
|
||||
"lint": "eslint . --ext .ts",
|
||||
"lint:fix": "eslint . --ext .ts --fix",
|
||||
"lint:fix": "pnpm run lint:ts:fix",
|
||||
"lint:ts:fix": "eslint . --ext .ts --fix",
|
||||
"test": "node --experimental-vm-modules node_modules/jest/bin/jest --bail --detectOpenHandles --forceExit",
|
||||
"clean": "rimraf node_modules dist coverage",
|
||||
"postpack": "shx rm -f oclif.manifest.json",
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
"lint:fix": "pnpm run -r --if-present lint:fix",
|
||||
"clean": "pnpm run -r --if-present clean && rm -rf node_modules",
|
||||
"test": "pnpm run -r --if-present test",
|
||||
"build": "pnpm run -r --if-present build"
|
||||
"build": "pnpm run -r --if-present build",
|
||||
"prepare": "husky"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "20.12.7",
|
||||
@@ -23,6 +24,7 @@
|
||||
"eslint": "8.57.0",
|
||||
"eslint-config-prettier": "9.1.0",
|
||||
"eslint-plugin-prettier": "5.1.3",
|
||||
"husky": "9.1.7",
|
||||
"prettier": "3.2.5",
|
||||
"rimraf": "5.0.5",
|
||||
"ts-node": "10.9.2",
|
||||
|
||||
12
pnpm-lock.yaml
generated
12
pnpm-lock.yaml
generated
@@ -26,6 +26,9 @@ importers:
|
||||
eslint-plugin-prettier:
|
||||
specifier: 5.1.3
|
||||
version: 5.1.3(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@3.2.5)
|
||||
husky:
|
||||
specifier: 9.1.7
|
||||
version: 9.1.7
|
||||
prettier:
|
||||
specifier: 3.2.5
|
||||
version: 3.2.5
|
||||
@@ -260,6 +263,8 @@ importers:
|
||||
specifier: 17.7.2
|
||||
version: 17.7.2
|
||||
|
||||
contracts/lib/forge-std: {}
|
||||
|
||||
e2e:
|
||||
devDependencies:
|
||||
'@jest/globals':
|
||||
@@ -5861,6 +5866,11 @@ packages:
|
||||
resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==}
|
||||
engines: {node: '>=16.17.0'}
|
||||
|
||||
husky@9.1.7:
|
||||
resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==}
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
i18next-browser-languagedetector@7.1.0:
|
||||
resolution: {integrity: sha512-cr2k7u1XJJ4HTOjM9GyOMtbOA47RtUoWRAtt52z43r3AoMs2StYKyjS3URPhzHaf+mn10hY9dZWamga5WPQjhA==}
|
||||
|
||||
@@ -17287,6 +17297,8 @@ snapshots:
|
||||
|
||||
human-signals@5.0.0: {}
|
||||
|
||||
husky@9.1.7: {}
|
||||
|
||||
i18next-browser-languagedetector@7.1.0:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.25.7
|
||||
|
||||
Reference in New Issue
Block a user