Skip to content

Commit 6739a86

Browse files
authoredJul 24, 2020
Add tests for per-task configuration (#115)
1 parent feb99c0 commit 6739a86

File tree

7 files changed

+168
-39
lines changed

7 files changed

+168
-39
lines changed
 

‎.travis.yml

+12-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,16 @@ language: java
22

33
jdk: openjdk8
44

5-
install: true
5+
install: skip
66

7-
script: ./gradlew clean build
7+
# https://guides.gradle.org/executing-gradle-builds-on-travisci/#enable_caching_of_downloaded_artifacts
8+
before_cache:
9+
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
10+
- rm -fr $HOME/.gradle/caches/*/plugin-resolution/
11+
12+
cache:
13+
directories:
14+
- $HOME/.gradle/caches/
15+
- $HOME/.gradle/wrapper/
16+
17+
script: ./gradlew build --info --stacktrace --parallel

‎README.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Add the following to your `build.gradle` file:
1212
```groovy
1313
plugins {
1414
// Checker Framework pluggable type-checking
15-
id 'org.checkerframework' version '0.5.6'
15+
id 'org.checkerframework' version '0.5.7'
1616
}
1717
1818
apply plugin: 'org.checkerframework'
@@ -80,7 +80,7 @@ the definitions of the custom qualifiers.
8080

8181
### Specifying a Checker Framework version
8282

83-
Version 0.5.6 of this plugin uses Checker Framework version 3.5.0 by default.
83+
Version 0.5.7 of this plugin uses Checker Framework version 3.5.0 by default.
8484
Anytime you upgrade to a newer version of this plugin,
8585
it might use a different version of the Checker Framework.
8686

@@ -181,7 +181,7 @@ plugin to the top-level project. For example:
181181

182182
```groovy
183183
plugins {
184-
id 'org.checkerframework' version '0.5.6' apply false
184+
id 'org.checkerframework' version '0.5.7' apply false
185185
}
186186
187187
subprojects { subproject ->
@@ -224,7 +224,7 @@ plugins {
224224
id "net.ltgt.errorprone" version "1.1.1" apply false
225225
// To do Checker Framework pluggable type-checking (and disable Error Prone), run:
226226
// ./gradlew compileJava -PuseCheckerFramework=true
227-
id 'org.checkerframework' version '0.5.6' apply false
227+
id 'org.checkerframework' version '0.5.7' apply false
228228
}
229229
230230
if (!project.hasProperty("useCheckerFramework")) {

‎build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ dependencies {
3232
}
3333

3434
group 'org.checkerframework'
35-
version '0.5.6'
35+
version '0.5.7'
3636

3737
gradlePlugin {
3838
plugins {

‎gradle/compile.gradle

+3-1
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@ tasks.withType(Test) {
3131
showCauses true
3232
showExceptions true
3333
showStackTraces true
34-
events 'failed', 'skipped'
34+
events 'failed', 'skipped', 'started', 'passed'
3535
}
36+
37+
maxParallelForks = 32
3638
}
3739

3840
tasks.withType(Groovydoc) {

‎settings.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* This file was generated by the Gradle 'init' task.
33
*
44
* The settings file is used to specify which projects to include in your build.
5-
*
5+
*
66
* Detailed information about configuring a multi-project build in Gradle can be found
77
* in the user guide at https://docs.gradle.org/5.0/userguide/multi_project_builds.html
88
*/

‎src/main/groovy/org/checkerframework/gradle/plugin/CheckerFrameworkPlugin.groovy

+59-19
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package org.checkerframework.gradle.plugin
22

3+
import org.gradle.api.Task
34
import org.gradle.api.artifacts.DependencyResolutionListener
45
import org.gradle.api.artifacts.ResolvableDependencies
56
import org.gradle.api.internal.artifacts.dependencies.DefaultExternalModuleDependency
67
import org.gradle.api.internal.artifacts.dependencies.DefaultSelfResolvingDependency
8+
import org.gradle.util.GradleVersion
79

810
import java.util.jar.JarFile
911

@@ -49,17 +51,40 @@ final class CheckerFrameworkPlugin implements Plugin<Project> {
4951
*/
5052
private final static def manifestLocation = "/checkerframework/"
5153

54+
/**
55+
* Configure each task in {@code project} with the given {@code taskType}.
56+
* <p>
57+
* We prefer to configure with {@link
58+
* org.gradle.api.tasks.TaskCollection#configureEach(org.gradle.api.Action)}
59+
* rather than {@link
60+
* org.gradle.api.tasks.TaskCollection#all(org.gradle.api.Action)}, but {@code
61+
* configureEach} is only available on Gradle 4.9 and newer, so this method
62+
* dynamically picks the better candidate based on the current Gradle version.
63+
* <p>
64+
* See also: <a href="https://docs.gradle.org/current/userguide/task_configuration_avoidance.html">
65+
* Gradle documentation: Task Configuration Avoidance</a>
66+
*/
67+
private static <S extends Task> void configureTasks(Project project, Class<S> taskType, Action<? super S> configure) {
68+
if (GradleVersion.current() < GradleVersion.version("4.9")) {
69+
project.tasks.withType(taskType).all configure
70+
} else {
71+
project.tasks.withType(taskType).configureEach configure
72+
}
73+
}
74+
5275
@Override void apply(Project project) {
5376
// Either get an existing CF config, or create a new one if none exists
5477
CheckerFrameworkExtension userConfig = project.extensions.findByType(CheckerFrameworkExtension.class)?:
5578
project.extensions.create("checkerFramework", CheckerFrameworkExtension)
5679
boolean applied = false
5780
(ANDROID_IDS + "java").each { id ->
5881
project.pluginManager.withPlugin(id) {
59-
LOG.info('Found plugin {}, applying checker compiler options.', id)
60-
configureProject(project, userConfig)
61-
applyToProject(project, userConfig)
62-
if (!applied) applied = true
82+
if (!applied) {
83+
LOG.info('Found plugin {}, applying checker compiler options.', id)
84+
configureProject(project, userConfig)
85+
applyToProject(project, userConfig)
86+
applied = true
87+
}
6388
}
6489
}
6590

@@ -215,10 +240,20 @@ final class CheckerFrameworkPlugin implements Plugin<Project> {
215240
void afterResolve(ResolvableDependencies resolvableDependencies) {}
216241
})
217242

218-
project.tasks.withType(AbstractCompile).all { AbstractCompile compile ->
219-
CheckerFrameworkTaskExtension checkerExtension =
220-
compile.extensions.create("checkerFramework", CheckerFrameworkTaskExtension)
221-
}
243+
configureTasks(project, AbstractCompile, { AbstractCompile compile ->
244+
def ext = compile.extensions.findByName("checkerFramework")
245+
if (ext == null) {
246+
LOG.info("Adding checkerFramework extension to task {}", compile.name)
247+
compile.extensions.create("checkerFramework", CheckerFrameworkTaskExtension)
248+
} else if (ext instanceof CheckerFrameworkTaskExtension) {
249+
LOG.debug("Task {} in project {} already has checkerFramework added to it;" +
250+
" make sure you're applying the org.checkerframework plugin after the Java plugin", compile.name,
251+
compile.project)
252+
} else {
253+
throw new IllegalStateException("Task " + compile.name + " in project " + compile.project +
254+
" already has a checkerFramework extension, but it's of an incorrect type " + ext.class)
255+
}
256+
})
222257
}
223258

224259
/**
@@ -281,8 +316,7 @@ final class CheckerFrameworkPlugin implements Plugin<Project> {
281316
}
282317
} catch (Exception e) {
283318
versionString = LIBRARY_VERSION
284-
LOG.warn("Unable to determine Checker Framework version. Assuming default is being used.")
285-
LOG.debug(e)
319+
LOG.warn("Unable to determine Checker Framework version. Assuming default is being used: {}", versionString, e.toString())
286320
}
287321

288322
if (javaSourceVersion.java8 && jvmVersion.isJava8()) {
@@ -297,8 +331,7 @@ final class CheckerFrameworkPlugin implements Plugin<Project> {
297331
// errorprone javac is required
298332
needErrorProneJavac = true
299333
LOG.warn("Defaulting to ErrorProne Javac, because on a Java 8 JVM and" +
300-
" cannot determine exact Checker Framework version.")
301-
LOG.debug(e)
334+
" cannot determine exact Checker Framework version.", e)
302335
}
303336
}
304337

@@ -309,10 +342,17 @@ final class CheckerFrameworkPlugin implements Plugin<Project> {
309342
createManifestTask.checkers = userConfig.checkers
310343
}
311344

312-
project.tasks.withType(AbstractCompile).all { AbstractCompile compile ->
313-
if (!compile.extensions.checkerFramework.skipCheckerFramework
314-
&& compile.hasProperty('options')
315-
&& !(userConfig.excludeTests && compile.name.toLowerCase().contains("test"))) {
345+
configureTasks(project, AbstractCompile, { AbstractCompile compile ->
346+
if (compile.extensions.checkerFramework.skipCheckerFramework) {
347+
LOG.info("skipping the Checker Framework for task " + compile.name +
348+
" because skipCheckerFramework property is set")
349+
return
350+
}
351+
if(userConfig.excludeTests && compile.name.toLowerCase().contains("test")) {
352+
LOG.info("skipping the Checker Framework for task {} because excludeTests property is set", compile.name)
353+
return
354+
}
355+
if (compile.hasProperty('options')) {
316356
compile.options.annotationProcessorPath = compile.options.annotationProcessorPath == null ?
317357
project.configurations.checkerFramework :
318358
project.configurations.checkerFramework.plus(compile.options.annotationProcessorPath)
@@ -361,12 +401,12 @@ final class CheckerFrameworkPlugin implements Plugin<Project> {
361401

362402
ANDROID_IDS.each { id ->
363403
project.plugins.withId(id) {
364-
options.bootstrapClasspath = project.files(System.getProperty("sun.boot.class.path")) + options.bootstrapClasspath
404+
compile.options.bootstrapClasspath = project.files(System.getProperty("sun.boot.class.path")) + compile.options.bootstrapClasspath
365405
}
366406
}
367-
options.fork = true
407+
compile.options.fork = true
368408
}
369-
}
409+
})
370410
}
371411
}
372412
}

‎src/test/groovy/org/checkerframework/gradle/plugin/CheckerFrameworkPluginSpec.groovy

+88-11
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,22 @@ package org.checkerframework.gradle.plugin
22

33
import org.gradle.testkit.runner.BuildResult
44
import org.gradle.testkit.runner.GradleRunner
5+
import org.gradle.util.GradleVersion
56
import spock.lang.Unroll
67
import test.BaseSpecification
78

89
final class CheckerFrameworkPluginSpec extends BaseSpecification {
910
static final List<String> TESTED_GRADLE_VERSIONS = [
1011
'3.4',
11-
'3.5',
1212
'4.0',
13-
'4.1',
14-
'4.2',
15-
'4.3',
16-
'4.4',
17-
'4.5',
18-
'4.6',
19-
'4.7',
2013
'4.8',
2114
'4.9',
2215
'4.10',
2316
'5.0',
17+
'5.5',
18+
'6.0',
19+
'6.4',
20+
'6.5',
2421
]
2522

2623
@Unroll def "java project running licenseReport using with gradle #gradleVersion"() {
@@ -115,7 +112,8 @@ final class CheckerFrameworkPluginSpec extends BaseSpecification {
115112
gradleVersion << TESTED_GRADLE_VERSIONS
116113
}
117114

118-
def 'with relevant plugin loaded subsequently, compiler settings are applied'() {
115+
@Unroll
116+
def 'with relevant plugin loaded subsequently, compiler settings are applied with gradle #gradleVersion'() {
119117
given:
120118
buildFile <<
121119
"""
@@ -146,13 +144,14 @@ final class CheckerFrameworkPluginSpec extends BaseSpecification {
146144
gradleVersion << TESTED_GRADLE_VERSIONS
147145
}
148146

149-
def 'with resolved configuration dependencies, compilation settings are still applied'() {
147+
@Unroll
148+
def 'with resolved configuration dependencies, compilation settings are still applied with gradle #gradleVersion'() {
150149
given:
151150
buildFile <<
152151
"""
153152
plugins {
154-
id 'org.checkerframework'
155153
id 'java'
154+
id 'org.checkerframework'
156155
id 'application'
157156
}
158157
@@ -179,4 +178,82 @@ final class CheckerFrameworkPluginSpec extends BaseSpecification {
179178
where:
180179
gradleVersion << TESTED_GRADLE_VERSIONS
181180
}
181+
182+
@Unroll
183+
def 'skipCheckerFramework can be used to skip checking individual tasks with gradle #gradleVersion'() {
184+
given:
185+
buildFile << """
186+
plugins {
187+
id 'java'
188+
id 'org.checkerframework'
189+
id 'application'
190+
}
191+
192+
repositories {
193+
maven {
194+
url "${getClass().getResource("/maven/").toURI()}"
195+
}
196+
}
197+
198+
tasks.withType(JavaCompile).all {
199+
configure {
200+
checkerFramework {
201+
skipCheckerFramework = true
202+
}
203+
}
204+
}
205+
""".stripIndent().trim()
206+
207+
when:
208+
BuildResult result = GradleRunner.create()
209+
.withGradleVersion(gradleVersion)
210+
.withProjectDir(testProjectDir.root)
211+
.withPluginClasspath()
212+
.withArguments('--info')
213+
.build()
214+
215+
then:
216+
result.
217+
output.
218+
contains('skipping the Checker Framework for task compileJava because skipCheckerFramework property is set')
219+
220+
where:
221+
gradleVersion << TESTED_GRADLE_VERSIONS
222+
}
223+
224+
@Unroll
225+
def 'plugin warns when applying org.checkerframework after java plugin with gradle #gradleVersion'() {
226+
given:
227+
buildFile << """
228+
plugins {
229+
id 'org.checkerframework'
230+
id 'java'
231+
}
232+
233+
repositories {
234+
maven {
235+
url "${getClass().getResource("/maven/").toURI()}"
236+
}
237+
}
238+
""".stripIndent().trim()
239+
240+
when:
241+
BuildResult result = GradleRunner.create()
242+
.withGradleVersion(gradleVersion)
243+
.withProjectDir(testProjectDir.root)
244+
.withPluginClasspath()
245+
.withArguments('--debug')
246+
.build()
247+
248+
then:
249+
result.
250+
output.
251+
contains("make sure you're applying the org.checkerframework plugin after the Java plugin")
252+
253+
where:
254+
// This particular behavior only shows up on Gradle 6.4+
255+
gradleVersion << TESTED_GRADLE_VERSIONS.stream().filter({
256+
GradleVersion.version(it) >= GradleVersion.version("6.4")
257+
})
258+
}
182259
}

0 commit comments

Comments
 (0)
Please sign in to comment.