@@ -2,15 +2,16 @@ import java.net.URI
22import java.time.Instant
33import java.util.Properties
44
5+
56plugins {
67 java
78 `maven- publish`
89 jacoco
910 signing
1011 id(" org.cyclonedx.bom" ) version " 1.7.2"
11- // TODO: static analysis. E.g.:
12+ id(" com.github.spotbugs" ) version " 5.0.13"
13+ // TODO: more static analysis. E.g.:
1214 // id("com.diffplug.spotless") version "6.11.0"
13- // id("com.github.spotbugs") version "4.8.0"
1415}
1516
1617repositories {
@@ -21,7 +22,6 @@ dependencies {
2122 testImplementation(" junit:junit:4.13.1" )
2223 testImplementation(" org.hamcrest:hamcrest:2.2" )
2324 testImplementation(" pl.pragmatists:JUnitParams:1.1.1" )
24- // https://mvnrepository.com/artifact/com.google.code.tempus-fugit/tempus-fugit
2525 testImplementation(" com.google.code.tempus-fugit:tempus-fugit:1.1" )
2626}
2727
@@ -54,19 +54,70 @@ tasks {
5454
5555 javadoc {
5656 // Suppressing Javadoc warnings is clunky, but there doesn't seem to be any nicer way to do it.
57- // https://stackoverflow.com/questions/52205209/configure-gradle-build- to-suppress -javadoc-console -warnings
57+ // https://stackoverflow.com/questions/62894307/option-xdoclintnone-does-not-work-in-gradle- to-ignore -javadoc-warnings
5858 options {
59- (this as CoreJavadocOptions ).addStringOption(" Xdoclint:none" , " -quiet" )
59+ this as StandardJavadocDocletOptions
60+ addBooleanOption(" Xdoclint:none" , true )
61+ addStringOption(" Xmaxwarns" , " 1" ) // best we can do is limit warnings to 1
62+ }
63+ }
64+
65+ // spotbugs-gradle-plugin creates a :spotbugsTest task by default, but we don't want it
66+ // see: https://github.com/spotbugs/spotbugs-gradle-plugin/issues/391
67+ project.gradle.startParameter.excludedTaskNames.add(" :spotbugsTest" )
68+
69+ spotbugsMain {
70+ val spotbugsBaselineFile = " $rootDir /config/spotbugs/baseline.xml"
71+
72+ // CI=true means we're in a CI workflow
73+ // https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables
74+ val ciWorkflow = System .getenv()[" CI" ].toBoolean()
75+ val baselining = project.hasProperty(" baseline" ) // e.g. `./gradlew :spotbugsMain -Pbaseline`
76+
77+ if (! baselining) {
78+ baselineFile.set(file(spotbugsBaselineFile))
79+ }
80+
81+ // The plugin only prints to console when no reports are configured
82+ // See: https://github.com/spotbugs/spotbugs-gradle-plugin/issues/172
83+ if (! ciWorkflow && ! baselining) {
84+ reports.create(" html" ).required.set(true )
85+ } else if (baselining) {
86+ // Note this path succeeds :spotbugsMain because *of course it does*
87+ ignoreFailures = true
88+ reports.create(" xml" ) {
89+ // Why bother? Otherwise we have kilobytes of workspace-specific absolute paths, statistics, etc.
90+ // cluttering up the baseline XML and preserved in perpetuity. It would be far better if we could use
91+ // the SpotBugs relative path support, but the way SpotBugs reporters are presently architected they
92+ // drop the `destination` information long before Project.writeXML uses its presence/absence to
93+ // determine whether to generate relative instead of absolute paths. So, contribute patch to SpotBugs or
94+ // write own SpotBugs reporter in parallel or... do this.
95+ // Improvements are definitely possible, but left as an exercise to the reader.
96+ doLast {
97+ // It would be super neat if we had some way to handle this xml processing directly inline, without
98+ // generating a temp file or at least without shelling out.
99+ // Use ant's xslt capabilities? Xalan? Saxon gradle plugin (eerohele)? javax.xml.transform?
100+ // In the mean time... xsltproc!
101+ exec {
102+ commandLine(
103+ " xsltproc" ,
104+ " --output" , spotbugsBaselineFile,
105+ " $rootDir /config/spotbugs/baseline.xslt" ,
106+ outputLocation.get().toString()
107+ )
108+ }
109+ }
110+ }
60111 }
61112 }
62113
63- create<Jar >(" sourcesJar" ) sourcesJar@ {
114+ create<Jar >(" sourcesJar" ) sourcesJar@{
64115 archiveClassifier.set(" sources" )
65116 from(sourceSets[" main" ].java.srcDirs)
66117 artifacts { sourcesArtifact = archives(this @sourcesJar) }
67118 }
68119
69- create<Jar >(" javadocJar" ) javadocJar@ {
120+ create<Jar >(" javadocJar" ) javadocJar@{
70121 archiveClassifier.set(" javadoc" )
71122 from(javadoc)
72123 artifacts { javadocArtifact = archives(this @javadocJar) }
@@ -79,7 +130,7 @@ tasks {
79130 */
80131 val generateJarInfo by creating<Task > {
81132 doLast {
82- val propertiesFile = File (" $generatedJarInfoDir /${project.name} .properties" )
133+ val propertiesFile = File (" $generatedJarInfoDir /${project.name} .properties" )
83134 propertiesFile.parentFile.mkdirs()
84135 val properties = Properties ()
85136 properties.setProperty(" build.version" , version.toString())
@@ -94,11 +145,11 @@ tasks {
94145 jacocoTestReport {
95146 dependsOn(test)
96147 reports {
97- xml.isEnabled = true
98- html.isEnabled = true
148+ xml.required.set( true )
149+ html.required.set( true )
99150 }
100151 doLast {
101- logger.quiet(" Coverage report written to file://${reports.html.destination } /index.html" )
152+ logger.quiet(" Coverage report written to file://${reports.html.outputLocation.get().toString() } /index.html" )
102153 }
103154 }
104155
@@ -131,7 +182,7 @@ publishing {
131182 licenses {
132183 license {
133184 name.set(" The Apache License, Version 2.0" )
134- url.set(" http ://www.apache.org/licenses/LICENSE-2.0.txt" )
185+ url.set(" https ://www.apache.org/licenses/LICENSE-2.0.txt" )
135186 }
136187 }
137188 developers {
0 commit comments