Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a task to compare public APIs for every stable module. #3183

Merged
merged 15 commits into from
May 7, 2021

Conversation

jkwatson
Copy link
Contributor

@jkwatson jkwatson commented Apr 27, 2021

This adds a japicmp task that will generate a diff of public APIs. By default, it will generate the current local version vs. the latest released version. You can also specify specific versions to compare and generate diffs for with two gradle properties:

For example
./gradlew japicmp -PapiBaseVersion=1.0.0 -PapiNewVersion=1.1.0
will generate diffs between 1.1.0 and 1.0.0.

I would like every PR to include updates to the diff files (if any), but I'm not sure the best way to enforce that.

I would also like, before every release, a maintainer generate the diffs vs. the previous release and make sure that there are no surprise API changes or breakages.

As a baseline, I have generated diffs between 1.1.0 and 1.0.0, for historical completeness, as well as the current diffs vs. the latest.

This code is pretty hacky, so suggestions for improvement are very welcome!

resolves #2692

Comparing source compatibility of against
*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.exporter.zipkin.ZipkinSpanExporter (not serializable)
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
+++ NEW FIELD: PUBLIC(+) STATIC(+) FINAL(+) java.util.logging.Logger baseLogger
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a bummer that I found while working on this. And, why I think we should make something like this check a part of our normal process.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Totally agree with above statement.

@codecov
Copy link

codecov bot commented Apr 27, 2021

Codecov Report

Merging #3183 (8901269) into main (910e66c) will not change coverage.
The diff coverage is n/a.

❗ Current head 8901269 differs from pull request most recent head a741131. Consider uploading reports for the commit a741131 to get more accurate results
Impacted file tree graph

@@     Coverage Diff      @@
##   main   #3183   +/-   ##
============================
============================

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 910e66c...a741131. Read the comment docs.

@@ -0,0 +1,2 @@
Comparing source compatibility of against
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: the lack of versions in the file appears to be due to this bug: melix/japicmp-gradle-plugin#31

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess in the meantime it wouldn't be that hard for us to overwrite the file with a line that has an appropriate version if we want to. But no big deal

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

definitely something we could enhance ourselves with a little sed or something.

@jkwatson jkwatson force-pushed the generate_api_diffs branch from 826b7ed to 891b1ad Compare April 27, 2021 21:46
@jkwatson
Copy link
Contributor Author

Also note that this picked up the API change from #2799 after I rebased. See commit 891b1ad

build.gradle.kts Outdated Show resolved Hide resolved
build.gradle.kts Outdated Show resolved Hide resolved
build.gradle.kts Outdated Show resolved Hide resolved
build.gradle.kts Show resolved Hide resolved
build.gradle.kts Outdated Show resolved Hide resolved
build.gradle.kts Outdated Show resolved Hide resolved
build.gradle.kts Outdated Show resolved Hide resolved
build.gradle.kts Outdated Show resolved Hide resolved
build.gradle.kts Outdated Show resolved Hide resolved
@@ -0,0 +1,2 @@
Comparing source compatibility of against
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it'd be better to aggregate all these into top level, docs/${newVersion}/${archivesBaseName} to get an idea of all the changes in a version more easily.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, at one point I had this implemented and decided it would be better to keep the diffs close to the source, but I don't feel super strongly about that.

Also, I did want to make sure that we saw diffs vs. the latest release. what directory would that end up in, do you think? Or, would we just put the concrete ones up at the top level for the historical records, and put the incremental snapshot changes inside the modules?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'd still be find with diff vs current (docs/current/) to be aggregated, and we get to see all the new API in the next version very easily.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both of my suggestions should have been docs/apidiffs by the way :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool. I'll update this to put everything under docs/apidiffs:

docs/apidiffs/current/<module>.txt
docs/apidiffs/v1.1.0_v1.0.0/<module>.txt

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, moved and regenerated. please take a look.

build.gradle.kts Show resolved Hide resolved
Copy link

@ghost ghost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great stuff, I'd really like to see that in instrumentation as well.

@@ -108,6 +108,8 @@ static Context root() {
* during an invocation to another thread. For example, you may use something like {@code Executor
* dbExecutor = Context.wrapTasks(threadPool)} to ensure calls like {@code dbExecutor.execute(()
* -> database.query())} have {@link Context} available on the thread executing database queries.
*
* @since 1.1.0
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Shows that the tool can be very useful also for documentation purposes.

Comparing source compatibility of against
*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.exporter.zipkin.ZipkinSpanExporter (not serializable)
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
+++ NEW FIELD: PUBLIC(+) STATIC(+) FINAL(+) java.util.logging.Logger baseLogger
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Totally agree with above statement.

@ocelotl
Copy link

ocelotl commented May 5, 2021

This is cool 😎 We are doing something similar in Python.

Copy link
Contributor

@anuraaga anuraaga left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm ok with this as-is, but do have a strongish preference to collecting the docs into one if not in this PR then a follow up

@@ -0,0 +1,2 @@
Comparing source compatibility of against
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'd still be find with diff vs current (docs/current/) to be aggregated, and we get to see all the new API in the next version very easily.

/**
* Locate the project's artifact of a particular version.
*/
fun Project.findArtifact(version: String) : File {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fun with kotlin? :P

@@ -0,0 +1,2 @@
Comparing source compatibility of against
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both of my suggestions should have been docs/apidiffs by the way :)

@@ -0,0 +1,2 @@
Comparing source compatibility of against
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess in the meantime it wouldn't be that hard for us to overwrite the file with a line that has an appropriate version if we want to. But no big deal

dependsOn("jar")
// the japicmp "old" version is either the user-specified one, or the latest release.
val userRequestedBase = project.properties["apiBaseVersion"] as String?
val baselineVersion: String = userRequestedBase ?: latestReleasedVersion
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've never seen this lazy pattern in any other language so far - that's pretty sweet

@jkwatson jkwatson force-pushed the generate_api_diffs branch 2 times, most recently from 11eb235 to 8901269 Compare May 6, 2021 20:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Automatic Binary Compatibility checking of API
3 participants