A set of plugins to support Git in the Gradle build tool.
There are three primary use cases for these plugins:
- Publishing to a Github Pages website. The
github-pagesplugin adds support for publishing static files to thegh-pagesbranch of a Git repository. - Managing your release process. The
grgit-releaseplugin adds an opinionated way to manage releases and comply with Semantic Versioning. - General Git actions. This plugin JAR depends on, and makes available, grgit which provides a Groovy API for interacting with Git repositories.
For more information see the documentation in the next sections.
API Documentation:
Credit goes to Peter Ledbrook for the initial
idea for the github-pages plugin.
Thanks to Zafar Khaja for the very helpful java-semver library.
Add the following lines to your build to use the gradle-git plugins.
buildscript {
repositories {
// jcenter()
mavenCentral()
}
dependencies {
classpath 'org.ajoberstar:gradle-git:<version>'
}
}
See the Release Notes at the bottom of this README for the available versions.
For freeform access to a Git repository, you only need the dependency on
gradle-git, no additional plugins need to be applied. Import the grgit
package and start using a repository.
import org.ajoberstar.grgit.*
ext.repo = Grgit.open(project.file('.'))
version = "1.0.0-${repo.head().abbreviatedId}"
task tagRelease << {
repo.tag.add {
name = version
message = "Release of ${version}"
}
}For details on the available methods/properties see the API docs of Grgit. Examples of how to use each operation are provided there.
Grgit provides multiple ways to authenticate with remote repositories. If using hardcoded credentials, it is suggested to use the system properties rather than including them in the repository.
See Grgit's AuthConfig docs for information on the various authentication options.
Methods that produce a Grgit instance, which includes clone, init, and open, all take a Credentials instance if
you want to provide hardcoded credentials programmatically.
apply plugin: 'github-pages'
githubPages {
repoUri = '...'
pages {
from javadoc.outputs.files
}
}See the GithubPagesPluginExtension docs for information on the defaults.
The plugin adds a single publishGhPages task that will clone the
repository, copy in the files in the pages CopySpec, add all of
the changes, commit, and push back to the remote.
Before describing this plugins functionality I want to point out the other plugins available (that I'm aware of):
- townsfolk/gradle-release - designed to work like the Maven Release plugin. If that's what you're 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
ariplugin. However, as of4/13/14it hasn't had any commits in 9 months.
The grgit-release plugin is intended to be opinionated, and I am not trying to meet all needs. The core principles of
this plugin are:
- Semantic versioning is the ideal way to version code (for most use cases).
- A Git repository contains enough information to be able to build useful version numbers that comply with semver, with limited direction from the user. The version should not need to be hardcoded into the source code.
The general functionality involves:
- Inferring the desired version based on the nearest tagged version(s) (similar to
git describe) and the users input of the scope of the changes being made and what stage of development they are in. - Ensuring all changes in the repository have been committed.
- Ensuring there aren't any commits in the upstream branch that haven't been merged yet.
- Validating that there have been commits since the nearest version. (Don't re-release with a different version.)
- Optionally, checking all Java/Groovy files for @since tags. If they exist, ensure that they match a version that has been tagged in the repository or the version that was just inferred.
- Execute whatever release tasks the user specified in the plugin configuration. (e.g.
build,publishToRepo) - Optionally, tag the release. Can be configured to only tag certain types of versions. (e.g. only
finalandrc) - Push changes in current branch to the remote. If a tag was made it will also be pushed.
Only the grgit property is mandatory. releaseTasks should be filled in if
you want the code built or published. Everything else has defaults, as noted
below.
apply plugin: 'grgit-release'
import org.ajoberstar.grgit.*
release {
grgit = Grgit.open(project.file('.'))
remote = 'upstream' // default is 'origin'
prefixTagNameWithV = false // default is true
releaseTasks = ['build', 'publishGhPages', 'bintrayUpload'] // defaults to []
enforceSinceTags = true // default is false
version {
untaggedStages = ['alpha'] // default is ['dev']
taggedStages = ['beta'] // default is ['milestone', 'rc']
useBuildMetadataForStage = { true } // default is { stage -> stage != 'final' }
createBuildMetadata = { new Date().format('yyyy.MM.dd.hh.mm.ss') } // default is { grgit.head().abbreviatedId }
}
generateTagMessage = { version -> // default is "Release of ${version}"
StringBuilder builder = new StringBuilder()
builder.append('Release of ')
builder.append(version)
builder.append('\n\n')
grgit.log {
range "v${version.nearest.normal.toString()}^{commit}", 'HEAD'
}.inject(builder) { bldr, commit ->
bldr.append('- ')
bldr.append(commit.shortMessage)
bldr.append('\n')
}
builder.toString()
}
}The two main concepts used as part of the version inference are:
- A normal version in the parlance of semver is
<major>.<minor>.<patch>without any pre-release info or build metadata. - The nearest version is determined by finding the shortest commit log between
a tagged version and the current
HEAD. In cases where there are multiple version tags with the same distance, they will be sorted according to semver rules and the one with the highest precedence will be returned. - scope - Changes can be either
MAJOR,MINOR, orPATCH. These correspond to the portions of a semver version<major>.<minor>.<patch>[.<pre-release>][+<build-metadata>] - stage - Correspond to stages of development. The entirety of available stages is
the union of
untaggedStagesandtaggedStageswith the addition offinal. Stages will be used as part of the pre-release info in a version:<stage>.<num>.- For untagged stages the
numwill correspond to the number of commits since the nearest tagged normal version. - For tagged stages the
numwill be incremented from the nearest version if it has the same normal component and stage. Otherwise it will be set to 1.
- For untagged stages the
There are 2 task rules added to handle releases:
ready<scope>VersionAs<stage>- (e.g.readyMinorVersionAsRc) This will run before any other tasks in the build.- Infers the version. If there have been no commits since the nearest version the task will fail.
- Checks for changes in the repository. If there are any changes they will be printed out and the task will fail.
- Fetches from remote.
- Checks current branch's tracking status to ensure it isn't behind. If it is behind the task will fail.
release<scope>VersionAs<stage>- (e.g.releasePatchVersionAsFinal) This will run after any tasks specified inreleaseTasksand the correspondingready<scope>VersionAs<Stage>.- Tags the version if
stageis eitherfinalor intaggedStages. - Pushes the current branch and, if created, the release tag to the remote.
- Tags the version if
Versions will be inferred in the following ways:
- If a
ready*task is executed, the version will be inferred during its execution, using the stage and scope from the name of the task. - Otherwise, the version will be inferred as soon as the task graph has been populated.
It will assume the scope is
PATCHand the stage is the first entry inuntaggedStagesset.- Given
untaggedStagesis aSortedSetand semver dictates lexicographical sorting of non-numeric components, this should be the stage with the lowest precedence.
- Given
If a build tries to access the version before it is inferred an IllegalStateException
will be thrown.
When a version is being inferred the first step is to find the nearest tagged version.
- All tags in the repository are listed.
- If the name cannot be parsed as a valid semver version, it is ignored. Prefixed
vs will be removed. - If the tag is not an ancestor of
HEAD, it is ignored.
- A commit log is generated between the tag and
HEAD. - The tag with the smallest log is returned.
- In cases where there are multiple tags with the smallest log, they will be ordered according to semver rules and the one with the highest precedence will be returned.
This is completed to determine both the absolute nearest version and the nearest normal version.
The normal component of the inferred version starts from the nearest normal version and the component corresponding to scope is incremented.
e.g. If the nearest normal version is 1.3.2 and the absolute nearest version is
1.4.0-milestone.2. Assume the stage is rc in all cases.
| Scope | Inferred Version |
|---|---|
PATCH |
1.3.3-rc.1 |
MINOR |
1.4.0-rc.1 |
MAJOR |
2.0.0-rc.1 |
The pre-release component is based on the requested stage. Untagged stages
are numbered by the count of commits since the nearest normal version. Tagged
stages are numbered in incrementing order within a stage.
e.g. If the nearest normal version is 1.3.2, the absolute nearest version is
1.4.0-milestone.2, and there have been 6 commits since 1.3.2. Assume
the scope is MINOR in all cases.
| Stage | Inferred Version |
|---|---|
dev |
1.4.0-dev.6 |
milestone |
1.4.0-milestone.3 |
rc |
1.4.0-rc.1 |
final |
1.4.0 |
The build-metadata is determined based on useBuildMetadataForStage and
createBuildMetadata. If any is created it is appended to the version after
a +. For example, with the defaults: 1.2.3-rc.1+123abcd
An additional task (validateSinceTags) is added to enforce @since tags in
Javadoc/Groovydoc comments. It defaults to checking all .java or .groovy files
in the main source set. This task only runs if release.enforceSinceTags is set
to true. By default this task will finalize the read* tasks.
The task will enforce that any @since tags used in the source code correspond to
a version considered valid in the repository.
For example, if the repository has the following tags:
- v0.1.0
- 0.2.1+gibberish
- nonsense (for the purposes of version inference this wouldn't be considered, but it is here)
Also assume that the user executed releaseMinorVersionAsRc. The only allowed
values for @since tags would be:
- 0.1.0
- 0.2.1+gibberish (
vprefixes should not be used) - nonsense
- 0.3.0 (can use the target normal version)
- 0.3.0-rc.1 (or the entire inferred version)
validateSinceTags {
source += sourceSets.test.allJava // defaults to sourceSets.main.allJava
}In case you plan to use Travis-CI make sure to follow the travis guide on encrypted keys to setup an encrypted authentication token like the following:
- Create a new "Personal Access Token” on Github at https://github.com/settings/applications and name it whatever fits your needs
- Install the travis CLI on your local machine via “gem install travis” (NOTE: ruby needs to be installed locally!!)
- Encrypt your Personal Access Token via “travis encrypt GH_TOKEN=”
- add the encrypted token to your
.travis.ymlfile like the following
# ...
env:
global:
- secure: "E6iGay3wQcbhAUM5S5WkjYUmg6b7oJG9l8T2y0WWRgx50oqR0/jGzCYHpJGCHlb9OOZpB2BnhpYS6fCg09MsPYKcgsMXgjYzozWGBYifBIVNI07zQhDByztWr3fsrwrZc31ifqC3EGL/UEwvN5F093rRufDw2jomGpFQn7gL4Kc="- Adjust your credentials in the
build.gradleto something like
githubPages {
// ...
credentials {
username = System.getenv('GH_TOKEN')
password = ''
}
}v0.8.0
- Updated
GithubPagesPluginExtensionto allow configuration of commit message used. - Added an opinionated release plugin
grgit-release. See docs above for info.
v0.7.1
- Fixed
publishGhPagesto actually work. (Sorry about that...)
v0.7.0
- Complete rewrite of the Git layer in the grgit library.
- Git functionality can be used in a more free form manner, rather than dedicated tasks for each operation.
- Breaking Changes:
- The API has almost completely changed. See the Groovydoc of gradle-git and grgit for details.
- Plugin requires Java 7. Comment on issue 42 if you have any feedback on that.
v0.6.5
- Fixing
GitPush.namesOrSpecs(String...)to avoid NPE.
v0.6.4
- Adding
targetPathproperty togithub-pagesplugin to allow pushing to branches besidesgh-pages. Contributed by Alexander Heusingfeld - Fix to bypass SSHAgentConnector in certain situations where correct libraries aren't in place.
v0.6.3
- Fixed jsch-agent-proxy support to fall back to other options when agents aren't really available. See #31.
v0.6.2
- Added
GitInitto simply initialize a new local Git repo. Contributed by Rasmus Praestholm
v0.6.1
- Updated
GitPushto support specifying branch names or specs to push. Contributed by Benjamin Muschko
v0.6.0
- Added support for jsch-agent-proxy. This allows use of sshagent and Pageant to provide ssh credentials.
v0.5.0
- Added support for checking out tags on
GitClone. - Fixed a bug with
GitAddthat prevented adding individual files from a subdirectory of the repository.
v0.4.0
- Minor update to
GitCommitto allow include/exclude rules for the files to commit, courtesy of Evgeny Shepelyuk.
v0.3.0
- Added
GitBranchCreate,GitBranchList,GitBranchTrackingStatus,GitCheckout,GitStatustasks courtesy of Evgeny Shepelyuk.
v0.2.3
- Added
GitCleanandGitLogtasks contributed by Alex Lixandru
NOTE: The GitLog tag only supports commit hashes (abbreviated or full). Tag names do not work
right now.
v0.2.2
- Fix: If
cloneGhPagesdoes not checkout thegh-pagesbranch, most likely because it doesn't exist, the task will fail.
v0.2.1
- Added
GitFetch,GitMerge,GitPull, andGitResettasks contributed by Alex Lixandru.
v0.2.0
This release does contain breaking changes.
- Consolidated plugins into
GithubPagesPlugin. The existingGithubPluginandGitPluginprovided no useful functionality. - Centralized implementation for retrieving authentication.
v0.1.2
- Added support for SSH connections with the help of Urs
v0.1.1
- Added
GitTagtask contributed by Urs Reupke. - The
repoPathfor all Git tasks is defaulted to the root project's directory.
v0.1.0
Initial release.
