GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — GitHub - nebula-plugins/nebula-release-plugin: Release opinions based around gradle-git

BranchesTags
Open more actions menu

Latest commit

 

History

695 Commits
695 Commits

Folders and files

NameName
Last commit message
Last commit date
.github
.github
 
 
docs
docs
 
 
gradle
gradle
 
 
src
src
 
 
.gitignore
.gitignore
 
 
CHANGELOG.md
CHANGELOG.md
 
 
CONTRIBUTING.md
CONTRIBUTING.md
 
 
LICENSE
LICENSE
 
 
README.md
README.md
 
 
build.gradle.kts
build.gradle.kts
 
 
gradle.lockfile
gradle.lockfile
 
 
gradle.properties
gradle.properties
 
 
gradlew
gradlew
 
 
gradlew.bat
gradlew.bat
 
 
settings.gradle
settings.gradle
 
 
stale_outputs_checked
stale_outputs_checked
 
 

Repository files navigation

nebula-release-plugin

Support Status Gradle Plugin Portal Maven Central Build Apache 2.0

This plugin provides opinions and tasks for the release process provided by gradle-git.

Experimental Isolated Projects support

The opt-in implementation currently covers ordinary help/build commands, root snapshot, candidate/final, and setup workflows with a Git repository, plus release-base and the full plugin's no-Git fallback. It provides common versions, leaf Java builds, and Maven/Ivy descriptors without cross-project mutable-state access. It does not yet establish general Isolated Projects support.

Enable the build-wide rollout flag in root gradle.properties:

nebula.release.isolatedProjectsSupport=true

Apply the companion in settings.gradle, using the same plugin version as the project plugin:

plugins {
    id 'com.netflix.nebula.release-settings' version '<plugin-version>'
}

rootProject.name = 'sample'
include 'library', 'application'

// Optional common inputs; defaults use Gradle properties and tags prefixed with v.
isolatedRelease {
    scope = 'minor'
    prefixTagsWithV = true
    remote = providers.gradleProperty('releaseRemote').orElse('origin')
}

Explicit isolatedRelease values take precedence over property conventions. gitRoot, scope, and version default to git.root, release.scope, and release.version, respectively. version and remote also accept providers. All common settings are frozen when settings evaluation completes; configure them in settings rather than project callbacks. -Prelease.version selects an explicit common version instead of inferring one from scope. verifySuppliedVersion defaults to true unless release.ignoreSuppliedVersionVerification is present (even with value false); an explicit settings value overrides that convention.

Apply com.netflix.nebula.release in the root and in each participating project's own build script or local convention. All projects receive the common version; projects without the release plugin do not become release participants.

Run ./gradlew snapshot, devSnapshot, immutableSnapshot, candidate, or final, or use ordinary help/build commands with default development versioning. The existing nebula.release.features.replaceDevWithImmutableSnapshot and nebula.release.features.immutableSnapshot.timestampPrecision properties also apply. Settings may override them using replaceDevWithImmutableSnapshot and timestampPrecision. One timestamp is captured during settings evaluation and shared by all projects; configuration-cache reuse retains that timestamp, and settings reevaluation captures a new one. Setup tasks retain default version selection unless a stage is explicitly supplied. Primary release workflows and their setup tasks require an initial Git commit; ordinary commands also support no-commit version inference. Cache-boundary tests on Gradle 9.0, 9.5, and 9.9 distinguish a whole-build cache hit from reconfiguration. Even an ignored child-script edit, with unchanged Git state, reconfigures settings and every project on these versions. Each project then receives the same refreshed timestamp. Partial project-cache reuse remains unverified: current Gradle task builds do not provide that mode. See the compatibility review for the evidence and remaining limits. Use the full root workflow names shown above, optionally prefixed with :; abbreviated workflow selectors receive a diagnostic. Custom workflow entry points have not been validated.

As in the existing implementation, inferred immutable snapshots do not create tags. Supplying -Prelease.version to immutableSnapshot creates and pushes a tag to the configured remote (default origin); snapshot and devSnapshot skip tagging even with an explicit version. Set isolatedRelease.checkRemoteBranchOnRelease = true in settings to enable the optional remote check for immutable snapshots and candidate/final releases. The existing release.disableGitChecks and release.travisci flags skip preparation and tagging.

candidate selects rc versioning; final selects a final version. Both require a clean working tree and an allowed release branch, including when Git skip flags are set. Settings expose releaseBranchPatterns, excludeBranchPatterns, and allowReleaseFromDetached with their existing defaults. Status is assigned locally as candidate or release; setup tasks assign that status without selecting a stage. Root Ivy descriptors receive the primary workflow status; child descriptor defaults retain existing behavior.

