I’m participating in nuggets Creators Camp # 4, click here to learn more and learn together!
preface
Recently, I was working on the front-end engineering of monorepo project, one part of which was related to Git commit. Therefore, I referred to several projects, summarized the relevant tool chain, and wrote an article.
The whole tool chain revolves around the generation, verification, and finally changelog generation of Git Commit message
Here are some of the tools used by the libraries I surveyed in this process:
tdesign-vue-next-starter | ant-design-vue | vue | vite | |
---|---|---|---|---|
Commit specification | Presents the specification | Presents the specification | An extension specification based on the Angular specification | An extension specification based on the Angular specification |
Generate a commit message | commitizen | x | x | x |
Check the commit message | commitlint | commitlint | Use custom scripts for verification | Use custom scripts for verification |
Generate the changelog | x | Custom scripts | conventional-changelog | conventional-changelog |
In addition to some customized tools in the project, I mainly used the following open source tools:
- Commitizen: Generates a commit message
- Commitlint: verifies the COMMIT Message
- Convention-changelog: generates changelog
Before we introduce these tools, let’s take a look at the commit specification that is most commonly used today
Presents the commit specification
There are a lot of articles on the net, we should also be very familiar with, do not understand the article can see Ruan Yifeng. The content of this section is derived from this article, and I will list some important points here
The Commit message consists of three parts: Header, Body, and Footer.
<type> (the < scope >) : < subject > / / short line < body > / / short line < footer >Copy the code
The Header is required, and the Body and Footer can be omitted.
Header types include the following seven types:
- Feat: New Feature
- Fix: Fixes bugs
- -Jenny: There are some docs.
- Style: format (changes that do not affect code execution)
- Refactor: refactoring (i.e. code changes that are not new features or bug fixes)
- Test: Adds a test
- Chore: Changes to the build process or helper
- Pref: Code changes that improve performance
The Body section is a detailed description of the commit, broken into multiple lines.
The Footer section is only used in two cases:
- Incompatible variationIn order to
BREAKING CHANGE
At the beginning, it is followed by a description of the change, along with the reasons for the change and the method of migration - Close the Issue
To rollback git commit, the commit message must begin with revert:.
revert: feat(pencil): add 'graphiteWidth' option
This reverts commit 667ecc1654a317a13331b17617d973392f415f02.
Copy the code
Commit tool chain
- Commitizen: Generates a commit message
- Commitlint: verifies the COMMIT Message
- Convention-changelog: generates changelog
These tools, they have different functions, so how do you link the flow of these tools together? Let’s start with git commit’s periodic hooks
Git hooks: Git hooks
pre-commit
Hook: Runs before submission information is typed and can be usedeslint
Wait for Linter’s code verification and repairprepare-commit-msg
Hook: Runs before starting the Commit Message editor. You can generate a Commit Message at this stage (where commitizen is running) so that you don’t open the editor and type a Commit messagecommit-msg
Hook: Fill in commit message and run ifGit abandons the commit if the hook script exits with a non-zero value. This can be used to verify that the Commit Message complies with the specification. (Commitlint runs at this stage)post-commit
Hook: Git commit executes after the commit process is complete
Changelog generation is not in git hooks, because it is not required for every commit, just before a new release
commitizen
Generate a Git commit message using the command line interface
Before using Commitizen, we first need to tell Commitizen which COMMIT specification we are using, so we can do the following configuration:
- Install dependencies, assuming we use
cz-conventional-changelog
As a configuration, more configurations can be viewedhere
npm install commitizen cz-conventional-changelog --save
Copy the code
- In package.json, add
commitizen
The configuration of the
{
"script": {"cz": "cz"
}
"config": {
"commitizen": {
"path": "cz-conventional-changelog"}}}Copy the code
So commitizen knows what specification we’re using
- Generate a COMMIT message and commit commit:
npx cz
#The result is as follows:
? Select the type of change that you are committing: feat: A new feature
? What is the scope of this change (e.g. component or file name): (press enter to skip)
? Write a short, imperative tense description of the change (max 94 chars): test
? Provide a longer description of the change: (press enter to skip)
? Are there any breaking changes? No
? Does this change affect any open issues? No
## commit Message: feat
Copy the code
The content of command line interaction is derived from the CONFIGURATION of CZ-Xconventional – Changelog. Different COMMIT specifications have different command line interaction
The command line interaction diagram is as follows:
How does it work with Git hooks?
Configure the git hook for prepare-commit-msg
# .git/hook/prepare-commit-msg
exec < /dev/tty && node_modules/.bin/cz --hook || true
Copy the code
At git-commit time, cz is executed to interactively generate commit information on the command line
-
Exec < /dev/tty, git hooks are not interactive by default. This command allows users to use their terminals to interact with Commizen during the hook.
-
Cz generates a commit message and commits the git hook. Cz generates a commit message and commits the git hook. Pass git commit command)
commitlint
Like ESLint, commitLint normalizes validation of commit messages.
Likewise, commitLint needs a configuration that tells it which specification we need to use. You can configure commitlint as follows:
// Create configuration files in the project root directory
// commitlint.config.js
module.exports = { extends: ['@commitlint/config-conventional']};Copy the code
Here is the @commitlint/ config-Conventional configuration. For other configurations, please check the official documentation.
Commitlint must be used with git hooks and validation must be performed after git commit information is generated/filled in. Therefore, the git hook used is commit-msg
# .git/hooks/pre-commit
npx commitlint -e $1
Copy the code
The $1
, the first argument of the command line is passed incommit-msg
Git hooks in the.git/COMMIT_EDITMSG
, the fileStores the message text for the commitCommitlint-e File path
: Reads the Git commit message text from the file
Git hook synchronization
Our Git commit hooks are written in the.git/hooks directory and are run when you run git commit
However, git client hooks are not committed to git repositories, which means that when someone clone the repository, the hooks are not copied
To address this pain point, we need to synchronize our Git hooks with a few helper tools, including husky and simle-Git-hooks
Using simple-git-hooks as an example, here is how to configure this function:
- Install dependencies
npm install simple-git-hooks --save-dev
Copy the code
- Configuration package. Json
{
"simple-git-hooks": {
"pre-commit": "npx lint-staged"."prepare-commit-msg": "exec < /dev/tty && node_modules/.bin/cz --hook || true"."commit-msg": "npx commitlint -e $1",}}Copy the code
- Run the command manually to install the hook to
.git/hooks
npx simple-git-hooks
Copy the code
Since package.json is uploaded to the Git repository, these hook configurations are also saved, and once you clone the repository, you simply install the hooks.
Changelog generation
The xcomm-Changelog is used to generate changelog. You only need to run the following command to generate the Changlog file
conventional-changelog -p angular -i CHANGELOG.md -s
Copy the code
-p
: The Angular commit specification-i
: Selects the input file-s
: The input file is the same as the output file
This command will add the latest version of CHANGELOG to the top of Changelog. md and will not modify the previous version of CHANGELOG
A single piece of changelog is a single Git commit message. Here is a changelog example (from @vitejs/plugin-vue) :
Generates the basic flow of Changelog
-
Split all commit messages based on git tags, which start with v, such as v1.9.3 and v1.9.2.
-
Filter out the COMMIT to generate Changelog.
- Not all types of messages generate ChangelogIn the Angular specification, only
feat
,fix
,pref
, as well asrevert
The rollback COMMIT is generated in Changelog. Other types need to be added. It is not recommended to putdocs
,chore
,style
,,refactor
,test
Join the changelog
- Not all types of messages generate ChangelogIn the Angular specification, only
-
Based on the filtered Commit message, the latest tag version of Changelog is generated
- Due to theYou can manually modify the Changelog file, soBy default, only the changelog with the most recent tag is generated, so parameters are needed
-i
, pass in the last Changelog file, and at the top of it, concatenate the newly generated Changelog
- Due to theYou can manually modify the Changelog file, soBy default, only the changelog with the most recent tag is generated, so parameters are needed
How does the Monorepo project generate Changelog?
Since there are multiple package packages in monorepo project, their Changelog needs to be separated separately.
However, according to the above generation method of Changelog, all the commit will be read and generated, without filtering the commit (excluding the commit that does not belong to this package).
Therefore, we need another parameter –commit-path:
Conventional -Changelog -p angular-i Changelog. md-s --commit-path < replace package directory >Copy the code
This tells xconvention-Changelog that every git commit file needs to be checked when changelog is generated. If the changed file is in the commit-path directory, The COMMIT is considered a valid COMMIT and is used to generate Changelog
The figure above shows how a commit is filtered through –commit-path. Because the packages of A and B are modified in the last commit, both A and B will have the commit information when they generate Changelog
conclusion
The commit tool chain has been introduced, and each tool has its own role to play, so you can choose whether or not to use these tools based on your own needs.
For example, tDesign-vue-next-starter is just a business template, not a tool library, and you don’t need Changelog (but you can).
Vite, Vue, etc., do not use Commitizen to generate a Commit message, because writing a Commit message might be more convenient (personally, I think it is more convenient), so it is not necessary.
Commit validation is done with commitLint and commitLint scripts. Vue and Vite extend the Angular specification, so validation scripts are also written by commitLint. You can also implement commitlint, which is probably not done for time reasons and is not of that high priority.
In fact, we don’t have to copy all of this, it’s more about understanding the process. For their own development of the project, only need to combine with their own needs.
If this article is of any help to you, please give me a thumbs-up 👍. Your encouragement is the biggest power on my way of creation