Coder Social home page Coder Social logo

palantir / gradle-revapi Goto Github PK

View Code? Open in Web Editor NEW
29.0 248.0 13.0 899 KB

Gradle plugin that uses Revapi to check whether you have introduced API/ABI breaks in your Java public API

License: Apache License 2.0

Shell 0.05% Java 66.63% FreeMarker 2.34% Groovy 30.99%
octo-correct-managed

gradle-revapi's Introduction

Autorelease

gradle-revapi

A gradle plugin which runs Revapi to warn you when there are breaks to your Java library's public API or ABI.

Using the plugin should be as simple as:

  1. Adding the plugin to your buildscript:

    buildscript {
        // ...
    
        dependencies {
            classpath 'com.palantir.gradle.revapi:gradle-revapi:<latest-version>'
        }
    }
  2. And then apply the plugin to all the projects you want to ensure API compatibility:

    // In my Java project's build.gradle that publishes a jar
    +apply plugin: 'com.palantir.revapi'
  3. Revapi will be run as part of ./gradlew check. Alternatively, you can call ./gradlew revapi directly.

Motivation

Accidentally releasing API or ABI breaks in java libraries has bad consequences for library consumers. In the case of API breaks, consumers have to perform some kind of manual action to upgrade to newer library versions, which may be difficult.

With ABI breaks, the situation can be even worse, as uses of the library compile but uses in jars of the old API fail at runtime. An example from Tritium is where a method was changed from a Map to a SortedMap. This compiles against direct dependencies but transitive dependencies using the older API would produce a NoSuchMethodError at runtime, which has caused a number of problems in production code. Similarly, there was a covariant return type change to docker-compose-rule (ImmutableDockerComposeRule -> DockerComposeRule) which caused ABI breaks in docker-proxy-rule, among projects.

Configuration

gradle-revapi should work out of the box for most uses cases once applied. By default it compares against the previous version of the jar from the project it is applied in by finding the last tag using git describe. However, if you need to need to override the artifact to compare against, you can do so:

revapi {
    oldGroup = '<artifact-group>'
    oldNamed = '<artifact-name>'
    oldVersion = '<artifact-version>'
}

Accepting breaks

Sometimes you may wish to break your API, or feel that the particular API break identified by revapi is acceptable to release. In these cases, there is an escape hatch you can use which should be automatically recommended to you in the error message gradle-revapi produces.

  • To accept a single break, run:

    ./gradlew revapiAcceptBreak --justification "{why this is ok}" \
            --code "{revapi check code}" \
            --old "{optional revapi description of old element}" \
            --new "{optional revapi description of new element}"
    
  • To accept all the breaks in a gradle project run:

    ./gradlew :project:revapiAcceptAllBreaks
    
  • To accept all the breaks in all gradle projects run:

    ./gradlew revapiAcceptAllBreaks
    

Running any of these tasks will add the breaks to the .palantir/revapi.yml file in the format"

acceptedBreaks:
  version:
    group:name:
    - code: "class"
      old: "class OldClass"
      new: null
      justification: "No one was using this"

Version overrides

Sometimes the previous release will have a successfully applied a git tag but a failed publish build. In this case gradle-revapi will fail as it cannot resolve the previous API to compare against. To resolve this, you can possible to set a version override that will use a different version instead of the last git tag. To do so, use the

./gradle revapiVersionOverride --replacement-version <last-published-version>

task to use correctly published version instead. This will creare an entry in .palantir/revapi.yml of the following format:

versionOverrides:
  group:name:version: versionOverride

gradle-revapi's People

Contributors

a10y avatar ash211 avatar brianwyka avatar crogers avatar fawind avatar iamdanfox avatar nmiyake avatar pkoenig10 avatar svc-autorelease avatar svc-excavator-bot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gradle-revapi's Issues

Allow overriding the java toolchain

Thank you for this plugin!

We have a project using the new Java Toolchains feature.
The build system for this project has JAVA_HOME pointing to a JRE, not a JDK.
In this project, revapiAnalyze fails with:

* What went wrong:
Execution failed for task ':pix-dict-api:revapiAnalyze'.
> Could not obtain the system compiler. Is tools.jar on the classpath?

We have inspected the source to see if there are the usual configuration properties for overriding the java toolchain but could not find any.

Revapi might use outdated tag

What happened?

When accepting breaks, gradle-revapi uses the previous local tag when adding the lock-file entry (ref). However e.g. when devs work on a PR for a longer time, their local git tags might become out-of-date and the tag added to the lock-file is no longer the most recent tag.

Note that as a workaround, devs can refresh the tags manually (e.g. using git pull --tags).

What did you want to happen?

We might want to refresh the local git tags before evaluating the tag to be put into the lockfile to make sure that this is an up-to-date version.

Check that my api depencenies include all types exposed in the api

What happened?

It's possible to publish an api that's not implementable by consumers by not bringing in transitive dependencies that you depend on at compile scope. For instance if I have an interface that exposes guava's ListenableFuture but guava is only an implementation for my package. The api will compile perfectly fine in my project but anyone consuming published package will see compile error

What did you want to happen?

Revapi should fail with a message indicating some of the classes in the api are not compile dependencies

Incompatible with Gradle v7

What happened?

Using the plugin with Gradle v7(.0.2) generates this error:

A problem was found with the configuration of task ':revapiAnalyze' (type 'RevapiAnalyzeTask').
  - Type 'com.palantir.gradle.revapi.RevapiAnalyzeTask' property 'analysisResultsFile' is annotated with @PathSensitive but that is not allowed for 'OutputFile' properties.
    
    Reason: This modifier is used in conjunction with a property of type 'OutputFile' but this doesn't have semantics.
    
    Possible solution: Remove the '@PathSensitive' annotation.
    
    Please refer to https://docs.gradle.org/7.0.2/userguide/validation_problems.html#incompatible_annotations for more details about this problem.

What did you want to happen?

The plugin should be compatible with Gradle v7 and no error should occur.

Add support for configurable Git tag prefix

What happened?

Currently the plugin supports previous version Git tags with a version number optionally prefixed with "v".

What did you want to happen?

Some projects have different versioning standards, so it would be good to add support for a configurable tag prefix (with a default of "v" for backwards compatibiltiy).

Make config file location configurable

revapi.yml output should alphabetical

It appears that both versionOverrides and acceptedBreaks render in a non-alphabetical order (and out of order with each other) when listing artifact/project keys in revapi.yml. This makes reviewing break listings in PRs, as well as reading the breaks post-facto, less predictable that it could be, and difficult to correlate across multiple versions' changes.

What happened?

Example revapi.yml in a recent PR after accepting changes (names notionalized but otherwise order is maintained):

versionOverrides:
  com.company.module:myproject-examples:1.100.0: "1.101.0-7-gabcdef0"
  com.company.module:myproject-api:1.100.0: "1.101.0-7-gabcdef0"
  com.company.module:myproject-runtime-module:1.100.0: "1.101.0-7-gabcdef0"
  com.company.module:binary-format:1.100.0: "1.101.0-7-gabcdef0"
  com.company.module:myproject-impl:1.100.0: "1.101.0-7-gabcdef0"
acceptedBreaks:
  "1.110.0":
    com.company.module:myproject-examples: []
    com.company.module:binary-format: []
    com.company.module:myproject-api:
    - code: "java.method.addedToInterface"
      ...
...

What did you want to happen?

It would be lexically natural and more review-friendly if the output was more like this:

versionOverrides:
  com.company.module:binary-format:1.100.0: "1.101.0-7-gabcdef0"
  com.company.module:myproject-api:1.100.0: "1.101.0-7-gabcdef0"
  com.company.module:myproject-examples:1.100.0: "1.101.0-7-gabcdef0"
  com.company.module:myproject-impl:1.100.0: "1.101.0-7-gabcdef0"
  com.company.module:myproject-runtime-module:1.100.0: "1.101.0-7-gabcdef0"
acceptedBreaks:
  "1.110.0":
    com.company.module:binary-format: []
    com.company.module:myproject-api:
    - code: "java.method.addedToInterface"
      ...
    com.company.module:myproject-examples: []
...

Automatically strip leading "v" from version tags

What happened?

The plugin failed to resolve the old version of our project because we use tags in the format vX.X.X, while maven coordinates usually use X.X.X.

What did you want to happen?

Tags should be normalized by stripping the leading "v".

Groovy sources are including in revapi check

What happened?

When you run gradle-revapi with groovy sources as well as java sources in your project, you get spurious break messages for groovy sources.

What did you want to happen?

gradle-revapi should ignore all non-java sources.

Ignoring beta/rc releases

A somewhat common practice is to publish beta or release candidate builds before a new major version of a library, to gather user feedback on a non-changing version. A way to ignore these versions as is done for snapshots would be useful to avoid needing hundreds of lines in the yaml config when we make breaking changes in a beta cycle (admittedly, it's not a huge deal as it's auto-generated). The maven plugin resolved a similar issue with a versionFormat option.

issues with classes from non java source: add option to exclude class entirely?

What happened?

I'm using gradle-revapi in a project which contains some scala code (because it involves some interactions with apache spark catalyst, which is a pretty scala heavy api).

I added a new constructor to a scala class, which takes an extra parameter (but keeping the old constructor too), which resulted in revapi detecting a large number of 'breaks', seemingly because some of the methods scala is creating behind the scenes changed - e.g. I see breaks such as:

- code: "java.method.removed"
      old: "method long scala.runtime.AbstractFunction1<T1, R>::apply$mcJJ$sp(long)\
        \ @ com.palantir.MyScalaClass$"
      new: null

What did you want to happen?

Ultimately it might be nice to try to use mima (https://github.com/lightbend/mima) for something like this.

For now it might be nice to be able to just exclude classes entirely from revapi checking (in this case there is no public facing api/abi change). This would avoid filling up revapi.yml with a large number of these breaks.

Analysis fails with dependency on source set

What happened?

I have an API project which generates source (from antlr) into a separate source set:

sourceSets {
    antlr
}
dependencies {
    compile sourceSets.antlr.output
}
jar {
    from sourceSets.antlr.output
    dependsOn antlrClasses
}

The revapi task fails with the following exception:

* Exception is:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':<project>:revapi'.
Caused by: java.lang.IllegalStateException: Failed to analyze archives in api API[archives=[<project>-0.1.0.jar], supplementary=[antlr, antlr4-4.7.2.jar, ..jars]]
        at org.revapi.java.JavaArchiveAnalyzer.analyze(JavaArchiveAnalyzer.java:84)
        at org.revapi.java.JavaArchiveAnalyzer.analyze(JavaArchiveAnalyzer.java:38)
        at org.revapi.Revapi.analyzeWith(Revapi.java:255)
        at org.revapi.Revapi.analyze(Revapi.java:164)
        at com.palantir.gradle.revapi.RevapiJavaTask.runRevapi(RevapiJavaTask.java:91)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:103)
        at org.gradle.api.internal.project.taskfactory.StandardTaskAction.doExecute(StandardTaskAction.java:49)
        at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:42)
        at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:28)
        at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:717)
        at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:684)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$5.run(ExecuteActionsTaskExecuter.java:476)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:402)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:394)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:92)
        at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:461)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:444)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.access$200(ExecuteActionsTaskExecuter.java:93)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$TaskExecution.execute(ExecuteActionsTaskExecuter.java:237)
        at org.gradle.internal.execution.steps.ExecuteStep.lambda$execute$1(ExecuteStep.java:33)
        at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:33)
        at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:26)
        at org.gradle.internal.execution.steps.CleanupOutputsStep.execute(CleanupOutputsStep.java:58)
        at org.gradle.internal.execution.steps.CleanupOutputsStep.execute(CleanupOutputsStep.java:35)
        at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:48)
        at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:33)
        at org.gradle.internal.execution.steps.CancelExecutionStep.execute(CancelExecutionStep.java:39)
        at org.gradle.internal.execution.steps.TimeoutStep.executeWithoutTimeout(TimeoutStep.java:73)
        at org.gradle.internal.execution.steps.TimeoutStep.execute(TimeoutStep.java:54)
        at org.gradle.internal.execution.steps.CatchExceptionStep.execute(CatchExceptionStep.java:35)
        at org.gradle.internal.execution.steps.CreateOutputsStep.execute(CreateOutputsStep.java:51)
        at org.gradle.internal.execution.steps.SnapshotOutputsStep.execute(SnapshotOutputsStep.java:45)
        at org.gradle.internal.execution.steps.SnapshotOutputsStep.execute(SnapshotOutputsStep.java:31)
        at org.gradle.internal.execution.steps.CacheStep.executeWithoutCache(CacheStep.java:208)
        at org.gradle.internal.execution.steps.CacheStep.execute(CacheStep.java:70)
        at org.gradle.internal.execution.steps.CacheStep.execute(CacheStep.java:45)
        at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:49)
        at org.gradle.internal.execution.steps.StoreSnapshotsStep.execute(StoreSnapshotsStep.java:43)
        at org.gradle.internal.execution.steps.StoreSnapshotsStep.execute(StoreSnapshotsStep.java:32)
        at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:38)
        at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:24)
        at org.gradle.internal.execution.steps.SkipUpToDateStep.executeBecause(SkipUpToDateStep.java:96)
        at org.gradle.internal.execution.steps.SkipUpToDateStep.lambda$execute$0(SkipUpToDateStep.java:89)
        at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:54)
        at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:38)
        at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:76)
        at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:37)
        at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:36)
        at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:26)
        at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:90)
        at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:48)
        at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:69)
        at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:47)
        at org.gradle.internal.execution.impl.DefaultWorkExecutor.execute(DefaultWorkExecutor.java:33)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:140)
        ... 35 more
Caused by: java.lang.IllegalStateException: Failed to copy class path element: antlr to /var/folders/<path>
        at org.revapi.java.compilation.Compiler.copyArchives(Compiler.java:204)
        at org.revapi.java.compilation.Compiler.compile(Compiler.java:104)
        at org.revapi.java.JavaArchiveAnalyzer.analyze(JavaArchiveAnalyzer.java:74)
        ... 96 more
Caused by: java.io.FileNotFoundException: <project>/build/classes/java/antlr (Is a directory)
        at org.revapi.simple.FileArchive.openStream(FileArchive.java:49)
        at org.revapi.java.compilation.Compiler.extracted(Compiler.java:219)
        at org.revapi.java.compilation.Compiler.copyArchives(Compiler.java:200)
        ... 98 more

gradle-revapi version 0.4.0

What did you want to happen?

Either source set dependencies are not treated as external dependencies (particularly in this case where the generated source should be analyzed as part of the contents of the jar), or this case fails with a clear error message and indication of how to fix (i.e. pull source set to a separate project and publish a separate jar).

Throws an exception on a project with no tags

What happened?

I added revapi to a new project (no tags) and ran ./gradlew check --stacktrace.

It failed as below, unsurprisingly as running
git describe --tags --abbrev=0 HEAD^ fails in exactly that way: fatal: No names found, cannot describe anything.

Using git 2.29.0 on macOS 10.15.7.

Bit surprising that Command is [] in the output - surely it should be [git, describe, --tags, --abbrev=0, HEAD^]?

Full exception:

FAILURE: Build failed with an exception.
* What went wrong:
Could not determine the dependencies of task ':revapiAnalyze'.
> Failed to query the value of task ':revapiAnalyze' property 'oldApiJars'.
   > Failed to query the value of extension 'revapi' property 'oldVersions'.
      > Failed running command:
        	Command:[]
        	Exit code: 128
        	Stdout:
        	Stderr:fatal: No names found, cannot describe anything.
* Try:
Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Exception is:
org.gradle.api.internal.tasks.TaskDependencyResolveException: Could not determine the dependencies of task ':revapiAnalyze'.
	at org.gradle.api.internal.tasks.CachingTaskDependencyResolveContext.getDependencies(CachingTaskDependencyResolveContext.java:69)
	at org.gradle.execution.plan.TaskDependencyResolver.resolveDependenciesFor(TaskDependencyResolver.java:46)
	at org.gradle.execution.plan.LocalTaskNode.getDependencies(LocalTaskNode.java:160)
	at org.gradle.execution.plan.LocalTaskNode.resolveDependencies(LocalTaskNode.java:128)
	at org.gradle.execution.plan.DefaultExecutionPlan.doAddNodes(DefaultExecutionPlan.java:167)
	at org.gradle.execution.plan.DefaultExecutionPlan.addEntryTasks(DefaultExecutionPlan.java:131)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph.addEntryTasks(DefaultTaskExecutionGraph.java:147)
	at org.gradle.execution.TaskNameResolvingBuildConfigurationAction.configure(TaskNameResolvingBuildConfigurationAction.java:49)
	at org.gradle.execution.DefaultBuildConfigurationActionExecuter.configure(DefaultBuildConfigurationActionExecuter.java:55)
	at org.gradle.execution.DefaultBuildConfigurationActionExecuter.access$000(DefaultBuildConfigurationActionExecuter.java:26)
	at org.gradle.execution.DefaultBuildConfigurationActionExecuter$1.proceed(DefaultBuildConfigurationActionExecuter.java:63)
	at org.gradle.execution.DefaultTasksBuildExecutionAction.configure(DefaultTasksBuildExecutionAction.java:45)
	at org.gradle.execution.DefaultBuildConfigurationActionExecuter.configure(DefaultBuildConfigurationActionExecuter.java:55)
	at org.gradle.execution.DefaultBuildConfigurationActionExecuter.access$000(DefaultBuildConfigurationActionExecuter.java:26)
	at org.gradle.execution.DefaultBuildConfigurationActionExecuter$1.proceed(DefaultBuildConfigurationActionExecuter.java:63)
	at org.gradle.execution.ExcludedTaskFilteringBuildConfigurationAction.configure(ExcludedTaskFilteringBuildConfigurationAction.java:48)
	at org.gradle.execution.DefaultBuildConfigurationActionExecuter.configure(DefaultBuildConfigurationActionExecuter.java:55)
	at org.gradle.execution.DefaultBuildConfigurationActionExecuter.lambda$select$0(DefaultBuildConfigurationActionExecuter.java:42)
	at org.gradle.internal.Factories$1.create(Factories.java:31)
	at org.gradle.api.internal.project.DefaultProjectStateRegistry.withMutableStateOfAllProjects(DefaultProjectStateRegistry.java:141)
	at org.gradle.api.internal.project.DefaultProjectStateRegistry.withMutableStateOfAllProjects(DefaultProjectStateRegistry.java:128)
	at org.gradle.execution.DefaultBuildConfigurationActionExecuter.select(DefaultBuildConfigurationActionExecuter.java:40)
	at org.gradle.initialization.DefaultTaskExecutionPreparer.prepareForTaskExecution(DefaultTaskExecutionPreparer.java:38)
	at org.gradle.initialization.BuildOperationFiringTaskExecutionPreparer$CalculateTaskGraph.populateTaskGraph(BuildOperationFiringTaskExecutionPreparer.java:117)
	at org.gradle.initialization.BuildOperationFiringTaskExecutionPreparer$CalculateTaskGraph.run(BuildOperationFiringTaskExecutionPreparer.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:56)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$run$1(DefaultBuildOperationExecutor.java:71)
	at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.runWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:45)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:71)
	at org.gradle.initialization.BuildOperationFiringTaskExecutionPreparer.prepareForTaskExecution(BuildOperationFiringTaskExecutionPreparer.java:56)
	at org.gradle.initialization.DefaultGradleLauncher.prepareTaskExecution(DefaultGradleLauncher.java:236)
	at org.gradle.initialization.DefaultGradleLauncher.doClassicBuildStages(DefaultGradleLauncher.java:166)
	at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:147)
	at org.gradle.initialization.DefaultGradleLauncher.executeTasks(DefaultGradleLauncher.java:123)
	at org.gradle.internal.invocation.GradleBuildController$1.create(GradleBuildController.java:72)
	at org.gradle.internal.invocation.GradleBuildController$1.create(GradleBuildController.java:67)
	at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:182)
	at org.gradle.internal.invocation.GradleBuildController.doBuild(GradleBuildController.java:67)
	at org.gradle.internal.invocation.GradleBuildController.run(GradleBuildController.java:56)
	at org.gradle.tooling.internal.provider.runner.BuildModelActionRunner.run(BuildModelActionRunner.java:54)
	at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
	at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
	at org.gradle.launcher.exec.BuildOutcomeReportingBuildActionRunner.run(BuildOutcomeReportingBuildActionRunner.java:63)
	at org.gradle.tooling.internal.provider.ValidatingBuildActionRunner.run(ValidatingBuildActionRunner.java:32)
	at org.gradle.tooling.internal.provider.FileSystemWatchingBuildActionRunner.run(FileSystemWatchingBuildActionRunner.java:66)
	at org.gradle.launcher.exec.BuildCompletionNotifyingBuildActionRunner.run(BuildCompletionNotifyingBuildActionRunner.java:41)
	at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner$3.call(RunAsBuildOperationBuildActionRunner.java:49)
	at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner$3.call(RunAsBuildOperationBuildActionRunner.java:44)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:200)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:195)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:62)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$call$2(DefaultBuildOperationExecutor.java:76)
	at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.callWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:54)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:76)
	at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner.run(RunAsBuildOperationBuildActionRunner.java:44)
	at org.gradle.launcher.exec.InProcessBuildActionExecuter.lambda$execute$0(InProcessBuildActionExecuter.java:54)
	at org.gradle.composite.internal.DefaultRootBuildState.run(DefaultRootBuildState.java:86)
	at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:53)
	at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:29)
	at org.gradle.launcher.exec.BuildTreeScopeLifecycleBuildActionExecuter.lambda$execute$0(BuildTreeScopeLifecycleBuildActionExecuter.java:33)
	at org.gradle.internal.buildtree.BuildTreeState.run(BuildTreeState.java:49)
	at org.gradle.launcher.exec.BuildTreeScopeLifecycleBuildActionExecuter.execute(BuildTreeScopeLifecycleBuildActionExecuter.java:32)
	at org.gradle.launcher.exec.BuildTreeScopeLifecycleBuildActionExecuter.execute(BuildTreeScopeLifecycleBuildActionExecuter.java:27)
	at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:104)
	at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:55)
	at org.gradle.tooling.internal.provider.SubscribableBuildActionExecuter.execute(SubscribableBuildActionExecuter.java:64)
	at org.gradle.tooling.internal.provider.SubscribableBuildActionExecuter.execute(SubscribableBuildActionExecuter.java:37)
	at org.gradle.tooling.internal.provider.SessionScopeLifecycleBuildActionExecuter.lambda$execute$0(SessionScopeLifecycleBuildActionExecuter.java:54)
	at org.gradle.internal.session.BuildSessionState.run(BuildSessionState.java:67)
	at org.gradle.tooling.internal.provider.SessionScopeLifecycleBuildActionExecuter.execute(SessionScopeLifecycleBuildActionExecuter.java:50)
	at org.gradle.tooling.internal.provider.SessionScopeLifecycleBuildActionExecuter.execute(SessionScopeLifecycleBuildActionExecuter.java:36)
	at org.gradle.tooling.internal.provider.GradleThreadBuildActionExecuter.execute(GradleThreadBuildActionExecuter.java:36)
	at org.gradle.tooling.internal.provider.GradleThreadBuildActionExecuter.execute(GradleThreadBuildActionExecuter.java:25)
	at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:59)
	at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:31)
	at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:55)
	at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:41)
	at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:47)
	at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:31)
	at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:65)
	at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:39)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:29)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:35)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.create(ForwardClientInput.java:78)
	at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.create(ForwardClientInput.java:75)
	at org.gradle.util.Swapper.swap(Swapper.java:38)
	at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:75)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.LogAndCheckHealth.execute(LogAndCheckHealth.java:55)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:63)
	at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:84)
	at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
	at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:52)
	at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:297)
	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
