Skip to content
This repository has been archived by the owner on Oct 5, 2018. It is now read-only.

Release Plugins

Andrew Oberstar edited this page Mar 8, 2017 · 20 revisions

One of the primary features of gradle-git is the pair of release plugins that allow you to infer your project's version and manage the tasks executed for your release process.

There are two plugins included:

  • org.ajoberstar.release-base Provides the basic functionality, but you configure how versions are inferred.
  • org.ajoberstar.release-opinion Adds an opinionated set of strategies to infer your project's version.

Plugins Block Dependency

plugins {
  // if you want to use the opinionated config
  id 'org.ajoberstar.release-opinion' version '<version>'

  // if you want to configure it to your preferences
  id 'org.ajoberstar.release-base' version '<version>'
}

Classic Plugin Dependency

// if you want to use the opinionated config
apply plugin: 'org.ajoberstar.release-opinion'

// if you want to configure it to your preferences
apply plugin: 'org.ajoberstar.release-base'

NOTE: Either plugin should only be applied to one project as it will apply the inferred version to all projects in the build.

Features

  • Configures the project's version based on the inference strategies you (or the opinion plugin) configure.
    • Version isn't inferred until it's used (i.e. project.version.toString() is called)
  • Adds a release task that:
    • Tags the version, if the inference strategy calls for it.
    • Pushes the current branch and all tags to the origin.

Release Process

Generally you will want to execute other tasks, such as build, uploadArchives, and/or publish* tasks. Use standard Gradle dependencies and task ordering to handle this.

tasks.release.dependsOn 'build', 'publishToMyRepo'

Execute the release task and (optionally, as noted below) specify the release.scope and/or release.stage properties.

./gradlew release -Prelease.scope=major -Prelease.stage=final

Version Inference

Why not hardcode the version?

Have you ever seen a commit message simply say "Bumping version number"? I imagine everyone has, but there's really no good reason for it.

While most build tools encourage (or force) you to hardcode your version number into the build script, Git illustrates the power of basing the version on your VCS tags, with the git describe command, which reflects the amount of change since the previous tag (e.g. 0.1.0-22-g26f678e).

This plugin leverages Git tags as the baseline your version is computed from.

What's in a version number?

While this plugin provides more general support, it has the most support for Semantic Versioning. SemVer provides a specific meaning to the difference between two version numbers, helping a consumer understand what scope of impact they should expect when upgrading.

A semantic version consists of <normal>[-<pre release>][+<build metadata>] (e.g. 1.2.3-rc.2+abcde1234). The normal component consists of <major>.<minor>.<patch>.

How do I use the opinion plugin?

After applying the plugin as noted at the top of this doc, your project will be ready to infer semantic versions based on the nearest tag and the release.scope and/or release.stage properties you can pass into your build.

Versions will fall into one of the following stages:

Name Creates Tag Requires Clean Repo Example
final yes yes 1.0.0
rc yes yes 1.1.0-rc.1
milestone yes yes 1.2.0-milestone.2
dev no no 1.3.0-dev.5+ae2dfa2
or 1.3.0-dev.5.uncommitted+ae2dfa2
or 1.3.0-milestone.1.dev.5+ae2dfa2

Additionally, if you provide no input (via the release.* properties) and have not made any changes since the last tagged version, that version will be reused.

Example Usage

As an example this walks you through a series of Gradle executions. A few things of note:

  • You don't need to use the release task to get version inference.
  • Without a scope input, it will detect it from the difference from the last final release and the last tagged one (e.g. a milestone of a minor version will default you to minor). If nothing detected, it will default to patch.
  • Without a stage input, it will default to dev (assuming you've made changes since the last tagged version).
Repo State Latest Version Tag Gradle Command (w/ gradle or gradlew in front) Inferred Version
3 commits and some uncommitted changes None test 0.0.1-dev.3.uncommitted+ae2dfa2
Ready to release a milestone None release -Prelease.scope=minor -Prelease.stage=milestone 0.1.0-milestone.1
More commits, no uncommitted 0.1.0-milestone.1 test 0.1.0-milestone.1.dev.2+5612df0
A couple more commits, want to publish 0.1.0-milestone.1 release -Prelease.stage=dev 0.1.0-milestone.1.dev.4+029b57e
Ready for another milestone 0.1.0-milestone.1 release -Prelease.stage=milestone 0.1.0-milestone.2
Rebuilding on another machine 0.1.0-milestone.2 build 0.1.0-milestone.2
ready for an rc 0.1.0-milestone.2 release -Prelease.stage=rc 0.1.0-rc.1
some uncommitted changes for a fix 0.1.0-rc.1 build 0.1.0-rc.1.dev.0.uncommitted+9686285
commit the fix and another rc 0.1.0-rc.1 release -Prelease.stage=rc 0.1.0-rc.2
ready for final release 0.1.0-rc.2 release -Prelease.stage=final 0.1.0
making a bug fix 0.1.0 release -Prelease.stage=rc 0.1.1-rc.1
fix is ready for final 0.1.1-rc.1 release -Prelease.scope=patch -Prelease.stage=final 0.1.1
more commits, with major changes 0.1.1 release -Prelease.scope=major -Prelease.stage=milestone 1.0.0-milestone.1
final of this 1.0.0-milestone.1 release -Prelease.stage=final 1.0.0
rc of minor change 1.0.0 release -Prelease.scope=minor -Prelease.stage=rc 1.1.0-rc.1
that minor was actually breaking 1.1.0-rc.1 release -Prelease.scope=major -Prelease.stage=rc 2.0.0-rc.1

Configuration

If you don't want to use the opinionated config, you can apply org.ajoberstar.release-base instead and configure it using the extension.

release {
  // if you don't apply org.ajoberstar.grgit, you need to specify the repository to interact with
  grgit = Grgit.open(currentDir: project.file('.'))

  /*
   * Base plugin adds no strategies.
   * Opinion plugin adds:
   *   RebuildVersionStrategy.INSTANCE
   *   Strategies.DEVELOPMENT
   *   Strategies.PRE_RELEASE
   *   Strategies.FINAL
   */

  // add your own choices from some pre-configured samples
  versionStrategy RebuildVersionStrategy.INSTANCE
  versionStrategy Strategies.SNAPSHOT
  versionStrategy Strategies.PRE_RELEASE_ALPHA_BETA
  versionStrategy Strategies.FINAL
  
  // add your own custom strategy
  versionStrategy(new CustomVersionStrategy())

  // the approach to creating tags can also be modified
  tagStrategy {
    prefixNameWithV = false // defaults to true
    generateMessage = { version -> "My new version $version.version" }
  }
}

Additional pre-built strategies are available in Strategies (source).

Other Options

There are certainly other options than gradle-git for Gradle release plugins. Here are the ones that I am aware of:

  • townsfolk/gradle-release - designed to work like the Maven Release plugin. If that's what you are looking for, this is your best option.
  • ari/gradle-release-plugin - Seems purely oriented around versioning the release and tagging it. Versions are generated dynamically based on current branch or tag.
  • stianh/gradle-release-plugin - Similar approach (and created before) the ari plugin. However, as of 4/13/14 it hasn't had any commits in 9 months.
  • netzwerg/gradle-release-plugin - Minimal plugin which operates on semantic version kept in version.txt file. Updates version, tags repo, pushes current branch ("no surprise" defaults, fully configurable). Runs non-interactively, thus well suited for CI.