Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
391 lines (260 sloc) 19.4 KB

Gradle SuperPOM of Tomasz Linkowski

Build (Linux) Build (Windows) Code coverage Codacy grade

Maven Central Javadocs Semantic Versioning Automated Release Notes by gren

This project is inspired by The Gradle SuperPOM post by Andres Almiray.

This projects provides two plugins:

  1. A Gradle Project plugin (id: pl.tlinkowski.gradle.my.superpom)

  2. A Gradle Settings plugin (id: pl.tlinkowski.gradle.my.settings)

Together, those two plugins preconfigure Gradle builds for each of my projects.

Usage

by Tomasz Linkowski

gradle.properties:

# Release scopes: [major, minor, patch]
reckon.scope=minor
# Dependencies
mySuperpomVersion=x.y.z

settings.gradle.kts:

buildscript {
  repositories {
    mavenCentral()
  }
  dependencies {
    val mySuperpomVersion: String by settings
    classpath(group = "pl.tlinkowski.gradle.my", name = "pl.tlinkowski.gradle.my.settings", version = mySuperpomVersion)
  }
}
apply(plugin = "pl.tlinkowski.gradle.my.settings")

build.gradle.kts:

plugins {
  id("pl.tlinkowski.gradle.my.superpom")
}

For a complete usage example, see sample-project.

by others

If you like what this plugin does, you can:

  1. Fork this project.
  2. Change data related to Tomasz Linkowski to match your person / organization (especially classes with My prefix).
  3. Set up your Bintray and Maven Central accounts.
  4. Release your own version of the Gradle Settings & SuperPOM plugin.

Features

Settings Plugin (id: pl.tlinkowski.gradle.my.settings)