Caused by: org.gradle.api.internal.provider.AbstractProperty$PropertyQueryException: Failed to query the value of task ':revapiAnalyze' property 'oldApiJars'.
	at org.gradle.api.internal.provider.AbstractProperty.calculatePresence(AbstractProperty.java:61)
	at org.gradle.api.internal.provider.AbstractMinimalProvider.isPresent(AbstractMinimalProvider.java:74)
	at org.gradle.api.internal.tasks.properties.bean.AbstractNestedRuntimeBeanNode$BeanPropertyValue.call(AbstractNestedRuntimeBeanNode.java:137)
	at org.gradle.util.GUtil.uncheckedCall(GUtil.java:452)
	at org.gradle.util.DeferredUtil.unpackNestableDeferred(DeferredUtil.java:64)
	at org.gradle.api.internal.file.collections.UnpackingVisitor.add(UnpackingVisitor.java:84)
	at org.gradle.api.internal.file.DefaultFileCollectionFactory$ResolvingFileCollection.visitChildren(DefaultFileCollectionFactory.java:310)
	at org.gradle.api.internal.file.CompositeFileCollection.visitDependencies(CompositeFileCollection.java:108)
	at org.gradle.api.internal.tasks.CachingTaskDependencyResolveContext$TaskGraphImpl.getNodeValues(CachingTaskDependencyResolveContext.java:112)
	at org.gradle.internal.graph.CachingDirectedGraphWalker$GraphWithEmptyEdges.getNodeValues(CachingDirectedGraphWalker.java:213)
	at org.gradle.internal.graph.CachingDirectedGraphWalker.doSearch(CachingDirectedGraphWalker.java:121)
	at org.gradle.internal.graph.CachingDirectedGraphWalker.findValues(CachingDirectedGraphWalker.java:73)
	at org.gradle.api.internal.tasks.CachingTaskDependencyResolveContext.getDependencies(CachingTaskDependencyResolveContext.java:67)
	... 115 more
