Skip to content

Repository files navigation

framefork-gradle-plugins

Opinionated Gradle convention plugins for the Framefork family of JVM libraries. A single settings plugin that a consumer applies with a version, after which every module gets uniform build, static-analysis, test and publishing conventions — with no per-module tool versions or copy-pasted buildSrc.

What it gives you

Apply one plugin and every library module gets, consistently:

  • Java toolchain model — compile on a modern JDK, emit older---release bytecode, run tests on a configurable JDK (compile-modern / target-old / test-anywhere).
  • Static-analysis strictnessError Prone + NullAway in JSpecify mode (onlyNullMarked + jspecifyMode), with @NullMarked package-info generation, over -Werror.
  • Tests — JUnit 5 on the JUnit Platform + readable test-logger output, with stray JUnit 4 substituted away.
  • Publishingmaven-publish staging with a full POM (for published library modules).
  • Kotlin — applied automatically only to modules that actually contain Kotlin sources.

Usage

In the consumer's settings.gradle.kts:

pluginManagement {
    repositories {
        mavenCentral()
        gradlePluginPortal()
    }
}

plugins {
    id("org.framefork.build") version "0.1.0"
}

framefork {
    minJavaVersion = 17    // --release bytecode target (the minimum Java a consumer needs)
    jdkVersion = 21        // compile/build toolchain (>= 21); override per-invocation with -Pjdk.version
    // testsJdkVersion = 21 // test-runtime JDK; defaults to the resolved jdkVersion; override with -Ptests.jdk.version
    // jspecifyMode = true  // NullAway JSpecify mode (default on)
}

The settings plugin discovers subprojects under modules/ (published libraries) and testing/ (internal test modules), so each module only declares which convention it wants — version-less, because the settings plugin puts them on the classpath:

// modules/foo/build.gradle.kts — a published library module
plugins {
    id("org.framefork.build.library-published")
}
// testing/bar/build.gradle.kts — an internal/test-only module (everything above, minus publishing)
plugins {
    id("org.framefork.build.library-internal")
}

A module whose classes carry Google @AutoService adds the version-less org.framefork.build.auto-service feature plugin after its library-* plugin; it wires the annotation (compileOnly) and its processor (annotationProcessor) with no versions:

// modules/foo/build.gradle.kts — a module that registers services via @AutoService
plugins {
    id("org.framefork.build.library-published")
    id("org.framefork.build.auto-service")
}

Kotlin modules need one thing more. The base wiring is javac's annotationProcessor, which only processes Java sources — @AutoService on a Kotlin class generates nothing through it (it fails open, silently). So a Kotlin module also applies a Kotlin annotation-processing backend, and auto-service wires the auto-service processor onto whichever one it finds (order-independent). Prefer KSP — it needs a version matching your Kotlin (KSP is not on the suite's classpath, unlike the kotlin("…") companions):

// KSP (preferred) — pick the KSP release matching the suite's bundled Kotlin
plugins {
    id("org.framefork.build.library-published")
    id("com.google.devtools.ksp") version "2.2.21-2.0.5"
    id("org.framefork.build.auto-service")
}
// kapt (fallback) — resolves version-less off the suite classpath
plugins {
    id("org.framefork.build.library-published")
    kotlin("kapt")
    id("org.framefork.build.auto-service")
}

If a Kotlin module applies auto-service but neither backend, the build still succeeds but warns that @AutoService on its Kotlin classes registers nothing — see Troubleshooting.

That's the whole consumer surface. No error-prone/nullaway/jspecify/auto-service versions, no buildSrc, no repeated toolchain wiring.

The framefork { } knobs

Knob Default Meaning
minJavaVersion 17 --release bytecode target — the minimum Java a consumer of the library needs.
jdkVersion 21 The JDK the compiler runs on (must be ≥ 21 for Error Prone). Overridable with -Pjdk.version=NN.
testsJdkVersion = resolved jdkVersion The JDK the tests execute on. Overridable with -Ptests.jdk.version=NN.
jspecifyMode true Whether NullAway runs in JSpecify generics mode.
sequentialTests true Run at most one test JVM at a time across all modules — mutual exclusion, not ordering. Set to false to let test JVMs run in parallel across modules.
dependencyLocking false Lock all configurations (LockMode DEFAULT) and provide the resolveAndLockAll maintenance task — see Troubleshooting.

Compilation always runs on a modern jdkVersion (so current Error Prone works) and emits --release minJavaVersion bytecode, so the same artifact is portable across JDKs. Testing across multiple JDKs is a CI-matrix concern — set -Ptests.jdk.version per matrix cell; the plugin models a single scalar, not a list.

Requirements

  • Gradle 9.0+ on the consumer side, with the Gradle daemon running on JDK 21+ — the plugin's module metadata requires a 21+ JVM to resolve at all (on CI, keep a 21+ JDK as the last setup-java entry so it becomes the default JAVA_HOME).
  • A JDK ≥ 21 available as a toolchain (plus whatever testsJdkVersion you target).

Building this repo

./gradlew build                              # compile + unit + functional tests
./gradlew functionalTest -PtestedGradleVersion=9.0   # replay the functional suite against the consumer baseline
./gradlew publishToMavenLocal                # install locally to try against a consumer

To try an unreleased version against a real consumer without publishing, publishToMavenLocal here and add mavenLocal() to the consumer's pluginManagement.repositories.

Documentation

  • Troubleshooting — common adoption failures (annotation-library -Werror breaks, JDK-knob errors, doclint, Kotlin, dependency locking) and their fixes.
  • Design decisions — why the suite is built the way it is (distribution, structure, the JDK model, the strictness stack, config-cache safety).
  • Contributing — building, testing, the codebase map, and the invariants a change must preserve.
  • Releasing — the Maven Central release procedure: pre-flight checks, triggering the workflow, and writing the changelog.

License

Released under the Apache License 2.0.

About

Opinionated Gradle convention plugins for Framefork JVM libraries: one settings plugin providing uniform build, static-analysis (Error Prone + NullAway + JSpecify), test, and publishing conventions.

Resources

Contributing

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages