tasks.register<JavaExec>("dialect") in spark/spark-4.0_2.13/build.gradle.kts writes spark/spark_dialect.yaml and declares no outputs. DialectSuite reads that same file, and all three variants' test tasks now declare it as an inputs.file. Gradle therefore sees a consumer with no producer, has no reason to order the two, and — worse — will snapshot the file at whatever state it happens to be in when the test task starts.
That is not just a theoretical ordering question. Reproduced on fix/dialect-generator-derived-model:
- Change
name: in spark/spark_dialect.yaml to something the generator would not emit.
./gradlew --parallel :spark:spark-4.0_2.13:dialect :spark:spark-3.4_2.12:test --tests '*DialectSuite*' — passes. dialect rewrites the file back to the correct content, and the test reads the rewritten content at runtime, but Gradle had already fingerprinted the edited file as the task's input. The successful outcome is recorded under that fingerprint.
- Re-edit
name: the same way and run ./gradlew :spark:spark-3.4_2.12:test --tests '*DialectSuite*' — reports UP-TO-DATE and passes, on a file that does not match the generator.
--rerun-tasks on that same file fails three tests, which is the correct outcome.
So one interleaved invocation is enough to bank a green result keyed to content that actually fails, and the stale pass then survives across later invocations.
Declaring the output is necessary but not sufficient: adding outputs.file("../spark_dialect.yaml") to the dialect task alone makes ./gradlew :spark:spark-4.0_2.13:dialect :spark:spark-4.0_2.13:test fail with
Task ':spark:spark-4.0_2.13:test' uses this output of task ':spark:spark-4.0_2.13:dialect' without declaring an explicit or implicit dependency.
which is Gradle correctly refusing the graph rather than a regression. The second half needs an ordering rule, and a plain dependsOn is the wrong one: it would have DialectSuite's byte-for-byte assertion compare the file against a copy the same generator had just written, which passes vacuously. mustRunAfter on dialect, or keeping the two out of one graph, preserves what the test is for. Note the dialect task is registered on spark-4.0_2.13 only while all three variants' tests consume the file, so the fix spans projects.
Follow-up from review of #1133.
tasks.register<JavaExec>("dialect")inspark/spark-4.0_2.13/build.gradle.ktswritesspark/spark_dialect.yamland declares nooutputs.DialectSuitereads that same file, and all three variants'testtasks now declare it as aninputs.file. Gradle therefore sees a consumer with no producer, has no reason to order the two, and — worse — will snapshot the file at whatever state it happens to be in when thetesttask starts.That is not just a theoretical ordering question. Reproduced on
fix/dialect-generator-derived-model:name:inspark/spark_dialect.yamlto something the generator would not emit../gradlew --parallel :spark:spark-4.0_2.13:dialect :spark:spark-3.4_2.12:test --tests '*DialectSuite*'— passes.dialectrewrites the file back to the correct content, and the test reads the rewritten content at runtime, but Gradle had already fingerprinted the edited file as the task's input. The successful outcome is recorded under that fingerprint.name:the same way and run./gradlew :spark:spark-3.4_2.12:test --tests '*DialectSuite*'— reportsUP-TO-DATEand passes, on a file that does not match the generator.--rerun-taskson that same file fails three tests, which is the correct outcome.So one interleaved invocation is enough to bank a green result keyed to content that actually fails, and the stale pass then survives across later invocations.
Declaring the output is necessary but not sufficient: adding
outputs.file("../spark_dialect.yaml")to thedialecttask alone makes./gradlew :spark:spark-4.0_2.13:dialect :spark:spark-4.0_2.13:testfail withwhich is Gradle correctly refusing the graph rather than a regression. The second half needs an ordering rule, and a plain
dependsOnis the wrong one: it would haveDialectSuite's byte-for-byte assertion compare the file against a copy the same generator had just written, which passes vacuously.mustRunAfterondialect, or keeping the two out of one graph, preserves what the test is for. Note thedialecttask is registered onspark-4.0_2.13only while all three variants' tests consume the file, so the fix spans projects.Follow-up from review of #1133.