Caused by: org.gradle.api.internal.provider.AbstractProperty$PropertyQueryException: Failed to query the value of extension 'revapi' property 'oldVersions'.
	at org.gradle.api.internal.provider.AbstractProperty.doCalculateValue(AbstractProperty.java:136)
	at org.gradle.api.internal.provider.AbstractProperty.calculateOwnValue(AbstractProperty.java:127)
	at org.gradle.api.internal.provider.AbstractMinimalProvider.get(AbstractMinimalProvider.java:84)
	at com.palantir.gradle.revapi.ResolveOldApi.resolveOldApiAcrossAllOldVersions(ResolveOldApi.java:55)
	at com.palantir.gradle.revapi.ResolveOldApi.lambda$oldApiProvider$0(ResolveOldApi.java:48)
	at com.palantir.gradle.revapi.GradleUtils$MemoizingSupplier.get(GradleUtils.java:49)
	at org.gradle.api.internal.provider.DefaultProvider.calculateOwnValue(DefaultProvider.java:66)
	at org.gradle.api.internal.provider.AbstractMinimalProvider.calculateValue(AbstractMinimalProvider.java:103)
	at org.gradle.api.internal.provider.TransformBackedProvider.calculateOwnValue(TransformBackedProvider.java:64)
	at org.gradle.api.internal.provider.AbstractMinimalProvider.calculatePresence(AbstractMinimalProvider.java:79)
	at org.gradle.api.internal.provider.MappingProvider.calculatePresence(MappingProvider.java:50)
	at org.gradle.api.internal.provider.AbstractProperty.calculatePresence(AbstractProperty.java:58)
	... 127 more
Caused by: java.lang.RuntimeException: Failed running command:
	Command:[]
	Exit code: 128
	Stdout:
	Stderr:fatal: No names found, cannot describe anything.
	at com.palantir.gradle.revapi.GitVersionUtils$GitResult.stdoutOrThrowIfNonZero(GitVersionUtils.java:115)
	at com.palantir.gradle.revapi.GitVersionUtils.previousGitTagFromRef(GitVersionUtils.java:57)
	at com.palantir.gradle.revapi.GitVersionUtils.access$000(GitVersionUtils.java:32)
	at com.palantir.gradle.revapi.GitVersionUtils$PreviousGitTags.tryAdvance(GitVersionUtils.java:135)
	at com.palantir.gradle.revapi.RevapiExtension.lambda$new$1(RevapiExtension.java:47)
	at org.gradle.api.internal.provider.DefaultProvider.calculateOwnValue(DefaultProvider.java:66)
	at org.gradle.api.internal.provider.AbstractMinimalProvider.calculateValue(AbstractMinimalProvider.java:103)
	at org.gradle.api.internal.provider.Collectors$ElementsFromCollectionProvider.collectEntries(Collectors.java:216)
	at org.gradle.api.internal.provider.AbstractCollectionProperty$CollectingSupplier.calculateValue(AbstractCollectionProperty.java:337)
	at org.gradle.api.internal.provider.AbstractCollectionProperty.calculateValueFrom(AbstractCollectionProperty.java:184)
	at org.gradle.api.internal.provider.AbstractCollectionProperty.calculateValueFrom(AbstractCollectionProperty.java:37)
	at org.gradle.api.internal.provider.AbstractProperty.doCalculateValue(AbstractProperty.java:133)
	... 138 more

What did you want to happen?

It should spot that there are no tags and skip the check. It looks like it's meant to -
GitVersionUtils.java#L53-L55 - but it doesn't work.

RevApi requires up to date with develop

What happened?

I made some internal code breaks. I resolved the breaks, but this was against an "old" tag i.e. someone released just after I resolved the breaks, so when this merged, I got a semantic merge conflict where I needed to resolve the breaks again and the metadata for the previous tag was ignored.

i.e. develop is compared to 0.162.0 vs 0.161.1 (where I resolved the breaks).

What did you want to happen?

It should recognise the break when it happened vs when it merged into develop, and not require me to be up to date with develop or submit extra prs after develop breaks.

What could we do?

Thoughts are whether we keyed the file by the break instead of the version, and the key can be some sort of hash. This would avoid the case outlined above, as you'd just look up the hash of the break. We could keep the version, but as some metadata, and that would give you the "logical" time when this break was made vs when it merged into develop. But it would be purely for informational purposes, unless there was another use for the version?

e.g. from

acceptedBreaks:
  0.162.2:
    com.palantir.atlasdb:atlasdb-config:
    - code: "java.method.removed"
      old: "method com.palantir.atlasdb.factory.ImmutableLocalPaxosServices.Builder\
        \ com.palantir.atlasdb.factory.ImmutableLocalPaxosServices.Builder::pingableLeader(com.palantir.leader.PingableLeader)"
      new: null
      justification: "this is internal code"

to

acceptedBreaks:
  com.palantir.atlasdb:atlasdb-config:
    0fb0236503:
      - code: "java.method.removed"
        old: "method com.palantir.atlasdb.factory.ImmutableLocalPaxosServices.Builder"
        new: null
        justification: "this is internal code"
        version-introduced: 0.162.2
      # any other hash collisions

@iamdanfox, @CRogers for SA.

Revapi often OOMs when run on a whole gradle project

What happened?

On projects with large APIs and/or many projects, gradle-revapi OOMs when run as ./gradlew revapi. I think this is mainly due to running Revapi in parallel say 8x, which can be too much.

What did you want to happen?