Use -Prelease.useLastTag=true to reuse a valid version tag on the current commit without creating or pushing a tag. Reuse takes precedence over release.version and validates the tag against the requested candidate/final stage. Snapshot workflows reject last-tag reuse. Direct release, postRelease, and prepare tasks retain their existing behavior; supplying release.stage selects inference without adding primary workflow branch validation or status changes.

Enable Gradle's own Isolated Projects setting separately, using the switch supported by your Gradle version. The plugin flag also selects the new implementation when Gradle isolation is disabled.

For com.netflix.nebula.release-base, select base mode in settings and apply the project plugin only at the root:

isolatedRelease {
    baseRelease = true
    defaultStage = 'dev'
}

Base mode exposes only root prepare and release tasks and assigns common versions locally. It does not add Java builds or publication descriptors to the release graph; wire consumer tasks explicitly, for example tasks.named('release') { dependsOn ':library:build' }. Consumer task names do not select a stage. Choose defaultStage, release.stage, a supplied version, or last-tag reuse. Built-in stages are dev, SNAPSHOT, snapshot, milestone, rc, and final; full mode also accepts defaultStage and defaults to dev (or snapshot with development replacement). Base uses stock strategy defaults: patch scope except uppercase SNAPSHOT, which defaults to minor, and commit-only development metadata. Base preparation remains enabled with last-tag reuse and the full plugin's Git skip flags. Built-in base inference and last-tag reuse require an initial Git commit; supplied versions work for ordinary commands without one.

Without a Git repository, the full plugin assigns the literal 0.1.0-dev.0.uncommitted version only to projects applying that plugin. Other projects retain their versions. It installs no release tasks or extensions, ignores release inference options, and permits subsequent direct version assignment, matching legacy behavior. Ordinary Java/Maven/Ivy tasks remain available. Creating or removing the Git repository invalidates cached mode selection.

The prototype rejects legacy release and nebulaRelease extension customizations, arbitrary custom strategies, and Artifactory integration in active full mode. Artifactory 6.0.0 and 6.0.4 fail strict Isolated Projects on help even without the release plugin, because they configure other projects. No supported Artifactory version range has been established. Use native Maven/Ivy publishing hooks below, or retain the legacy release path with Gradle isolation disabled for Artifactory builds. Use the settings adapters for built-in defaults, versions, remotes, tag prefixes, and branch/check policies. Configure supported common inputs in settings or through Gradle properties; root extra properties are not imported. Keep the flag disabled to use existing release behavior. Remove or conditionally apply the settings companion when disabling the flag.

See the implementation spec for the support boundary, validation requirements, and remaining milestones.

Optional Configuration

If you want the release plugin to trigger or finalize a publishing task you will need to configure it:

tasks.named('release') {
    dependsOn ':library:publish'
    finalizedBy ':application:publish'
}

Configure each project's Maven/Ivy publications and repositories in its own build script or local convention. Task paths allow the root to request publishing without accessing another project's task container. Both full and base modes support these hooks. The release plugin does not add publishing tasks for other projects automatically, and direct descriptor commands do not trigger these hooks.

Gradle runs dependencies before release and finalizers after it, including when release is skipped or fails. Last-tag reuse suppresses tagging but still runs the publishing hooks. Choose finalizers only when that behavior is intended.

Opinions

Project using this plugin will use semantic versions style strings. e.g. major.minor.patch-<prerelease>+<metadata>

All tasks default to bumping the minor version.

Extension Provided

