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

[Backport] [2.x] Reconsider the breaking changes check policy to detect breaking changes against released versions (#13292) #13310

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/detect-breaking-change.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ jobs:
- uses: gradle/gradle-build-action@v3
with:
cache-disabled: true
arguments: japicmp
# The 2.14.0 is already reporting breaking changes (see please https://github.com/opensearch-project/OpenSearch/issues/13308)
arguments: japicmp -Djapicmp.compare.version=2.14.0-SNAPSHOT
gradle-version: 8.7
build-root-directory: server
- if: failure()
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- Improve built-in secure transports support ([#12907](https://github.com/opensearch-project/OpenSearch/pull/12907))
- Update links to documentation in rest-api-spec ([#13043](https://github.com/opensearch-project/OpenSearch/pull/13043))
- Refactoring globMatch using simpleMatchWithNormalizedStrings from Regex ([#13104](https://github.com/opensearch-project/OpenSearch/pull/13104))
- [BWC and API enforcement] Reconsider the breaking changes check policy to detect breaking changes against released versions ([#13292](https://github.com/opensearch-project/OpenSearch/pull/13292))

### Deprecated

Expand Down
15 changes: 15 additions & 0 deletions DEVELOPER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
- [Developer API](#developer-api)
- [User API](#user-api)
- [Experimental Development](#experimental-development)
- [API Compatibility Checks](#api-compatibility-checks)
- [Backports](#backports)
- [LineLint](#linelint)
- [Lucene Snapshots](#lucene-snapshots)
Expand Down Expand Up @@ -607,6 +608,20 @@ a LTS feature but with additional guard rails and communication mechanisms to si
release, or be removed altogether. Any Developer or User APIs implemented along with the experimental feature should be marked with `@ExperimentalApi` (or documented as
`@opensearch.experimental`) annotation to signal the implementation is not subject to LTS and does not follow backwards compatibility guidelines.

#### API Compatibility Checks

The compatibility checks for public APIs are performed using [japicmp](https://siom79.github.io/japicmp/) and are available as separate Gradle tasks (those are run on demand at the moment):

```
./gradlew japicmp
```

By default, the API compatibility checks are run against the latest released version of the OpenSearch, however the target version to compare to could be provided using system property during the build, fe.:

```
./gradlew japicmp -Djapicmp.compare.version=2.14.0-SNAPSHOT
```

### Backports

The Github workflow in [`backport.yml`](.github/workflows/backport.yml) creates backport PRs automatically when the original PR with an appropriate label `backport <backport-branch-name>` is merged to main with the backport workflow run successfully on the PR. For example, if a PR on main needs to be backported to `1.x` branch, add a label `backport 1.x` to the PR and make sure the backport workflow runs on the PR along with other checks. Once this PR is merged to main, the workflow will create a backport PR to the `1.x` branch.
Expand Down
60 changes: 41 additions & 19 deletions server/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,22 @@ tasks.named("testingConventions").configure {
}
}

// Set to current version by default
def japicmpCompareTarget = System.getProperty("japicmp.compare.version")
if (japicmpCompareTarget == null) { /* use latest released version */
// Read the list from maven central.
// Fetch the metadata and parse the xml into Version instances, pick the latest one
japicmpCompareTarget = new URL('https://repo1.maven.org/maven2/org/opensearch/opensearch/maven-metadata.xml').openStream().withStream { s ->
new XmlParser().parse(s)
.versioning.versions.version
.collect { it.text() }.findAll { it ==~ /\d+\.\d+\.\d+/ }
.collect { org.opensearch.gradle.Version.fromString(it) }
.toSorted()
.last()
.toString()
}
}

def generateModulesList = tasks.register("generateModulesList") {
List<String> modules = project(':modules').subprojects.collect { it.name }
File modulesFile = new File(buildDir, 'generated-resources/modules.txt')
Expand Down Expand Up @@ -416,53 +432,59 @@ tasks.named("sourcesJar").configure {
}
}

/** Compares the current build against a snapshot build */
/** Compares the current build against a laltest released version or the version supplied through 'japicmp.compare.version' system property */
tasks.register("japicmp", me.champeau.gradle.japicmp.JapicmpTask) {
oldClasspath.from(files("${buildDir}/snapshot/opensearch-${version}.jar"))
logger.info("Comparing public APIs from ${version} to ${japicmpCompareTarget}")
oldClasspath.from(files("${buildDir}/japicmp-target/opensearch-${japicmpCompareTarget}.jar"))
newClasspath.from(tasks.named('jar'))
onlyModified = true
failOnModification = true
ignoreMissingClasses = true
annotationIncludes = ['@org.opensearch.common.annotation.PublicApi', '@org.opensearch.common.annotation.DeprecatedApi']
txtOutputFile = layout.buildDirectory.file("reports/java-compatibility/report.txt")
htmlOutputFile = layout.buildDirectory.file("reports/java-compatibility/report.html")
dependsOn downloadSnapshot
dependsOn downloadJapicmpCompareTarget
}

/** 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')
}
logger.info("Public APIs changes incompatiable with ${japicmpCompareTarget} target have been detected")
}
}

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

repositories {
maven {
url mavenSnapshotRepoUrl
}
// Add repository for snapshot artifacts if japicmp compare target version is snapshot
if (japicmpCompareTarget.endsWith("-SNAPSHOT")) {
def repos = project.getRepositories();
MavenArtifactRepository opensearchRepo = repos.maven(repo -> {
repo.setName("opensearch-snapshots");
repo.setUrl(mavenSnapshotRepoUrl);
});

repos.exclusiveContent(exclusiveRepo -> {
exclusiveRepo.filter(descriptor -> descriptor.includeGroup(groupId));
exclusiveRepo.forRepositories(opensearchRepo);
});
}

configurations {
snapshotArtifact
japicmpCompareTargetArtifact {
exclude group: 'org.apache.lucene'
}
}

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

from configurations.snapshotArtifact
into "$buildDir/snapshot"
from configurations.japicmpCompareTargetArtifact
into "$buildDir/japicmp-target"
}

/** Check if the sha is in the current history */
Expand Down
Loading