Skip to content

Commit

Permalink
Introduce Gradle build scripts
Browse files Browse the repository at this point in the history
This commit stream introduces Gradle/Kotlin build scripts to
replace the Maven build scripts once functional parity is confirmed.

Side effects of this conversion include:

* Removal of the Java 11+ requirement for the generation of _complete_ javadoc; complete javadoc can now be generated using Java 8
* Removal of the paremt POM as a published artifact; the published modules now include POMs that do not rely on the parent

This commit stream includes a modification to PortManager needed under Java 17+ that, for unknown reasons, was not needed under Maven.
  • Loading branch information
cljohnso committed Nov 14, 2023
1 parent 99555ea commit 58f497d
Show file tree
Hide file tree
Showing 23 changed files with 1,416 additions and 17 deletions.
8 changes: 4 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
target/
dependency-reduced-pom.xml

*.iml
.idea/
/bin/
*~
# Gradle
.gradle/
**/build/
!**/src/**/build/
12 changes: 3 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ This project operates under the following constraints:
1. **Changes must not be _breaking_**; programs built to compile and run
using version 0.0.1 artifacts from this project must be able to
compile and run with version 0.0.2 artifacts from this project.
1. **This project should not be _branched_**. Maintaining multiple versions
2. **This project should not be _branched_**. Maintaining multiple versions
of this project is not desirable.
1. The `tools` module may not rely on any third-party artifacts other than:
3. The `tools` module may not rely on any third-party artifacts other than:
* `org.slf4j:slf4j-api`
* `com.github.spotbugs:spotbugs-annotations`
1. The `test-tools` module may rely on test-support artifacts in
4. The `test-tools` module may rely on test-support artifacts in
common use though these artifacts should generally be optional
for consumers of the `test-tools` module. For example, the
following artifacts might be used:
Expand All @@ -24,9 +24,3 @@ This project operates under the following constraints:
If an artifact on which `test-tools` relies makes a breaking change,
introduce new artifact containing the breaking components -- not a
new version of the `test-tools` artifact.

## Notes

* While the project is currently designed to produce artifacts operable under Java 8, the complete Javadoc
will not be produced unless a Java 11 runtime is used during the build. (The plugin used to generate
diagrams included in the Javadoc requires running under Java 11.)
40 changes: 40 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import java.time.Duration

plugins {
base
id("io.github.gradle-nexus.publish-plugin") version "1.3.0"
id("org.nosphere.apache.rat")
}

val defaultVersion: String by project
val sonatypeUser: String by project
val sonatypePwd: String by project

group = "org.terracotta"
version = defaultVersion

repositories {
mavenCentral() // See https://github.com/eskatos/creadur-rat-gradle/issues/26
}

tasks {
rat {
approvedLicense("Apache License Version 2.0")
include("buildSrc/src/**")
exclude("**/org.terracotta.java-conventions.gradle.kts")
}
}

nexusPublishing {
repositories {
sonatype {
username = sonatypeUser
password = sonatypePwd
}
}
// Sonatype is often very slow in these operations:
transitionCheckOptions {
delayBetween = Duration.ofSeconds((findProperty("delayBetweenRetriesInSeconds") ?: "10").toString().toLong())
maxRetries = (findProperty("numberOfRetries") ?: "100").toString().toInt()
}
}
23 changes: 23 additions & 0 deletions buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
plugins {
`kotlin-dsl`
}

repositories {
// Use the plugin portal to apply community plugins in convention plugins.
gradlePluginPortal()
}

dependencies {
implementation("net.sourceforge.plantuml:plantuml:1.2023.11")
implementation("com.github.spotbugs.snom:spotbugs-gradle-plugin:5.0.13")
implementation("org.nosphere.apache.rat:org.nosphere.apache.rat.gradle.plugin:0.8.0")
}

gradlePlugin {
plugins {
create("plantUml") {
id = "org.terracotta.utilities.plugins.plantuml"
implementationClass = "org.terracotta.utilities.plugins.PlantUmlPlugin"
}
}
}
236 changes: 236 additions & 0 deletions buildSrc/src/main/kotlin/org.terracotta.java-conventions.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
import com.github.spotbugs.snom.SpotBugsPlugin
import com.github.spotbugs.snom.SpotBugsTask
import org.gradle.api.Action
import org.gradle.api.attributes.java.TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE
import org.gradle.api.plugins.JavaPlugin.RUNTIME_ELEMENTS_CONFIGURATION_NAME
import java.util.regex.Pattern

plugins {
`java-library`
`maven-publish`
signing
id("checkstyle")
id("com.github.spotbugs")
id("org.nosphere.apache.rat")
}

val slf4jBaseVersion: String by project
val slf4jUpperVersion: String by project
val slf4jRangeVersion by extra("[${slf4jBaseVersion},${slf4jUpperVersion})")
val logbackBaseVersion: String by project
val logbackUpperVersion: String by project
val logbackRangeVersion by extra("[${logbackBaseVersion},${logbackUpperVersion})")
val junitVersion: String by project
val hamcrestVersion: String by project
val mockitoVersion: String by project
val spotbugsAnnotationsVersion: String by project

group = "org.terracotta"
version = project.rootProject.version

repositories {
mavenLocal()
maven {
url = uri("https://repo.maven.apache.org/maven2/")
}
}

dependencies {
api("org.slf4j:slf4j-api:${slf4jRangeVersion}")
compileOnly("com.github.spotbugs:spotbugs-annotations:${spotbugsAnnotationsVersion}")

testCompileOnly("com.github.spotbugs:spotbugs-annotations:${spotbugsAnnotationsVersion}")
testImplementation("org.hamcrest:hamcrest:${hamcrestVersion}")
testImplementation("junit:junit:${junitVersion}") {
exclude(mapOf("group" to "org.hamcrest"))
}
testImplementation("org.mockito:mockito-core:${mockitoVersion}")
}