Configures:

  1. plugin management:

    • Maven Central repository for pl.tlinkowski.gradle.my.superpom (this plugin is not deployed to Gradle Plugin Portal as it's not a general-use plugin)

    • automatic version resolution for pl.tlinkowski.gradle.my.superpom (using mySuperpomVersion property in gradle.properties)

  2. project structure (inspired by Kordamp project structure):

    • subprojects in subprojects directory
    • build file names changed from build.gradle.kts to <subproject-name>.gradle.kts
    • build files required for all subprojects
    • subprojects optionally grouped under subdirectories (e.g. subprojects/sample/pl.tlinkowski.xyz.sample)

Project Plugin (id: pl.tlinkowski.gradle.my.superpom)

Project Preconfiguration

This is the basic feature described by Andres Almiray in his post.

This SuperPOM plugin can be applied to the root project only, and it does the following:

  1. for all projects:

    • applies: idea plugin

    • configures: Maven Central repository

  2. for the root project:

  3. for subprojects:

Comprehensive Release Process

This plugin configures a comprehensive release process by:

  • exposing release Gradle task (which serves as the root of a complex task chain)

  • providing shared release.bat script (which simply calls gradle clean followed by gradle release -Preckon.stage=final)

The comprehensive release process is configured by MyComprehensiveReleaseConfigurator and includes:

  1. Release validation (requirements: clean repo, pushed master branch, reckon.stage=final property)
  2. Full clean build (to make 100% sure we can release)
  3. Confirmations to make sure the release is going fine
  4. Changelog generation (by gren, requires Node.js)
  5. Tagging the release in Git
  6. Publishing to GitHub (by gren, requires Node.js)
  7. Publishing to central repos (JCenter & Maven Central)
  8. Post-release reset of the release scope for reckon in gradle.properties

This is how a Gradle build log of such a release process looks:

> Task :validateReleasePossible        // 1

> Task :<subproject-1>:[...]           // 2
> Task :<subproject-1>:build           // 2

> Task :<subproject-2>:[...]           // 2
> Task :<subproject-2>:build           // 2

> Task :confirmReleaseProcessLaunch    // 3
=== Do you want to begin the release process for version 0.1.0 of 'sample-project'? [y/N] ===
y

> Task :addTemporaryVersionTag         // 4 (required by gren)
> Task :generateChangelog              // 4 (gren)
> Task :removeTemporaryVersionTag      // 4 (no longer needed)

> Task :confirmChangelogPush           // 3
=== Do you want to push the updated CHANGELOG.md and continue with the release process? [y/N] ===
y

> Task :pushUpdatedChangelog           // 4
> Task :addFinalVersionTag             // 5

> Task :confirmFinalPublication        // 3
=== Are you SURE you want to publish the code at 0.1.0 tag to GitHub, JCenter & MavenCentral? [y/N] ===
y

> Task :releaseToGitHub                // 6 (gren)

> Task :<subproject-1>:[...]                               // 7
> Task :<subproject-1>:publishMainPublicationToMavenLocal  // 7

> Task :<subproject-2>:[...]                               // 7
> Task :<subproject-2>:publishMainPublicationToMavenLocal  // 7

> Task :injectReleasePasswords         // 7

> Task :<subproject-1>:[...]           // 7
> Task :<subproject-1>:bintrayUpload   // 7

> Task :<subproject-2>:[...]           // 7
> Task :<subproject-2>:bintrayUpload   // 7

> Task :bintrayPublish                 // 7
> Task :releaseToCentralRepos          // 7
> Task :release
> Task :resetScopeInGradleProperties   // 8
> Task :pushUpdatedGradleProperties    // 8

Note the injectReleasePasswords task, which obtains the following passwords for performing a release:

  • bintrayApiKey: from Gradle properties (i.e. ~/.gradle/gradle.properties),
  • gnupgPassphrase, sonatypePassword: by requesting them in a Swing dialog (not suitable for CI)

Also, note that thanks to reckon plugin, we don't need to do the classic "pre-release version bumps". Instead, we:

  • automatically reset the version scope after a release to patch (= "post-release version bump")
  • manually change the scope to minor or major whenever we commit any changes that are in such scope

Gradle Configuration Sharing

A large part of the build configuration for:

is shared as pl.tlinkowski.gradle.my.superpom.shared package (see MyCompleteSharedConfigPlugin).

Thanks to this, we don't have to:

  • duplicate large portions of configuration between the source and target projects, nor

  • apply the previous version of this plugin to itself to avoid the duplication mentioned above (as Andres Almiray suggests in his post)

This is achieved by synchronizing the contents of the SuperPOM plugin's shared package with a corresponding shared package in buildSrc (see buildSrc/build.gradle.kts for details).

Gradle Property Sharing

Gradle properties at gradle/shared-gradle.properties are shared by SuperpomSharedFileExportPlugin (a part of direct file sharing mechanism). Then, these properties are imported by:

If a shared property to be imported already exists, it's ignored with a warning.

Direct File Sharing

Selected files in this project can be directly exported to projects that apply this SuperPOM plugin. It can be viewed as a "sync" operation between this (source) project and all target projects.

The files to be shared are specified in SuperpomFileSharing (usually, it's a good idea to git-ignore them in target projects). Currently, the following files are shared directly:

  • idea: parts of IntelliJ configuration from .idea directory (subdirectories codeStyles, copyright, inspectionProfiles)

  • release: files related to releasing, like release.bat script and Node.js configuration for gren

  • ci: configuration for Continuous Integration environments, i.e. .appveyor.yml and .travis.yml files (these files should not be git-ignored in target projects)

  • lombok: Lombok configuration, i.e. lombok.config file

This feature is implemented:

  • in SuperpomSharedFileExportPlugin, by registering a special exportSharedFiles task for this (source) project

    • the task zips files to be exported and places the resulting archive in the resources of the SuperPOM plugin
  • in SuperpomSharedFileImportPlugin, by registering a special importSharedFiles task for a target project

    • the task reads the archive as a resource and unzips it in the corresponding location

Lombok

If superpom.useLombok is true, this plugin (through LombokConfigPlugin):

  • adds compileOnly and annotationProcessor dependencies on Project Lombok (like gradle-lombok plugin)

  • configures delombokJava task, which generates delomboked version of the main Java source code (like gradle-delombok plugin, but in a JPMS-compatible way)

  • configures javadoc task to use the delomboked source code as its source (otherwise, JavaDoc wouldn't reflect code generated by Lombok at all)

Naming Convention

This project applies a naming convention for Maven & JPMS by Christian Stein. In short:

Gradle project name = JPMS module name

The SuperPOM plugin enforces this convention by ensuring that the Gradle project name (i.e. Maven artifactId):

  • starts with Maven groupId

  • is a prefix of every package in the project

  • equals JPMS module name (only if module-info.java is present)

  • is valid automatic JPMS module name (only if module-info.java is absent)

Requirements

Gradle 5+, JDK 11+.

About the Author

See my webpage (tlinkowski.pl) or find me on Twitter (@t_linkowski).

You can’t perform that action at this time.