-
Notifications
You must be signed in to change notification settings - Fork 87
Fix pjf crashing when we force realization of the spotlessJava task #1319
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| /* | ||
| * (c) Copyright 2019 Palantir Technologies Inc. All rights reserved. | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
| package com.palantir.javaformat.gradle | ||
|
|
||
| import nebula.test.IntegrationTestKitSpec | ||
|
|
||
|
|
||
| class FormatterLazinessTest extends IntegrationTestKitSpec { | ||
| private static final CLASSPATH_FILE = new File("build/impl.classpath").absolutePath | ||
|
|
||
| private GradlewExecutor executor | ||
|
|
||
| def setup() { | ||
| definePluginOutsideOfPluginBlock = true | ||
| keepFiles = true | ||
| executor = new GradlewExecutor(projectDir) | ||
| } | ||
|
|
||
| def "formatter is not loaded even if spotlessJava is realized lazily"() { | ||
| // language=Gradle | ||
| buildFile << """ | ||
| buildscript { | ||
| repositories { | ||
| maven { | ||
| url 'https://artifactory.palantir.build/artifactory/release-jar' | ||
| metadataSources { mavenPom(); ignoreGradleMetadataRedirection() } | ||
| } | ||
| } | ||
|
|
||
| dependencies { | ||
| classpath 'com.diffplug.spotless:spotless-plugin-gradle:6.22.0' | ||
| } | ||
| } | ||
|
|
||
| allprojects { | ||
| apply plugin: 'java' | ||
| apply plugin: 'com.diffplug.spotless' | ||
| apply plugin: 'com.palantir.java-format' | ||
|
|
||
| repositories { | ||
| maven { url 'https://artifactory.palantir.build/artifactory/release-jar' } | ||
| } | ||
| } | ||
|
|
||
| project.getTasks().getByName("spotlessJava") | ||
| """.stripIndent(true) | ||
|
|
||
| file("versions.props") | ||
| file("versions.lock") | ||
|
|
||
| runTasks('wrapper') | ||
|
|
||
| buildFile << """ | ||
| dependencies { | ||
| palantirJavaFormat files(file("${CLASSPATH_FILE}").text.split(':')) | ||
| } | ||
| """.stripIndent() | ||
|
|
||
| when: | ||
| def result = executor.runGradlewTasks('--info') | ||
|
|
||
| then: | ||
| assert result.success | ||
| println(result.standardOutput) | ||
| result.standardOutput.contains('BUILD SUCCESSFUL') | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| /* | ||
| * (c) Copyright 2025 Palantir Technologies Inc. All rights reserved. | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| package com.palantir.javaformat.gradle | ||
|
|
||
| import nebula.test.functional.internal.classpath.ClasspathAddingInitScriptBuilder | ||
| import org.gradle.internal.impldep.org.eclipse.jgit.annotations.NonNull | ||
|
|
||
| import java.nio.charset.StandardCharsets | ||
| import java.nio.file.Path | ||
| import java.util.concurrent.TimeUnit | ||
| import java.util.stream.Collectors | ||
| import java.util.stream.Stream | ||
|
|
||
| /** | ||
| * IntegrationTestKitSpec currently [loads more than what it needs into the classpath](https://github.com/nebula-plugins/nebula-test/blob/c5d3af9004898276bde5c68da492c6b0b4c5facc/src/main/groovy/nebula/test/IntegrationTestKitBase.groovy#L136) | ||
| * This means the Formatter is loaded onto the classpath eagerly, [erroneously](https://github.com/palantir/palantir-java-format/blob/00b08d2f471d66382d6c4cd2d05f56b6bb546ad3/gradle-palantir-java-format/src/main/java/com/palantir/javaformat/gradle/spotless/PalantirJavaFormatStep.java#L83). | ||
| * As a workaround, let's use the classpath produced by Gradle Test Kit in plugin-under-test-metadata.properties | ||
| * This classpath only contains the dependencies required by the plugin, as well as the plugin itself. | ||
| * This means no more eager loading of Formatters onto the classpath, no more complaints from PalantirJavaFormatStep | ||
| */ | ||
| class GradlewExecutor { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ensure this is used by the existing spotless test |
||
| private File projectDir | ||
|
|
||
| GradlewExecutor(@NonNull File projectDir) { | ||
| this.projectDir = projectDir | ||
| } | ||
|
|
||
| private static Iterable<File> getBuildPluginClasspathInjector() { | ||
| return getPluginClasspathInjector(Path.of("../gradle-palantir-java-format/build/pluginUnderTestMetadata/plugin-under-test-metadata.properties")) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Try and get this from a system property, so you're inherently relying the on the structure of your build. Then in your gradle file, ensure that the task that will run this test, has it as a system property. If you were to make the change to nebula, I imagine this is what you'd want to do. i.e. if the system property is there, then use that, if not then fallback to whatever mechanism they currently have. |
||
| } | ||
|
|
||
| private static Iterable<File> getPluginClasspathInjector(Path path) { | ||
| File propertiesFile = path.toFile() | ||
| Properties properties = new Properties() | ||
| propertiesFile.withInputStream { inputStream -> | ||
| properties.load(inputStream) | ||
| } | ||
| String classpath = properties.getProperty('implementation-classpath') | ||
| return classpath.split(File.pathSeparator).collect { new File(it) } | ||
| } | ||
|
|
||
| GradlewExecutionResult runGradlewTasks(String... tasks) { | ||
| ProcessBuilder processBuilder = getProcessBuilder(tasks) | ||
| Process process = processBuilder.start() | ||
| String output = readAllInput(process.getInputStream()) | ||
| process.waitFor(1, TimeUnit.MINUTES) | ||
| GradlewExecutionResult result = new GradlewExecutionResult(process.exitValue(), output) | ||
| return result | ||
|
Comment on lines
+61
to
+62
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: return directly |
||
| } | ||
|
|
||
| final class GradlewExecutionResult { | ||
|
|
||
| final Boolean success | ||
| final String standardOutput | ||
| final Throwable failure | ||
|
|
||
| GradlewExecutionResult(int exitValue, String output) { | ||
| this.success = exitValue == 0 | ||
| this.standardOutput = output | ||
| this.failure = exitValue != 0 ? new RuntimeException(String.format("Build failed with exitCode %s", exitValue)) : null | ||
| } | ||
| } | ||
|
|
||
| private static String readAllInput(InputStream inputStream) { | ||
| try (Stream<String> lines = | ||
| new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).lines()) { | ||
| return lines.collect(Collectors.joining("\n")); | ||
| } | ||
| } | ||
|
|
||
| private ProcessBuilder getProcessBuilder(String... tasks) { | ||
| File initScript = new File(projectDir, "init.gradle") | ||
| ClasspathAddingInitScriptBuilder.build(initScript, getBuildPluginClasspathInjector().toList()) | ||
| List<String> arguments = ["./gradlew", "--init-script", initScript.toPath().toString()] | ||
| Arrays.asList(tasks).forEach(arguments::add) | ||
| ProcessBuilder processBuilder = new ProcessBuilder() | ||
| .command(arguments) | ||
| .directory(projectDir) | ||
| .redirectErrorStream(true) | ||
| return processBuilder | ||
|
Comment on lines
+90
to
+94
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. return directly |
||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not valid javadoc (yet - it is in java 23). Can you use the proper links and what not. Not doing a proper review, was just curious what was going on
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep gotcha.