We should allow configuration to limit the task concurrency so Revapi does not OOM. Gradle 6 will have the ideal feature for this, SharedResource. Alternatively, we could immetiadely use a Semaphore to restrict concurrency, however this would block tasks (rather than SharedResource which will run some other task if there aren't enough permits) and we'd need to think carefully to ensure this wouldn't cause a deadlock.

Another possibility is the APIs themselves are too large - we current use the RUNTIME_ELEMENTS classpath rather than API_ELEMENTS which is likely much larger, however some people still have implementation dependencies in their accidentally public APIs internally, and this change might break them.

IncompatibleClassChangeError when invoking gradle revapi

I apply the plugin and invoked gradle revapi and the following error occured:

java.lang.IncompatibleClassChangeError
        at com.palantir.gradle.revapi.GradleUtils$$Lambda$1728.0000000064801A80.call(Unknown Source)

I am using the following version:
id "com.palantir.revapi" version "1.1.3"

I have also tried with version 1.1.2

build fails inside gitlab ci

What happened?

Seeing this error when running gradlew check inside gitlab ci. seems the way revapi uses git requires has some issues.
works fine locally or in circleci.


  | Caused by: java.lang.RuntimeException: Failed running command: |  
-- | -- | --
  | Command:[] |  
  | Exit code: 128 |  
  | Stdout: |  
  | Stderr:fatal: No names found, cannot describe anything. |  
  |   |  




  |   | at com.palantir.gradle.revapi.GitVersionUtils$GitResult.stdoutOrThrowIfNonZero(GitVersionUtils.java:115) |  
-- | -- | -- | --
  |   | at com.palantir.gradle.revapi.GitVersionUtils.previousGitTagFromRef(GitVersionUtils.java:57) |  
  |   | at com.palantir.gradle.revapi.GitVersionUtils.access$000(GitVersionUtils.java:32) |  
  |   | at com.palantir.gradle.revapi.GitVersionUtils$PreviousGitTags.tryAdvance(GitVersionUtils.java:135) |  
  |   | at com.palantir.gradle.revapi.RevapiExtension.lambda$new$1(RevapiExtension.java:47) |  
  |   | at org.gradle.api.internal.provider.DefaultProvider.calculateOwnValue(DefaultProvider.java:66) |  
  |   | at org.gradle.api.internal.provider.AbstractMinimalProvider.calculateValue(AbstractMinimalProvider.java:103) |  
  |   | at org.gradle.api.internal.provider.Collectors$ElementsFromCollectionProvider.collectEntries(Collectors.java:216) |  
  |   | at org.gradle.api.internal.provider.AbstractCollectionProperty$CollectingSupplier.calculateValue(AbstractCollectionProperty.java:337) |  
  |   | at org.gradle.api.internal.provider.AbstractCollectionProperty.calculateValueFrom(AbstractCollectionProperty.java:184) |  
  |   | at org.gradle.api.internal.provider.AbstractCollectionProperty.calculateValueFrom(AbstractCollectionProperty.java:37) |  
  |   | at org.gradle.api.internal.provider.AbstractProperty.doCalculateValue(AbstractProperty.java:133) |  
  |   | at org.gradle.api.internal.provider.AbstractProperty.calculateOwnValue(AbstractProperty.java:127) |  
  |   | at org.gradle.api.internal.provider.AbstractMinimalProvider.get(AbstractMinimalProvider.java:84) |  
  |   | at com.palantir.gradle.revapi.ResolveOldApi.resolveOldApiAcrossAllOldVersions(ResolveOldApi.java:55) |  
  |   | at com.palantir.gradle.revapi.ResolveOldApi.lambda$oldApiProvider$0(ResolveOldApi.java:48) |  
  |   | at com.palantir.gradle.revapi.GradleUtils$MemoizingSupplier.get(GradleUtils.java:49) |  
  |   | at org.gradle.api.internal.provider.DefaultProvider.calculateOwnValue(DefaultProvider.java:66) |  
  |   | at org.gradle.api.internal.provider.AbstractMinimalProvider.calculateValue(AbstractMinimalProvider.java:103) |  
  |   | at org.gradle.api.internal.provider.TransformBackedProvider.calculateOwnValue(TransformBackedProvider.java:64) |  
  |   | at org.gradle.api.internal.provider.AbstractMinimalProvider.calculatePresence(AbstractMinimalProvider.java:79) |  
  |   | at org.gradle.api.internal.provider.MappingProvider.calculatePresence(MappingProvider.java:50) |  
  |   | at org.gradle.api.internal.provider.AbstractProperty.calculatePresence(AbstractProperty.java:58) |  
  |   | at org.gradle.api.internal.provider.AbstractMinimalProvider.isPresent(AbstractMinimalProvider.java:74) |  
  |   | at org.gradle.api.internal.tasks.properties.bean.AbstractNestedRuntimeBeanNode$BeanPropertyValue.call(AbstractNestedRuntimeBeanNode.java:137) |  
  |   | at org.gradle.util.GUtil.uncheckedCall(GUtil.java:442) |  
  |   | at org.gradle.util.DeferredUtil.unpackNestableDeferred(DeferredUtil.java:64) |  
  |   | at org.gradle.api.internal.file.collections.UnpackingVisitor.add(UnpackingVisitor.java:84) |  
  |   | at org.gradle.api.internal.file.DefaultFileCollectionFactory$ResolvingFileCollection.visitChildren(DefaultFileCollectionFactory.java:310) |  
  |   | at org.gradle.api.internal.file.CompositeFileCollection.visitDependencies(CompositeFileCollection.java:108) |  
  |   | at org.gradle.api.internal.tasks.CachingTaskDependencyResolveContext$TaskGraphImpl.getNodeValues(CachingTaskDependencyResolveContext.java:112) |  
  |   | at org.gradle.internal.graph.CachingDirectedGraphWalker$GraphWithEmptyEdges.getNodeValues(CachingDirectedGraphWalker.java:213) |  
  |   | at org.gradle.internal.graph.CachingDirectedGraphWalker.doSearch(CachingDirectedGraphWalker.java:121) |  
  |   | at org.gradle.internal.graph.CachingDirectedGraphWalker.findValues(CachingDirectedGraphWalker.java:73) |  
  |   | at org.gradle.api.internal.tasks.CachingTaskDependencyResolveContext.getDependencies(CachingTaskDependencyResolveContext.java:67) |  
  |   | at org.gradle.execution.plan.TaskDependencyResolver.resolveDependenciesFor(TaskDependencyResolver.java:46) |  
  |   | at org.gradle.execution.plan.LocalTaskNode.getDependencies(LocalTaskNode.java:160) |  
  |   | at org.gradle.execution.plan.LocalTaskNode.resolveDependencies(LocalTaskNode.java:128) |  
  |   | at org.gradle.execution.plan.DefaultExecutionPlan.doAddNodes(DefaultExecutionPlan.java:163) |  
  |   | at org.gradle.execution.plan.DefaultExecutionPlan.addEntryTasks(DefaultExecutionPlan.java:133) |  
  |   | at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph.addEntryTasks(DefaultTaskExecutionGraph.java:147) |  
  |   | at org.gradle.execution.TaskNameResolvingBuildConfigurationAction.configure(TaskNameResolvingBuildConfigurationAction.java:49) |  
  |   | at org.gradle.execution.DefaultBuildConfigurationActionExecuter.configure(DefaultBuildConfigurationActionExecuter.java:58) |  
  |   | at org.gradle.execution.DefaultBuildConfigurationActionExecuter.access$200(DefaultBuildConfigurationActionExecuter.java:26) |  
  |   | at org.gradle.execution.DefaultBuildConfigurationActionExecuter$2.proceed(DefaultBuildConfigurationActionExecuter.java:66) |  
  |   | at org.gradle.execution.DefaultTasksBuildExecutionAction.configure(DefaultTasksBuildExecutionAction.java:45) |  
  |   | at org.gradle.execution.DefaultBuildConfigurationActionExecuter.configure(DefaultBuildConfigurationActionExecuter.java:58) |  
  |   | at org.gradle.execution.DefaultBuildConfigurationActionExecuter.access$200(DefaultBuildConfigurationActionExecuter.java:26) |  
  |   | at org.gradle.execution.DefaultBuildConfigurationActionExecuter$2.proceed(DefaultBuildConfigurationActionExecuter.java:66) |  
  |   | at org.gradle.execution.ExcludedTaskFilteringBuildConfigurationAction.configure(ExcludedTaskFilteringBuildConfigurationAction.java:48) |  
  |   | at org.gradle.execution.DefaultBuildConfigurationActionExecuter.configure(DefaultBuildConfigurationActionExecuter.java:58) |  
  |   | at org.gradle.execution.DefaultBuildConfigurationActionExecuter.access$200(DefaultBuildConfigurationActionExecuter.java:26) |  
  |   | at org.gradle.execution.DefaultBuildConfigurationActionExecuter$1.run(DefaultBuildConfigurationActionExecuter.java:44)


What did you want to happen?

build without errors.

gradle 6.6.1
"com.palantir.revapi" version "1.4.3"

False positive when moving a class from one package to dependent package

What happened?

If you move class Foo from project core to project dependency, where core depends on dependency as api, then revapi will create a spurious error saying it's a breaking change, even though the class is still on the classpath when using core.

What did you want to happen?

Revapi should not create an error in this case.

Allow whitelisting/enumeration of specific classes as API surface

What happened?

We develop a number of Gradle plugins, where we define the API to be the plugin id and Gradle extension(s). Implementation code wires the extension properties to Gradle tasks, and we consider the extensions to be the consumer-facing API. (IOW we follow guidance here: https://docs.gradle.org/current/userguide/custom_plugins.html#sec:mapping_extension_properties_to_task_properties, Capturing user input from the build script through an extension and mapping it to input/output properties of a custom task is a useful pattern. The build script author interacts only with the DSL defined by the extension. The imperative logic is hidden in the plugin implementation.)

We find that when we modify how the tasks work or how they wire together, we often get revapi flags that need to be accepted and documented - however we don't consider these API changes, and want our consumers focusing on changes in the extension as how they should interact with our product.

In a more conventional Java product we might go with separate *-api and *-impl projects and only apply revapi to the former; however with a small Gradle-plugin project with a handful of classes, splitting out projects seems like needless complication of the repo itself in order to take advantage of the revapi tool.

What did you want to happen?

It would be nice if the revapi extension offered a class whitelist option or enumeration mode where developers could designate specific classes in a project to be the API surfaces, with revapi flagging and annotating changes to those classes, with other classes judged implementation details that don't require changes to be logged in the revapi.yml.

Merging in develop to PRs before a recent publish has finished causes revapi to report `Failed to resolve old API`

What happened?

If you have a project with long publish builds, you can merge develop into PRs before the publish build on that develop commit has finished. Revapi will fail with:

java.lang.IllegalStateException: Failed to resolve old API, meaning revapi cannot use it tofind API/ABI breaks. This usually happens when the last
release was git tagged correctly but the publish build was not successful. If this is the case, there are two options:

But this is annoying and you need to do it for every publish you wait for, which is bad on repos that release very often.

What did you want to happen?

Perhaps revapi could automatically look back to (a limited number of) previous versions if the most recent tag is not found (and fall back to the versionOverride workflow when we run out of attempts). This has a couple of downsides:

  • The builds are not truly repeatable, as running the build will do something different before and after the publish has succeeded.
  • If the version being published had revapi temporarily removed or was in some other way modified before release, reavpi could have false positives or even miss breaks.

However, both these seem worse IMO that trying our best to verify against the latest release when we can, and working for those using the default workflow.

No documented way of creating new sub-project

What happened?

When creating a new subproject in an existing project with revapi enabled, revapi errors out with no apparent way of marking the break through the config interface (it always fails with a "Failed to resolve old API"-type error).

The errors in the template take the pattern of:

  We tried version $latest but it failed with errors:
  Could not find $project:$pkg:$latest.
  Searched in the following locations:
    - ...
    - ...

...

What did you want to happen?

Either a command to tell revapi that a project was just added, or a way to get the revapiAcceptAllBreaks command to work in those circumstances. If there already exists a way to handle this, we should document it in the readme.

Guidance on running revapi in a github action - seems to pass when fails locally

What happened?

./gradlew revapi is passing during our github action in the Apache Iceberg project when breaking changes are introduced.

These same breaking changes cause failures locally.

I've seen it mostly say skipping. I believe this is because we have the github cache action.

I removed the github cache action in my fork. That seems to cause revapi to run (revapiAnalyze running is in the debug output), but it still passes.

Our .palantir/revapi.yml file can be found here: https://github.com/apache/iceberg/blob/master/.palantir/revapi.yml

What did you want to happen?

For a breaking change in a branch with master as its target to break in our Github Action CI, like it does locally.

Here's an example that should fail (or at least does locally):

Is it possible that when we git checkout via actions/checkout, that the proper branch and overrride is not discovered? Are there CLI flags I can use to force it to use a specific version JAR from maven as the old version?

Thank you for developing this gradle plugin. We'd love to get this resolved as the Apache Iceberg community has come to rely on this and we need it to work in our CI as well (and will make the necessary changes, but need help determining what they are). Thank you!

Please support non-English

What happened?

When using in an non-English environment, This plugin will not work properly.

Such as #504 will not work.

The err doesn't contains the specific characters, while it output like

$git describe --tags --abbrev=0

fatal: 没有标签能描述 '7ff467106431cdd8715aeec9b5f58458dc5d2102'。
尝试 --always,或者创建一些标签。

What did you want to happen?

Do set LANGUAGE = en_US when invoking git commands

Don't care about `java.element.nowDeprecated`

What happened?

Someone ended up adding the following to their .palantir/revapi.yml:

 - code: "java.element.nowDeprecated"
      old: "class com.palantir.witchcraft.config.ClientTrustStoreConfiguration.Builder"
      new: "class com.palantir.witchcraft.config.ClientTrustStoreConfiguration.Builder"
      justification: "Non source breaking changes to expand keystores to support pem\
        \ files"

But I don't think it's really valuable.

What did you want to happen?

People should be free to deprecate stuff if they want to.

Adding an endpoint to a conjure definition causes revapi to fail

What happened?

If you add an endpoint to conjure, and have gradle-revapi applied, it will give you an error saying "Method was added to an interface". Technically, this could be seen as a break as there's nothing stopping other people using that generated interface to implement their own service implementation, but seems very heavyweight/frictionful.

What did you want to happen?

We could ignore everything except ABI breaks that are not also API breaks (these are dangerous and we still want to prevent them) for conjure classes. At least with changes that are API breaks, compilation will fail (unlike these solely ABI breaks).

Adding a method to an immutables interface or abstract class causes reavpi to fail

What happened?

When you add a new field to an immutables class:

@Value.Immutable
public interface Foo {
    String existing();
+   int newMethod();
}

you get an error message like so:

method int Foo::newMethod(): Method was added to an interface.

What did you want to happen?

Since API consumers are not expected to implement immutables interfaces, there is possibly too much overhead here and we should ignore the "Method was added to an interface" check.

Thank you!

Hey palantir team,

Thank you very much for this opensource project,
It enabled me to write my own gradle plugin that checks the binary compatibility for scala.
I really liked the git tag idea and resovling an artifact that is the same as the project would have taken me several days without this example!

https://github.com/borissmidt/gradle-mima-plugin (its still very rough)

Unable to modify default configuration

What happened?

Running the revapi task does not report certain changes, because the minSeverity config is set to BREAKING.

What did you want to happen?

I want to have the ability to customize the config options given to revapi. I used the standalone version to confirm that there are API changes between the two jars, but they are not binary breaking (just source breaking and binary potentially breaking).

Help ignoring specific packages

I've reviewed the various documentation and I can't figure out how to mark a particular package as internal/ignored so that revapi doesn't complain when it changes. Any advice or examples on how I can do that?

ConcurrentModificationException applying 1.0.5 before publishing plugins

What happened?

I'm applying revapi 1.0.5 right after applying java-library but before applying other plugins that configure publishing (in this project):

apply plugin: 'java-library'
apply plugin: 'com.palantir.revapi'
apply from: rootProject.file('gradle/publish-jar.gradle')

I then get this error:

Stack trace
Caused by: org.gradle.api.internal.plugins.PluginApplicationException: Failed to apply plugin [id 'com.palantir.revapi']
        at org.gradle.api.internal.plugins.DefaultPluginManager.doApply(DefaultPluginManager.java:167)
        at org.gradle.api.internal.plugins.DefaultPluginManager.apply(DefaultPluginManager.java:136)
        at org.gradle.api.internal.plugins.DefaultObjectConfigurationAction.applyType(DefaultObjectConfigurationAction.java:129)
        at org.gradle.api.internal.plugins.DefaultObjectConfigurationAction.access$200(DefaultObjectConfigurationAction.java:38)
        at org.gradle.api.internal.plugins.DefaultObjectConfigurationAction$3.run(DefaultObjectConfigurationAction.java:93)
        at org.gradle.api.internal.plugins.DefaultObjectConfigurationAction.execute(DefaultObjectConfigurationAction.java:152)
        at org.gradle.api.internal.project.AbstractPluginAware.apply(AbstractPluginAware.java:49)
        at org.gradle.api.internal.project.ProjectScript.apply(ProjectScript.java:41)
        at org.gradle.api.Script$apply$1.callCurrent(Unknown Source)
        at build_5noics6iamd59kl2acirukei.run(/Users/dsanduleac/code/external/palantir-java-format-2/palantir-java-format-api/build.gradle:2)
        at org.gradle.groovy.scripts.internal.DefaultScriptRunnerFactory$ScriptRunnerImpl.run(DefaultScriptRunnerFactory.java:91)
        ... 187 more
Caused by: java.util.ConcurrentModificationException
        at org.gradle.api.internal.collections.FilteredCollection$FilteringIterator.findNext(FilteredCollection.java:121)
        at org.gradle.api.internal.collections.FilteredCollection$FilteringIterator.next(FilteredCollection.java:140)
        at org.gradle.api.internal.DefaultDomainObjectCollection$IteratorImpl.next(DefaultDomainObjectCollection.java:479)
        at com.palantir.gradle.revapi.RevapiPlugin.apply(RevapiPlugin.java:60)
        at com.palantir.gradle.revapi.RevapiPlugin.apply(RevapiPlugin.java:34)
        at org.gradle.api.internal.plugins.ImperativeOnlyPluginTarget.applyImperative(ImperativeOnlyPluginTarget.java:43)
        at org.gradle.api.internal.plugins.RuleBasedPluginTarget.applyImperative(RuleBasedPluginTarget.java:51)
        at org.gradle.api.internal.plugins.DefaultPluginManager.addPlugin(DefaultPluginManager.java:181)
        at org.gradle.api.internal.plugins.DefaultPluginManager.access$300(DefaultPluginManager.java:51)
        at org.gradle.api.internal.plugins.DefaultPluginManager$AddPluginBuildOperation.run(DefaultPluginManager.java:276)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:402)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:394)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:92)
        at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31)
        at org.gradle.api.internal.plugins.DefaultPluginManager$2.execute(DefaultPluginManager.java:159)
        at org.gradle.api.internal.plugins.DefaultPluginManager$2.execute(DefaultPluginManager.java:156)
        at org.gradle.configuration.internal.DefaultUserCodeApplicationContext.apply(DefaultUserCodeApplicationContext.java:49)
        at org.gradle.api.internal.plugins.DefaultPluginManager.doApply(DefaultPluginManager.java:156)
        ... 197 more

