Skip to content

Commit ec180c5

Browse files
netdpbwmdietl
andauthored
Use published conformance tests (#126)
Use the published JSpecify artifacts instead of requiring a local clone of https://github.com/jspecify/jspecify. Allow the user to include a local clone with `--included-build path/to/jspecify`, and use those artifacts instead in that case. Part of #107. --------- Co-authored-by: Werner Dietl <[email protected]>
1 parent e43c104 commit ec180c5

File tree

8 files changed

+134
-41
lines changed

8 files changed

+134
-41
lines changed

.github/workflows/build.yml

+11-4
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,15 @@ jobs:
1010
run:
1111
working-directory: jspecify-reference-checker
1212
steps:
13-
- name: Check out the code
13+
- name: Check out jspecify-reference checker
1414
uses: actions/checkout@v4
1515
with:
1616
path: jspecify-reference-checker
17+
- name: Check out jspecify
18+
uses: actions/checkout@v4
19+
with:
20+
repository: jspecify/jspecify
21+
path: jspecify
1722
- name: Set up Java
1823
uses: actions/setup-java@v4
1924
with:
@@ -22,13 +27,15 @@ jobs:
2227
- name: Set up Gradle
2328
uses: gradle/gradle-build-action@v2
2429
- name: Build and Test
25-
run: ./gradlew build conformanceTests demoTest
30+
run: ./gradlew build conformanceTests demoTest --include-build ../jspecify
2631
env:
2732
SHALLOW: 1
2833
- name: Check out jspecify/samples-google-prototype
2934
if: always()
30-
run: git checkout samples-google-prototype
35+
run: |
36+
git fetch --depth=1 origin samples-google-prototype
37+
git checkout samples-google-prototype
3138
working-directory: jspecify
3239
- name: Run Samples Tests
3340
if: always()
34-
run: ./gradlew jspecifySamplesTest
41+
run: ./gradlew jspecifySamplesTest --include-build ../jspecify

README.md

+9-3
Original file line numberDiff line numberDiff line change
@@ -58,20 +58,26 @@ git clone https://github.com/jspecify/jspecify-reference-checker
5858
cd jspecify-reference-checker
5959
```
6060

61-
Now build it, which will retrieve a lot of other code too, and will take 10-15 minutes:
61+
Now build it, which will retrieve a lot of other code too, and will take 10-15
62+
minutes:
6263

6364
```sh
6465
./gradlew assemble
6566
```
6667

67-
Now try the sample file:
68+
### Demonstration
69+
70+
Run the checker on the sample file:
6871

6972
```sh
7073
cd $root_dir/jspecify-reference-checker
7174
./demo SimpleSample.java
7275
```
7376

74-
After ~10 seconds delay, you should see
77+
(If you haven't [built the reference checker](#building) yet, this will build it
78+
the first time you run it.)
79+
80+
After that, you should see:
7581

7682
```
7783
SimpleSample.java:7: error: [nullness] incompatible types in return.

build.gradle

+31-13
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,32 @@ plugins {
1010
}
1111

1212
repositories {
13+
mavenLocal()
14+
maven {
15+
// Nexus snapshot repository
16+
url = "https://s01.oss.sonatype.org/content/repositories/snapshots/"
17+
}
1318
mavenCentral()
1419
}
1520

16-
configurations {
17-
errorproneJavac
18-
conformanceTestSuite
19-
}
20-
2121
ext {
2222
checkerFramework = gradle.includedBuild("checker-framework")
23-
jspecify = gradle.includedBuild("jspecify")
23+
24+
// null if not included with `--include-build path/to/jspecify`
25+
jspecify = gradle.includedBuilds.find { it.name == 'jspecify' }
26+
}
27+
28+
configurations {
29+
errorproneJavac
30+
conformanceTestSuite {
31+
// When including a local JSpecify build, depend on the local test suite.
32+
// See https://docs.gradle.org/current/userguide/cross_project_publications.html#sec:variant-aware-sharing.
33+
if (jspecify != null) {
34+
attributes {
35+
attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category, 'conformance-tests'))
36+
}
37+
}
38+
}
2439
}
2540

