Skip to content

Commit e0d11b9

Browse files
committed
Adopt new Roseau features
* Exclude internal APIs from check * Ignore accepted changes * Fail on unignored breaking change * Generate HTML report (cherry picked from commit 4a249e2)
1 parent 6d61c78 commit e0d11b9

File tree

4 files changed

+84
-7
lines changed

4 files changed

+84
-7
lines changed

gradle/config/roseau/config.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
common:
2+
excludes:
3+
annotations:
4+
- name: org.apiguardian.api.API
5+
args: { status: org.apiguardian.api.API$Status.INTERNAL }

gradle/plugins/backward-compatibility/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ dependencies {
99
implementation("junitbuild.base:dsl-extensions")
1010
implementation(libs.plugins.download.markerCoordinates)
1111
implementation(libs.plugins.japicmp.markerCoordinates)
12+
implementation(libs.jackson.dataformat.yaml)
1213
}
1314

1415
tasks.compileJava {

gradle/plugins/backward-compatibility/src/main/kotlin/junitbuild.backward-compatibility.gradle.kts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,13 @@ val roseau by tasks.registering(RoseauDiff::class) {
8181
libraryClasspath.from(configurations.compileClasspath)
8282
v1 = downloadPreviousReleaseJar.map { it.outputFiles.single() }
8383
v2 = tasks.jar.flatMap { it.archiveFile }.map { it.asFile }
84-
csvReport = layout.buildDirectory.file("reports/roseau/breaking-changes.csv")
84+
configFile = rootProject.layout.projectDirectory.file("gradle/config/roseau/config.yaml")
85+
rootProject.layout.projectDirectory.file("gradle/config/roseau/accepted-breaking-changes.csv").asFile.let {
86+
if (it.exists()) {
87+
acceptedChangesCsvFile = it
88+
}
89+
}
90+
reportDir = layout.buildDirectory.dir("reports/roseau")
8591
}
8692

8793
val japicmp by tasks.registering(JapicmpTask::class) {

gradle/plugins/backward-compatibility/src/main/kotlin/junitbuild/compatibility/roseau/RoseauDiff.kt

Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,27 @@
11
package junitbuild.compatibility.roseau
22

3+
import com.fasterxml.jackson.databind.ObjectMapper
4+
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
5+
import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator.Feature.WRITE_DOC_START_MARKER
36
import org.gradle.api.DefaultTask
7+
import org.gradle.api.GradleException
48
import org.gradle.api.file.ConfigurableFileCollection
9+
import org.gradle.api.file.DirectoryProperty
510
import org.gradle.api.file.RegularFileProperty
611
import org.gradle.api.tasks.CacheableTask
712
import org.gradle.api.tasks.Classpath
813
import org.gradle.api.tasks.CompileClasspath
9-
import org.gradle.api.tasks.OutputFile
14+
import org.gradle.api.tasks.InputFile
15+
import org.gradle.api.tasks.Optional
16+
import org.gradle.api.tasks.OutputDirectory
17+
import org.gradle.api.tasks.PathSensitive
18+
import org.gradle.api.tasks.PathSensitivity
1019
import org.gradle.api.tasks.TaskAction
1120
import org.gradle.kotlin.dsl.assign
1221
import org.gradle.process.ExecOperations
1322
import java.io.ByteArrayOutputStream
23+
import java.io.File
24+
import java.io.FileOutputStream
1425
import javax.inject.Inject
1526

1627
@CacheableTask
@@ -31,12 +42,29 @@ abstract class RoseauDiff : DefaultTask() {
3142
@get:CompileClasspath
3243
abstract val v2: RegularFileProperty
3344

34-
@get:OutputFile
35-
abstract val csvReport: RegularFileProperty
45+
@get:InputFile
46+
@get:PathSensitive(PathSensitivity.NONE)
47+
abstract val configFile: RegularFileProperty
48+
49+
@get:InputFile
50+
@get:PathSensitive(PathSensitivity.NONE)
51+
@get:Optional
52+
abstract val acceptedChangesCsvFile: RegularFileProperty
53+
54+
@get:OutputDirectory
55+
abstract val reportDir: DirectoryProperty
3656

3757
@TaskAction
3858
fun run() {
39-
csvReport.get().asFile.parentFile.mkdirs()
59+
val reportDir = reportDir.get().asFile.absoluteFile
60+
val reports = listOf(
61+
Report(reportDir.resolve("breaking-changes.html"), Report.Format.HTML),
62+
Report(reportDir.resolve("breaking-changes.csv"), Report.Format.CSV)
63+
)
64+
reports.forEach { report -> report.file.delete() }
65+
66+
val effectiveConfigFile = writeEffectiveConfigFile(reports)
67+
4068
val output = ByteArrayOutputStream()
4169
val result = execOperations.javaexec {
4270
mainClass = "io.github.alien.roseau.cli.RoseauCLI"
@@ -46,16 +74,53 @@ abstract class RoseauDiff : DefaultTask() {
4674
"--v1", v1.get().asFile.absolutePath,
4775
"--v2", v2.get().asFile.absolutePath,
4876
"--diff",
49-
"--report", csvReport.get().asFile.absolutePath,
50-
"--fail",
77+
"--fail-on-bc",
78+
"--config", effectiveConfigFile.absolutePath,
5179
)
80+
if (acceptedChangesCsvFile.isPresent) {
81+
args("--ignored", acceptedChangesCsvFile.get().asFile.absolutePath)
82+
}
5283
standardOutput = output
5384
errorOutput = output
5485
isIgnoreExitValue = true
5586
}
5687
if (result.exitValue != 0) {
5788
System.out.write(output.toByteArray())
5889
System.out.flush()
90+
reports.filter { it.file.exists() }.let { writtenReports ->
91+
if (writtenReports.isNotEmpty()) {
92+
println("Reports:")
93+
writtenReports.forEach {
94+
println("- ${it.format.name}: ${it.file.toURI()}")
95+
}
96+
}
97+
}
98+
if (result.exitValue == 1) {
99+
throw GradleException("Breaking API changes detected")
100+
}
101+
result.assertNormalExitValue()
102+
}
103+
}
104+
105+
private fun writeEffectiveConfigFile(reports: List<Report>): File {
106+
val effectiveConfigFile = temporaryDir.resolve("roseau.yaml")
107+
configFile.get().asFile.copyTo(effectiveConfigFile, overwrite = true)
108+
FileOutputStream(effectiveConfigFile, true).bufferedWriter().use { writer ->
109+
val yamlFactory = YAMLFactory.builder().disable(WRITE_DOC_START_MARKER).build()
110+
val mapper = ObjectMapper(yamlFactory)
111+
mapper.writeValue(
112+
writer, mapOf(
113+
"reports" to reports
114+
)
115+
)
116+
}
117+
return effectiveConfigFile
118+
}
119+
120+
private data class Report(val file: File, val format: Format) {
121+
enum class Format {
122+
HTML, CSV
59123
}
60124
}
125+
61126
}

0 commit comments

Comments
 (0)