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.
Top comments (0)