What did you want to happen?

No crash.

Vulnerabilities

What happened?

The dependencies of this plugin have some vulnerabilies.
They are reported by the gradle/actions/dependency-submission action (for example) and show up in the GitHub Dependabot > Security tab.

Screenshot 2024-02-22 at 14 46 20 Screenshot 2024-02-22 at 14 46 38 Screenshot 2024-02-22 at 14 46 59

What did you want to happen?

No vulnerabilities.

revapi plugin doesn't detect change after upgrading to gradle 8.2.0/8.3.0

What happened?

I'm using revapi gradle plugin 1.7.0. With Gradle 8.1.1, all works fine. If I change an API, revapi detects it and my build fails with API/ABI breaks detected.. All good.

However, since Gradle 8.2.0 (and it's still the case with Gradle 8.3.0), API changes are not detected instead of failing when an API breaks is detected.

As it's with the same revapi gradle plugin version (1.7.0), I suspect a change in Gradle 8.2 (maybe needing a change in revapi plugin). I gonna do a git bisect to find what changed in Gradle 8.2 (compared to Gradle 8.1).

What did you want to happen?

revapi plugin should work with Gradle 8.2+.

Guidance or Ideas on support ignoring certain classes of changes

What happened?

Feature request / tool usage assistance!

What did you want to happen?

The Revapi project defines a way to ignore certain types of changes, for example, adding a method to an interface is called out in the docs (though that way of using the maven plugin is apparently deprecated but the idea remains the same)

We’ve begun using gradle-revapi in the Apache Iceberg project, and we’d very much like to suppress BREAKS for “method added to interface”, as the way we use the project / perform releases, we don’t generally expect it to be a problem.

Is it possible to ignore certain types of “breaking” changes now with the existing gradle revapi package? I didn’t see anything, so this is partially a feature request.

I’m somewhat new to revapi myself so it’s possible this is already achievable and I just don’t have my configuration files correctly. But this does appear to be possible with the maven revapi plugin.

Thank you for this wonderful plug-in!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.