Commitlint and Commitizen are the tools that regulate Git commit information.
Commitlint validates the commit information, commItizen fills in the commit information. In the Git commit workflow, commitLint is applied to the commit-msg phase and commitizen to the pre-commit phase. They do not interfere with each other and complement each other.
It seems that the world is in peace, however, both follow their own rules, and there is no unified interface for each to do their own thing. Collaborating in the same process, configured with two sets of rules, is always a bit of a nuisance.
Why not?
Why can’t you use the same rule configuration? Because the mechanics of the two tools are so different.
commitlint
Commitlint: commitlint: commitlint: commitlint: commitlint: commitlint: commitlint: commitlint: commitlint
We know that one of the most widely agreed base specifications is Conventionalcommits.
<type>[scope]: <subject>
[body]
[footer]
Copy the code
It is made up of type, scope, Subject, body, and footer parts. Commitlint is set up on top of the underlying specification. That is, it believes that a submitted message string can be parses into these parts, and then checks that the parts are compliant.
Once you know how commitLint works, it’s easy to understand how it works. In simple terms, it runs as follows: parse the commit information → determine the rule set → perform the rule check
Parsing the submission information
First it parses the commit information string to a structured object through the parserPreset parser, for example:
For example, the following information is submitted
fix(package1): update title
The old title is overdated
Issues: https://github.com/conventional-changelog/commitlint/issues/2507
Copy the code
Is resolved as a
{
"header": "fix(package1): update title"."type": "fix"."scope": "package1"."subject": "update title"."body": "The old title is overdated"."footer": "Issues: https://github.com/conventional-changelog/commitlint/issues/2507"."references": [
"https://github.com/conventional-changelog/commitlint/issues/2507"]}Copy the code
Determine rule set
Next, it generates the rule set from the rule configuration file. Commitlint’s configuration file is commitlint.config.js, which contains the extends, rules, plugins fields, etc. If you’ve used ESLint before, this may sound familiar to those of you who have used ESLint, but the extends field in a configuration similar to ESLint inherits the existing configuration, and rules defines the rules.
In a nutshell, this step resolves the configuration file into a set of rules that can be used later. Let’s take a short look at what the rule set looks like:
{
'subject-full-stop': [2, 'never', '.'],
'subject-case': [
2,
'never',
['sentence-case', 'start-case', 'pascal-case', 'upper-case'],
],
'subject-empty': [2, 'never'],
}
Copy the code
The key is the rule name and the value is the rule parameter. A rule actually corresponds to a logical function. Commitlint’s built-in rule logic is maintained by a list of key-value pairs. Let’s take a look at the subject-full-stop logical function.
// subject-full-stop.ts
import message from '@commitlint/message';
import {SyncRule} from '@commitlint/types';
export const subjectFullStop: SyncRule<string> = (
parsed,
when = 'always',
value = '. '
) = > {
const input = parsed.subject;
if(! input) {return [true];
}
const negated = when === 'never';
const hasStop = input[input.length - 1] === value;
return [
negated ? !hasStop : hasStop,
message(['subject', negated ? 'may not' : 'must'.'end with full stop']]), };Copy the code
The first argument parsed to the subject-full-stop function is the structure object generated in the first step; The second parameter, when, is the second element in the rule value and represents either the conditional prefix is or is not; The third parameter, value, is the third element in the rule value and represents the specific value.
The subject-full-stop function returns the verification result and an error message.
Now let’s look at what the rules mean, for example
'subject-full-stop': [2, 'never', '.']
: indicates that the title cannot be.
The end of the'subject-full-stop: [2, 'always', '!']'
: indicates that the title must end with!
The end of the
Looking back at the logic of the subject-full-stop function above, it does.
Performing a rule check
At this stage, commitlint iterates over the ruleset and executes the corresponding logical functions. Finally, the validation results are formatted and the report is output.
commitizen
Commitlint communicates directly with configuration files. Unlike commitizen, commItizen itself has no relation to the commit information rules. Commitizen provides only a framework for interacting with Git. It passes Inquirer objects to adapters that describe the command line filling process and return information that the user has filled out. So what really matters, and what is relevant to the rules, is the adapter.
inquirerIs a toolset that encapsulates common command-line interfaces, such as Input, confirm, list, Checkbox, editor, etc.
Most Commitizen adapters describe the command line interaction process according to a specific specification, such as the CZ-Conventional Changelog based on the Conventional Changelog specification. With this mechanism, if developers wanted to make their own rules, they had to learn to use the Inquirer to create a new adapter from scratch, which was not easy to use. Is there any support for custom adapters? Yes, cz-customizable is the existence of the special.
Cz-customizable externalizes a configuration file.cz-config.js, designs some configurable fields, and cZ-Customizable reads the configuration and converts it into an Inquirer based command line interaction process.
The following is an example of the cz-Customizable configuration:
module.exports = {
// Type Indicates an optional list
types: [{value: 'feat'.name: 'feat: A new feature' },
{ value: 'fix'.name: 'fix: A bug fix'},].// Scope Optional list
scopes: [{ name: 'accounts' }, { name: 'admin' }, { name: 'exampleScope' }, { name: 'changeMe'}].// Overwrite the interactive prompt
messages: {
type: "Please select your submission type".scope: 'Please select SCOPE'.subject: 'Brief description of this modification :\n'.body: 'provides information about the modifications more specific (optional), use "|" line: \ n'.confirmCommit: 'Are you sure to submit information? ',},// skip any questions you want
skipQuestions: ['body'].// limit subject length
subjectLimit: 100};Copy the code
How to achieve sharing?
Now that we understand the mechanisms of CommitLint and Commitizen, let’s consider the core issue: how to get both of them to share the same rule configuration.
There are two ideas:
- From the commitLint configuration, read the commitLint configuration and generate the corresponding command line commit process, that is, create a CommItizen adapter, @commitLint /cz-commitlint implemented
- From the z-Customizable configuration, translate the Z-Customizable configuration to the commitLint rule, that is, create a commitlint configuration, commitlint-config-cz has been implemented
cz-commitlint
The @commitlint/cz-commitlint configuration process is simple
Install commitizen and commitLint and cz-commitLint
npm install --save-dev @commitlint/cz-commitlint commitizen @commitlint/cli
# or yarn
yarn add -D @commitlint/cz-commitlint commitizen @commitlint/cli
Copy the code
Configure the CommItizen adapter in package.json
{
"scripts": {
"commit": "git-cz"
},
"config": {
"commitizen": {
"path": "@commitlint/cz-commitlint"}}}Copy the code
Install and configure the required specifications, such as the Conventional – Changelog specification
npm install --save-dev @commitlint/config-conventional
# or yarn
yarn add -D @commitlint/config-conventional
# configuration commitlint. Config. Js
echo "module.exports = {extends: ['@commitlint/config-conventional']};" > commitlint.config.js
Copy the code
commitlint-config-cz
The configuration process for commitlint-config-cz is also not complex
Install Commitizen and commitlint and cz-customizable and commitlint-config-cz
npm install --save-dev commitlint-config-cz commitizen cz-customizable @commitlint/cli
# or yarn
yarn add -D commitlint-config-cz commitizen cz-customizable @commitlint/cli
Copy the code
Configure the CommItizen adapter in package.json
{
"scripts": {
"commit": "git-cz"
},
"config": {
"commitizen": {
"path": "node_modules/cz-customizable"}}}Copy the code
Set it in commitlint.config.js
module.exports = {
extends: [
'cz']};Copy the code
Configure.cz-config.js, optionally based on the official template.
How to choose
Both have applicable scenarios
@commitLint /cz-commitlint is suitable for using an existing specification or for custom extensions based on an existing specification.
Commitlint-config-cz is suitable for full customization scenarios that do not depend on existing specifications.
Z-commitlint can also implement full customization, but it requires understanding commitLint’s configuration and rules, which is a bit more of a hurdle than the simple and intuitive configuration of.cz-config.js, but this may not be an issue for front-end developers who are comfortable with ESLint.