Class ReleaseFlowPlugin

java.lang.Object
io.github.duckasteroid.gradle.versioning.releaseflow.ReleaseFlowPlugin
All Implemented Interfaces:
org.gradle.api.Plugin<org.gradle.api.Project>

public class ReleaseFlowPlugin extends Object implements org.gradle.api.Plugin<org.gradle.api.Project>
Opt-in release-engineering tasks for a develop -> release -> main git flow. Apply alongside io.github.duckasteroid.version (which computes project.ext.tagPrefix / modulePath that these tasks reuse rather than recomputing) - this plugin has no dependency on any Java-toolchain-configuring plugin, except installReleaseWorkflows (see its own comment further down), which is the one task that genuinely needs one.

Ten tasks total. tagReleaseCandidate/promoteReleaseCandidate are the release-time counterpart to the version plugin's ordinary-build version resolution (they don't just compute a version, they actually create and push a tag for it) for the applying project alone - handy for local, single-module work. tagReleaseCandidates/ promoteReleaseCandidates (plural) are what CI actually calls: they loop every project in the build that applies this plugin, so the same mechanism covers a single-module repo, several independently-versioned modules, or a shared root version, without any of those shapes needing special-case configuration. changelogForReleaseCandidate/changelogForRelease generate release notes for the applying project alone; explainVersion/ explainVersions print (and, by default, write to build/version-report.json) a read-only preview of what tagReleaseCandidate(s) would actually do right now, without tagging or pushing anything; installReleaseWorkflows/checkReleaseWorkflows install/verify the GitHub Actions workflow files that invoke the plural tasks above. All ten are plain Gradle tasks, runnable locally as well as from CI.

tagReleaseCandidate/promoteReleaseCandidate respect release.forceVersion as the ultimate backstop: if set, it's used verbatim, no commit analysis runs at all. This check is deliberately repeated at every call site rather than shared, so the backstop can never be silently bypassed by one call site forgetting to check it.

Task actions below capture everything they need (tagPrefix, modulePath, projectDir, the forceVersion property) as plain local values during task configuration, and shell out via plain ProcessBuilder (see ReleaseGitOps) rather than any live-Project access at execution time - accessing the live Project object from a task action at execution time is unsupported under the configuration cache, so nothing in a doLast block below may reference the enclosing Project. The plural aggregator tasks follow the same rule: the list of applying projects is captured as plain data (a ReleaseFlowPlugin.Target per project, never a live Project reference) from a projectsEvaluated callback, which runs at configuration time, not from inside their own doLast actions.

releaseCandidates { } controls what tagReleaseCandidate(s) does once a new RC exists for a module: release candidates aren't permanent, so by default every previous RC's GitHub Release (never its tag or published package) is deleted, regardless of whether the candidate version itself changed mid-cycle. tagReleaseCandidates records what got superseded per module in each build/release-manifest.json entry's supersededTags field for the CI workflow to act on; the singular tagReleaseCandidate only prints the leapfrog warning, since it has no GitHub integration point of its own to prune anything through. promoteReleaseCandidate(s) never prunes - by the time a promotion happens there's only ever one live RC for that module left to promote.

  • Constructor Details

    • ReleaseFlowPlugin

      public ReleaseFlowPlugin()
  • Method Details

    • apply

      public void apply(org.gradle.api.Project project)
      Specified by:
      apply in interface org.gradle.api.Plugin<org.gradle.api.Project>