nebulaRelease {
  Set<String> releaseBranchPatterns = [/master/, /HEAD/, /main/, /(release(-|\/))?\d+(\.\d+)?\.x/, /v?\d+\.\d+\.\d+/] as Set
  Set<String> excludeBranchPatterns = [] as Set
  String shortenedBranchPattern = /(?:(?:bugfix|feature|hotfix|release)(?:-|\/))?(.+)/

  void addReleaseBranchPattern(String pattern)
  void addExcludeBranchPattern(String pattern)
}
Property Type Default Description
releaseBranchPatterns Set<String> [master, HEAD, main, (release(-|\/))?\d+(\.\d+)?\.x, v?\d+\.\d+\.\d+] Branch patterns that are acceptable to release from. The default pattern will match things like master, 1.2.x, release-42.x, release/2.x, v1.2.3. If the set is empty releases will be possible from any branch that doesn't match excludeBranchPatterns.
excludeBranchPatterns Set<String> [] Branch patterns that you cannot release from. If a branch matches both releaseBranchPatterns and excludeBranchPatterns it will be excluded.
shortenedBranchPattern String (?:(?:bugfix|feature|hotfix|release)(?:-|\/))?(.+) Branch widget1 will append widget1 to snapshot version numbers, and branch (feature|bugfix|release|hotfix)/widget2 will append widget2 to snapshot version numbers. You may configure this field, the regex is expected to have exactly one capture group.
Method Arguments Description
addReleaseBranchPattern String pattern Calling this method will add a pattern to the set of releaseBranchPatterns, usage: nebulaRelease { addReleaseBranchPattern(/myregex/)
addExcludeBranchPattern String pattern Calling this method will add a pattern to the set of excludeBranchPatterns, usage: nebulaRelease { addExcludeBranchPattern(/myregex/)

Tasks Provided

All tasks will trigger gradle-git's release task which is configured to depend on the build task if the project produces JVM based jar or war artifacts.

  • final - Sets the version to the appropriate <major>.<minor>.<patch>, creates tag v<major>.<minor>.<patch>
  • candidate - Sets the version to the appropriate <major>.<minor>.<patch>-rc.#, creates tag v<major>.<minor>.<patch>-rc.# where # is the number of release candidates for this version produced so far. 1st 1.0.0 will be 1.0.0-rc.1, 2nd 1.0.0-rc.2 and so on.
  • devSnapshot - Sets the version to the appropriate <major>.<minor>.<patch>-dev.#+<hash>, does not create a tag. Where # is the number of commits since the last release and hash is the git hash of the current commit. If releasing a devSnapshot from a branch not listed in the releaseBranchPatterns and not excluded by excludeBranchPatterns the version will be <major>.<minor>.<patch>-dev.#+<branchname>.<hash>
    • You can use nebula.release.features.replaceDevWithImmutableSnapshot=true in your gradle.properties file to change pattern of version to <major>.<minor>.<patch>-snapshot.<timestamp>+<hash>. Where timestamp is UTC time in YYYYMMddHHmm format, ex. 201907052105 and hash is the git hash of the current commit. If releasing a immutableSnapshot from a branch not listed in the releaseBranchPatterns and not excluded by excludeBranchPatterns the version will be <major>.<minor>.<patch>-snapshot.<timestamp>+<branchname>.<hash>
  • snapshot - Sets the version to the appropriate <major>.<minor>.<patch>-SNAPSHOT, does not create a tag.

Use of devSnapshot vs snapshot is a project by project choice of whether you want maven style versioning (snapshot) or semantic versioned snapshots (devSnapshot).

Immutable snapshots

For devSnapshot task, you can use nebula.release.features.replaceDevWithImmutableSnapshot=true in your gradle.properties file to change pattern of version to <major>.<minor>.<patch>-snapshot.<timestamp>+<hash>. Where timestamp is UTC time in YYYYMMddHHmm format, ex. 201907052105 and hash is the git hash of the current commit. If releasing a immutableSnapshot from a branch not listed in the releaseBranchPatterns and not excluded by excludeBranchPatterns the version will be <major>.<minor>.<patch>-snapshot.<timestamp>+<branchname>.<hash>

Timestamp precision

This was introduced in 20.1.0

The time precision used by the plugin to calculate immutable snapshot timestamp is configurable through the nebula.release.features.immutableSnapshot.timestampPrecision For example: nebula.release.features.immutableSnapshot.timestampPrecision=MINUTES

The default value is MINUTES.

The supported precision values are:

  • DAYS: produces yyyyMMdd
  • HOURS: produces yyyyMMddHH
  • MINUTES: produces yyyyMMddHHmm
  • SECONDS: produces yyyyMMddHHmmss
  • MILLISECONDS: produces YYYYMMddHHmmssSSS

Versioning Notes

We attempt to pick up on the fact that you're on certain release branches.

Examples:

  • On release/1.x - The plugin will default to versioning you 1.0.0-SNAPSHOT
  • On 3.x - The plugin will default to versioning you 3.0.0-SNAPSHOT
  • On 4.2.x - The plugin will default to versioning you 4.2.0-SNAPSHOT

Releasing: Bumping major or patch versions

There are many cases where a project may want to bump a part of the version string besides the minor number.

  • bump the major number: ./gradlew <snapshot|devSnapshot|candidate|final> -Prelease.scope=major
  • bump the patch number: ./gradlew <snapshot|devSnapshot|candidate|final> -Prelease.scope=patch

Releasing: Using last tag

In the scenario, where the tag is already created but you want to go through the release process, you can use the "Last Tag Strategy". When enabled, the plugin will respect the last tag as the version. This works well in a CI environment where a user will tag the code, and CI is configured to do just the release upon finding a new tag. The tag names need to follow the versioning scheme, e.g. "v1.0.1". To enact, provide the release.useLastTag project property, e.g.

git tag v1.0.0
./gradlew -Prelease.useLastTag=true final

Overriding version from the command line

To set the version from the command line, set the release.version system property:

./gradlew -Prelease.version=1.2.3 final

Caveats

First release with this plugin

If this is the first time releasing with this plugin and you've released in the past you may need to create a tag in your repository. You should find the hash of your latest release and create a tag of the format v<major>.<minor>.<patch> e.g. v1.4.2. For example, if the hash of your last release was da5d4f9:

git tag v1.4.2 da5d4f9
git push --tags
./gradlew final

Initial version not 0.1.0 or 1.0.0

This will create a tag v<string> where String is whatever you set on release.version. If you want the plugin to work from here on out you should choose a version that matches semantic versioning described above.

./gradlew -Prelease.version=42.5.0 final

Git root is in a different location from Gradle root

The plugin assumes Git root is in the same location as Gradle root. If this isn't the case, you may specify a different path for Git root via the git.root Gradle property. For example:

./gradlew -Pgit.root=<git root path> final

Sanitize versions

Historically, this plugin generated versions using build metadata which comes after the + sign. While we suggest using this approach to be semver compliant, some people has raised their need for removing the build medata and make it part of the pre-release string.

For this, starting on version 11.0.0 we have introduced a sanitizeVersion flag. Ex.

./gradlew -Prelease.sanitizeVersion=true devSnapshot

This will generate a version string similar to: 0.1.0-dev.2.e1c43c7

Please note that now the build metadata is part of the pre-release information and could affect how versions are handled by a SemVer library/tool.

Lifecycle Hooks

For devSnapshot

  • devSnapshotSetup - any kind of setup is good to live around here, e.g. setting status, various checks
  • release - probably have release dependOn any assemble and check tasks, dependsOn devSnapshotSetup
  • postRelease - any steps you want to happen after the repo tag, in our case this is where publishing happens since if the publish partially fails we don't want to fix the tags, dependsOn release
  • devSnapshot - command line task to kick off devSnapshot workflow, dependsOn postRelease

For snapshot

  • snapshotSetup - any kind of setup is good to live around here, e.g. setting status, various checks
  • release - probably have release dependOn any assemble and check tasks, dependsOn snapshotSetup
  • postRelease - any steps you want to happen after the repo tag, in our case this is where publishing happens since if the publish partially fails we don't want to fix the tags, dependsOn release
  • snapshot - command line task to kick off snapshot workflow, dependsOn postRelease

For candidate

  • candidateSetup - any kind of setup is good to live around here, e.g. setting status, various checks
  • release - this is where the tag is pushed to the repo, so probably have release dependOn any assemble and check tasks, dependsOn candidateSetup
  • postRelease - any steps you want to happen after the repo tag, in our case this is where publishing happens since if the publish partially fails we don't want to fix the tags, dependsOn release
  • candidate - command line task to kick off candidate workflow, dependsOn postRelease

For final

  • finalSetup - any kind of setup is good to live around here, e.g. setting status, various checks
  • release - this is where the tag is pushed to the repo, so probably have release dependOn any assemble and check tasks, dependsOn finalSetup
  • postRelease - any steps you want to happen after the repo tag, in our case this is where publishing happens since if the publish partially fails we don't want to fix the tags, dependsOn release
  • final - command line task to kick off final workflow, dependsOn postRelease

Gradle and Java Compatibility

The current development build uses a Java 17 toolchain for plugin compilation. CI runs the full build with test JVMs 17, 21, and 25.

Validation Gradle versions
Legacy and experimental opt-in workflow suites 9.0.0 and 9.5.0
Additional configuration-cache/timestamp boundary probe 9.9.0

The 9.9.0 probe covers cold configuration, whole-build cache reuse, and an ignored child-script change. It does not establish the complete release workflow matrix on that version. These results describe the development branch, including its experimental opt-in implementation; they do not change the compatibility of older published plugin versions.

LICENSE

Copyright 2014-2025 Netflix, Inc.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

About

Release opinions based around gradle-git

Resources

Readme
Apache-2.0 license

Contributing

Contributing
Activity
Custom properties

Stars

237 stars

Watchers

25 watching

Forks

59 forks
Report repository

Releases

Packages

Used by

Contributors

Languages

You are visitor 01402520 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.