diff --git a/.husky/commit-msg b/.husky/commit-msg new file mode 100755 index 00000000..e171b515 --- /dev/null +++ b/.husky/commit-msg @@ -0,0 +1,11 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +if ! [ -x "$(command -v npm)" ]; then + echo "npm: command not found" + echo "If you use a version manager tool such as nvm and a git GUI such as GitKraken, please read: https://typicode.github.io/husky/#/?id=command-not-found" >&2 + exit 1 +else + npm run lint && node_modules/@babel/node/bin/babel-node.js scripts/commit-msg.js +fi + diff --git a/package-lock.json b/package-lock.json index 052f2120..4a746347 100644 --- a/package-lock.json +++ b/package-lock.json @@ -50,6 +50,7 @@ "eslint-plugin-import": "^2.23.2", "eslint-plugin-jest": "^24.3.6", "git-changelog": "^2.0.0", + "husky": "^7.0.4", "inquirer": "^8.1.0", "jest": "^27.4.5", "jest-canvas-mock": "^2.3.1", @@ -10956,6 +10957,21 @@ } } }, + "node_modules/husky": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/husky/-/husky-7.0.4.tgz", + "integrity": "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==", + "dev": true, + "bin": { + "husky": "lib/bin.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, "node_modules/ibm-cloud-sdk-core": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/ibm-cloud-sdk-core/-/ibm-cloud-sdk-core-2.11.0.tgz", @@ -28956,6 +28972,12 @@ } } }, + "husky": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/husky/-/husky-7.0.4.tgz", + "integrity": "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==", + "dev": true + }, "ibm-cloud-sdk-core": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/ibm-cloud-sdk-core/-/ibm-cloud-sdk-core-2.11.0.tgz", diff --git a/package.json b/package.json index 399453b3..5c115a06 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "dev:server": "npm run train && cross-env LEON_NODE_ENV=development nodemon --watch server ./server/src/index.js --ignore server/src/tmp/ --exec babel-node", "wake": "cross-env LEON_HOST=http://localhost LEON_PORT=1337 node hotword/index.js", "delete-dist:server": "shx rm -rf ./server/dist", + "prepare": "husky install", "build": "npm run build:app && npm run build:server", "build:app": "cross-env LEON_NODE_ENV=production babel-node scripts/app/run-build-app.js", "build:server": "npm run delete-dist:server && npm run train && babel ./server/src -d ./server/dist --copy-files && shx mkdir -p server/dist/tmp", @@ -92,6 +93,7 @@ "eslint-plugin-import": "^2.23.2", "eslint-plugin-jest": "^24.3.6", "git-changelog": "^2.0.0", + "husky": "^7.0.0", "inquirer": "^8.1.0", "jest": "^27.4.5", "jest-canvas-mock": "^2.3.1", diff --git a/scripts/commit-msg.js b/scripts/commit-msg.js new file mode 100644 index 00000000..ee863dba --- /dev/null +++ b/scripts/commit-msg.js @@ -0,0 +1,37 @@ +import fs from 'fs' +import path from 'path' + +import log from '@/helpers/log' + +/** + * This script is executed after "git commit" or "git merge" (Git hook https://git-scm.com/docs/githooks#_commit_msg) + * it ensures the authenticity of commit messages + */ +log.info('Checking commit message...') + +const commitEditMsgFile = '.git/COMMIT_EDITMSG' + +if (fs.existsSync(commitEditMsgFile)) { + try { + const commitMessage = fs.readFileSync(commitEditMsgFile, 'utf8') + const packagesDir = 'packages' + const packages = fs.readdirSync(packagesDir) + .filter((entity) => fs.statSync(path.join(packagesDir, entity)).isDirectory()) + const packagesScopeString = packages.map((pkg, i) => { + if (packages.length === i + 1) return pkg + return `${pkg}|` + }).join('') + + const regex = `(build|BREAKING|chore|ci|docs|feat|fix|perf|refactor|style|test)(\\((web app|server|hotword|package\\/(${packagesScopeString})))?\\)?: .{1,50}` // eslint-disable-line no-useless-escape + + if (commitMessage.match(regex) !== null) { + log.success('Commit message validated') + } else { + log.error(`Commit message does not match the format: ${regex}`) + process.exit(1) + } + } catch (e) { + log.error(e.message) + process.exit(1) + } +}