Commits
Lint the log with the same tool that lints the docs: a convention for the subject, body, and trailers, spelling on the body, and a hook that stops a bad commit.
A commit message has a subject, a blank line, a body, and trailers, and every project has rules about each. Commits is a package of those rules: the conventions people follow, Conventional Commits, Angular's format, gitmoji, Emoji-Log, the seven rules, the Linux kernel's patch format, the Go project's, a Jira key, and the rule sets of the linters people run, commitlint, gitlint, committed, conform, and commitizen, each transcribed rule for rule. A textfsm View reads the message into its parts, so a rule reaches the subject the way it reaches a heading.
Install
The package is in the library, so its name is enough:
StylesPath = styles
Packages = Commits
[COMMIT_EDITMSG]
BasedOnStyles = Commits, Conventional$ vale syncThe package brings the section, the View, and Commits, the core every convention shares: a blank line after the subject, the imperative mood, no whitespace at the edges, no fix or wip for a subject. You name the convention beside it.
Conventional
The specification, and only it
Commitlint
commitlint's rules, with config-conventional's on; goes with Conventional
Angular
Angular's guidelines; goes with Conventional
Gitmoji
One of the 75 gitmojis first, then a message
EmojiLog
One of Emoji-Log's seven labels
SevenRules
Chris Beams's seven rules: 50 characters, a capital, no period, the body wrapped at 72
Kernel
Subsystem prefix, 75 columns, Signed-off-by:, the Fixes: and Closes: tag forms
Go
Package prefix, no capital, Fixes #123
Jira
An issue key in the subject
Gitlint
gitlint's built-in rules at their defaults
Committed
committed's defaults
Conform
conform's commit policy
Commitizen
cz check's schema; goes with Conventional
Levels and toggles work as they do for any rule, and a limit is a parameter set with the bracket key:
A rule a tool leaves off by default, commitlint's scope-enum or references-empty, is off here too; Commitlint.References = YES turns it on. Each rule file in the package's styles opens with what it reports and why, carries its level, and links the passage it enforces. A guide per tool, commitlint, gitlint, committed, conform, and commitizen, maps that tool's config to the rules here.
The hook
A commit-msg hook receives the path of the message file. Vale reads it on stdin, and --path names the section that applies, since the text has no name of its own:
Vale exits non-zero on an error-level alert, so the commit stops with the alerts on screen. Lines Git adds as commentary, and the diff commit -v appends, are never seen by a rule. The package's script/commit-msg is that hook with two additions: messages Git writes itself, merges, reverts, and the fixup! and squash! that autosquash reads, are let through, and on a fresh clone it runs vale sync once, when the StylesPath has no Commits in it.
Git keeps .git/hooks outside version control, so a hook copied there protects one clone. To ship it with the repository, put it in a tracked directory and point core.hooksPath at it, once per clone:
A prepare script in package.json or a make setup target runs that for every contributor. The hook runners do the same thing under the hood, with husky, lefthook, or the pre-commit framework:
CI and pull requests
Because the message comes in on stdin, the same command works on what was pushed, on each commit of a pull request, and on the request's description:
Nothing on the server side can run a hook for a client, so the check in CI is the backstop for a clone that skipped the setup.
Output
The report can take the shape of the tool a team used before. The package ships templates, picked with --output by name once synced:
gitlint.tmpl, committed.tmpl, and conform.tmpl print those tools' forms, github.tmpl prints GitHub Actions annotations so an alert lands on the pull request at its line, and hook.tmpl is a short form for the terminal.
Spelling and the rest of Vale
The body is read as Markdown, so Vale.Spelling skips an identifier in backticks and catches a misspelling in prose, and any style already in use on the docs runs on the log with one line of config:
Your own rules
A rule reaches a part of the message by its scope, subject, gap, body, or trailer, and a rule that spans two parts is a conditional whose in names the second:
To change a list a rule holds, the types a project accepts, extend the rule in a style of your own with the pattern rewritten, and turn the original off. The TextFSM guide is the View itself: how the template reads a message, and how the same approach reads a subtitle file or a transcript.
Last updated