Software developers spend all their creative energy on productive work. There is absolutely zero release overhead because all software is released automatically.
Encourage and help software developers set up their releases to be fully automated.
Our plugin generates changelog based on commit history and Github pull requests/issues. Optionally, the changelog content can be posted to Github Releases. This plugin is very small (<1kloc) and has a single dependency "com.eclipsesource.minimal-json:minimal-json:0.9.5". The dependency is very small (30kb), stable (no changes since 2017), and brings zero transitive dependencies.
Example (more examples):
- 2020-07-15 - 1 commit(s) by Szczepan Faber
- Fixed broken links (#12)
Also check out shipkit-auto-version plugin that automatically picks the next version for the release.
shipkit-auto-version
and shipkit-changelog
plugins work together perfectly.
Use the highest version available in the Gradle Plugin Portal:
plugins {
id "org.shipkit.shipkit-changelog" version "x.y.z"
}
tasks.named("generateChangelog") {
previousRevision = "v0.0.1"
repository = "shipkit/shipkit-changelog"
githubToken = System.getenv("GITHUB_TOKEN") // using env var to avoid checked-in secrets
newTagRevision = System.getenv("GITHUB_SHA") // using an env var automatically exported by Github Actions
}
Realistic example, also uses a sibling plugin shipkit-auto-version plugin at version: . Code sample source: gradle/release.gradle
plugins {
id 'org.shipkit.shipkit-changelog' version "x.y.z"
id 'org.shipkit.shipkit-github-release' version "x.y.z"
id 'org.shipkit.shipkit-auto-version' version "x.y.z"
}
tasks.named("generateChangelog") {
previousRevision = project.ext.'shipkit-auto-version.previous-tag'
githubToken = System.getenv("GITHUB_TOKEN") // using env var to avoid checked-in secrets
repository = "shipkit/shipkit-changelog"
}
tasks.named("githubRelease") {
dependsOn tasks.named("generateChangelog")
repository = "shipkit/shipkit-changelog"
changelog = tasks.named("generateChangelog").get().outputFile
githubToken = System.getenv("GITHUB_TOKEN") // using env var to avoid checked-in secrets
newTagRevision = System.getenv("GITHUB_SHA") // using an env var automatically exported by Github Actions
}
The standard way to enable the automated tasks read/write to Github are the
personal access tokens.
Shipkit Changelog plugin needs a token to fetch tickets and post releases via Github REST API.
The token is set in the task configuration in *.gradle file via githubToken
property.
When creating a new token using Github UI, make sure to select the repo/public_repo
scope
(more info on scopes).
When using Github Actions then you can use the built-in GITHUB_TOKEN
secret.
You can pass it via an environment variable:
- name: Publish githubRelease
run: ./gradlew githubRelease
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
Read more about Github Action's GITHUB_TOKEN.
In Shipkit Changelog plugin the githubToken
property should be supplied by the env variable to keep things safe.
The token grants write access to the repository and it should not be exposed / checked-in.
CI systems are often configured by default to perform Git fetch with minimum amount of commits. However, our changelog plugin needs commits in order to generate the release notes. When using Github Actions, please configure your checkout action to fetch the entire history. Based on our tests in Mockito project, the checkout of the entire Mockito history (dating 2008) has negligible performance implication (adds ~2 secs to the checkout).
- uses: actions/checkout@v2 # docs: https://github.com/actions/checkout
with:
fetch-depth: '0' # will fetch the entire history
For proper release tagging the newTagRevision
property needs to be set.
This property is set with the SHA of the commit that will be tagged when Github release is created.
Recommended way to do this is to use your CI system's built-in env variable that exposes the revision the CI is building.
Github Actions expose GITHUB_SHA
and hence we are using it in the code samples.
You can read more about all default env variables exposed by Github Actions.
Note that you can use any CI system, not necessarily Github Actions.
Just refer to the documentation of your CI system to learn what are its default env variables.
By default the plugin assumes "v" prefix notation for tags, for example: "v1.0.0".
To use a different tag notation, such as "release-1.0.0" or "1.0.0" use releaseTag
and releaseName
properties on the tasks.
See reference code examples.
- https://github.com/shipkit/shipkit-demo (great example/reference project)
- https://github.com/shipkit/shipkit-changelog (this project)
- https://github.com/shipkit/shipkit-auto-version
- https://github.com/mockito/mockito
- https://github.com/mockito/mockito-scala
- https://github.com/mockito/mockito-testng
There are other Gradle plugins or tools that provide similar functionality:
-
github-changelog-generator is a popular Ruby Gem (6K stars on Github) that generates changelog based on commits/pull requests but does not publish Github releases (#56). Our plugin is a pure Gradle solution and it can publish a Github release.
-
Github Action Release Drafter drafts the next release notes as pull requests are merged. This is a good option when the team wants to release on demand. Our plugin is great for fully automated releases on every merged pull request.
-
Gradle Plugin git-changelog-gradle-plugin seems like a nice plugin, maintained but not very popular (<50 stars on Github) and pulls in a lot of other dependencies (#21). Our plugin is simpler, smaller and brings only one dependency (that is very small, simple and has no transitive dependencies).
-
Semantic Release semantic-release is a npm module for fully automated "semantic" releases, with changelog generation.
It has impressive 10K stars on Github. Our plugin is less opinionated, smaller, simpler and a pure Gradle solution.
Pick the best tool that work for you and start automating releases and changelog generation!
- Collect commits between 2 revisions
- Find ticket IDs based on '#' prefix in commit messages (e.g. looking for #1, #50, etc.)
- Use Github REST API to collect ticket information (issue or pull request) from Github
- Create markdown file using the PR/issue titles
Uses Github REST API to post releases.
Basic task configuration (source: ChangelogPluginIntegTest)
plugins {
id 'org.shipkit.shipkit-changelog'
}
tasks.named("generateChangelog") {
previousRevision = "v3.3.10"
repository = "mockito/mockito"
githubToken = System.getenv("GITHUB_TOKEN") // using env var to avoid checked-in secrets
newTagRevision = System.getenv("GITHUB_SHA") // using an env var automatically exported by Github Actions
}
Complete task configuration (source: ChangelogPluginIntegTest)
plugins {
id 'org.shipkit.shipkit-changelog'
}
tasks.named("generateChangelog") {
//file where the release notes are generated, default as below
outputFile = new File(buildDir, "changelog.md")
//Working directory for running 'git' commands, default as below
workingDir = project.projectDir
//Github url, configure if you use Github Enterprise, default as below
githubUrl = "https://github.com"
//Github API url, configure if you use Github Enterprise, default as below
githubApiUrl = "https://api.github.com"
//The release date, the default is today date
date = "2020-06-06"
//Previous revision to generate changelog, *no default*
previousRevision = "v3.3.10"
//Current revision to generate changelog, default as below
revision = "HEAD"
//The release version, default as below
version = project.version
//Release tag, by default it is "v" + project.version
releaseTag = "v" + project.version
//Repository to look for tickets, *no default*
repository = "mockito/mockito"
//Token used for fetching tickets, *empty*
githubToken = System.getenv("GITHUB_TOKEN") // using env var to avoid checked-in secrets
}
Basic task configuration (source: GithubReleasePluginIntegTest)
plugins {
id 'org.shipkit.shipkit-github-release'
}
tasks.named("githubRelease") {
repository = "shipkit/shipkit-changelog"
changelog = file("changelog.md")
githubToken = System.getenv("GITHUB_TOKEN") // using env var to avoid checked-in secrets
newTagRevision = System.getenv("GITHUB_SHA") // using an env var automatically exported by Github Actions
}
Complete task configuration (source: GithubReleasePluginIntegTest)
plugins {
id 'org.shipkit.shipkit-github-release'
}
tasks.named("githubRelease") {
//Github API url, configure if you use Github Enterprise, default as below
githubApiUrl = "https://api.github.com"
//Repository where to create a release, *no default*
repository = "shipkit/shipkit-changelog"
//The file with changelog (release notes), *no default*
changelog = file("changelog.md")
//The name of the release, default as below
releaseName = "v" + project.version
//Github token used for posting to Github API, *no default*
githubToken = System.getenv("GITHUB_TOKEN") // using env var to avoid checked-in secrets
//SHA of the revision from which release is created; *no default*
newTagRevision = System.getenv("GITHUB_SHA") // using an env var automatically exported by Github Actions
//Release tag, by default it is "v" + project.version
releaseTag = "v" + project.version
}
This project loves contributions!
In order to test the plugin behavior locally, first you need to install the plugin locally, and then use the locally released version in a selected test project. Example workflow:
- Clone this repo, load the project into the IntelliJ IDEA, and make the code changes.
- Run
./gradlew publishToMavenLocal
task to publish the new version locally. This version contains your changes implemented in the previous step. Observe the build output and note down the version that was published. We are using maven local because that's the easiest way to publish and consume a new version locally. - Select a test project where you want to observe/test changes implemented in the previous step. For example, you can use your fork of this repo as the test project.
- Ensure that the test project is correctly configured in the Gradle build file.
It needs to declare
mavenLocal()
as a first repository inbuildscript.repositories
(code link, might be stale). Also, it needs to use the correct version of the plugin (the version that was published in the earlier step). Here's where the version is declared in the build file: code link (might be stale).