2641
java {
@@ -41,16 +56,20 @@ dependencies {
4156
testImplementation libs.jspecify.conformanceTestFramework
4257
testRuntimeOnly libs.jsr305 // jsr305 annotations are in some of the samples
4358

44-
// TODO: Depend on a group:artifact:version rather than a file.
45-
conformanceTestSuite files("${jspecify.projectDir}/conformance-tests/build/distributions/conformance-tests-0.0.0-SNAPSHOT.zip")
59+
conformanceTestSuite libs.jspecify.conformanceTests
4660

4761
errorproneJavac libs.errorProne.javac
4862
errorprone libs.errorProne.core
4963
}
5064

5165
// Assemble checker-framework when assembling the reference checker.
5266
assemble.dependsOn(checkerFramework.task(":assemble"))
53-
assemble.dependsOn(jspecify.task(":assemble"))
67+
68+
// If built with `--include-build path/to/jspecify` then
69+
// assemble jspecify when assembling the reference checker.
70+
if (jspecify != null) {
71+
assemble.dependsOn(jspecify.task(':assemble'))
72+
}
5473

5574
tasks.withType(JavaCompile).configureEach {
5675
options.compilerArgs.add("-Xlint:all")
@@ -110,15 +129,14 @@ test {
110129
tasks.register('jspecifySamplesTest', Test) {
111130
description = 'Run the checker against the JSpecify samples.'
112131
group = 'verification'
132+
shouldRunAfter test
113133
include '**/NullSpecTest$Lenient.class'
114134
include '**/NullSpecTest$Strict.class'
115135

116136
inputs.files(unzipConformanceTestSuite)
117137
}
118138

119139
tasks.register('unzipConformanceTestSuite', Copy) {
120-
// TODO: Don't explicitly depend on an included build's task.
121-
dependsOn jspecify.task(':conformance-tests:build')
122140
dependsOn configurations.conformanceTestSuite
123141
from zipTree(configurations.conformanceTestSuite.singleFile)
124142
into layout.buildDirectory.dir("conformanceTests")
@@ -127,6 +145,7 @@ tasks.register('unzipConformanceTestSuite', Copy) {
127145
tasks.register('conformanceTests', Test) {
128146
group = 'verification'
129147
include '**/ConformanceTest.class'
148+
shouldRunAfter test
130149

131150
// Conformance tests
132151
inputs.files(unzipConformanceTestSuite)
@@ -140,7 +159,6 @@ tasks.register('conformanceTests', Test) {
140159
}
141160

142161
// Conformance tests run on the samples directory
143-
inputs.dir("${unzipConformanceTestSuite.destinationDir}/samples")
144162
inputs.files("tests/ConformanceTestOnSamples-report.txt")
145163
doFirst {
146164
systemProperties([
@@ -168,7 +186,7 @@ tasks.register('demoTest', Exec) {
168186
ignoreExitValue = true
169187
errorOutput = new ByteArrayOutputStream()
170188
doLast {
171-
if (!errorOutput.toString().startsWith("SimpleSample.java:7: error:")) {
189+
if (!errorOutput.toString().contains("SimpleSample.java:7: error:")) {
172190
throw new AssertionError("`./demo SimpleSample.java` did not run correctly. Error output:\n$errorOutput")
173191
}
174192
}

demo

+21-4
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,32 @@
11
#!/bin/sh
22
# A quick and easy way to run the reference checker on some standalone code.
3-
# If you set the CLASSPATH environment variable it will ues it, adding its own entries to that list.
3+
# If you set the CLASSPATH environment variable it will use it, adding its own entries to that list.
44
# To integrate the checker into a more complex build, reading the below should give you what you need to know.
55

66
dir=$(dirname $0)
7-
ourclasspath="$dir/../jspecify/build/libs/jspecify-0.0.0-SNAPSHOT.jar:$dir/build/libs/jspecify-reference-checker.jar"
7+
jspecify="${dir}/../jspecify/build/libs/jspecify-0.0.0-SNAPSHOT.jar"
8+
if [ ! -e "${jspecify}" ]; then
9+
version=0.3.0
10+
jspecify="${dir}/build/jspecify-${version}.jar"
11+
if [ ! -e "${jspecify}" ]; then
12+
echo "Downloading $(basename "${jspecify}") from Maven central"
13+
mvn -q org.apache.maven.plugins:maven-dependency-plugin:3.6.1:copy \
14+
-Dartifact="org.jspecify:jspecify:${version}" \
15+
-DoutputDirectory="$(dirname "${jspecify}")"
16+
fi
17+
fi
18+
jspecify_reference_checker="${dir}/build/libs/jspecify-reference-checker.jar"
19+
if [ ! -e "${jspecify_reference_checker}" ]; then
20+
echo "Assembling jspecify-reference-checker"
21+
./gradlew assemble
22+
fi
823

9-
export CLASSPATH="$ourclasspath:$CLASSPATH"
24+
ourclasspath="${jspecify}:${jspecify_reference_checker}"
25+
26+
export CLASSPATH="${ourclasspath}:$CLASSPATH"
1027

1128
$dir/../checker-framework/checker/bin/javac \
12-
-processorpath "$ourclasspath" \
29+
-processorpath "${ourclasspath}" \
1330
-processor com.google.jspecify.nullness.NullSpecChecker \
1431
-AcheckImpl \
1532
-AassumePure \

docs/development.md

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Development
2+
3+
## Codevelopment with Checker Framework fork
4+
5+
This project depends on
6+
an [unreleased fork of the Checker Framework][jspecify-checker-framework].
7+
(The [main-eisop branch] represents ongoing work to depend on a released version
8+
of the [EISOP] fork instead.)
9+
10+
Because of that dependency, this build clones that unreleased fork into the
11+
sibling directory `../checker-framwork`.
12+
_That_ build then clones some other projects into other sibling directories. It
13+
expects `../jdk` to contain an annotated JDK, so our build
14+
clones [JSpecify's][jspecify-jdk] there.
15+
16+
## Codevelopment with JSpecify
17+
18+
This project depends on two artifacts built from the main [JSpecify repo]
19+
[jspecify-jspecify]:
20+
21+
1. the annotations: `org.jspecify:jspecify`
22+
2. the conformance test suite: `org.jspecify.conformance:conformance-tests`
23+
24+
For each of those dependencies, developers can depend on either a published
25+
version (fixed or snapshot) or a local build.
26+
27+
In order to depend on a specific commit or uncommitted state of those artifacts,
28+
clone the repo (or your fork) somewhere, and pass
29+
`--include-build path/to/jspecify` to Gradle when building. The local clone will
30+
be used for both the annotations and the conformance test suite.
31+
32+
By default the reference checker depends on version `0.3.0` of the annotations,
33+
and version `0.0.0-SNAPSHOT` of the conformance test suite.
34+
35+
In order to depend on a different published version of either artifact, set
36+
Gradle properties on the command line.
37+
38+
* `-Porg.jspecify:jspecify=0.2.0` would change the version of the annotations.
39+
* `-Porg.jspecify.conformance:conformance-tests=0.3.0` would change the version
40+
of the conformance test suite.
41+
42+
[EISOP]: https://github.com/eisop/checker-framework
43+
[jspecify-checker-framework]: https://github.com/jspecify/checker-framework
44+
[jspecify-jdk]: https://github.com/jspecify/jdk
45+
[jspecify-jspecify]: https://github.com/jspecify/jspecify
46+
[main-eisop branch]: https://github.com/jspecify/jspecify-reference-checker/tree/main-eisop

gradle.properties

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
org.jspecify\:jspecify=0.3.0
2+
org.jspecify.conformance\:conformance-test-framework=0.0.0-SNAPSHOT
3+
org.jspecify.conformance\:conformance-tests=0.0.0-SNAPSHOT

initialize-project

-4
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,6 @@ git_clone() {
6363
run "${git[@]}" "https://github.com/jspecify/${repo}.git" "../${repo}"
6464
}
6565

66-
# Fetch all branches even when $SHALLOW is set so we can check out
67-
# samples-google-prototype to run samples tests.
68-
git_clone jspecify --no-single-branch
69-
7066
git_clone jdk --depth 1 --single-branch
7167

7268
git_clone checker-framework

settings.gradle

+13-13
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,11 @@ include 'conformance-test-framework'
66
// See https://docs.gradle.org/current/userguide/composite_builds.html#included_build_declaring_substitutions
77
includeBuild(".")
88

9-
def initializeProject() {
10-
exec {
11-
executable './initialize-project'
12-
}
13-
}
14-
15-
includeBuild("../jspecify") {
16-
initializeProject()
9+
exec {
10+
executable './initialize-project'
1711
}
1812

19-
includeBuild("../checker-framework") {
20-
initializeProject()
21-
}
13+
includeBuild("../checker-framework")
2214

2315
dependencyResolutionManagement {
2416
versionCatalogs {
@@ -33,11 +25,19 @@ dependencyResolutionManagement {
3325
library("errorProne-core", "com.google.errorprone:error_prone_core:2.18.0")
3426
library("errorProne-javac", "com.google.errorprone:javac:9+181-r4173-1")
3527
library("guava", "com.google.guava:guava:31.1-jre")
36-
library("jspecify", "org.jspecify:jspecify:0.0.0-SNAPSHOT")
37-
library("jspecify-conformanceTestFramework", "org.jspecify.conformance:conformance-test-framework:0.0.0-SNAPSHOT")
28+
29+
// Related JSpecify project versions are specified in gradle.properties, and can be overridden on the Gradle command line.
30+
library("jspecify", libraryVersion('org.jspecify:jspecify'))
31+
library("jspecify-conformanceTestFramework", libraryVersion('org.jspecify.conformance:conformance-test-framework'))
32+
library("jspecify-conformanceTests", libraryVersion('org.jspecify.conformance:conformance-tests'))
33+
3834
library("jsr305", "com.google.code.findbugs:jsr305:3.0.2")
3935
library("junit", "junit:junit:4.12")
4036
library("truth", "com.google.truth:truth:1.1.3")
4137
}
4238
}
4339
}
40+
41+
String libraryVersion(String groupArtifact) {
42+
return "$groupArtifact:${settings[groupArtifact]}"
43+
}

0 commit comments

Comments
 (0)