From 353045442435dcb8f5989dbe3e8f353f23fd2e07 Mon Sep 17 00:00:00 2001 From: Finlay Williams Date: Tue, 22 Jul 2025 13:32:04 +0100 Subject: [PATCH 01/12] messing --- .../org/revapi/gradle/GitVersionUtils.java | 122 ++++++------------ .../org/revapi/gradle/RevapiExtension.java | 11 +- .../revapi/gradle/GitVersionUtilsSpec.groovy | 11 +- .../org/revapi/gradle/RevapiSpec.groovy | 6 + 4 files changed, 59 insertions(+), 91 deletions(-) diff --git a/src/main/java/org/revapi/gradle/GitVersionUtils.java b/src/main/java/org/revapi/gradle/GitVersionUtils.java index f93c3ad6..465a5be2 100644 --- a/src/main/java/org/revapi/gradle/GitVersionUtils.java +++ b/src/main/java/org/revapi/gradle/GitVersionUtils.java @@ -16,55 +16,45 @@ package org.revapi.gradle; -import java.io.ByteArrayOutputStream; -import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.List; -import java.util.Optional; -import java.util.Spliterator; -import java.util.function.Consumer; import java.util.stream.Stream; -import java.util.stream.StreamSupport; -import org.gradle.api.Project; +import javax.inject.Inject; +import org.gradle.api.file.ProjectLayout; +import org.gradle.api.provider.Provider; +import org.gradle.api.provider.ProviderFactory; +import org.gradle.process.ExecOutput; import org.gradle.process.ExecResult; import org.immutables.value.Value; -final class GitVersionUtils { - private GitVersionUtils() {} +public abstract class GitVersionUtils { - public static Stream previousGitTags(Project project) { - return StreamSupport.stream(new PreviousGitTags(project), false) - .filter(tag -> !isInitial000Tag(project, tag)) - .map(GitVersionUtils::stripVFromTag); - } - - private static Optional previousGitTagFromRef(Project project, String ref) { - String beforeLastRef = ref + "^"; - - GitResult beforeLastRefTypeResult = execute(project, "git", "cat-file", "-t", beforeLastRef); + @Inject + protected abstract ProviderFactory getProviderFactory(); - boolean thereIsNoCommitBeforeTheRef = !beforeLastRefTypeResult.stdout().equals("commit"); - if (thereIsNoCommitBeforeTheRef) { - return Optional.empty(); - } - - GitResult describeResult = execute(project, "git", "describe", "--tags", "--abbrev=0", beforeLastRef); + @Inject + protected abstract ProjectLayout getProjectLayout(); - if (describeResult.stderr().contains("No tags can describe") - || describeResult.stderr().contains("No names found, cannot describe anything")) { - return Optional.empty(); - } + public final Provider> previousGitTags() { + return execute("git", "tag", "-l", "--merged", "HEAD^", "--sort=-committerdate") + .map(tagsResult -> { + if (tagsResult.exitCode() != 0 || tagsResult.stdout().isEmpty()) { + return Stream.empty(); + } - return Optional.of(describeResult.stdoutOrThrowIfNonZero()); + return Arrays.stream(tagsResult.stdout().split("\n")) + .filter(tag -> !isInitial000Tag(tag)) + .map(GitVersionUtils::stripVFromTag); + }); } - private static boolean isInitial000Tag(Project project, String tag) { + private boolean isInitial000Tag(String tag) { if (!tag.equals("0.0.0")) { return false; } - GitResult foo = execute(project, "git", "rev-parse", "--verify", "--quiet", "0.0.0^"); - boolean parentDoesNotExist = foo.exitCode() != 0; + GitResult result = execute("git", "rev-parse", "--verify", "--quiet", "0.0.0^").get(); + boolean parentDoesNotExist = result.exitCode() != 0; return parentDoesNotExist; } @@ -76,22 +66,23 @@ private static String stripVFromTag(String tag) { } } - private static GitResult execute(Project project, String... command) { - ByteArrayOutputStream stdout = new ByteArrayOutputStream(); - ByteArrayOutputStream stderr = new ByteArrayOutputStream(); - - ExecResult execResult = project.exec(spec -> { - spec.setCommandLine(Arrays.asList(command)); - spec.setStandardOutput(stdout); - spec.setErrorOutput(stderr); - spec.setIgnoreExitValue(true); + private Provider execute(String... command) { + ExecOutput output = getProviderFactory().exec(execSpec -> { + execSpec.commandLine((Object[]) command); + execSpec.setIgnoreExitValue(true); + execSpec.setWorkingDir(getProjectLayout().getProjectDirectory()); }); - return GitResult.builder() - .exitCode(execResult.getExitValue()) - .stdout(new String(stdout.toByteArray(), StandardCharsets.UTF_8).trim()) - .stderr(new String(stderr.toByteArray(), StandardCharsets.UTF_8).trim()) - .build(); + Provider stdout = output.getStandardOutput().getAsText(); + Provider stderr = output.getStandardError().getAsText(); + Provider result = output.getResult(); + + return stdout.zip(stderr, (out, err) -> new Object[] {out, err}) + .zip(result, (outErr, res) -> GitResult.builder() + .exitCode(res.getExitValue()) + .stdout(((String) outErr[0]).trim()) + .stderr(((String) outErr[1]).trim()) + .build()); } @Value.Immutable @@ -122,41 +113,4 @@ static Builder builder() { return new Builder(); } } - - private static final class PreviousGitTags implements Spliterator { - private final Project project; - private String lastSeenRef = "HEAD"; - - PreviousGitTags(Project project) { - this.project = project; - } - - @Override - public boolean tryAdvance(Consumer action) { - Optional tag = previousGitTagFromRef(project, lastSeenRef); - - if (!tag.isPresent()) { - return false; - } - - lastSeenRef = tag.get(); - action.accept(lastSeenRef); - return true; - } - - @Override - public Spliterator trySplit() { - return null; - } - - @Override - public long estimateSize() { - return Long.MAX_VALUE; - } - - @Override - public int characteristics() { - return 0; - } - } } diff --git a/src/main/java/org/revapi/gradle/RevapiExtension.java b/src/main/java/org/revapi/gradle/RevapiExtension.java index bd5e4405..402eae56 100644 --- a/src/main/java/org/revapi/gradle/RevapiExtension.java +++ b/src/main/java/org/revapi/gradle/RevapiExtension.java @@ -22,17 +22,21 @@ import org.gradle.api.provider.ListProperty; import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; +import org.gradle.api.tasks.Nested; import org.revapi.gradle.config.GroupAndName; import org.revapi.gradle.config.GroupNameVersion; import org.revapi.gradle.config.Version; @SuppressWarnings("DesignForExtension") -public class RevapiExtension { +public abstract class RevapiExtension { private final Property oldGroup; private final Property oldName; private final ListProperty oldVersions; private final Provider oldGroupAndName; + @Nested + protected abstract GitVersionUtils getGitVersionUtils(); + public RevapiExtension(Project project) { this.oldGroup = project.getObjects().property(String.class); this.oldGroup.set( @@ -42,9 +46,8 @@ public RevapiExtension(Project project) { this.oldName.set(project.getProviders().provider(project::getName)); this.oldVersions = project.getObjects().listProperty(String.class); - this.oldVersions.set(project.getProviders() - .provider( - () -> GitVersionUtils.previousGitTags(project).limit(3).collect(Collectors.toList()))); + this.oldVersions.set(getGitVersionUtils().previousGitTags().map(versions -> versions.limit(3) + .collect(Collectors.toList()))); this.oldGroupAndName = project.provider(() -> GroupAndName.builder().group(oldGroup.get()).name(oldName.get()).build()); diff --git a/src/test/groovy/org/revapi/gradle/GitVersionUtilsSpec.groovy b/src/test/groovy/org/revapi/gradle/GitVersionUtilsSpec.groovy index 29b57373..05f90fc1 100644 --- a/src/test/groovy/org/revapi/gradle/GitVersionUtilsSpec.groovy +++ b/src/test/groovy/org/revapi/gradle/GitVersionUtilsSpec.groovy @@ -68,17 +68,21 @@ class GitVersionUtilsSpec extends AbstractProjectSpec { def 'return a number of tags that are behind a tag'() { when: git.command 'git commit --allow-empty -m "First"' - git.command 'git tag 1' + git.command 'git tag 5' + // need to sleep for at least a second so each commit is in its own timestamp to ensure sort order is correct + sleep(1001) git.command 'git commit --allow-empty -m "Second"' git.command 'git tag 2' + sleep(1001) git.command 'git commit --allow-empty -m "Third"' git.command 'git tag 3' + sleep(1001) git.command 'git commit --allow-empty -m "Fourth"' git.command 'git tag 4' then: - assert previousGitTags() == ["3", "2", "1"] + assert previousGitTags() == ["3", "2", "5"] } def 'when the initial commit is 0.0.0, ignore it as its the first, unpublished release'() { @@ -113,6 +117,7 @@ class GitVersionUtilsSpec extends AbstractProjectSpec { } private List previousGitTags() { - GitVersionUtils.previousGitTags(getProject()).collect(Collectors.toList()) + GitVersionUtils utils = getProject().objects.newInstance(GitVersionUtils.class) + utils.previousGitTags().get().collect(Collectors.toList()) } } diff --git a/src/test/groovy/org/revapi/gradle/RevapiSpec.groovy b/src/test/groovy/org/revapi/gradle/RevapiSpec.groovy index fff69f94..4b510008 100644 --- a/src/test/groovy/org/revapi/gradle/RevapiSpec.groovy +++ b/src/test/groovy/org/revapi/gradle/RevapiSpec.groovy @@ -293,14 +293,19 @@ class RevapiSpec extends IntegrationSpec { """.stripIndent() git.command 'git add .' + sleep(1001) git.command 'git commit -m 0.1.0' + sleep(1001) git.command 'git tag 0.1.0' + sleep(1001) runTasksSuccessfully('publish') and: git.command 'git commit --allow-empty -m publish-failed' + sleep(1001) git.command 'git tag 0.2.0' + sleep(1001) and: writeToFile javaFile, """ @@ -308,6 +313,7 @@ class RevapiSpec extends IntegrationSpec { """.stripIndent() git.command 'git commit -am new-work' + sleep(1001) then: def standardError = runTasksWithFailure('revapi').standardError From 27af76ec68eb127824c68a0bf9c80c288366f8dc Mon Sep 17 00:00:00 2001 From: Finlay Williams Date: Wed, 23 Jul 2025 11:05:31 +0100 Subject: [PATCH 02/12] tidy --- .../org/revapi/gradle/GitVersionUtils.java | 21 +++++-------------- .../org/revapi/gradle/RevapiSpec.groovy | 6 ------ 2 files changed, 5 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/revapi/gradle/GitVersionUtils.java b/src/main/java/org/revapi/gradle/GitVersionUtils.java index 465a5be2..32054fee 100644 --- a/src/main/java/org/revapi/gradle/GitVersionUtils.java +++ b/src/main/java/org/revapi/gradle/GitVersionUtils.java @@ -39,7 +39,7 @@ public final Provider> previousGitTags() { return execute("git", "tag", "-l", "--merged", "HEAD^", "--sort=-committerdate") .map(tagsResult -> { if (tagsResult.exitCode() != 0 || tagsResult.stdout().isEmpty()) { - return Stream.empty(); + return Stream.empty(); } return Arrays.stream(tagsResult.stdout().split("\n")) @@ -53,9 +53,10 @@ private boolean isInitial000Tag(String tag) { return false; } - GitResult result = execute("git", "rev-parse", "--verify", "--quiet", "0.0.0^").get(); - boolean parentDoesNotExist = result.exitCode() != 0; - return parentDoesNotExist; + return execute("git", "rev-parse", "--verify", "--quiet", "0.0.0^") + .get() + .exitCode() + != 0; } private static String stripVFromTag(String tag) { @@ -95,18 +96,6 @@ interface GitResult { List command(); - default String stdoutOrThrowIfNonZero() { - if (exitCode() == 0) { - return stdout(); - } - - throw new RuntimeException("Failed running command:\n" - + "\tCommand:" + command() + "\n" - + "\tExit code: " + exitCode() + "\n" - + "\tStdout:" + stdout() + "\n" - + "\tStderr:" + stderr() + "\n"); - } - class Builder extends ImmutableGitResult.Builder {} static Builder builder() { diff --git a/src/test/groovy/org/revapi/gradle/RevapiSpec.groovy b/src/test/groovy/org/revapi/gradle/RevapiSpec.groovy index 4b510008..fff69f94 100644 --- a/src/test/groovy/org/revapi/gradle/RevapiSpec.groovy +++ b/src/test/groovy/org/revapi/gradle/RevapiSpec.groovy @@ -293,19 +293,14 @@ class RevapiSpec extends IntegrationSpec { """.stripIndent() git.command 'git add .' - sleep(1001) git.command 'git commit -m 0.1.0' - sleep(1001) git.command 'git tag 0.1.0' - sleep(1001) runTasksSuccessfully('publish') and: git.command 'git commit --allow-empty -m publish-failed' - sleep(1001) git.command 'git tag 0.2.0' - sleep(1001) and: writeToFile javaFile, """ @@ -313,7 +308,6 @@ class RevapiSpec extends IntegrationSpec { """.stripIndent() git.command 'git commit -am new-work' - sleep(1001) then: def standardError = runTasksWithFailure('revapi').standardError From facccafd48bcf1ef2c99d8e2ee9f66ff16c96536 Mon Sep 17 00:00:00 2001 From: Finlay Williams Date: Wed, 23 Jul 2025 11:10:18 +0100 Subject: [PATCH 03/12] tidy --- src/test/groovy/org/revapi/gradle/GitVersionUtilsSpec.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/groovy/org/revapi/gradle/GitVersionUtilsSpec.groovy b/src/test/groovy/org/revapi/gradle/GitVersionUtilsSpec.groovy index 05f90fc1..f6161113 100644 --- a/src/test/groovy/org/revapi/gradle/GitVersionUtilsSpec.groovy +++ b/src/test/groovy/org/revapi/gradle/GitVersionUtilsSpec.groovy @@ -68,7 +68,7 @@ class GitVersionUtilsSpec extends AbstractProjectSpec { def 'return a number of tags that are behind a tag'() { when: git.command 'git commit --allow-empty -m "First"' - git.command 'git tag 5' + git.command 'git tag 1' // need to sleep for at least a second so each commit is in its own timestamp to ensure sort order is correct sleep(1001) git.command 'git commit --allow-empty -m "Second"' @@ -82,7 +82,7 @@ class GitVersionUtilsSpec extends AbstractProjectSpec { git.command 'git tag 4' then: - assert previousGitTags() == ["3", "2", "5"] + assert previousGitTags() == ["3", "2", "1"] } def 'when the initial commit is 0.0.0, ignore it as its the first, unpublished release'() { From 80ef379dfa2362541fa7d58086fec3ba7dc0587f Mon Sep 17 00:00:00 2001 From: Finlay Williams Date: Wed, 23 Jul 2025 12:54:59 +0100 Subject: [PATCH 04/12] tests with cc --- build.gradle | 11 +- .../org/revapi/gradle/RevapiSpec.groovy | 126 ++++++++---------- versions.lock | 40 +++--- versions.props | 4 +- 4 files changed, 89 insertions(+), 92 deletions(-) diff --git a/build.gradle b/build.gradle index f5d6ce59..8b85d22c 100644 --- a/build.gradle +++ b/build.gradle @@ -4,12 +4,14 @@ buildscript { repositories { mavenCentral() { metadataSources { mavenPom(); ignoreGradleMetadataRedirection() } } gradlePluginPortal() { metadataSources { mavenPom(); ignoreGradleMetadataRedirection() } } + mavenLocal() } dependencies { classpath 'com.palantir.jakartapackagealignment:jakarta-package-alignment:0.6.0' classpath 'com.palantir.gradle.externalpublish:gradle-external-publish-plugin:1.11.0' classpath 'com.palantir.javaformat:gradle-palantir-java-format:2.47.0' + classpath 'com.palantir.gradle.plugintesting:gradle-plugin-testing:999' } } @@ -23,6 +25,7 @@ plugins { repositories { mavenCentral() { metadataSources { mavenPom(); ignoreGradleMetadataRedirection() } } + mavenLocal() } group 'org.revapi' @@ -33,6 +36,7 @@ apply plugin: 'java-gradle-plugin' apply plugin: 'java-library' apply plugin: 'groovy' apply plugin: 'com.palantir.external-publish-jar' +apply plugin: 'com.palantir.gradle-plugin-testing' sourceCompatibility = 1.8 @@ -48,10 +52,12 @@ dependencies { testImplementation platform('org.junit:junit-bom') testImplementation 'com.netflix.nebula:nebula-test' - testImplementation "org.junit.jupiter:junit-jupiter" testImplementation 'org.mockito:mockito-core' testImplementation 'org.assertj:assertj-core' - testRuntimeOnly "org.junit.vintage:junit-vintage-engine" + testImplementation 'org.junit.jupiter:junit-jupiter' + testRuntimeOnly 'org.junit.platform:junit-platform-engine' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + testRuntimeOnly 'org.junit.vintage:junit-vintage-engine' annotationProcessor "org.immutables:value" annotationProcessor "org.immutables:serial" @@ -68,6 +74,7 @@ test { environment = System.getenv().entrySet().stream() .filter { entry -> entry.key != 'CIRCLE_TEST_REPORTS' } .collect(Collectors.toMap({ it.key }, { it.value })) + systemProperty 'ignoreDeprecations', 'true' } gradlePlugin { diff --git a/src/test/groovy/org/revapi/gradle/RevapiSpec.groovy b/src/test/groovy/org/revapi/gradle/RevapiSpec.groovy index fff69f94..ecdf22ad 100644 --- a/src/test/groovy/org/revapi/gradle/RevapiSpec.groovy +++ b/src/test/groovy/org/revapi/gradle/RevapiSpec.groovy @@ -16,19 +16,19 @@ package org.revapi.gradle +import com.palantir.gradle.plugintesting.ConfigurationCacheSpec import spock.lang.Ignore import java.util.regex.Pattern -import nebula.test.IntegrationSpec -import nebula.test.functional.ExecutionResult +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.TaskOutcome import spock.util.environment.RestoreSystemProperties -class RevapiSpec extends IntegrationSpec { +class RevapiSpec extends ConfigurationCacheSpec { private Git git def setup() { git = new Git(projectDir) - System.setProperty("ignoreDeprecations", "true") } def 'fails when comparing produced jar versus some random other jar'() { @@ -118,17 +118,18 @@ class RevapiSpec extends IntegrationSpec { public class Foo extends org.junit.rules.ExternalResource { } '''.stripIndent() - println runTasksSuccessfully("publish").standardOutput + println runTasksWithConfigurationCache("publish").output and: buildFile.text = buildFile.text.replace('implementation', 'compileOnly') then: - def executionResult = runTasks('revapi') - println executionResult.standardOutput - println executionResult.standardError - executionResult.rethrowFailure() + def buildResult = runTasksWithConfigurationCacheAndCheck('revapi') + println buildResult.output + if (buildResult.task(':revapi').outcome != TaskOutcome.SUCCESS) { + throw new RuntimeException("Task failed: ${buildResult.output}") + } } def 'revapiAcceptAllBreaks succeeds when there are no breaking changes'() { @@ -252,9 +253,9 @@ class RevapiSpec extends IntegrationSpec { """.stripIndent() then: - def executionResult = runTasksSuccessfully('revapi') - executionResult.wasSkipped(':revapiAnalyze') - executionResult.wasSkipped(':revapi') + def buildResult = runTasksWithConfigurationCacheAndCheck('revapi') + assert buildResult.task(':revapiAnalyze').outcome == TaskOutcome.SKIPPED + assert buildResult.task(':revapi').outcome == TaskOutcome.SKIPPED } def 'when the previous git tag has failed to publish, it will look back up to a further git tag'() { @@ -310,8 +311,8 @@ class RevapiSpec extends IntegrationSpec { git.command 'git commit -am new-work' then: - def standardError = runTasksWithFailure('revapi').standardError - assert standardError.contains('willBeRemoved') + def buildResult = runTasksAndFail('revapi') + assert buildResult.output.contains('willBeRemoved') } def 'if there are no published versions of the library at all, ./gradlew revapi doesnt fail'() { @@ -320,9 +321,9 @@ class RevapiSpec extends IntegrationSpec { writeHelloWorld() then: - def executionResult = runTasksSuccessfully('revapi') - executionResult.wasSkipped(':revapiAnalyze') - executionResult.wasSkipped(':revapi') + def buildResult = runTasksWithConfigurationCacheAndCheck('revapi') + assert buildResult.task(':revapiAnalyze').outcome == TaskOutcome.SKIPPED + assert buildResult.task(':revapi').outcome == TaskOutcome.SKIPPED } def 'if there are no published versions of the library at all, ./gradlew revapiAcceptAllBreaks is a no-op'() { @@ -331,9 +332,9 @@ class RevapiSpec extends IntegrationSpec { writeHelloWorld() then: - def executionResult = runTasksSuccessfully('revapiAcceptAllBreaks') - executionResult.wasSkipped(':revapiAnalyze') - executionResult.wasSkipped(':revapiAcceptAllBreaks') + def buildResult = runTasksWithConfigurationCacheAndCheck('revapiAcceptAllBreaks') + assert buildResult.task(':revapiAnalyze').outcome == TaskOutcome.SKIPPED + assert buildResult.task(':revapiAcceptAllBreaks').outcome == TaskOutcome.SKIPPED } def 'if there are no published versions of the library at all, ./gradlew revapiAcceptBreak doesnt fail'() { @@ -342,9 +343,9 @@ class RevapiSpec extends IntegrationSpec { writeHelloWorld() then: - def executionResult = runTasksSuccessfully('revapiAcceptBreak', '--justification', 'foo', '--code', 'bar', + def buildResult = runTasksWithConfigurationCacheAndCheck('revapiAcceptBreak', '--justification', 'foo', '--code', 'bar', '--old', 'old', '--new', 'new') - executionResult.wasExecuted(':revapiAcceptBreak') + assert buildResult.task(':revapiAcceptBreak').outcome in [TaskOutcome.SUCCESS, TaskOutcome.UP_TO_DATE] } private File setupUnpublishedLibrary() { @@ -506,13 +507,13 @@ class RevapiSpec extends IntegrationSpec { '''.stripIndent() when: - println runTasksSuccessfully("publish").standardOutput + println runTasksSuccessfully("publish").output writeToFile two, 'src/main/java/foo/Foo.java', originalJavaFile.text originalJavaFile.delete() and: - println runTasksSuccessfully("revapi").standardOutput + println runTasksSuccessfully("revapi").output and: def oneBuildGradle = new File(one, 'build.gradle') @@ -565,12 +566,12 @@ class RevapiSpec extends IntegrationSpec { '''.stripIndent() and: - println runTasksSuccessfully("publish").standardOutput + println runTasksSuccessfully("publish").output javaFileInDependentProject.text = javaFileInDependentProject.text.replace('}', 'void foo();\n}') then: - println runTasksSuccessfully("revapi").standardOutput + println runTasksSuccessfully("revapi").output } def 'should not say there are breaks in api dependencies when nothing has changed'() { @@ -608,10 +609,10 @@ class RevapiSpec extends IntegrationSpec { ''' and: - println runTasksSuccessfully("publish").standardOutput + println runTasksSuccessfully("publish").output then: - println runTasksSuccessfully("revapi").standardOutput + println runTasksSuccessfully("revapi").output } def 'ignores scala classes'() { @@ -665,10 +666,10 @@ class RevapiSpec extends IntegrationSpec { class Foo {} '''.stripIndent() - println runTasksSuccessfully("publish").standardOutput + println runTasksSuccessfully("publish").output then: - println runTasksSuccessfully("revapi").standardOutput + println runTasksSuccessfully("revapi").output } def 'detects breaks in groovy code'() { @@ -705,7 +706,7 @@ class RevapiSpec extends IntegrationSpec { } '''.stripIndent() - println runTasksSuccessfully("publish").standardOutput + println runTasksWithConfigurationCache("publish").output and: writeToFile groovyFile, ''' @@ -714,11 +715,11 @@ class RevapiSpec extends IntegrationSpec { '''.stripIndent() then: - def stderr = runRevapiExpectingFailure() + def output = runRevapiExpectingFailure() - assert stderr.contains('java.method.removed') - assert stderr.contains('method java.lang.String foo.Foo::getSomeProperty()') - assert stderr.contains('method void foo.Foo::setSomeProperty(java.lang.String)') + assert output.contains('java.method.removed') + assert output.contains('method java.lang.String foo.Foo::getSomeProperty()') + assert output.contains('method void foo.Foo::setSomeProperty(java.lang.String)') } def 'does not throw exception when baseline-circleci is applied before this plugin'() { @@ -766,8 +767,8 @@ class RevapiSpec extends IntegrationSpec { """.stripIndent() then: - runTasksSuccessfully('revapi').wasExecuted('revapiAnalyze') - runTasksSuccessfully('revapi').wasUpToDate('revapiAnalyze') + assert runTasksSuccessfully('revapi').task(':revapiAnalyze').outcome == TaskOutcome.SUCCESS + assert runTasksSuccessfully('revapi').task(':revapiAnalyze').outcome == TaskOutcome.UP_TO_DATE } def 'is not up to date when public (not private) api has changed'() { @@ -796,7 +797,7 @@ class RevapiSpec extends IntegrationSpec { '''.stripIndent() then: - runTasksSuccessfully('revapi').wasExecuted('revapiAnalyze') + assert runTasksSuccessfully('revapi').task(':revapiAnalyze').outcome == TaskOutcome.SUCCESS writeToFile javaFile, ''' public class Foo { @@ -805,7 +806,7 @@ class RevapiSpec extends IntegrationSpec { } '''.stripIndent() - runTasksSuccessfully('revapi').wasUpToDate('revapiAnalyze') + assert runTasksSuccessfully('revapi').task(':revapiAnalyze').outcome == TaskOutcome.UP_TO_DATE writeToFile javaFile, ''' public class Foo { @@ -814,7 +815,7 @@ class RevapiSpec extends IntegrationSpec { } '''.stripIndent() - runTasksSuccessfully('revapi').wasExecuted('revapiAnalyze') + assert runTasksSuccessfully('revapi').task(':revapiAnalyze').outcome == TaskOutcome.SUCCESS } def 'compatible with gradle-shadow-jar'() { @@ -847,12 +848,12 @@ class RevapiSpec extends IntegrationSpec { '''.stripIndent() and: - println runTasksSuccessfully('publish').standardOutput + println runTasksSuccessfully('publish').output file(shadowedClass).delete() then: - println runTasksSuccessfully('revapi').standardOutput + println runTasksSuccessfully('revapi').output } def 'changing a protected method in an immutables class is not a break'() { @@ -965,16 +966,15 @@ class RevapiSpec extends IntegrationSpec { writeOutImmutablesClass { it.oldText } and: - runTasksSuccessfully('publish') + runTasksWithConfigurationCache('publish') writeOutImmutablesClass { it.newText } then: - def executionResult = runTasks('revapi') - println executionResult.standardError - !executionResult.success + def buildResult = runTasksAndFail('revapi') + println buildResult.output - def errorMessage = executionResult.failure.cause.cause.message + def errorMessage = buildResult.output errorMessage.contains 'There were Java public API/ABI breaks reported by revapi:' for (MethodChange methodChange : methodChanges) { @@ -1086,7 +1086,7 @@ class RevapiSpec extends IntegrationSpec { runTasksSuccessfully('compileConjure') then: - runTasksWithFailure(':api-jersey:revapi') + runTasksAndFail(':api-jersey:revapi') def jerseyJunit = new File(projectDir, 'api-jersey/build/junit-reports/revapi/revapi-api-jersey.xml').text assert jerseyJunit.contains('java.class.removed-interface services.RenamedService') @@ -1097,7 +1097,7 @@ class RevapiSpec extends IntegrationSpec { assert !jerseyJunit.contains('services.TestService::renamedToSomethingElse()') assert !jerseyJunit.contains('java.annotation.attributeValueChanged') - runTasksWithFailure(':api-retrofit:revapi') + runTasksAndFail(':api-retrofit:revapi') def retrofitJunit = new File(projectDir, 'api-retrofit/build/junit-reports/revapi/revapi-api-retrofit.xml').text assert retrofitJunit.contains('java.class.removed-interface services.RenamedServiceRetrofit') @@ -1184,10 +1184,9 @@ class RevapiSpec extends IntegrationSpec { } private String runRevapiExpectingFailure() { - ExecutionResult executionResult = runTasksWithFailure("revapi") - println executionResult.standardOutput - println executionResult.standardError - return executionResult.standardError + BuildResult buildResult = runTasksAndFail("revapi") + println buildResult.output + return buildResult.output } private void andJunitXmlToHaveBeenProduced(String projectName) { @@ -1196,22 +1195,11 @@ class RevapiSpec extends IntegrationSpec { assert junitOutput.text.contains("java.class.removed") } - @Override - ExecutionResult runTasksSuccessfully(String... tasks) { - ExecutionResult result = runTasks(tasks) - if (result.failure) { - println result.standardOutput - result.rethrowFailure() - } - result - } - - @Override - ExecutionResult runTasksWithFailure(String... tasks) { - ExecutionResult result = runTasks(tasks) - if (result.success) { - println result.standardOutput - assert false + private BuildResult runTasksSuccessfully(String... tasks) { + BuildResult result = runTasksWithConfigurationCacheAndCheck(tasks) + if (result.task(':' + tasks[0])?.outcome == TaskOutcome.FAILED) { + println result.output + throw new RuntimeException("Task failed: ${result.output}") } result } diff --git a/versions.lock b/versions.lock index 10342302..0936ba60 100644 --- a/versions.lock +++ b/versions.lock @@ -4,17 +4,16 @@ com.fasterxml.jackson.core:jackson-core:2.14.2 (3 constraints: 55402771) com.fasterxml.jackson.core:jackson-databind:2.14.2 (3 constraints: 0733c1e3) com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.14.2 (1 constraints: 3b053d3b) com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.14.2 (1 constraints: 3b053d3b) -com.google.code.findbugs:jsr305:3.0.2 (1 constraints: 170aecb4) -com.google.errorprone:error_prone_annotations:2.26.1 (1 constraints: 4d0a46bf) -com.google.guava:failureaccess:1.0.2 (1 constraints: 150ae2b4) -com.google.guava:guava:33.2.1-jre (1 constraints: a9067053) +com.google.errorprone:error_prone_annotations:2.36.0 (1 constraints: 4d0a49bf) +com.google.guava:failureaccess:1.0.3 (1 constraints: 160ae3b4) +com.google.guava:guava:33.4.8-jre (2 constraints: da1e577d) com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava (1 constraints: bd17c918) com.google.j2objc:j2objc-annotations:3.0.0 (1 constraints: 150aeab4) -org.checkerframework:checker-qual:3.42.0 (1 constraints: 4b0a47bf) org.freemarker:freemarker:2.3.33 (2 constraints: 5e13e559) org.immutables:serial:2.10.1 (1 constraints: 3605303b) org.immutables:value:2.10.1 (1 constraints: 3605303b) org.jboss:jboss-dmr:1.2.0.Final (1 constraints: 710a5ab9) +org.jspecify:jspecify:1.0.0 (1 constraints: 130ae0b4) org.revapi:revapi:0.11.1 (4 constraints: 8532f166) org.revapi:revapi-basic-features:0.8.1 (1 constraints: 0b050436) org.revapi:revapi-java:0.19.1 (1 constraints: 3d053f3b) @@ -25,25 +24,28 @@ org.yaml:snakeyaml:1.33 (1 constraints: 6f17f827) [Test dependencies] cglib:cglib-nodep:3.2.2 (1 constraints: 490ded24) -com.netflix.nebula:nebula-test:10.0.0 (1 constraints: 3305273b) -junit:junit:4.13.2 (2 constraints: 6a1ed87b) +com.netflix.nebula:nebula-test:10.6.2 (2 constraints: d61de72d) +com.palantir.gradle.plugintesting:configuration-cache-spec:999 (1 constraints: c104512c) +com.palantir.gradle.plugintesting:plugin-testing-core:999 (1 constraints: c104512c) +junit:junit:4.13.2 (2 constraints: ca1e3ab9) net.bytebuddy:byte-buddy:1.14.16 (2 constraints: f8167267) net.bytebuddy:byte-buddy-agent:1.14.15 (1 constraints: 760bb5e9) -org.apiguardian:apiguardian-api:1.1.2 (6 constraints: 896455cc) +org.apiguardian:apiguardian-api:1.1.2 (7 constraints: cc761de9) org.assertj:assertj-core:3.26.0 (1 constraints: 3d054b3b) -org.codehaus.groovy:groovy:3.0.6 (2 constraints: 1e1b476d) +org.codehaus.groovy:groovy:3.0.21 (3 constraints: 103436dc) org.hamcrest:hamcrest:2.2 (1 constraints: d20cdc04) org.hamcrest:hamcrest-core:1.3 (1 constraints: cc05fe3f) -org.junit:junit-bom:5.10.2 (1 constraints: 3a05433b) -org.junit.jupiter:junit-jupiter:5.10.2 (1 constraints: 3f09b79e) -org.junit.jupiter:junit-jupiter-api:5.10.2 (4 constraints: 2f393ee2) -org.junit.jupiter:junit-jupiter-engine:5.10.2 (2 constraints: 7317c263) -org.junit.jupiter:junit-jupiter-params:5.10.2 (2 constraints: 7317c263) -org.junit.platform:junit-platform-commons:1.10.2 (3 constraints: 692ae28e) -org.junit.platform:junit-platform-engine:1.10.2 (4 constraints: ea379e38) -org.junit.vintage:junit-vintage-engine:5.10.2 (1 constraints: 3f09b79e) +org.junit:junit-bom:5.13.4 (1 constraints: 3f054e3b) +org.junit.jupiter:junit-jupiter:5.13.4 (1 constraints: 4409c29e) +org.junit.jupiter:junit-jupiter-api:5.13.4 (5 constraints: fe4f85b3) +org.junit.jupiter:junit-jupiter-engine:5.13.4 (2 constraints: 7d17a564) +org.junit.jupiter:junit-jupiter-params:5.13.4 (3 constraints: 382e9ca9) +org.junit.platform:junit-platform-commons:1.13.4 (3 constraints: 782ad891) +org.junit.platform:junit-platform-engine:1.13.4 (5 constraints: 734a41d4) +org.junit.platform:junit-platform-launcher:1.13.4 (1 constraints: 4009aa9e) +org.junit.vintage:junit-vintage-engine:5.13.4 (1 constraints: 4409c29e) org.mockito:mockito-core:5.12.0 (1 constraints: 3a05473b) org.objenesis:objenesis:3.3 (2 constraints: 9b17f557) org.opentest4j:opentest4j:1.3.0 (2 constraints: cf209249) -org.spockframework:spock-core:2.0-M4-groovy-3.0 (2 constraints: e822d65a) -org.spockframework:spock-junit4:2.0-M4-groovy-3.0 (1 constraints: 25115ddf) +org.spockframework:spock-core:2.3-groovy-3.0 (3 constraints: 2c3deb38) +org.spockframework:spock-junit4:2.3-groovy-3.0 (1 constraints: 7a1000b0) diff --git a/versions.props b/versions.props index 5936b298..b60c40bd 100644 --- a/versions.props +++ b/versions.props @@ -1,6 +1,6 @@ com.fasterxml.jackson.core:jackson-databind = 2.14.2 -com.netflix.nebula:nebula-test = 10.0.0 -org.junit:junit-bom = 5.10.2 +com.netflix.nebula:nebula-test = 10.6.2 +org.junit:junit-bom = 5.13.4 org.revapi:revapi-basic-features = 0.8.1 org.revapi:revapi-java = 0.19.1 org.revapi:revapi-reporter-text = 0.10.1 From abc936342046d5de48c7463e1f27572bad0ae61c Mon Sep 17 00:00:00 2001 From: Finlay Williams Date: Wed, 23 Jul 2025 14:13:26 +0100 Subject: [PATCH 05/12] fix all configuration cache issues and test --- .../revapi/gradle/ConjureProjectFilters.java | 9 +-- .../revapi/gradle/RevapiAcceptBreakTask.java | 22 +++---- .../org/revapi/gradle/RevapiAnalyzeTask.java | 62 ++++++------------- .../java/org/revapi/gradle/RevapiPlugin.java | 43 +++++++++---- .../org/revapi/gradle/RevapiReportTask.java | 40 +++++------- .../gradle/RevapiVersionOverrideTask.java | 15 ++--- .../org/revapi/gradle/RevapiSpec.groovy | 26 +++++--- 7 files changed, 96 insertions(+), 121 deletions(-) diff --git a/src/main/java/org/revapi/gradle/ConjureProjectFilters.java b/src/main/java/org/revapi/gradle/ConjureProjectFilters.java index e8c9741e..ec7fa9f8 100644 --- a/src/main/java/org/revapi/gradle/ConjureProjectFilters.java +++ b/src/main/java/org/revapi/gradle/ConjureProjectFilters.java @@ -18,7 +18,6 @@ import com.fasterxml.jackson.databind.node.ArrayNode; import java.util.Optional; -import org.gradle.api.Project; final class ConjureProjectFilters { private static final ArrayNode CHECKS_FOR_CLIENT_PROJECTS = RevapiConfig.createArrayNode() @@ -29,16 +28,12 @@ final class ConjureProjectFilters { private ConjureProjectFilters() {} - public static RevapiConfig forProject(Project project) { - boolean isConjure = Optional.ofNullable(project.getParent()) - .map(parentProject -> parentProject.getPluginManager().hasPlugin("com.palantir.conjure")) - .orElse(false); - + public static RevapiConfig forProject(String projectName, boolean isConjure) { if (!isConjure) { return RevapiConfig.empty(); } - return checksForProjectName(project.getName()) + return checksForProjectName(projectName) .map(checks -> RevapiConfig.empty().withExtension(CheckWhitelist.EXTENSION_ID, checks)) .orElseGet(RevapiConfig::empty); } diff --git a/src/main/java/org/revapi/gradle/RevapiAcceptBreakTask.java b/src/main/java/org/revapi/gradle/RevapiAcceptBreakTask.java index 46818cb7..590df6e9 100644 --- a/src/main/java/org/revapi/gradle/RevapiAcceptBreakTask.java +++ b/src/main/java/org/revapi/gradle/RevapiAcceptBreakTask.java @@ -20,6 +20,7 @@ import java.util.Optional; import org.gradle.api.DefaultTask; import org.gradle.api.provider.Property; +import org.gradle.api.tasks.Input; import org.gradle.api.tasks.Internal; import org.gradle.api.tasks.TaskAction; import org.gradle.api.tasks.options.Option; @@ -27,28 +28,23 @@ import org.revapi.gradle.config.GroupNameVersion; import org.revapi.gradle.config.Justification; -public class RevapiAcceptBreakTask extends DefaultTask { +public abstract class RevapiAcceptBreakTask extends DefaultTask { private static final String CODE_OPTION = "code"; private static final String OLD_OPTION = "old"; private static final String NEW_OPTION = "new"; private static final String JUSTIFICATION_OPTION = "justification"; - private final Property configManager = - getProject().getObjects().property(ConfigManager.class); private final Property code = getProject().getObjects().property(String.class); private final Property oldElement = getProject().getObjects().property(String.class); private final Property newElement = getProject().getObjects().property(String.class); private final Property justification = getProject().getObjects().property(Justification.class); - public RevapiAcceptBreakTask() { - getOutputs().upToDateWhen(_ignored -> false); - } + @Input + protected abstract Property getGroupNameVersion(); @Internal - final Property getConfigManager() { - return configManager; - } + protected abstract Property getConfigManager(); @Option(option = CODE_OPTION, description = "Revapi change code") public final void setCode(String codeString) { @@ -75,10 +71,10 @@ public final void addVersionOverride() { ensurePresent(code, CODE_OPTION); ensurePresent(justification, JUSTIFICATION_OPTION); - configManager + getConfigManager() .get() .modifyConfigFile(revapiConfig -> revapiConfig.addAcceptedBreaks( - oldGroupNameVersion(), + getGroupNameVersion().get(), Collections.singleton(AcceptedBreak.builder() .code(code.get()) .oldElement(Optional.ofNullable(oldElement.getOrNull())) @@ -92,8 +88,4 @@ private void ensurePresent(Property prop, String option) { throw new IllegalArgumentException("Please supply the --" + option + " param to this task"); } } - - private GroupNameVersion oldGroupNameVersion() { - return getProject().getExtensions().getByType(RevapiExtension.class).oldGroupNameVersion(); - } } diff --git a/src/main/java/org/revapi/gradle/RevapiAnalyzeTask.java b/src/main/java/org/revapi/gradle/RevapiAnalyzeTask.java index f9fd0da7..5ad28cfa 100644 --- a/src/main/java/org/revapi/gradle/RevapiAnalyzeTask.java +++ b/src/main/java/org/revapi/gradle/RevapiAnalyzeTask.java @@ -42,63 +42,40 @@ import org.slf4j.LoggerFactory; @CacheableTask -public class RevapiAnalyzeTask extends DefaultTask { +public abstract class RevapiAnalyzeTask extends DefaultTask { private static final Logger log = LoggerFactory.getLogger(RevapiAnalyzeTask.class); - private final SetProperty acceptedBreaks = - getProject().getObjects().setProperty(AcceptedBreak.class); - private final Property newApiJars = - getProject().getObjects().property(FileCollection.class); - private final Property newApiDependencyJars = - getProject().getObjects().property(FileCollection.class); - private final Property jarsToReportBreaks = - getProject().getObjects().property(FileCollection.class); - private final Property oldApiJars = - getProject().getObjects().property(FileCollection.class); - private final Property oldApiDependencyJars = - getProject().getObjects().property(FileCollection.class); - private final RegularFileProperty analysisResultsFile = - getProject().getObjects().fileProperty(); + @Input + protected abstract SetProperty getAcceptedBreaks(); @Input - public final SetProperty getAcceptedBreaks() { - return acceptedBreaks; - } + protected abstract Property getProjectName(); + + @Input + protected abstract Property getIsConjure(); @CompileClasspath - public final Property getNewApiJars() { - return newApiJars; - } + protected abstract Property getNewApiJars(); @CompileClasspath - public final Property getNewApiDependencyJars() { - return newApiDependencyJars; - } + protected abstract Property getNewApiDependencyJars(); @CompileClasspath - public final Property getJarsToReportBreaks() { - return jarsToReportBreaks; - } + protected abstract Property getJarsToReportBreaks(); @CompileClasspath - public final Property getOldApiJars() { - return oldApiJars; - } + protected abstract Property getOldApiJars(); @CompileClasspath - public final Property getOldApiDependencyJars() { - return oldApiDependencyJars; - } + protected abstract Property getOldApiDependencyJars(); @OutputFile - public final RegularFileProperty getAnalysisResultsFile() { - return analysisResultsFile; - } + protected abstract RegularFileProperty getAnalysisResultsFile(); @TaskAction protected final void runRevapi() throws Exception { - API oldApi = api(oldApiJars, oldApiDependencyJars); - API newApi = api(newApiJars, newApiDependencyJars); + API oldApi = api(getOldApiJars(), getOldApiDependencyJars()); + API newApi = api(getNewApiJars(), getNewApiDependencyJars()); log.info("Old API: {}", oldApi); log.info("New API: {}", newApi); @@ -111,13 +88,14 @@ protected final void runRevapi() throws Exception { .build(); RevapiConfig revapiConfig = RevapiConfig.mergeAll( - RevapiConfig.defaults(jarsToReportBreaks.get()), + RevapiConfig.defaults(getJarsToReportBreaks().get()), RevapiConfig.empty() .withTextReporter( "gradle-revapi-results.ftl", - analysisResultsFile.getAsFile().get()), + getAnalysisResultsFile().getAsFile().get()), revapiIgnores(), - ConjureProjectFilters.forProject(getProject()), + ConjureProjectFilters.forProject( + getProjectName().get(), getIsConjure().get()), ImmutablesFilter.CONFIG); log.info("revapi config:\n{}", revapiConfig.configAsString()); @@ -133,7 +111,7 @@ protected final void runRevapi() throws Exception { } private RevapiConfig revapiIgnores() { - return RevapiConfig.empty().withIgnoredBreaks(acceptedBreaks.get()); + return RevapiConfig.empty().withIgnoredBreaks(getAcceptedBreaks().get()); } private API api(Provider apiJars, Provider dependencyJars) { diff --git a/src/main/java/org/revapi/gradle/RevapiPlugin.java b/src/main/java/org/revapi/gradle/RevapiPlugin.java index 8e6feb3b..7081f15c 100644 --- a/src/main/java/org/revapi/gradle/RevapiPlugin.java +++ b/src/main/java/org/revapi/gradle/RevapiPlugin.java @@ -20,6 +20,7 @@ import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; +import org.gradle.api.DefaultTask; import org.gradle.api.Plugin; import org.gradle.api.Project; import org.gradle.api.Task; @@ -108,6 +109,30 @@ public void apply(Project project) { task.getAnalysisResultsFile().set(new File(project.getBuildDir(), "revapi/revapi-results.json")); + task.getProjectName().set(project.getName()); + task.getIsConjure() + .set(Optional.ofNullable(project.getParent()) + .map(parentProject -> + parentProject.getPluginManager().hasPlugin("com.palantir.conjure")) + .orElse(false)); + + task.onlyIf(oldApiIsPresent); + }); + + TaskProvider acceptBreakTaskTaskProvider = project.getTasks() + .register(ACCEPT_BREAK_TASK_NAME, RevapiAcceptBreakTask.class, task -> { + task.getConfigManager().set(configManager); + task.getGroupNameVersion().set(project.getProviders().provider(extension::oldGroupNameVersion)); + task.doNotTrackState("This task should always run."); + }); + + TaskProvider acceptAllBreaksProjectTaskProvider = project.getTasks() + .register(ACCEPT_ALL_BREAKS_TASK_NAME, RevapiAcceptAllBreaksTask.class, task -> { + task.dependsOn(analyzeTask); + + task.getOldGroupNameVersion().set(project.getProviders().provider(extension::oldGroupNameVersion)); + task.getConfigManager().set(configManager); + task.getAnalysisResultsFile().set(analyzeTask.flatMap(RevapiAnalyzeTask::getAnalysisResultsFile)); task.onlyIf(oldApiIsPresent); }); @@ -116,27 +141,19 @@ public void apply(Project project) { task.dependsOn(analyzeTask); task.getAnalysisResultsFile().set(analyzeTask.flatMap(RevapiAnalyzeTask::getAnalysisResultsFile)); task.getJunitOutputFile().set(junitOutput(project)); + task.getAcceptAllBreaksTaskPath().set(acceptBreakTaskTaskProvider.map(DefaultTask::getPath)); + task.getAcceptAllBreaksProjectTaskPath() + .set(acceptAllBreaksProjectTaskProvider.map(DefaultTask::getPath)); task.onlyIf(oldApiIsPresent); }); project.getTasks().findByName(LifecycleBasePlugin.CHECK_TASK_NAME).dependsOn(reportTask); - project.getTasks().register(ACCEPT_ALL_BREAKS_TASK_NAME, RevapiAcceptAllBreaksTask.class, task -> { - task.dependsOn(analyzeTask); - - task.getOldGroupNameVersion().set(project.getProviders().provider(extension::oldGroupNameVersion)); - task.getConfigManager().set(configManager); - task.getAnalysisResultsFile().set(analyzeTask.flatMap(RevapiAnalyzeTask::getAnalysisResultsFile)); - task.onlyIf(oldApiIsPresent); - }); - project.getTasks().register(VERSION_OVERRIDE_TASK_NAME, RevapiVersionOverrideTask.class, task -> { task.getConfigManager().set(configManager); - }); - - project.getTasks().register(ACCEPT_BREAK_TASK_NAME, RevapiAcceptBreakTask.class, task -> { - task.getConfigManager().set(configManager); + task.getGroupNameVersion().set(project.getProviders().provider(extension::oldGroupNameVersion)); + task.doNotTrackState("This task should always run."); }); } diff --git a/src/main/java/org/revapi/gradle/RevapiReportTask.java b/src/main/java/org/revapi/gradle/RevapiReportTask.java index 315aef98..bae0de62 100644 --- a/src/main/java/org/revapi/gradle/RevapiReportTask.java +++ b/src/main/java/org/revapi/gradle/RevapiReportTask.java @@ -27,56 +27,46 @@ import java.util.Map; import org.gradle.api.DefaultTask; import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.provider.Property; import org.gradle.api.tasks.InputFile; +import org.gradle.api.tasks.Internal; import org.gradle.api.tasks.OutputFile; import org.gradle.api.tasks.TaskAction; import org.revapi.gradle.config.Justification; -public class RevapiReportTask extends DefaultTask { - private final RegularFileProperty analysisResultsFile = - getProject().getObjects().fileProperty(); - private final RegularFileProperty junitOutputFile = - getProject().getObjects().fileProperty(); +public abstract class RevapiReportTask extends DefaultTask { + + @Internal + protected abstract Property getAcceptAllBreaksTaskPath(); + + @Internal + protected abstract Property getAcceptAllBreaksProjectTaskPath(); @InputFile - public final RegularFileProperty getAnalysisResultsFile() { - return analysisResultsFile; - } + protected abstract RegularFileProperty getAnalysisResultsFile(); @OutputFile - public final RegularFileProperty getJunitOutputFile() { - return junitOutputFile; - } + protected abstract RegularFileProperty getJunitOutputFile(); @TaskAction public final void reportBreaks() throws Exception { AnalysisResults results = - AnalysisResults.fromFile(analysisResultsFile.getAsFile().get()); + AnalysisResults.fromFile(getAnalysisResultsFile().getAsFile().get()); Configuration freeMarkerConfiguration = createFreeMarkerConfiguration(); Map templateData = new HashMap<>(); templateData.put("results", results); - templateData.put( - "acceptBreakTask", - getProject() - .getTasks() - .withType(RevapiAcceptBreakTask.class) - .getByName(RevapiPlugin.ACCEPT_BREAK_TASK_NAME) - .getPath()); + templateData.put("acceptBreakTask", getAcceptAllBreaksTaskPath().get()); templateData.put( "acceptAllBreaksProjectTask", - getProject() - .getTasks() - .withType(RevapiAcceptAllBreaksTask.class) - .getByName(RevapiPlugin.ACCEPT_ALL_BREAKS_TASK_NAME) - .getPath()); + getAcceptAllBreaksProjectTaskPath().get()); templateData.put("acceptAllBreaksEverywhereTask", RevapiPlugin.ACCEPT_ALL_BREAKS_TASK_NAME); templateData.put("explainWhy", Justification.YOU_MUST_ENTER_JUSTIFICATION); Template junitTemplate = freeMarkerConfiguration.getTemplate("gradle-revapi-junit-template.ftl"); junitTemplate.process( templateData, - Files.newBufferedWriter(junitOutputFile.getAsFile().get().toPath(), StandardCharsets.UTF_8)); + Files.newBufferedWriter(getJunitOutputFile().getAsFile().get().toPath(), StandardCharsets.UTF_8)); Template textTemplate = freeMarkerConfiguration.getTemplate("gradle-revapi-text-template.ftl"); StringWriter textOutputWriter = new StringWriter(); diff --git a/src/main/java/org/revapi/gradle/RevapiVersionOverrideTask.java b/src/main/java/org/revapi/gradle/RevapiVersionOverrideTask.java index 8364481b..468865d0 100644 --- a/src/main/java/org/revapi/gradle/RevapiVersionOverrideTask.java +++ b/src/main/java/org/revapi/gradle/RevapiVersionOverrideTask.java @@ -18,12 +18,13 @@ import org.gradle.api.DefaultTask; import org.gradle.api.provider.Property; +import org.gradle.api.tasks.Input; import org.gradle.api.tasks.Internal; import org.gradle.api.tasks.TaskAction; import org.gradle.api.tasks.options.Option; import org.revapi.gradle.config.GroupNameVersion; -public class RevapiVersionOverrideTask extends DefaultTask { +public abstract class RevapiVersionOverrideTask extends DefaultTask { public static final String REPLACEMENT_VERSION_OPTION = "replacement-version"; private final Property configManager = @@ -31,9 +32,8 @@ public class RevapiVersionOverrideTask extends DefaultTask { private final Property replacementVersion = getProject().getObjects().property(String.class); - public RevapiVersionOverrideTask() { - getOutputs().upToDateWhen(_ignored -> false); - } + @Input + protected abstract Property getGroupNameVersion(); @Internal final Property getConfigManager() { @@ -53,10 +53,7 @@ public final void addVersionOverride() { configManager .get() - .modifyConfigFile(config -> config.addVersionOverride(oldGroupNameVersion(), replacementVersion.get())); - } - - private GroupNameVersion oldGroupNameVersion() { - return getProject().getExtensions().getByType(RevapiExtension.class).oldGroupNameVersion(); + .modifyConfigFile(config -> + config.addVersionOverride(getGroupNameVersion().get(), replacementVersion.get())); } } diff --git a/src/test/groovy/org/revapi/gradle/RevapiSpec.groovy b/src/test/groovy/org/revapi/gradle/RevapiSpec.groovy index ecdf22ad..cbafc24e 100644 --- a/src/test/groovy/org/revapi/gradle/RevapiSpec.groovy +++ b/src/test/groovy/org/revapi/gradle/RevapiSpec.groovy @@ -125,7 +125,7 @@ class RevapiSpec extends ConfigurationCacheSpec { then: - def buildResult = runTasksWithConfigurationCacheAndCheck('revapi') + def buildResult = runTasksSuccessfully('revapi') println buildResult.output if (buildResult.task(':revapi').outcome != TaskOutcome.SUCCESS) { throw new RuntimeException("Task failed: ${buildResult.output}") @@ -150,7 +150,7 @@ class RevapiSpec extends ConfigurationCacheSpec { """.stripIndent() then: - runTasksSuccessfully("revapiAcceptAllBreaks", "--justification", "fight me") + runTasksWithConfigurationCache("revapiAcceptAllBreaks", "--justification", "fight me") } def 'does not error out when project has a version greater than the "old version"'() { @@ -253,7 +253,7 @@ class RevapiSpec extends ConfigurationCacheSpec { """.stripIndent() then: - def buildResult = runTasksWithConfigurationCacheAndCheck('revapi') + def buildResult = runTasksSuccessfully('revapi') assert buildResult.task(':revapiAnalyze').outcome == TaskOutcome.SKIPPED assert buildResult.task(':revapi').outcome == TaskOutcome.SKIPPED } @@ -272,7 +272,7 @@ class RevapiSpec extends ConfigurationCacheSpec { buildFile << """ plugins { - id 'com.palantir.git-version' version '3.1.0' + id 'com.palantir.git-version' version '4.0.0' } apply plugin: '${TestConstants.PLUGIN_NAME}' @@ -297,7 +297,7 @@ class RevapiSpec extends ConfigurationCacheSpec { git.command 'git commit -m 0.1.0' git.command 'git tag 0.1.0' - runTasksSuccessfully('publish') + runTasksWithConfigurationCache('publish') and: git.command 'git commit --allow-empty -m publish-failed' @@ -321,7 +321,7 @@ class RevapiSpec extends ConfigurationCacheSpec { writeHelloWorld() then: - def buildResult = runTasksWithConfigurationCacheAndCheck('revapi') + def buildResult = runTasksSuccessfully('revapi') assert buildResult.task(':revapiAnalyze').outcome == TaskOutcome.SKIPPED assert buildResult.task(':revapi').outcome == TaskOutcome.SKIPPED } @@ -332,7 +332,7 @@ class RevapiSpec extends ConfigurationCacheSpec { writeHelloWorld() then: - def buildResult = runTasksWithConfigurationCacheAndCheck('revapiAcceptAllBreaks') + def buildResult = runTasksSuccessfully('revapiAcceptAllBreaks') assert buildResult.task(':revapiAnalyze').outcome == TaskOutcome.SKIPPED assert buildResult.task(':revapiAcceptAllBreaks').outcome == TaskOutcome.SKIPPED } @@ -343,7 +343,7 @@ class RevapiSpec extends ConfigurationCacheSpec { writeHelloWorld() then: - def buildResult = runTasksWithConfigurationCacheAndCheck('revapiAcceptBreak', '--justification', 'foo', '--code', 'bar', + def buildResult = runTasksSuccessfully('revapiAcceptBreak', '--justification', 'foo', '--code', 'bar', '--old', 'old', '--new', 'new') assert buildResult.task(':revapiAcceptBreak').outcome in [TaskOutcome.SUCCESS, TaskOutcome.UP_TO_DATE] } @@ -418,7 +418,7 @@ class RevapiSpec extends ConfigurationCacheSpec { and: !revapiYml.exists() - runTasksSuccessfully("revapiAcceptAllBreaks", "--justification", "it's all good :)") + runTasksWithConfigurationCache("revapiAcceptAllBreaks", "--justification", "it's all good :)") revapiYml.text.contains('java.class.removed') then: @@ -736,7 +736,13 @@ class RevapiSpec extends ConfigurationCacheSpec { } dependencies { - classpath 'com.palantir.baseline:gradle-baseline-java:5.61.0' + classpath 'com.palantir.baseline:gradle-baseline-java:6.48.0' + } + } + + allprojects { + repositories { + mavenCentral() } } From 51fe379910717b92a241b7edf0630ccaecb70ecf Mon Sep 17 00:00:00 2001 From: Finlay Williams Date: Wed, 23 Jul 2025 15:02:51 +0100 Subject: [PATCH 06/12] fix --- .../org/revapi/gradle/GitVersionUtils.java | 111 +++++++++++++++--- .../org/revapi/gradle/RevapiExtension.java | 4 +- .../revapi/gradle/GitVersionUtilsSpec.groovy | 6 +- 3 files changed, 97 insertions(+), 24 deletions(-) diff --git a/src/main/java/org/revapi/gradle/GitVersionUtils.java b/src/main/java/org/revapi/gradle/GitVersionUtils.java index 32054fee..d3c5640a 100644 --- a/src/main/java/org/revapi/gradle/GitVersionUtils.java +++ b/src/main/java/org/revapi/gradle/GitVersionUtils.java @@ -16,10 +16,14 @@ package org.revapi.gradle; -import java.util.Arrays; import java.util.List; +import java.util.Optional; +import java.util.Spliterator; +import java.util.function.Consumer; import java.util.stream.Stream; +import java.util.stream.StreamSupport; import javax.inject.Inject; +import org.gradle.api.file.Directory; import org.gradle.api.file.ProjectLayout; import org.gradle.api.provider.Provider; import org.gradle.api.provider.ProviderFactory; @@ -35,25 +39,46 @@ public abstract class GitVersionUtils { @Inject protected abstract ProjectLayout getProjectLayout(); - public final Provider> previousGitTags() { - return execute("git", "tag", "-l", "--merged", "HEAD^", "--sort=-committerdate") - .map(tagsResult -> { - if (tagsResult.exitCode() != 0 || tagsResult.stdout().isEmpty()) { - return Stream.empty(); - } - - return Arrays.stream(tagsResult.stdout().split("\n")) - .filter(tag -> !isInitial000Tag(tag)) - .map(GitVersionUtils::stripVFromTag); - }); + public final Stream previousGitTags() { + return StreamSupport.stream( + new PreviousGitTags( + getProviderFactory(), getProjectLayout().getProjectDirectory()), + false) + .filter(tag -> !isInitial000Tag( + getProviderFactory(), getProjectLayout().getProjectDirectory(), tag)) + .map(GitVersionUtils::stripVFromTag); } - private boolean isInitial000Tag(String tag) { + private static Optional previousGitTagFromRef( + ProviderFactory providerFactory, Directory directory, String ref) { + String beforeLastRef = ref + "^"; + + GitResult beforeLastRefTypeResult = execute(providerFactory, directory, "git", "cat-file", "-t", beforeLastRef) + .get(); + + boolean thereIsNoCommitBeforeTheRef = !beforeLastRefTypeResult.stdout().equals("commit"); + if (thereIsNoCommitBeforeTheRef) { + return Optional.empty(); + } + + GitResult describeResult = execute( + providerFactory, directory, "git", "describe", "--tags", "--abbrev=0", beforeLastRef) + .get(); + + if (describeResult.stderr().contains("No tags can describe") + || describeResult.stderr().contains("No names found, cannot describe anything")) { + return Optional.empty(); + } + + return Optional.of(describeResult.stdoutOrThrowIfNonZero()); + } + + private static boolean isInitial000Tag(ProviderFactory providerFactory, Directory directory, String tag) { if (!tag.equals("0.0.0")) { return false; } - return execute("git", "rev-parse", "--verify", "--quiet", "0.0.0^") + return execute(providerFactory, directory, "git", "rev-parse", "--verify", "--quiet", "0.0.0^") .get() .exitCode() != 0; @@ -67,11 +92,12 @@ private static String stripVFromTag(String tag) { } } - private Provider execute(String... command) { - ExecOutput output = getProviderFactory().exec(execSpec -> { + private static Provider execute( + ProviderFactory providerFactory, Directory directory, String... command) { + ExecOutput output = providerFactory.exec(execSpec -> { execSpec.commandLine((Object[]) command); execSpec.setIgnoreExitValue(true); - execSpec.setWorkingDir(getProjectLayout().getProjectDirectory()); + execSpec.setWorkingDir(directory); }); Provider stdout = output.getStandardOutput().getAsText(); @@ -96,10 +122,61 @@ interface GitResult { List command(); + default String stdoutOrThrowIfNonZero() { + if (exitCode() == 0) { + return stdout(); + } + + throw new RuntimeException("Failed running command:\n" + + "\tCommand:" + command() + "\n" + + "\tExit code: " + exitCode() + "\n" + + "\tStdout:" + stdout() + "\n" + + "\tStderr:" + stderr() + "\n"); + } + class Builder extends ImmutableGitResult.Builder {} static Builder builder() { return new Builder(); } } + + private static final class PreviousGitTags implements Spliterator { + private final ProviderFactory providerFactory; + private final Directory directory; + private String lastSeenRef = "HEAD"; + + PreviousGitTags(ProviderFactory providerFactory, Directory directory) { + this.providerFactory = providerFactory; + this.directory = directory; + } + + @Override + public boolean tryAdvance(Consumer action) { + Optional tag = previousGitTagFromRef(providerFactory, directory, lastSeenRef); + + if (!tag.isPresent()) { + return false; + } + + lastSeenRef = tag.get(); + action.accept(lastSeenRef); + return true; + } + + @Override + public Spliterator trySplit() { + return null; + } + + @Override + public long estimateSize() { + return Long.MAX_VALUE; + } + + @Override + public int characteristics() { + return 0; + } + } } diff --git a/src/main/java/org/revapi/gradle/RevapiExtension.java b/src/main/java/org/revapi/gradle/RevapiExtension.java index 402eae56..bd7b5340 100644 --- a/src/main/java/org/revapi/gradle/RevapiExtension.java +++ b/src/main/java/org/revapi/gradle/RevapiExtension.java @@ -46,8 +46,8 @@ public RevapiExtension(Project project) { this.oldName.set(project.getProviders().provider(project::getName)); this.oldVersions = project.getObjects().listProperty(String.class); - this.oldVersions.set(getGitVersionUtils().previousGitTags().map(versions -> versions.limit(3) - .collect(Collectors.toList()))); + this.oldVersions.set(project.getProviders() + .provider(() -> getGitVersionUtils().previousGitTags().limit(3).collect(Collectors.toList()))); this.oldGroupAndName = project.provider(() -> GroupAndName.builder().group(oldGroup.get()).name(oldName.get()).build()); diff --git a/src/test/groovy/org/revapi/gradle/GitVersionUtilsSpec.groovy b/src/test/groovy/org/revapi/gradle/GitVersionUtilsSpec.groovy index f6161113..fe4ccdab 100644 --- a/src/test/groovy/org/revapi/gradle/GitVersionUtilsSpec.groovy +++ b/src/test/groovy/org/revapi/gradle/GitVersionUtilsSpec.groovy @@ -69,14 +69,10 @@ class GitVersionUtilsSpec extends AbstractProjectSpec { when: git.command 'git commit --allow-empty -m "First"' git.command 'git tag 1' - // need to sleep for at least a second so each commit is in its own timestamp to ensure sort order is correct - sleep(1001) git.command 'git commit --allow-empty -m "Second"' git.command 'git tag 2' - sleep(1001) git.command 'git commit --allow-empty -m "Third"' git.command 'git tag 3' - sleep(1001) git.command 'git commit --allow-empty -m "Fourth"' git.command 'git tag 4' @@ -118,6 +114,6 @@ class GitVersionUtilsSpec extends AbstractProjectSpec { private List previousGitTags() { GitVersionUtils utils = getProject().objects.newInstance(GitVersionUtils.class) - utils.previousGitTags().get().collect(Collectors.toList()) + utils.previousGitTags().collect(Collectors.toList()) } } From f7d769541e16599a80e95cb0850b0b151f523820 Mon Sep 17 00:00:00 2001 From: Finlay Williams Date: Wed, 23 Jul 2025 16:26:06 +0100 Subject: [PATCH 07/12] more abstract --- .../revapi/gradle/RevapiAcceptBreakTask.java | 49 ++++++++----------- .../gradle/RevapiVersionOverrideTask.java | 24 +++------ 2 files changed, 28 insertions(+), 45 deletions(-) diff --git a/src/main/java/org/revapi/gradle/RevapiAcceptBreakTask.java b/src/main/java/org/revapi/gradle/RevapiAcceptBreakTask.java index 590df6e9..0d0b4b87 100644 --- a/src/main/java/org/revapi/gradle/RevapiAcceptBreakTask.java +++ b/src/main/java/org/revapi/gradle/RevapiAcceptBreakTask.java @@ -34,52 +34,43 @@ public abstract class RevapiAcceptBreakTask extends DefaultTask { private static final String NEW_OPTION = "new"; private static final String JUSTIFICATION_OPTION = "justification"; - private final Property code = getProject().getObjects().property(String.class); - private final Property oldElement = getProject().getObjects().property(String.class); - private final Property newElement = getProject().getObjects().property(String.class); - private final Property justification = - getProject().getObjects().property(Justification.class); - @Input - protected abstract Property getGroupNameVersion(); - - @Internal - protected abstract Property getConfigManager(); - @Option(option = CODE_OPTION, description = "Revapi change code") - public final void setCode(String codeString) { - this.code.set(codeString); - } + public abstract Property getCode(); + @Input @Option(option = OLD_OPTION, description = "Old API element") - public final void setOldElement(String oldElementString) { - this.oldElement.set(oldElementString); - } + public abstract Property getOldElement(); + @Input @Option(option = NEW_OPTION, description = "New API element") - public final void setNewElement(String newElementString) { - this.newElement.set(newElementString); - } + public abstract Property getNewElement(); + @Input @Option(option = JUSTIFICATION_OPTION, description = "Justification for why these breaks are ok") - public final void setJustification(String justificationString) { - this.justification.set(Justification.fromString(justificationString)); - } + public abstract Property getJustificationString(); + + @Input + protected abstract Property getGroupNameVersion(); + + @Internal + protected abstract Property getConfigManager(); @TaskAction public final void addVersionOverride() { - ensurePresent(code, CODE_OPTION); - ensurePresent(justification, JUSTIFICATION_OPTION); + ensurePresent(getCode(), CODE_OPTION); + ensurePresent(getJustificationString(), JUSTIFICATION_OPTION); getConfigManager() .get() .modifyConfigFile(revapiConfig -> revapiConfig.addAcceptedBreaks( getGroupNameVersion().get(), Collections.singleton(AcceptedBreak.builder() - .code(code.get()) - .oldElement(Optional.ofNullable(oldElement.getOrNull())) - .newElement(Optional.ofNullable(newElement.getOrNull())) - .justification(justification.get()) + .code(getCode().get()) + .oldElement(Optional.ofNullable(getOldElement().getOrNull())) + .newElement(Optional.ofNullable(getNewElement().getOrNull())) + .justification(Justification.fromString( + getJustificationString().get())) .build()))); } diff --git a/src/main/java/org/revapi/gradle/RevapiVersionOverrideTask.java b/src/main/java/org/revapi/gradle/RevapiVersionOverrideTask.java index 468865d0..4be4bd61 100644 --- a/src/main/java/org/revapi/gradle/RevapiVersionOverrideTask.java +++ b/src/main/java/org/revapi/gradle/RevapiVersionOverrideTask.java @@ -27,33 +27,25 @@ public abstract class RevapiVersionOverrideTask extends DefaultTask { public static final String REPLACEMENT_VERSION_OPTION = "replacement-version"; - private final Property configManager = - getProject().getObjects().property(ConfigManager.class); - private final Property replacementVersion = - getProject().getObjects().property(String.class); - @Input protected abstract Property getGroupNameVersion(); @Internal - final Property getConfigManager() { - return configManager; - } + protected abstract Property getConfigManager(); + @Input @Option(option = REPLACEMENT_VERSION_OPTION, description = "The version to use instead of the default oldVersion") - public final void setReplacementVersion(String replacementVersionValue) { - replacementVersion.set(replacementVersionValue); - } + public abstract Property getReplacementVersion(); @TaskAction public final void addVersionOverride() { - if (!replacementVersion.isPresent()) { - throw new RuntimeException("Please supply the --" + REPLACEMENT_VERSION_OPTION + " param this task"); + if (!getReplacementVersion().isPresent()) { + throw new RuntimeException("Please supply the --" + REPLACEMENT_VERSION_OPTION + " param to this task"); } - configManager + getConfigManager() .get() - .modifyConfigFile(config -> - config.addVersionOverride(getGroupNameVersion().get(), replacementVersion.get())); + .modifyConfigFile(config -> config.addVersionOverride( + getGroupNameVersion().get(), getReplacementVersion().get())); } } From c1d21e407d38559a62ddcd76465f19c0b7f17c77 Mon Sep 17 00:00:00 2001 From: Finlay Williams Date: Thu, 24 Jul 2025 09:31:26 +0100 Subject: [PATCH 08/12] change function name --- src/main/java/org/revapi/gradle/ConjureProjectFilters.java | 2 +- src/main/java/org/revapi/gradle/RevapiAnalyzeTask.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/revapi/gradle/ConjureProjectFilters.java b/src/main/java/org/revapi/gradle/ConjureProjectFilters.java index ec7fa9f8..ce6ce938 100644 --- a/src/main/java/org/revapi/gradle/ConjureProjectFilters.java +++ b/src/main/java/org/revapi/gradle/ConjureProjectFilters.java @@ -28,7 +28,7 @@ final class ConjureProjectFilters { private ConjureProjectFilters() {} - public static RevapiConfig forProject(String projectName, boolean isConjure) { + public static RevapiConfig from(String projectName, boolean isConjure) { if (!isConjure) { return RevapiConfig.empty(); } diff --git a/src/main/java/org/revapi/gradle/RevapiAnalyzeTask.java b/src/main/java/org/revapi/gradle/RevapiAnalyzeTask.java index 5ad28cfa..49d8ad31 100644 --- a/src/main/java/org/revapi/gradle/RevapiAnalyzeTask.java +++ b/src/main/java/org/revapi/gradle/RevapiAnalyzeTask.java @@ -94,7 +94,7 @@ protected final void runRevapi() throws Exception { "gradle-revapi-results.ftl", getAnalysisResultsFile().getAsFile().get()), revapiIgnores(), - ConjureProjectFilters.forProject( + ConjureProjectFilters.from( getProjectName().get(), getIsConjure().get()), ImmutablesFilter.CONFIG); From 6e40d31990c4163cb00cb4a63b7c4bb13ad18349 Mon Sep 17 00:00:00 2001 From: Finlay Williams Date: Thu, 24 Jul 2025 09:50:02 +0100 Subject: [PATCH 09/12] be more accurate --- src/test/groovy/org/revapi/gradle/RevapiSpec.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/groovy/org/revapi/gradle/RevapiSpec.groovy b/src/test/groovy/org/revapi/gradle/RevapiSpec.groovy index cbafc24e..491d9675 100644 --- a/src/test/groovy/org/revapi/gradle/RevapiSpec.groovy +++ b/src/test/groovy/org/revapi/gradle/RevapiSpec.groovy @@ -345,7 +345,7 @@ class RevapiSpec extends ConfigurationCacheSpec { then: def buildResult = runTasksSuccessfully('revapiAcceptBreak', '--justification', 'foo', '--code', 'bar', '--old', 'old', '--new', 'new') - assert buildResult.task(':revapiAcceptBreak').outcome in [TaskOutcome.SUCCESS, TaskOutcome.UP_TO_DATE] + assert buildResult.task(':revapiAcceptBreak').outcome == TaskOutcome.SUCCESS } private File setupUnpublishedLibrary() { From 2964e7895a5b759755eb1061fd32899598478fa0 Mon Sep 17 00:00:00 2001 From: Finlay Williams Date: Thu, 24 Jul 2025 10:11:56 +0100 Subject: [PATCH 10/12] keep with failure --- .../org/revapi/gradle/RevapiSpec.groovy | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/test/groovy/org/revapi/gradle/RevapiSpec.groovy b/src/test/groovy/org/revapi/gradle/RevapiSpec.groovy index 491d9675..210e8c14 100644 --- a/src/test/groovy/org/revapi/gradle/RevapiSpec.groovy +++ b/src/test/groovy/org/revapi/gradle/RevapiSpec.groovy @@ -311,7 +311,7 @@ class RevapiSpec extends ConfigurationCacheSpec { git.command 'git commit -am new-work' then: - def buildResult = runTasksAndFail('revapi') + def buildResult = runTasksWithFailure('revapi') assert buildResult.output.contains('willBeRemoved') } @@ -977,7 +977,7 @@ class RevapiSpec extends ConfigurationCacheSpec { writeOutImmutablesClass { it.newText } then: - def buildResult = runTasksAndFail('revapi') + def buildResult = runTasksWithFailure('revapi') println buildResult.output def errorMessage = buildResult.output @@ -1092,7 +1092,7 @@ class RevapiSpec extends ConfigurationCacheSpec { runTasksSuccessfully('compileConjure') then: - runTasksAndFail(':api-jersey:revapi') + runTasksWithFailure(':api-jersey:revapi') def jerseyJunit = new File(projectDir, 'api-jersey/build/junit-reports/revapi/revapi-api-jersey.xml').text assert jerseyJunit.contains('java.class.removed-interface services.RenamedService') @@ -1103,7 +1103,7 @@ class RevapiSpec extends ConfigurationCacheSpec { assert !jerseyJunit.contains('services.TestService::renamedToSomethingElse()') assert !jerseyJunit.contains('java.annotation.attributeValueChanged') - runTasksAndFail(':api-retrofit:revapi') + runTasksWithFailure(':api-retrofit:revapi') def retrofitJunit = new File(projectDir, 'api-retrofit/build/junit-reports/revapi/revapi-api-retrofit.xml').text assert retrofitJunit.contains('java.class.removed-interface services.RenamedServiceRetrofit') @@ -1190,7 +1190,7 @@ class RevapiSpec extends ConfigurationCacheSpec { } private String runRevapiExpectingFailure() { - BuildResult buildResult = runTasksAndFail("revapi") + BuildResult buildResult = runTasksWithFailure("revapi") println buildResult.output return buildResult.output } @@ -1209,4 +1209,13 @@ class RevapiSpec extends ConfigurationCacheSpec { } result } + + private BuildResult runTasksWithFailure(String... tasks) { + BuildResult result = runTasksAndFailWithConfigurationCache(tasks) + if (result.task(':' + tasks[0])?.outcome == TaskOutcome.SUCCESS) { + println result.output + throw new RuntimeException("Task succeded: ${result.output}") + } + result + } } From 3188085578c79843b7a7ceedebbb69c2b9e9c20b Mon Sep 17 00:00:00 2001 From: Finlay Williams Date: Thu, 24 Jul 2025 10:23:02 +0100 Subject: [PATCH 11/12] final touches --- src/test/groovy/org/revapi/gradle/RevapiSpec.groovy | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/groovy/org/revapi/gradle/RevapiSpec.groovy b/src/test/groovy/org/revapi/gradle/RevapiSpec.groovy index 210e8c14..ca77808b 100644 --- a/src/test/groovy/org/revapi/gradle/RevapiSpec.groovy +++ b/src/test/groovy/org/revapi/gradle/RevapiSpec.groovy @@ -507,7 +507,7 @@ class RevapiSpec extends ConfigurationCacheSpec { '''.stripIndent() when: - println runTasksSuccessfully("publish").output + println runTasksWithConfigurationCache("publish").output writeToFile two, 'src/main/java/foo/Foo.java', originalJavaFile.text originalJavaFile.delete() @@ -566,7 +566,7 @@ class RevapiSpec extends ConfigurationCacheSpec { '''.stripIndent() and: - println runTasksSuccessfully("publish").output + println runTasksWithConfigurationCache("publish").output javaFileInDependentProject.text = javaFileInDependentProject.text.replace('}', 'void foo();\n}') @@ -609,7 +609,7 @@ class RevapiSpec extends ConfigurationCacheSpec { ''' and: - println runTasksSuccessfully("publish").output + println runTasksWithConfigurationCache("publish").output then: println runTasksSuccessfully("revapi").output @@ -666,7 +666,7 @@ class RevapiSpec extends ConfigurationCacheSpec { class Foo {} '''.stripIndent() - println runTasksSuccessfully("publish").output + println runTasksWithConfigurationCache("publish").output then: println runTasksSuccessfully("revapi").output From 126924f4c5f8a50b14a2e04357009e51e95ab51b Mon Sep 17 00:00:00 2001 From: Finlay Williams Date: Mon, 28 Jul 2025 09:17:03 +0100 Subject: [PATCH 12/12] use released version of plugin testing --- build.gradle | 4 +--- versions.lock | 12 ++++++------ 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/build.gradle b/build.gradle index 8b85d22c..af4e124d 100644 --- a/build.gradle +++ b/build.gradle @@ -4,14 +4,13 @@ buildscript { repositories { mavenCentral() { metadataSources { mavenPom(); ignoreGradleMetadataRedirection() } } gradlePluginPortal() { metadataSources { mavenPom(); ignoreGradleMetadataRedirection() } } - mavenLocal() } dependencies { classpath 'com.palantir.jakartapackagealignment:jakarta-package-alignment:0.6.0' classpath 'com.palantir.gradle.externalpublish:gradle-external-publish-plugin:1.11.0' classpath 'com.palantir.javaformat:gradle-palantir-java-format:2.47.0' - classpath 'com.palantir.gradle.plugintesting:gradle-plugin-testing:999' + classpath 'com.palantir.gradle.plugintesting:gradle-plugin-testing:0.10.0' } } @@ -25,7 +24,6 @@ plugins { repositories { mavenCentral() { metadataSources { mavenPom(); ignoreGradleMetadataRedirection() } } - mavenLocal() } group 'org.revapi' diff --git a/versions.lock b/versions.lock index 0936ba60..3e515828 100644 --- a/versions.lock +++ b/versions.lock @@ -25,21 +25,21 @@ org.yaml:snakeyaml:1.33 (1 constraints: 6f17f827) [Test dependencies] cglib:cglib-nodep:3.2.2 (1 constraints: 490ded24) com.netflix.nebula:nebula-test:10.6.2 (2 constraints: d61de72d) -com.palantir.gradle.plugintesting:configuration-cache-spec:999 (1 constraints: c104512c) -com.palantir.gradle.plugintesting:plugin-testing-core:999 (1 constraints: c104512c) +com.palantir.gradle.plugintesting:configuration-cache-spec:0.10.0 (1 constraints: 3305233b) +com.palantir.gradle.plugintesting:plugin-testing-core:0.10.0 (1 constraints: 3305233b) junit:junit:4.13.2 (2 constraints: ca1e3ab9) net.bytebuddy:byte-buddy:1.14.16 (2 constraints: f8167267) net.bytebuddy:byte-buddy-agent:1.14.15 (1 constraints: 760bb5e9) org.apiguardian:apiguardian-api:1.1.2 (7 constraints: cc761de9) org.assertj:assertj-core:3.26.0 (1 constraints: 3d054b3b) -org.codehaus.groovy:groovy:3.0.21 (3 constraints: 103436dc) +org.codehaus.groovy:groovy:3.0.25 (3 constraints: 14347add) org.hamcrest:hamcrest:2.2 (1 constraints: d20cdc04) org.hamcrest:hamcrest-core:1.3 (1 constraints: cc05fe3f) org.junit:junit-bom:5.13.4 (1 constraints: 3f054e3b) -org.junit.jupiter:junit-jupiter:5.13.4 (1 constraints: 4409c29e) -org.junit.jupiter:junit-jupiter-api:5.13.4 (5 constraints: fe4f85b3) +org.junit.jupiter:junit-jupiter:5.13.4 (2 constraints: 540ebf67) +org.junit.jupiter:junit-jupiter-api:5.13.4 (5 constraints: 01507ab5) org.junit.jupiter:junit-jupiter-engine:5.13.4 (2 constraints: 7d17a564) -org.junit.jupiter:junit-jupiter-params:5.13.4 (3 constraints: 382e9ca9) +org.junit.jupiter:junit-jupiter-params:5.13.4 (3 constraints: 3b2e71aa) org.junit.platform:junit-platform-commons:1.13.4 (3 constraints: 782ad891) org.junit.platform:junit-platform-engine:1.13.4 (5 constraints: 734a41d4) org.junit.platform:junit-platform-launcher:1.13.4 (1 constraints: 4009aa9e)