configurations.all {
// Spotbugs has an internal SLF4J conflict ...
if (SpotBugsPlugin.CONFIG_NAME != this.name) {
resolutionStrategy {
failOnVersionConflict()
}
}
}

java {
sourceCompatibility = JavaVersion.VERSION_1_8
withSourcesJar()
withJavadocJar()
}

publishing {
repositories {
// For publication testing ...
maven(uri(layout.buildDirectory.dir("publishing-repository"))) {
name = "buildLocal"
}
}

publications.register<MavenPublication>("maven") {
from(components["java"])

pom {
description.convention(project.provider { project.description })

licenses {
license {
name.convention("The Apache License, Version 2.0")
url.convention("https://www.apache.org/licenses/LICENSE-2.0.txt")
}
}
developers {
developer {
name.convention("Terracotta Engineers")
email.convention("[email protected]")
organization.convention("Terracotta Inc., a wholly-owned subsidiary of Software AG USA, Inc.")
organizationUrl.convention("https://terracotta.org")
}
}
scm {
connection.convention("scm:git:https://github.com/terracotta-oss/terracotta-utilities.git")
developerConnection.convention("scm:git:[email protected]:terracotta-oss/terracotta-utilities.git")
url.convention("https://github.com/terracotta-oss/terracotta-utilities")
}
}
}
}

checkstyle {
toolVersion = "9.3" // Latest version supporting Java 8
configFile = rootDir.resolve("config/checkstyle.xml")
configDirectory.convention(layout.projectDirectory.dir("config/checkstyle"))
}

tasks {
withType<JavaCompile> {
options.encoding = "UTF-8"
options.isDeprecation = true
options.isWarnings = true
options.compilerArgs.addAll(listOf("-Xlint:all", "-Werror"))
}

withType<Javadoc> {
isFailOnError = false

(options as StandardJavadocDocletOptions).apply {
quiet()
encoding = "UTF-8"
author(false)
showFromProtected()
use(true)

// Avoid complaints about tablew@summary
addBooleanOption("Xdoclint:all,-accessibility", true) // https://discuss.gradle.org/t/how-to-send-x-option-to-javadoc/23384/5
}
}

test {
useJUnit()
}

withType<SpotBugsTask> {
reports {
register("xml") {
required.set(false)
}
register("html") {
required.set(true)
}
}
}

spotbugsTest {
enabled = false
}

rat {
approvedLicense("Apache License Version 2.0")
exclude("build/**") // Avoid implicit dependency error on task outputs
exclude("target/**")
exclude("build.gradle.kts")
}

// CopySpec common to executable and sources Jars
val pomAndLicense = project.copySpec {
into("META-INF/maven/${project.group}/${project.name}") {
from({ tasks.named("generatePomFileForMavenPublication") })
rename(Pattern.quote("pom-default.xml"), "pom.xml")
}
into("") {
from(project.rootProject.rootDir.resolve("LICENSE"))
}
}

val versionPattern = Pattern.compile("(?<major>\\d+)\\.(?<minor>\\d+)\\..*")
@Throws(InvalidUserCodeException::class)
fun specVersion(version: String) : String {
val matcher = versionPattern.matcher(version)
return if (matcher.matches()) {
matcher.group("major") + "." + matcher.group("minor")
} else {
throw InvalidUserCodeException("Version string \"${version}\" is not in major.minor.<rest> format")
}
}

// Manifest construct common to executable and sources Jars
val commonManifest = Action<Manifest> {
val jdkSpec = configurations.named(RUNTIME_ELEMENTS_CONFIGURATION_NAME)
.map { c -> JavaVersion.toVersion(c.attributes.getAttribute(TARGET_JVM_VERSION_ATTRIBUTE) ?: 8) }

attributes(
linkedMapOf(
"Build-Jdk-Spec" to jdkSpec,
"Built-By" to System.getProperty("user.name"),
"Build-Jdk" to System.getProperty("java.version"),
"Specification-Title" to project.description,
"Specification-Version" to specVersion(project.version.toString()),
"Implementation-Title" to project.name,
"Implementation-Vendor-Id" to project.group,
"Implementation-Version" to project.version,
)
)
}

jar {
with(pomAndLicense)
manifest(commonManifest)
}

named<Jar>("sourcesJar") {
with(pomAndLicense)
manifest(commonManifest)
}
}

signing {
/*
* By default, signing uses the 'signing.keyId', 'signing.secretKeyRingFile', and 'signing.password'
* values provided through the gradle.properties file (or some other Gradle property-setting mechanism).
* This scheme does not require special signatory setup methods.
*
* For CI-based publishing, use of the 'ORG_GRADLE_PROJECT_{signingKey,signingPassword,signingKeyId}'
* environment variables supply an ASCII-armored key and require the use of the 'useInMemoryPgpKeys'
* setup method.
*
* If 'ORG_GRADLE_PROJECT_signingKey' environment variable is set, use the 'useInMemoryPgpKeys'
* method; otherwise, the default, property-based method is used.
*/
if (hasProperty("signingKey")) {
val signingKey: String by project
val signingPassword: String by project
if (hasProperty("signingKeyId")) {
val signingKeyId: String by project
useInMemoryPgpKeys(signingKeyId, signingKey, signingPassword)
} else {
useInMemoryPgpKeys(signingKey, signingPassword)
}
}

// Require signing when requested -- either explicitly or via "publish"
setRequired({ gradle.taskGraph.hasTask(tasks.named("signMavenPublication").get()) })
sign(publishing.publications)
}
Loading

0 comments on commit 58f497d

Please sign in to comment.