Skip to content

Commit

Permalink
Detect breaking changes on pull requests
Browse files Browse the repository at this point in the history
Adds a gradle task and github action to check for breaking changes made
to the APIs in server by running comparison against most resent snapshot
build on sonotype maven repository.

Only classes with @publicapi are checked for breaking changes.

Uses japicmp to perform the comparison against the jar files, learn
more https://siom79.github.io/japicmp/

Signed-off-by: Peter Nied <[email protected]>
  • Loading branch information
peternied committed Mar 28, 2024
1 parent eba3b57 commit 0262eb6
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 1 deletion.
24 changes: 24 additions & 0 deletions .github/workflows/detect-breaking-change.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: "Detect Breaking Changes"
on: [push, pull_request]
jobs:
detect-breaking-change:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: temurin # Temurin is a distribution of adoptium
java-version: 21
- uses: gradle/gradle-build-action@v3
with:
arguments: japicmp
gradle-version: 8.7
build-root-directory: server
- if: failure()
run: cat server/build/reports/java-compatibility/report.txt
- if: failure()
uses: actions/upload-artifact@v4
with:
name: java-compatibility-report.html
path: ${{ github.workspace }}/server/build/reports/java-compatibility/report.html

1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- Allow setting KEYSTORE_PASSWORD through env variable ([#12865](https://github.com/opensearch-project/OpenSearch/pull/12865))
- [Concurrent Segment Search] Perform buildAggregation concurrently and support Composite Aggregations ([#12697](https://github.com/opensearch-project/OpenSearch/pull/12697))
- [Concurrent Segment Search] Disable concurrent segment search for system indices and throttled requests ([#12954](https://github.com/opensearch-project/OpenSearch/pull/12954))
- Detect breaking changes on pull requests ([#9044](https://github.com/opensearch-project/OpenSearch/pull/9044))

### Dependencies
- Bump `org.apache.commons:commons-configuration2` from 2.10.0 to 2.10.1 ([#12896](https://github.com/opensearch-project/OpenSearch/pull/12896))
Expand Down
79 changes: 79 additions & 0 deletions server/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ plugins {
id('opensearch.publish')
id('opensearch.internal-cluster-test')
id('opensearch.optional-dependencies')
id('me.champeau.gradle.japicmp') version '0.4.2'
}

publishing {
Expand Down Expand Up @@ -378,3 +379,81 @@ tasks.named("sourcesJar").configure {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
}

/** Compares the current build against a snapshot build */
tasks.register("japicmp", me.champeau.gradle.japicmp.JapicmpTask) {
oldClasspath.from(files("${buildDir}/snapshot/opensearch-${version}.jar"))
newClasspath.from(tasks.named('jar'))
onlyModified = true
failOnModification = true
ignoreMissingClasses = true
annotationIncludes = ['@org.opensearch.common.annotation.PublicApi']
txtOutputFile = layout.buildDirectory.file("reports/java-compatibility/report.txt")
htmlOutputFile = layout.buildDirectory.file("reports/java-compatibility/report.html")
dependsOn downloadSnapshot
}

/** If the Java API Comparison task failed, print a hint if the change should be merged from its target branch */
gradle.taskGraph.afterTask { Task task, TaskState state ->
if (task.name == 'japicmp' && state.failure != null) {
def sha = getGitShaFromJar("${buildDir}/snapshot/opensearch-${version}.jar")
logger.info("Incompatiable java api from snapshot jar built off of commit ${sha}")

if (!inHistory(sha)) {
logger.warn('\u001B[33mPlease merge from the target branch and run this task again.\u001B[0m')
}
}
}

/** Downloads latest snapshot from maven repository */
tasks.register("downloadSnapshot", Copy) {
def mavenSnapshotRepoUrl = "https://aws.oss.sonatype.org/content/repositories/snapshots/"
def groupId = "org.opensearch"
def artifactId = "opensearch"

repositories {
maven {
url mavenSnapshotRepoUrl
}
}

configurations {
snapshotArtifact
}

dependencies {
snapshotArtifact("${groupId}:${artifactId}:${version}:")
}

from configurations.snapshotArtifact
into "$buildDir/snapshot"
}

/** Check if the sha is in the current history */
def inHistory(String sha) {
try {
def commandCheckSha = "git merge-base --is-ancestor ${sha} HEAD"
commandCheckSha.execute()
return true
} catch (Exception) {
return false
}
}

/** Extracts the Git SHA used to build a jar from its manifest */
def getGitShaFromJar(String jarPath) {
def sha = ''
try {
// Open the JAR file
def jarFile = new java.util.jar.JarFile(jarPath)
// Get the manifest from the JAR file
def manifest = jarFile.manifest
def attributes = manifest.mainAttributes
// Assuming the Git SHA is stored under an attribute named 'Git-SHA'
sha = attributes.getValue('Change')
jarFile.close()
} catch (IOException e) {
println "Failed to read the JAR file: $e.message"
}
return sha
}
2 changes: 1 addition & 1 deletion server/src/main/java/org/opensearch/plugins/Plugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@
*
* @opensearch.api
*/
@PublicApi(since = "1.0.0")
// @PublicApi(since = "1.0.0")
public abstract class Plugin implements Closeable {

/**
Expand Down

0 comments on commit 0262eb6

Please sign in to comment.