Kinga
Posted on March 2, 2022
I guess I'm not alone wishing that rush uses commit messages for change log generation.
It's actually not so difficult (once it's done 😎).
Requirements
- I want to use my commit messages to generate change log files. I already lint them with commitlint to ensure correct format.
- I want to follow conventional commits specification when generating the change log and bumping version:
-
fix: a commit of the type
fix
patches a bug in your codebase (this correlates withPATCH
in Semantic Versioning). -
feat: a commit of the type feat introduces a new feature to the codebase (this correlates with
MINOR
in Semantic Versioning). -
BREAKING CHANGE: a commit that has a footer
BREAKING CHANGE:
, or appends a!
after the type/scope, introduces a breaking API change (correlating withMAJOR
in Semantic Versioning). A BREAKING CHANGE can be part of commits of any type. - types other than
fix:
andfeat:
are allowed, for example @commitlint/config-conventional recommendsbuild:
,chore:
,ci:
,docs:
,style:
,refactor:
,perf:
,test:
, and others.
-
fix: a commit of the type
- If my commits are not
fix:
,feat:
, or a breaking change, I don't want to generate rush change files. - If I'm committing with the same message, I want to skip change file generation.
- I want to make sure that
rush change --verify
will pass, before I push my code. I don't want to learn that my PR fails because I forgot to generate the, that's way too late.
Design
Trigger with post-commit
This hook is invoked by
git commit
. It takes no parameters, and is invoked after a commit is made.
This hook is meant primarily for notification, and cannot affect the outcome of git commit.
Perfect. I want to take the last two commits anyway, and I want to make sure that any failures in my code will not affect commits.
Custom rush command
The hook will call a custom rush command, which will in turn execute my custom script. One advantage of using custom command is that I benefit from autoinstallers that install all required packages
Autoinstaller
Rush autoinstaller will take care of installing any packages I need in my script. I don't want to install them in the repo's root, this is not how rush works.
And finally, the script itself
The javascript script with... well, yes, the business logic.
My toolbox
I need couple of things here.
-
@microsoft/rush-lib with:
-
RushConfiguration
class representing the Rush configuration for a repository, based on the "rush.json" configuration file, -
ProjectChangeAnalyzer
that gets a list of projects that have changed. *Caution: * this is still in Preview. Do not use this API in a production environment, -
ChangeManager
class that helps with programmatically interacting with Rush's change files.
-
-
@rushstack/node-core-library providing
Terminal
andConsoleTerminalProvider
classes needed when callingprojectAnalyzer.getChangedProjectsAsync
. - gitlog: a Git log parser for Node.JS because I need a solution to correctly read the commits, even if they span multiple lines.
- recommended-bump to calculate the recommended bump respecting Conventional Commits specification.
Ready? Steady? Go!
Autoinstaller
You know the drill. Create rush-changemanager
autoinstaller using the following commands:
rush init-autoinstaller --name rush-changemanager
cd common/autoinstallers/rush-changemanager
pnpm add @microsoft/rush-lib
pnpm add @rushstack/node-core-library
pnpm add gitlog
pnpm add recommended-bump
# When you are finished, run this command to ensure that the
# common/autoinstallers/rush-commitizen/ppnpm-lock.yaml file is up to date
rush update-autoinstaller --name rush-changemanager
You should now have the following package.json file:
common\autoinstallers\rush-changemanager\package.json
{
"name": "rush-changemanager",
"version": "1.0.0",
"private": true,
"dependencies": {
"@microsoft/rush-lib": "^5.62.4",
"@rushstack/node-core-library": "^3.45.0",
"gitlog": "^4.0.4",
"recommended-bump": "^1.5.2"
}
}
Custom command
Add the changefiles
command to the command-line.json file
common\config\rush\command-line.json
{
"$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json",
"commands": [
{
"name": "changefiles",
"commandKind": "global",
"summary": "",
"autoinstallerName": "rush-changemanager",
"shellCommand": "node common/scripts/rush-changefiles.js"
}
],
//...
}
The script
Create a rush-changefiles.js file in the common\scripts folder.
Before we dive in into the business logic implementation, let's make sure everything works as it should. I'm just going to print "rush-changefiles.js" to the console output.
common\scripts\rush-changefiles.js
console.log("rush-changefiles.js")
Test
Invoke the new changefiles
command:
rush changefiles
You will see that rush is executing the new command, installs all the packages needed by the autoinstaller, and prints the "rush-changefiles.js" to the console.
The autoinstaller job is only executed the first time, if you run the rush changefiles
again, it will complete much faster:
Now, the only thing that is missing, is the actual business logic.
Source Code
You may find the source code on GitHub.
Posted on March 2, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.