Custom Partials with Lerna and conventional-changelog

Jay Kariesch
3 min readAug 21, 2021

Out of the box, conventional-changelog is a great addition to any release flow. But in my case, I needed a few additions to graduate my release notes from “dev readable” to “stakeholder readable”.

While the old <type>(scope): subject is often sufficient for a glancing developer, more than 72 characters is needed to really articulate a fix or feat to those with no context of a codebase.

In my case, I needed to accomplish a few things:

  1. Add the commit body to changelogs.
  2. Automatically link to our third party project management software.
  3. Get my team onboard with:
git commit -m "type(scope): subject" -m "A nice message for stakeholders and devs" -m "#<issue id>"

Getting Started

I decided to go with conventional-changelog-conventionalcommits since its parser will extract an issue/ticket number for you via the issuePrefixes property.

While great, it doesn’t solve the issue of adding the commit body out of the box. This requires an update to the commitPartial property.

Let’s take a look at conventional-changelog-conventionalcommits and how to use it as a function, and also use it with lerna .

Basic Usage

Basic usage looks like this:

'use strict'
const config = require('conventional-changelog-conventionalcommits')
module.exports = config({
"issuePrefixes": ["TEST-"],
"issueUrlFormat": "myBugTracker.com/{prefix}{id}"
})

It’s pretty straightforward.

  1. Create a file called changelog-preset.config.js .
  2. Toss the code above into it.
  3. In your lerna.json , add "changelogPreset": "./changelog-preset.config.js" .

Updating Templates

The problem we’re left with is the API itself doesn’t expose a way to change the commitPartial.hbs template file (see here), so we have to modify the output of the config function. Where it gets a bit confusing is the output object has two objects with different names that are identical:

{ conventionalChangelog, writerOpts, ...rest }

conventionalChangelog and writerOps .

For lerna , we need to update properties on conventionalChangelog to make a change to a changelog template.

This means we need to do something like this in our changelog-preset.config.js :

const commitPartial = `// some hbs code`module.exports = config({
"issuePrefixes": ["TEST-"],
"issueUrlFormat": "myBugTracker.com/{prefix}{id}"
}).then((preset => {
preset.conventionalChangelog.writerOpts.commitPartial = commitPartial
return preset
})

Our handlebars (hbs) code will be a variation of the default template with the addition of body, and we’ll inline it with a template literal:

const commitPartial = `
*{{#if scope}} **{{scope}}:**
{{~/if}} {{#if subject}}
{{~subject}}
{{~else}}
{{~header}}
{{~/if}}

{{~!-- commit link --}}{{~#if hash}} {{#if @root.linkReferences~}}
([{{shortHash}}]({{commitUrlFormat}}))
{{~else}}
{{~shortHash}}
{{~/if}}{{~/if}}

{{~!-- commit references --}}
{{~#if references~}}
, closes
{{~#each references}} {{#if @root.linkReferences~}}
[
{{~#if this.owner}}
{{~this.owner}}/
{{~/if}}
{{~this.repository}}{{this.prefix}}{{this.issue}}]({{issueUrlFormat}})
{{~else}}
{{~#if this.owner}}
{{~this.owner}}/
{{~/if}}
{{~this.repository}}{{this.prefix}}{{this.issue}}
{{~/if}}{{/each}}
{{~/if}}
{{#if body}}
<br/>
{{body}} // The addition
{{~/if}}
`module.exports = config({
"issuePrefixes": ["TEST-"],
"issueUrlFormat": "myBugTracker.com/{prefix}{id}"
}).then((preset => {
preset.conventionalChangelog.writerOpts.commitPartial = commitPartial
return preset
})

Issue URL

If you have trouble getting the results you want from issueUrlFormat , you can hardcode your issue URL, and grab the issue number from this.issue :

const commitPartial = `
*{{#if scope}} **{{scope}}:**

// ...some code
{{~this.repository}}{{this.prefix}}{{this.issue}}](https://some-tracker.com/project/{{this.issue}}) // ...some code
`

Lerna Config

In your lerna.json , you’ll want something like this:

{
"packages": ["packages/*"],
"version": "independent",
"changelogPreset": "./changelog-preset.config.js",
"command": {
"version": {
"message": "chore(release): release",
}
}
}

Release Command

In your release pipeline, add the following:

npx lerna version --yes --conventional-commits --create-release github

That’s it! You’ll now have a commit body in your release notes. Additional formatting to the template is completely up to you.

--

--