import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { `java-library` } repositories { mavenCentral() } java { toolchain { languageVersion.set(JavaLanguageVersion.of(21)) } sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } tasks.withType().configureEach { options.compilerArgs.add("-Werror") options.release.set(8) } tasks.named("jar") { manifest { attributes(mapOf( "Implementation-Title" to project.name, "Implementation-Version" to project.version )) } } tasks.withType().configureEach { useJUnitPlatform() // Run tests in parallel to some degree. maxParallelForks = (Runtime.getRuntime().availableProcessors() / 2).coerceAtLeast(1) forkEvery = 100 testLogging { exceptionFormat = TestExceptionFormat.FULL } } val palantir by configurations.creating dependencies { palantir("com.palantir.javaformat:palantir-java-format:2.89.0") } fun registerPalantir( name: String, description: String, ) { val javaName = "${name}Java" tasks.register(javaName) { group = "Verification" this.description = description classpath = palantir mainClass = "com.palantir.javaformat.java.Main" // Avoid an `IllegalAccessError` on Java 9+. jvmArgs( "--add-exports", "jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED", "--add-exports", "jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports", "jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED", "--add-exports", "jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED", "--add-exports", "jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED", ) // Use paths relative to the current module. val argumentFile = project.layout.buildDirectory.file("palantir-$name-args.txt").get().asFile val lastRunTimeFile = project.layout.buildDirectory.file("palantir-$name-last-run.txt").get().asFile // Read the time when this task was last executed for this module (if ever). val lastRunTime = lastRunTimeFile.takeIf { it.exists() }?.readText()?.toLongOrNull() ?: 0L // Use a `fileTree` relative to the module's source directory. val javaFiles = project.fileTree("src") { include("**/*.java") } // Determine if any files need to be formatted or linted and continue only if there is at least // one file. onlyIf { javaFiles.any { it.lastModified() > lastRunTime } } inputs.files(javaFiles) doFirst { // Create the argument file and set the preferred formatting style. argumentFile.parentFile.mkdirs() argumentFile.writeText("--palantir\n") if (name == "lint") { // For lint, do a dry run, so no files are modified. Set the exit code to 1 (instead of // the default 0) if any files need to be formatted, indicating that linting has failed. argumentFile.appendText("--dry-run\n") argumentFile.appendText("--set-exit-if-changed\n") } else { // `--dry-run` and `--replace` (for in-place formatting) are mutually exclusive. argumentFile.appendText("--replace\n") } // Write the modified files to the argument file. javaFiles.filter { it.lastModified() > lastRunTime } .forEach { argumentFile.appendText("${it.absolutePath}\n") } } doLast { // Record the last execution time for later up-to-date checking. lastRunTimeFile.writeText(System.currentTimeMillis().toString()) } // Pass the argument file using the @ symbol args = listOf("@${argumentFile.absolutePath}") outputs.upToDateWhen { javaFiles.none { it.lastModified() > lastRunTime } } } tasks.named(name) { dependsOn(tasks.named(javaName)) } } registerPalantir(name = "format", description = "Formats all Java source files.") registerPalantir(name = "lint", description = "Verifies all Java source files are formatted.")