hsk-commit-conventions
v1.2.4
Published
Hasaki Commit Conventions
Readme
hsk-commit-conventions
Preset commitlint + cz-git (czg) cho team Hasaki: conventional commits + bắt buộc trailer func: / task: + auto-link tới Hasaki Work. Đi kèm CLI commit-conventions init scaffold Husky + config vào repo consumer trong dưới một phút.
Mục lục
- Bắt đầu nhanh
- Quy ước commit Hasaki
- Cài đặt vào repo
commit-conventions initlàm gì?- Workflow commit hàng ngày
- Tuỳ chỉnh theo repo
- Nhập nhiều func code
- Biến môi trường
- Các CLI bundled
- Troubleshooting
- Phát triển / Test trước publish
Bắt đầu nhanh
# 1) Cài vào repo app (devDependency)
npm add -D hsk-commit-conventions
# hoặc: yarn add -D hsk-commit-conventions
# hoặc: pnpm add -D hsk-commit-conventions
# 2) Scaffold config + Husky hooks + devDeps phụ thuộc
npx commit-conventions init
# 3) Tạo commit theo wizard
npm run cz # gọi czg với UI prompt
# hoặc: yarn cz
# hoặc: npx czLưu ý: chỉ chạy npm add mà không chạy init thì repo chưa có Husky, chưa có file config — package chỉ tồn tại trong node_modules.
Quy ước commit Hasaki
Cấu trúc message
<type>(<scope>): <subject>
<body — tuỳ chọn, mô tả chi tiết>
func: <FUNC_CODE>[,<FUNC_CODE_2>,...]
task : [#<TASK_ID>](<task_url>)| Phần | Bắt buộc? | Ràng buộc mặc định |
| --------- | ------------------------------------------ | --------------------------------------------------------------- |
| type | Có | Một trong danh sách bên dưới, lowercase |
| scope | Có (rule scope-empty: never) | Mặc định chat / core / ui — override per-repo |
| subject | Có | ≤ 200 ký tự (commitlint) / ≤ 72 ký tự (cz-git prompt) |
| body | Không | Cách header một dòng trống |
| func: | Có — trừ chore / docs / ci | Khớp regex ^[A-Z0-9_]+$. Cho phép nhiều mã cách dấu phẩy. |
| task: | Có — trừ chore / docs / ci | Mã alphanumeric, số ID (có/không #), hoặc markdown link |
subject-case đang tắt (rule [0, "never", []]) — nghĩa là không ép kiểu Title/lower/Sentence cho subject, bạn tự do viết.
Các type được hỗ trợ
Mặc định từ src/constant/commit.mjs:
| Type | Khi nào dùng | Cần func/task? |
| ---------- | ------------------------------------------------------------- | -------------- |
| feat | Tính năng mới | ✅ |
| fix | Sửa bug | ✅ |
| docs | Chỉ chỉnh tài liệu | ❌ |
| config | Đổi config | ✅ |
| style | Format / khoảng trắng, không đổi logic | ✅ |
| refactor | Refactor không thêm tính năng, không sửa bug | ✅ |
| perf | Cải thiện performance | ✅ |
| test | Thêm / sửa test | ✅ |
| build | Đổi build system | ✅ |
| ci | Đổi cấu hình CI | ❌ |
| chore | Việc lặt vặt khác (không đụng src hay test) | ❌ |
| revert | Revert commit trước | ✅ |
Type bỏ qua func/task được hardcode ở cả JS (
GIT_COMMIT_SKIP_FUNC_TASK_TYPES) và bash hook (regex^(chore|docs|ci)\(). Khi thêm/bớt, phải sửa cả hai chỗ.
Trailer func: / task:
Func code — định danh chức năng nội bộ (vd. CHW_CKH_APP_0001 = "Nhận lịch hẹn"). Danh sách mặc định trong src/constant/commit-func-choices.mjs; override per-repo qua funcCodeChoices.
- Một mã:
func: CHW_CKH_APP_0001 - Nhiều mã (custom mode, không khoảng trắng quanh dấu phẩy):
func: CHW_CKH_APP_0001,CHW_CKH_CON_0002
Task code — ID task trên Hasaki Work. Hook bash chấp nhận 3 dạng:
| Dạng | Ví dụ |
| ----------------- | ----------------------------------------------------------------------- |
| Markdown link | task : [#11886551](https://work.hasaki.vn/tasks?task_id=11886551) |
| Số (có/không #) | task: 11886551 hoặc task: #11886551 |
| Mã alphanumeric | task: WHR_DOC_CAT_0001 |
Khi dùng cz (czg) và task là số, formatter tự bọc thành markdown link bằng template URL (HASAKI_WORK_TASK_URL_TEMPLATE, mặc định https://work.hasaki.vn/tasks?task_id={taskId}).
Ví dụ đầy đủ
Một feat đơn giản (số task):
feat(chat): thêm chức năng ghim tin nhắn
func: CHW_CKH_CON_0008
task : [#11886551](https://work.hasaki.vn/tasks?task_id=11886551)Fix với body chi tiết, nhiều func:
fix(core): không cho gửi lịch hẹn khi đang fetch user
Trước đây nút "Gửi" không bị disable trong lúc đang gọi API getUser,
gây lỗi race khi user bấm liên tục.
func: CHW_CKH_APP_0002,CHW_CKH_APP_0004
task : [#11886612](https://work.hasaki.vn/tasks?task_id=11886612)Chore — không cần func/task:
chore(core): bump prettier 3.4 → 3.5Docs:
docs(ui): cập nhật README cho component AvatarCài đặt vào repo
Yêu cầu
- Node ≥ 18 (Husky 9 + ESM
.mjsconfigs). - Bash sẵn sàng cho hook
commit-msg. Trên Windows dùng Git Bash hoặc WSL. - Một trong:
npm/yarn(1.x hoặc Berry) /pnpm.
Cài package
npm add -D hsk-commit-conventions
# yarn add -D hsk-commit-conventions
# pnpm add -D hsk-commit-conventionsYarn 1 đôi khi chỉ cảnh báo thiếu peer thay vì cài — init sẽ tự bù bằng cách ghi vào devDependencies rồi chạy install lại.
Chạy init
npx commit-conventions initLệnh không có flag — chỉ một sub-command init. Có thể chạy lại nhiều lần; không ghi đè file config bạn đã chỉnh tay, luôn ghi lại hooks Husky.
Kiểm tra cài đặt
# Kiểm tra hook đã được cài
ls -l .husky/commit-msg .husky/pre-commit
# Thử commit (sẽ chạy hook)
echo "test" >> README.md
git add README.md
yarn cz # hoặc: npx cz / npm run czcommit-conventions init làm gì?
Toàn bộ trong src/bin/commit-conventions.js.
1. Cập nhật package.json của repo
{
"scripts": {
"prepare": "npx husky", // nếu trống / là "husky" / "husky install"
"cz": "czg", // nếu chưa có
"cz-multi": "cz-multi" // nếu chưa có
},
"config": {
"commitizen": {
"path": "./node_modules/cz-git",
"czConfig": "./cz-git.config.mjs"
}
},
"devDependencies": {
// tất cả peerDependencies của hsk-commit-conventions + prettier
}
}Sau đó chạy install phù hợp lockfile (pnpm install / yarn / npm install).
2. Tạo file config (chỉ nếu chưa tồn tại)
| File | Nội dung mặc định |
| -------------------------- | ----------------------------------------------------------------- |
| commitlint.config.mjs | defineCommitlintConfig({}) — dùng default Hasaki |
| cz-git.config.mjs | defineCzGitConfig({}) |
| lint-staged.config.cjs | require("hsk-commit-conventions/lint-staged") — chạy prettier |
3. Cài Husky 9 + ghi lại hooks (luôn overwrite)
.husky/commit-msg ← copy từ templates/commit-msg.bash (bash)
.husky/pre-commit ← npx --no-install lint-stagedHook commit-msg:
- Bỏ qua
Merge/Revert. - Bỏ qua type
chore(...)/docs(...)/ci(...). - Chạy
npx --no -- commitlint --edit <msg-file>. grepchắc chắn có dòngfunc: <CODE>.grepchắc chắn có dòngtask: <CODE | số | markdown-link>.
Workflow commit hàng ngày
Cách 1 — yarn cz (khuyến nghị, dùng czg)
git add -p # hoặc git add <file>
yarn cz # hoặc: npm run cz / npx czczg sẽ hỏi tuần tự:
- Type (mũi tên + Enter).
- Scope — chọn trong list hoặc nhập custom (mặc định
allowCustomScopes: true). - Subject — ≤
subjectLimit(mặc định 72 trong cz-git, header tối đa 200 trong commitlint). - Body — Enter qua nếu không có.
- Breaking change — Enter qua nếu không có.
- Func code — chọn trong
funcCodeChoices, gõ để filter, hoặc nhập custom (mặc địnhallowCustomIssuePrefix: true).- Với type
chore/docs/cicó lựa chọn "Bỏ qua func/task". - Chế độ custom: gõ
CODE1,CODE2,CODE3(không khoảng trắng) để gắn nhiều func.
- Với type
- Task code — bắt buộc nếu đã nhập func; bỏ qua nếu chọn "Bỏ qua".
- Xác nhận commit →
yđể chạygit commit.
Sau commit thành công, nếu có taskUrl, console in [cz-git] Task Work: <url>. Bật CZ_GIT_OPEN_TASK_URL=1 để tự mở URL trên trình duyệt mặc định (chỉ local; CI tự skip).
Cách 2 — yarn cz-multi (alternative readline)
yarn cz-multi # hoặc: npx cz-multiCode tại src/preset/cz-multi.js — UI text-only, không đẹp bằng czg nhưng hỗ trợ multi-select func bằng số (toggle on/off, gõ done khi xong). Hữu ích khi terminal không tương thích inquirer/czg.
Cách 3 — git commit -m (manual)
Vẫn hợp lệ nếu message đúng format. Hook commit-msg sẽ chạy commitlint + check trailer; trượt là commit bị huỷ.
git commit -m "feat(chat): thêm icon emoji" \
-m "" \
-m "func: CHW_CKH_CON_0004" \
-m "task: 11886551"Tuỳ chỉnh theo repo
Khi override scopes hoặc types, phải chỉnh đồng thời cả commitlint.config.mjs và cz-git.config.mjs — không có config dùng chung tự động.
Ví dụ override scope + max length
// commitlint.config.mjs
import { defineCommitlintConfig } from "hsk-commit-conventions/preset";
export default defineCommitlintConfig({
scopes: ["api", "web", "admin"],
subjectMaxLength: 120,
});// cz-git.config.mjs
import { defineCzGitConfig } from "hsk-commit-conventions/preset";
export default defineCzGitConfig({
scopes: ["api", "web", "admin"],
subjectLimit: 120,
});Toàn bộ option (từ JSDoc CommitConventionOverrides trong src/preset/index.mjs)
| Option | Áp dụng cho | Mặc định | Ghi chú |
| ------------------------ | -------------------------- | ------------------------------------ | --------------------------------------------------------------------------------------------- |
| scopes | cả hai | ["chat", "core", "ui"] | Rule scope-enum. Để rỗng → dùng default. |
| types | cả hai | 12 type ở trên | Truyền string[] hoặc {value,name}[]. |
| subjectMaxLength | commitlint | 200 | Rule header-max-length. |
| subjectLimit | cz-git prompt | 72 | Giới hạn cho prompt cz-git (khác subjectMaxLength của commitlint). |
| skipFuncTaskTypes | cả hai + formatter | ["chore","docs","ci"] | Phải sync với regex bash hook (xem templates/commit-msg.bash:9). |
| taskWorkUrlTemplate | formatter | https://work.hasaki.vn/tasks?task_id={taskId} | Có {taskId}. Env HASAKI_WORK_TASK_URL_TEMPLATE override. |
| buildTaskWorkUrl | formatter | (dùng template) | Hàm (taskId) => string thay thế hoàn toàn template. |
| funcCodeChoices | cz-git prompt + whitelist | 20 mã CHW | string[] hoặc {value,name}[]. |
| taskCodeChoices | cz-git prompt + whitelist | [] | Để rỗng → task chỉ bị check regex (không whitelist). |
| funcTaskCodeRe | formatter | /^[A-Z0-9_]+$/ | Regex chung cho cả func + task nếu không truyền riêng. Sync với hook. |
| funcCodeRe | formatter | = funcTaskCodeRe | Override regex chỉ cho func. |
| taskCodeRe | formatter | = funcTaskCodeRe | Override regex chỉ cho task. |
| restrictFuncToChoices | formatter | false | true → mỗi mã func phải nằm trong funcCodeChoices. |
| restrictTaskToChoices | formatter | undefined | false → tắt whitelist task; undefined → enforce nếu taskCodeChoices không rỗng. |
| allowCustomScopes | cz-git prompt | true | Cho phép gõ scope custom. |
| allowEmptyScopes | cz-git prompt | false | scope-empty: never của commitlint vẫn chặn ở hook → để true ở đây không có tác dụng. |
| allowCustomIssuePrefix | cz-git prompt | true | Cho phép gõ func ngoài danh sách. |
| allowEmptyIssuePrefix | cz-git prompt | true | Cho phép bỏ qua issue prefix (cho chore/docs/ci). |
| emptyIssuePrefixAlias | cz-git prompt | "Bỏ qua func/task (chore / docs / ci)" | Label cho lựa chọn "skip". |
| commitlintRules | commitlint | - | Object merge vào rules (override / thêm rule). |
| helpUrl / parserPreset / formatter / extends | commitlint | (đã set sẵn) | Pass thẳng vào UserConfig. |
| czGitMessages | cz-git prompt | (đã set tiếng Việt) | Merge vào messages của prompt. |
Tuỳ chỉnh danh sách func per-project
// cz-git.config.mjs
import { defineCzGitConfig } from "hsk-commit-conventions/preset";
export default defineCzGitConfig({
funcCodeChoices: [
{ value: "API_AUTH_LOGIN", name: "API: Đăng nhập" },
{ value: "API_AUTH_LOGOUT", name: "API: Đăng xuất" },
"API_USER_PROFILE", // string cũng được — name = value
],
restrictFuncToChoices: true, // ép phải chọn trong list
});Tuỳ chỉnh URL template
// cz-git.config.mjs
export default defineCzGitConfig({
taskWorkUrlTemplate: "https://jira.company.vn/browse/{taskId}",
});
// hoặc đặt env:
// HASAKI_WORK_TASK_URL_TEMPLATE="https://jira.company.vn/browse/{taskId}"Env được đọc một lần khi module
src/constant/commit.mjsđược import. Đổi env runtime không có tác dụng.
Tuỳ chỉnh regex (nâng cao)
Nếu mã func có format khác (vd. chứa chữ thường, có dấu -):
// cz-git.config.mjs
export default defineCzGitConfig({
funcTaskCodeRe: /^[A-Za-z0-9_-]+$/,
});⚠ Phải đồng bộ regex trong
.husky/commit-msg— file template gốc dùng[A-Z0-9_]+. Sau khi đổi cần sửa hook tại consumer hoặc copy thủ công.
Nhập nhiều func code
Khi một thay đổi đụng nhiều chức năng cùng lúc, gắn nhiều func code cách nhau dấu phẩy:
func: CHW_CKH_APP_0001,CHW_CKH_APP_0004Quy tắc:
- Không có khoảng trắng quanh dấu phẩy (
A,B✅,A, B⚠️ — vẫn được parse ở dạng 2 dòng cz-git, nhưng kém an toàn ở fallback single-line). - Mỗi mã phải khớp
funcCodeRe. - Nếu
restrictFuncToChoices: true, mỗi mã phải nằm trongfuncCodeChoices.
Hỗ trợ ở các UI:
| Cách commit | Hỗ trợ multi-func |
| ------------------------- | ---------------------------------------------------------------- |
| yarn cz (czg) — chọn từ list | Mặc định một mã. Cần nhập custom để gắn nhiều. |
| yarn cz (czg) — custom | ✅ Gõ CODE1,CODE2 |
| yarn cz-multi | ✅ Multi-select bằng số, tự join , |
| git commit -m manual | ✅ Gõ thẳng vào trailer |
Logic tách + validate trong cz-git-format-message.mjs (splitFuncCodes).
Biến môi trường
| Biến | Đọc ở đâu | Ý nghĩa |
| ------------------------------- | ---------------------------------------- | ---------------------------------------------------------------------------------------- |
| HASAKI_WORK_TASK_URL_TEMPLATE | src/constant/commit.mjs (1 lần lúc import) | Template URL task, phải có {taskId}. Mặc định https://work.hasaki.vn/tasks?task_id={taskId}. |
| CZ_GIT_OPEN_TASK_URL | cz-git-format-message.mjs (mỗi commit) | 1 / true → tự mở URL task sau commit local (open / xdg-open / start). 0 → tắt. |
| CI | cz-git-format-message.mjs | Truthy → luôn không mở browser, kể cả khi CZ_GIT_OPEN_TASK_URL=1. |
Các CLI bundled
| Bin | File proxy | Việc |
| ------------------------ | ----------------------------------------- | ------------------------------------------------------------------- |
| commit-conventions | bin/commit-conventions.cjs | Hiện chỉ có init. Scaffold Husky + config + devDeps. |
| cz | bin/czg-proxy.cjs | Resolve czg trong node_modules của package và exec. Không cần repo cài thêm czg. |
| cz-multi | bin/cz-multi.cjs | Wizard readline tự viết — alternative cho czg. |
Troubleshooting
husky: command not found khi git commit
- Mở
package.jsonxác nhậnscripts.prepare === "npx husky". - Chạy lại
npm install(hoặcyarn/pnpm install) đểprepaređược trigger. - Husky 9 không có lệnh
husky installnữa — nếu thấyprepare: "husky install"trong repo cũ,initsẽ tự sửa.
❌ Missing func: <FUNCTION_CODE> in commit message
- Type không nằm trong
chore/docs/ci→ bắt buộc có dòngfunc: CODE. - Kiểm tra:
- Đúng prefix
func:(cho phép khoảng trắng quanh:). - Mã match
[A-Z0-9_]+(chữ in, số, gạch dưới).
- Đúng prefix
- Nếu type của bạn không cần func/task, thêm vào
skipFuncTaskTypesvà sửa regex^(chore|docs|ci)\(trong.husky/commit-msg.
❌ Missing task: <TASK_CODE>
- Cần một trong:
task: SOME_CODE/task: 123/task: #123/task : [#123](url). - Khoảng trắng quanh
:được phép —task:vàtask :cùng OK.
[cz-git] Mã func "X" không nằm trong danh sách
- Đang bật
restrictFuncToChoices: true. Hoặc bỏ option đó, hoặc thêmXvàofuncCodeChoices.
[cz-git] Cần hai mã func và task: hai dòng riêng, hoặc một dòng hai mã cách bởi khoảng trắng
- Trailer footer cz-git phải có cả func và task. Type
chore/docs/cithì chọn "Bỏ qua func/task" thay vì để trống một bên.
Windows: hook không chạy
.husky/commit-msglà bash script. Cài Git for Windows (kèm Git Bash) hoặc dùng WSL. PowerShell thuần không chạy được hook bash.
Đổi regex func/task xong vẫn bị từ chối
- Đổi trong cz-git config không tự cập nhật
.husky/commit-msg. Phải sửa file hook ở consumer repo, hoặc chạy lạicommit-conventions init(nhưng init copy template gốc — phải patch lại sau init).
Phát triển / Test trước publish
Trong repo này:
yarn # cài deps
yarn cz-multi # smoke test wizard
npm pack --dry-run # xem file nào sẽ được publish (theo `files` trong package.json)Test integration ở repo consumer (không cần publish):
# Option A: link trực tiếp tới folder
npm add -D file:/absolute/path/to/hsk-commit-conventions
npx commit-conventions init
# Option B: pack rồi install
cd /path/to/hsk-commit-conventions
npm pack # tạo hsk-commit-conventions-X.Y.Z.tgz
cd /path/to/consumer-app
npm add -D /path/to/hsk-commit-conventions-X.Y.Z.tgz
npx commit-conventions initCấu trúc nguồn:
src/
constant/
commit.mjs ← Single source of truth: types, scopes, regex, URL template
commit-func-choices.mjs ← Danh sách func mặc định (values + names paired)
preset/
index.mjs ← Public: defineCommitlintConfig, defineCzGitConfig
resolve-overrides.mjs ← Merge overrides + defaults → Resolved
build-commitlint.mjs ← Resolved → @commitlint UserConfig
build-cz-git.mjs ← Resolved → cz-git UserConfig
cz-multi.js ← Readline wizard (cz-multi CLI)
bin/
commit-conventions.js ← Implementation của `init`
cz-git-format-message.mjs ← formatMessageCB cho cz-git (validate + format trailer)
templates/
commit-msg.bash ← Hook copy vào .husky/commit-msg của consumer
bin/ ← Proxies CJS cho bin entries
configs/lint-staged.cjs ← Preset lint-stagedXem CLAUDE.md để biết các invariant cần giữ đồng bộ giữa các file khi sửa.
