git-changelog-lib
git-changelog-lib copied to clipboard
Generate changelog, and/or next version, with, or without, conventional commits from a GIT repository
Git Changelog Lib
This is a library that can:
- Generate a changelog, or releasenotes, from a GIT repository.
- Determine next version, based on format of commits since last release.
It is fully configurable with a Mustache (Handlebars) template and helpers.
The changelog can:
- Be stored to file, like
CHANGELOG.md. There are some templates used for testing available here. - Or, just rendered to a
String.
It can integrate with Jira, Redmine, GitLab and/or GitHub to retrieve the title of issues.
Usage
This software can be used:
- With a Gradle plugin.
- With a Maven plugin.
- With a Jenkins plugin.
- From command line.
- As a library Maven Central.
There are examples of different templates in the code that are used for testing.
Template - Simple
Here is an example template.
# Changelog
Changelog for {{ownerName}} {{repoName}}.
{{#tags}}
## {{name}}
{{#issues}}
{{#hasIssue}}
{{#hasLink}}
### {{name}} [{{issue}}]({{link}}) {{title}} {{#hasIssueType}} *{{issueType}}* {{/hasIssueType}} {{#hasLabels}} {{#labels}} *{{.}}* {{/labels}} {{/hasLabels}}
{{/hasLink}}
{{^hasLink}}
### {{name}} {{issue}} {{title}} {{#hasIssueType}} *{{issueType}}* {{/hasIssueType}} {{#hasLabels}} {{#labels}} *{{.}}* {{/labels}} {{/hasLabels}}
{{/hasLink}}
{{/hasIssue}}
{{^hasIssue}}
### {{name}}
{{/hasIssue}}
{{#commits}}
**{{{messageTitle}}}**
{{#messageBodyItems}}
* {{.}}
{{/messageBodyItems}}
[{{hash}}](https://github.com/{{ownerName}}/{{repoName}}/commit/{{hash}}) {{authorName}} *{{commitTime}}*
{{/commits}}
{{/issues}}
{{/tags}}
Template - Conventional
If you are using conventional commits:
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
You can use built in helpers to produce a nice changelog. You can add your own helpers (using Javascript or Java) as described here.
{{#tags}}
{{#ifReleaseTag .}}
## [{{name}}](https://gitlab.com/html-validate/html-validate/compare/{{name}}) ({{tagDate .}})
{{#ifContainsBreaking commits}}
### Breaking changes
{{#commits}}
{{#ifCommitBreaking .}}
- {{#eachCommitScope .}} **{{.}}** {{/eachCommitScope}} {{{commitDescription .}}} ([{{hash}}](https://github.com/{{ownerName}}/{{repoName}}/commit/{{hash}}))
{{/ifCommitBreaking}}
{{/commits}}
{{/ifContainsBreaking}}
{{#ifContainsType commits type='feat'}}
### Features
{{#commits}}
{{#ifCommitType . type='feat'}}
- {{#eachCommitScope .}} **{{.}}** {{/eachCommitScope}} {{{commitDescription .}}} ([{{hash}}](https://github.com/{{ownerName}}/{{repoName}}/commit/{{hash}}))
{{/ifCommitType}}
{{/commits}}
{{/ifContainsType}}
{{#ifContainsType commits type='fix'}}
### Bug Fixes
{{#commits}}
{{#ifCommitType . type='fix'}}
- {{#eachCommitScope .}} **{{.}}** {{/eachCommitScope}} {{{commitDescription .}}} ([{{hash}}](https://github.com/{{ownerName}}/{{repoName}}/commit/{{hash}}))
{{/ifCommitType}}
{{/commits}}
{{/ifContainsType}}
{{/ifReleaseTag}}
{{/tags}}
Partials
You can use partials in your templates.
changelog.hbs
{{#commits}}
{{> commit}}
{{/commits}}
commit.partial
## {{authorName}} - {{commitTime}}
[{{hashFull}}](https://server/{{hash}})
{{{message}}}
This is configured like:
gitChangelogApi
.withTemplateBaseDir("...")
.withTemplateSuffix(".partial"); //Optional, defaults to ".partial"
Helpers
Some helpers are implemented in this library. And users can also add more helpers as described in Handlebars.
ifReleaseTag <Tag>
Conditional, renders a block if given Tag matches release-tag.
{{#tags}}
{{#ifReleaseTag .}}
"{{.}}" is a release tag
{{/ifReleaseTag}}
{{/tags}}
tagDate <Tag>
Renders date of Tag on format YYYY-MM-DD.
{{#tags}}
{{tagDate .}}
{{/tags}}
ifContainsIssueType <List<Issue>>
Conditional, renders a block if given List<Issue> contains given type.
{{#ifContainsIssueType issues type="Bug"}}
issues contains bugs
{{/ifContainsIssueType}}
ifContainsIssueTypeOtherThan <List<Issue>>
Conditional, renders a block if given List<Issue> contains issues that don't match the given type.
{{#ifContainsIssueTypeOtherThan issues type="fix"}}
commits contains other types than fix
{{/ifContainsIssueTypeOtherThan}}
ifContainsType <List<Commit>>
Conditional, renders a block if given List<Commits> contains given type.
{{#ifContainsType commits type="fix"}}
commits contains fixes
{{/ifContainsType}}
ifContainsTypeOtherThan <List<Commit>>
Conditional, renders a block if given List<Commits> contains commits that don't match the given type.
{{#ifContainsTypeOtherThan commits type="fix"}}
commits contains other types than fix
{{/ifContainsTypeOtherThan}}
ifContainsBreaking <List<Commit>>
Conditional, renders a block if given List<Commits> contains breaking changes.
{{#ifContainsBreaking commits}}
commits contains fixes
{{/ifContainsBreaking}}
commitDate <Commit>
Renders date of Commit on format YYYY-MM-DD.
{{#commits}}
{{commitDate .}}
{{/commits}}
commitDescription <Commit>
Renders description of Commit.
{{#commits}}
{{commitDescription .}}
{{/commits}}
revertedCommit <Commit>
Renders reverted commit refered to by Commit.
{{#commits}}
{{revertedCommit .}}
{{/commits}}
ifIssueType <Issue> type="<type>"
Conditional, renders a block if given Issue is of type.
{{#issues}}
{{#ifIssueType . type="fix"}} is type fix {{/ifIssueType}}
{{/issues}}
ifIssueTypeOtherThan <Issue> type="<type>"
Conditional, renders a block if given Issue is of type.
{{#issues}}
{{#ifIssueTypeOtherThan . type="fix"}} is not type fix {{/ifIssueTypeOtherThan}}
{{/issues}}
ifCommitType <Commit> type="<type>"
Conditional, renders a block if given Commit is of type.
{{#commits}}
{{#ifCommitType . type="fix"}} is type fix {{/ifCommitType}}
{{/commits}}
ifCommitTypeOtherThan <Commit> type="<type>"
Conditional, renders a block if given Commit is of type.
{{#commits}}
{{#ifCommitTypeOtherThan . type="fix"}} is not type fix {{/ifCommitTypeOtherThan}}
{{/commits}}
ifCommitBreaking <Commit>
Conditional, renders a block if given Commit is breaking.
{{#commits}}
{{#ifCommitBreaking .}} is breaking {{/ifCommitBreaking}}
{{/commits}}
ifCommitScope <Commit> scope="utils"
Conditional, renders a block if given Commit has scope.
{{#commits}}
{{#ifCommitScope . scope="utils"}} is scope utils {{/ifCommitScope}}
{{/commits}}
ifCommitHasFooters <Commit>
Conditional, renders a block if given Commit has footers.
{{#commits}}
{{#ifCommitHasFooters .}} has footers {{/ifCommitHasFooters}}
{{/commits}}
ifCommitHasParagraphs <Commit>
Conditional, renders a block if given Commit has paragraphs.
{{#commits}}
{{#ifCommitHasParagraphs .}} has paragraphs {{/ifCommitHasParagraphs}}
{{/commits}}
eachCommitScope <Commit>
Renders block for each scope in Commit.
{{#commits}}
{{#eachCommitScope .}}
scope: {{.}}
{{/eachCommitScope}}
{{/commits}}
eachCommitRefs <Commit>
Renders block for each refs in Commit.
{{#commits}}
{{#eachCommitRefs .}}
references issue: {{.}}
{{/eachCommitRefs}}
{{/commits}}
eachCommitFixes <Commit>
Renders block for each fixes in Commit.
{{#commits}}
{{#eachCommitFixes .}}
fixes issue: {{.}}
{{/eachCommitFixes}}
{{/commits}}
eachCommitParagraph <Commit>
Renders block for each paragraph in Commit.
{{#commits}}
{{#eachCommitParagraph .}}
{{.}}
{{/eachCommitParagraph}}
{{/commits}}
eachCommitFooter <Commit>
Renders block for each footer in Commit.
{{#commits}}
{{#eachCommitFooter .}}
{{token}}
{{/eachCommitFooter}}
{{/commits}}
ifFooterHasValue <Footer>
Conditional, renders a block if given Footer has value.
{{#commits}}
{{#eachCommitFooter .}}
{{#ifFooterHasValue .}}
{{{value}}}
{{/ifFooterHasValue}}
{{/eachCommitFooter}}
{{/commits}}
ifEquals <a> <b>
Conditional, renders a block if a equals b.
{{#tags}}
{{name}} Unreleased ? {{#ifEquals name "Unreleased"}} ja {{else}} nej {{/ifEquals}}
{{/tags}}
ifMatches <a> <b>
Conditional, renders a block if a matches regexp b.
{{#eachCommitFixes .}}
{{#ifMatches . "^[A-Z]+-[0-9]+"}}
fixes : "{{subString . 0 3}}" and number {{subString . 4}}
{{/ifMatches}}
{{/eachCommitFixes}}
subString <a> <b> <c>
Works just like Java substring.
{{#eachCommitFixes .}}
{{#ifMatches . "^[A-Z]+-[0-9]+"}}
fixes : "{{subString . 0 3}}" and number {{subString . 4}}
{{/ifMatches}}
{{/eachCommitFixes}}
Context
The template is supplied with this context:
Click here to show context
- ownerName (Derived from the clone URL, for this repo it would be "tomasbjerre")
- repoName (Derived from the clone URL, for this repo it would be "git-changelog-lib")
- urlParts (Derived from the clone URL, for this repo it would be [git-changelog-lib, tomasbjerre, [email protected]])
* commits
- authorName
- authorEmailAddress
- commitTime
- hash
- hashFull
- merge (True if this is a merge-commit)
- message (The full message)
- messageTitle (Only the first line of the message)
- messageBody (Everything, except the title)
* messageBodyItems (List of strings, the lines after the title)
* tags
- name
- annotation
- tagTime
- hasTagTime
* commits
- authorName
- authorEmailAddress
- commitTime
- hash
- hashFull
- merge (True if this is a merge-commit)
- message (The full message)
- messageTitle (Only the first line of the message)
- messageBody (Everything, except the title)
* messageBodyItems (List of strings, the lines after the title)
* authors
- authorName
- authorEmail
* commits
- authorName
- authorEmailAddress
- commitTime
- hash
- hashFull
- merge (True if this is a merge-commit)
- message (The full message)
- messageTitle (Only the first line of the message)
- messageBody (Everything, except the title)
* messageBodyItems (List of strings, the lines after the title)
* issueTypes
- name (Like GitHub, GitLab, Jira, ...)
* issues
- name
- hasIssue
- issue
- hasLink
- link
- hasTitle
- title
- hasDescription
- description
- hasType
- type
- isJira
- isGitHub
- isGitLab
- isCustom
- isNoIssue
- hasLabels
- labels
- hasLinkedIssues
- linkedIssues
* commits
- authorName
- authorEmailAddress
- commitTime
- hash
- hashFull
- merge (True if this is a merge-commit)
- message (The full message)
- messageTitle (Only the first line of the message)
- messageBody (Everything, except the title)
* messageBodyItems (List of strings, the lines after the title)
* authors
- authorName
- authorEmail
* commits
- authorName
- authorEmailAddress
- commitTime
- hash
- hashFull
- merge (True if this is a merge-commit)
- message (The full message)
- messageTitle (Only the first line of the message)
- messageBody (Everything, except the title)
* messageBodyItems (List of strings, the lines after the title)
* issues
- name
- hasIssue
- issue
- hasLink
- link
- hasTitle
- title
- hasDescription
- description
- hasType
- type
- isJira
- isGitHub
- isGitLab
- isCustom
- isNoIssue
- hasLabels
- labels
- hasLinkedIssues
- linkedIssues
* commits
- authorName
- authorEmailAddress
- commitTime
- hash
- hashFull
- merge (True if this is a merge-commit)
- message (The full message)
- messageTitle (Only the first line of the message)
- messageBody (Everything, except the title)
* messageBodyItems (List of strings, the lines after the title)
* authors
- authorName
- authorEmail
* commits
- authorName
- authorEmailAddress
- commitTime
- hash
- hashFull
- merge (True if this is a merge-commit)
- message (The full message)
- messageTitle (Only the first line of the message)
- messageBody (Everything, except the title)
* messageBodyItems (List of strings, the lines after the title)
* authors
- authorName
- authorEmail
* commits
- authorName
- authorEmailAddress
- commitTime
- hash
- hashFull
- merge (True if this is a merge-commit)
- message (The full message)
- messageTitle (Only the first line of the message)
- messageBody (Everything, except the title)
* messageBodyItems (List of strings, the lines after the title)
* issues
- name
- hasIssue
- issue
- hasLink
- link
- hasTitle
- title
- hasDescription
- description
- hasType
- type
- isJira
- isGitHub
- isGitLab
- isCustom
- isNoIssue
- hasLabels
- labels
- hasLinkedIssues
- linkedIssues
* commits
- authorName
- authorEmailAddress
- commitTime
- hash
- hashFull
- merge (True if this is a merge-commit)
- message (The full message)
- messageTitle (Only the first line of the message)
- messageBody (Everything, except the title)
* messageBodyItems (List of strings, the lines after the title)
* authors
- authorName
- authorEmail
* commits
- authorName
- authorEmailAddress
- commitTime
- hash
- hashFull
- merge (True if this is a merge-commit)
- message (The full message)
- messageTitle (Only the first line of the message)
- messageBody (Everything, except the title)
* messageBodyItems (List of strings, the lines after the title)
Library
It has a builder for creating the changelog.
gitChangelogApiBuilder()
.withFromCommit(ZERO_COMMIT)
.withToRef("refs/heads/master")
.withTemplatePath("changelog.mustache")
.render();
It can be used to calculate next version number, based on commits:
def nextVersion = gitChangelogApiBuilder()
.withSemanticMajorVersionPattern("^[Bb]reaking")
.withSemanticMinorVersionPattern("[Ff]eature")
.getNextSemanticVersion();
println "Next version:" + nextVersion.toString();
println " Major:" + nextVersion.getMajor();
println " Minor:" + nextVersion.getMinor();
println " Patch:" + nextVersion.getPatch();
Settings can be supplied with the build or from a JSON config (documented here).