Skip to content

Commit

Permalink
Add a script to test the current repo state with a set of bazel versi…
Browse files Browse the repository at this point in the history
…ons, and generate a compatibility matrix.
  • Loading branch information
cgruber committed Aug 10, 2019
1 parent ecc8957 commit 3f9752c
Show file tree
Hide file tree
Showing 3 changed files with 207 additions and 0 deletions.
40 changes: 40 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,46 @@ KOTLINC_RELEASE = {
kotlin_repositories(compiler_release = KOTLINC_RELEASE)
```

# Bazel Kotlin Rules compatibility

Which version of *rules_kotlin* can you use with which version of Bazel (best
effort testing)?

| Compatibility | legacy_continued | Errors |
| ---- | ---- | ---- |
| 0.16.0 | ![No] | Compilation failed (Exit 1) |
| 0.16.1 | ![No] | Compilation failed (Exit 1) |
| 0.17.1 | ![No] | Compilation failed (Exit 1) |
| 0.17.2 | ![No] | Compilation failed (Exit 1) |
| 0.18.0 | ![Yes] | |
| 0.18.1 | ![Yes] | |
| 0.19.0 | ![Yes] | |
| 0.19.1 | ![Yes] | |
| 0.19.2 | ![Yes] | |
| 0.20.0 | ![Yes] | |
| 0.21.0 | ![Yes] | |
| 0.22.0 | ![Yes] | |
| 0.23.0 | ![Yes] | |
| 0.23.1 | ![Yes] | |
| 0.23.2 | ![Yes] | |
| 0.24.0 | ![Yes] | |
| 0.24.1 | ![Yes] | |
| 0.25.0 | ![Yes] | |
| 0.25.1 | ![Yes] | |
| 0.25.2 | ![Yes] | |
| 0.25.3 | ![Yes] | |
| 0.26.0 | ![Yes] | |
| 0.26.1 | ![Yes] | |
| 0.27.0 | ![Yes] | |
| 0.27.1 | ![Yes] | |
| 0.27.2 | ![Yes] | |
| 0.28.0 | ![Yes] | |
| 0.28.1 | ![Yes] | |

[Yes]: https://img.shields.io/static/v1.svg?label=&message=Yes&color=green
[No]: https://img.shields.io/static/v1.svg?label=&message=No&color=red
[Unknown]: https://img.shields.io/static/v1.svg?label=&message=???&color=lightgrey

# License

This project is licensed under the [Apache 2.0 license](LICENSE), as are all contributions
Expand Down
132 changes: 132 additions & 0 deletions scripts/test_version.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#!/usr/bin/env kscript

// Build the dagger example using different versions, via bazelisk.

@file:Include("test_version_utils.kt")


val TARGET = "//examples/dagger/..."
val PRE_FLAGS = "--bazelrc=/dev/null"
val BAZEL_EXEC = "bazel $PRE_FLAGS"
// Versions to test.
val VERSIONS = """
0.16.0
0.16.1
0.17.1
0.17.2
0.18.0
0.18.1
0.19.0
0.19.1
0.19.2
0.20.0
0.21.0
0.22.0
0.23.0
0.23.1
0.23.2
0.24.0
0.24.1
0.25.0
0.25.1
0.25.2
0.25.3
0.26.0
0.26.1
0.27.0
0.27.1
0.27.2
0.28.0
0.28.1
""".trimIndent().trim().split("\n")

val VERSION_WIDTH = VERSIONS.map(String::length).max() ?: 10
println("Testing with bazel versions: ${VERSIONS.joinToString(" ")}")

enum class Status { SUCCESS, FAILURE }
data class VerifyResult(
val status: Status,
val code: Int = 0,
val output: String? = null
)

val outputFile = File(if (args.size >= 1) args[0] else "matrix.md")

fun Process.errorText(): String = errorStream.bufferedReader().readText()
fun Process.result(): VerifyResult =
when (this.exitValue()) {
0 -> VerifyResult(Status.SUCCESS, 0, errorText())
else -> VerifyResult(Status.FAILURE, exitValue(), errorText())
}

val matrix = mutableMapOf<String, VerifyResult>()
loop@ for (version in VERSIONS) {
try {
// clean as a fire and forget.
print("Testing version $version...")
print(" cleaning...")
"$BAZEL_EXEC clean".cmd().withEnv("USE_BAZEL_VERSION", version).exec(10)
print(" running...")
val proc: Process =
"$BAZEL_EXEC build $TARGET".cmd().withEnv("USE_BAZEL_VERSION", version).exec(10)
with(proc.result()) {
matrix[version] = this
if (status == Status.FAILURE) {
print(" writing log...")
val outputlog = "Execution log for $BAZEL_EXEC build $TARGET\n${output ?: "No log"}"
outputFile.resolveSibling("bazel_$version.log").writeText(outputlog)
}
println(" done: ${this.status}")
}
} catch (err: Exception) {
println("${err.javaClass.simpleName} while running bazel: ${err.message}")
err.printStackTrace()
}
}

fun format(matrix: Map<String, VerifyResult>): String =
matrix.entries
.map { (version, result) ->
val status = when (result.status) {
Status.SUCCESS -> "![Yes]"
Status.FAILURE -> "![No]"
else -> "![Unknown]"
}
val error = when {
result.output == null -> ""
result.output.contains("error 404") -> "404 error fetching bazel"
result.output.contains("ERROR") -> {
result.output
.lines()
.filter { it.contains("ERROR") }
.joinToString("<br />")
}
result.output.contains("FATAL") -> {
result.output
.lines()
.filter { it.contains("FATAL") }
.map { it.after("] ").trim() }
.joinToString("<br />")
}
else -> ""
}
"\n | ${version.pad()} | ${status.pad(6)} | $error |"
}
.joinToString("")
println("writing markdown to $outputFile")
outputFile.writeText(
"""
# Bazel Kotlin Rules compatibility
Which version of *rules_kotlin* can you use with which version of Bazel (best
effort testing)?
| Compatibility | Current | Errors |
| ---- | ---- | ---- |${format(matrix)}
[Yes]: https://img.shields.io/static/v1.svg?label=&message=Yes&color=green
[No]: https://img.shields.io/static/v1.svg?label=&message=No&color=red
[Unknown]: https://img.shields.io/static/v1.svg?label=&message=???&color=lightgrey
""".trimIndent()
)
35 changes: 35 additions & 0 deletions scripts/test_version_utils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import java.util.concurrent.TimeUnit
import java.io.File

fun String.cmd(workingDir: File = File(".")): ProcessBuilder {
val parts = this.split("\\s".toRegex())
return ProcessBuilder(*parts.toTypedArray())
.directory(workingDir)
.redirectOutput(ProcessBuilder.Redirect.PIPE)
.redirectError(ProcessBuilder.Redirect.PIPE)
}

fun List<String>.parseMap(separator: String = "="): Map<String, String> =
this.map { if (!it.trim().isEmpty()) it.split(separator) else null }
.filterNotNull()
.map { (key, value) -> key to value }
.toMap()

fun ProcessBuilder.withEnv(key: String, value: String): ProcessBuilder {
this.environment()[key] = value
return this
}

/** Starts the process and blocks until it terminates or the timeout is reached. */
fun ProcessBuilder.exec(timeout: Long = 30, unit: TimeUnit = TimeUnit.MINUTES): Process =
this.start().also { it.waitFor(timeout, unit) }

// padEnd with a default.
fun String.pad(width: Int = VERSION_WIDTH) = this.padEnd(width)

/** Returns the substring after the delimiter, or itself if the delelimiter is not found */
fun String.after(delimiter: String) =
with(this.split(delimiter, limit = 2)) {
if (size > 1) this[1]
else this[0]
}

0 comments on commit 3f9752c

Please sign in to comment.