From 2b1196651b9bc13c6ce0a310d7d7b52ce725648d Mon Sep 17 00:00:00 2001
From: Vojin Jovanovic
Date: Sat, 15 Nov 2025 19:42:24 +0100
Subject: [PATCH 1/9] Test only the changed libraries on relevant JDKs
---
.github/workflows/checkstyle-skip.yml | 1 +
.github/workflows/checkstyle.yml | 1 +
.../workflows/create-scheduled-release.yml | 2 +-
.github/workflows/scan-docker-images.yml | 4 +-
.github/workflows/test-all-metadata-skip.yml | 17 ---
.github/workflows/test-all-metadata.yml | 6 -
.../workflows/test-changed-metadata-skip.yml | 6 +-
.github/workflows/test-changed-metadata.yml | 8 +-
.../org.graalvm.internal.tck-harness.gradle | 125 ++++++++++++------
.../internal/tck/harness/TckExtension.java | 14 --
10 files changed, 100 insertions(+), 84 deletions(-)
delete mode 100644 .github/workflows/test-all-metadata-skip.yml
diff --git a/.github/workflows/checkstyle-skip.yml b/.github/workflows/checkstyle-skip.yml
index bed200961..365b82c9c 100644
--- a/.github/workflows/checkstyle-skip.yml
+++ b/.github/workflows/checkstyle-skip.yml
@@ -3,6 +3,7 @@ name: "Check code style"
on:
pull_request:
paths:
+ - 'docs/*'
- '**.md'
- 'library-and-framework-list*.json'
diff --git a/.github/workflows/checkstyle.yml b/.github/workflows/checkstyle.yml
index 5ca5ec034..a299a3e40 100644
--- a/.github/workflows/checkstyle.yml
+++ b/.github/workflows/checkstyle.yml
@@ -3,6 +3,7 @@ name: "Check code style"
on:
pull_request:
paths-ignore:
+ - 'docs/*'
- '**.md'
- 'library-and-framework-list*.json'
diff --git a/.github/workflows/create-scheduled-release.yml b/.github/workflows/create-scheduled-release.yml
index 693a62166..7c465d613 100644
--- a/.github/workflows/create-scheduled-release.yml
+++ b/.github/workflows/create-scheduled-release.yml
@@ -31,7 +31,7 @@ jobs:
id: set-matrix
run: |
LATEST_TAG=$(git tag --list | sort -V | tail -1)
- ./gradlew generateMatrixDiffCoordinates -PbaseCommit=$(git show-ref -s $LATEST_TAG) -PnewCommit=$(git rev-parse HEAD)
+ ./gradlew generateChangedCoordinatesMatrix -PbaseCommit=$(git show-ref -s $LATEST_TAG) -PnewCommit=$(git rev-parse HEAD)
release:
needs: get-changed-metadata
diff --git a/.github/workflows/scan-docker-images.yml b/.github/workflows/scan-docker-images.yml
index fbb179262..21a7c11a8 100644
--- a/.github/workflows/scan-docker-images.yml
+++ b/.github/workflows/scan-docker-images.yml
@@ -1,11 +1,11 @@
name: "Scan docker images from the allowed docker images list"
on:
- # we should run this job if somebody wants to add/update allowed docker images
+ # we run this job if somebody wants to add/update allowed docker images
pull_request:
paths:
- 'tests/tck-build-logic/src/main/resources/allowed-docker-images/**'
- # we should run this job once a week to check if new vulnerabilities are found in existing images
+ # we run this job once a week to check if new vulnerabilities are found in existing images
schedule:
- cron: "0 0 * * 6"
diff --git a/.github/workflows/test-all-metadata-skip.yml b/.github/workflows/test-all-metadata-skip.yml
deleted file mode 100644
index a9289b2b3..000000000
--- a/.github/workflows/test-all-metadata-skip.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-name: "Test all metadata"
-
-on:
- push:
- branches:
- - master
- paths:
- - '**.md'
- - 'library-and-framework-list*.json'
- workflow_dispatch:
-
-jobs:
- build:
- name: "π§ͺ All metadata tests have passed"
- runs-on: ubuntu-latest
- steps:
- - run: 'echo "No build required"'
diff --git a/.github/workflows/test-all-metadata.yml b/.github/workflows/test-all-metadata.yml
index 9c4490e11..3c7e003ec 100644
--- a/.github/workflows/test-all-metadata.yml
+++ b/.github/workflows/test-all-metadata.yml
@@ -1,12 +1,6 @@
name: "Test all metadata"
on:
- push:
- branches:
- - master
- paths-ignore:
- - '**.md'
- - 'library-and-framework-list*.json'
workflow_dispatch:
concurrency:
diff --git a/.github/workflows/test-changed-metadata-skip.yml b/.github/workflows/test-changed-metadata-skip.yml
index 81bfd24b3..94cedf047 100644
--- a/.github/workflows/test-changed-metadata-skip.yml
+++ b/.github/workflows/test-changed-metadata-skip.yml
@@ -4,9 +4,9 @@ on:
pull_request:
branches:
- master
- paths:
- - '**.md'
- - 'library-and-framework-list*.json'
+ paths-ignore:
+ - 'metadata/*'
+ - 'tests/*'
jobs:
get-changed-metadata:
diff --git a/.github/workflows/test-changed-metadata.yml b/.github/workflows/test-changed-metadata.yml
index d29dceebb..b8d5e4b94 100644
--- a/.github/workflows/test-changed-metadata.yml
+++ b/.github/workflows/test-changed-metadata.yml
@@ -4,9 +4,9 @@ on:
pull_request:
branches:
- master
- paths-ignore:
- - '**.md'
- - 'library-and-framework-list*.json'
+ paths:
+ - 'metadata/*'
+ - 'tests/*'
concurrency:
group: "workflow = ${{ github.workflow }}, ref = ${{ github.event.ref }}, pr = ${{ github.event.pull_request.id }}"
@@ -35,7 +35,7 @@ jobs:
- name: "πΈοΈ Populate matrix"
id: set-matrix
run: |
- ./gradlew generateMatrixDiffCoordinates -PbaseCommit=${{ github.event.pull_request.base.sha }} -PnewCommit=${{ github.event.pull_request.head.sha }}
+ ./gradlew generateChangedCoordinatesMatrix -PbaseCommit=${{ github.event.pull_request.base.sha }} -PnewCommit=${{ github.event.pull_request.head.sha }}
test-changed-metadata:
name: "π§ͺ ${{ matrix.coordinates }} (GraalVM for JDK ${{ matrix.version }} @ ${{ matrix.os }})"
diff --git a/tests/tck-build-logic/src/main/groovy/org.graalvm.internal.tck-harness.gradle b/tests/tck-build-logic/src/main/groovy/org.graalvm.internal.tck-harness.gradle
index 63b6e3ca7..6edc8d8e6 100644
--- a/tests/tck-build-logic/src/main/groovy/org.graalvm.internal.tck-harness.gradle
+++ b/tests/tck-build-logic/src/main/groovy/org.graalvm.internal.tck-harness.gradle
@@ -10,7 +10,7 @@ plugins {
}
import groovy.json.JsonOutput
-import org.graalvm.internal.tck.ContributionTask
+import org.graalvm.internal.tck. ContributionTask
import org.graalvm.internal.tck.DockerTask
import org.graalvm.internal.tck.ConfigFilesChecker
import org.graalvm.internal.tck.ScaffoldTask
@@ -24,6 +24,7 @@ import org.graalvm.internal.tck.harness.tasks.JavaTestInvocationTask
import org.graalvm.internal.tck.harness.tasks.NativeTestCompileInvocationTask
import org.graalvm.internal.tck.updaters.FetchExistingLibrariesWithNewerVersionsTask
import org.graalvm.internal.tck.updaters.GroupUnsupportedLibraries
+import org.gradle.util.internal.VersionNumber
import static org.graalvm.internal.tck.Utils.generateTaskName
@@ -31,6 +32,15 @@ import static org.graalvm.internal.tck.Utils.generateTaskName
logger.lifecycle("GraalVM Reachability Metadata TCK")
logger.lifecycle("---------------------------------")
+def writeGithubOutput(String key, String value) {
+ def path = System.getenv("GITHUB_OUTPUT")
+ if (path == null || path.trim().isEmpty()) {
+ println "${key}=${value}"
+ } else {
+ new File(path).append("${key}=${value}\n")
+ }
+}
+
String coordinateFilter = Objects.requireNonNullElse(project.findProperty("coordinates"), "")
List matchingCoordinates = tck.getMatchingCoordinates(coordinateFilter)
@@ -132,7 +142,6 @@ Provider diff = tasks.register("diff", DefaultTask) { task ->
}
List diffCoordinates = new ArrayList<>()
-boolean testAll = false
if (project.hasProperty("baseCommit")) {
String baseCommit = project.findProperty("baseCommit")
String newCommit = Objects.requireNonNullElse(project.findProperty("newCommit"), "HEAD")
@@ -146,8 +155,6 @@ if (project.hasProperty("baseCommit")) {
dependsOn(taskTaskName)
}
}
-
- testAll = tck.shouldTestAll()
}
def matrixDefault = [
@@ -155,7 +162,7 @@ def matrixDefault = [
"17",
"latest-ea"
],
- "os" : ["ubuntu-latest"] // TODO: Add support for "windows-latest", "macos-latest"
+ "os" : ["ubuntu-latest"]
]
final String METADATA_GROUP = "Metadata"
@@ -169,12 +176,12 @@ Provider generateMatrixMatchingCoordinates = tasks.register("generateMatri
"coordinates": matchingCoordinates
]
matrix.putAll(matrixDefault)
- new File(System.getenv("GITHUB_OUTPUT")).append("matrix=${JsonOutput.toJson(matrix)}\n")
+ writeGithubOutput("matrix", JsonOutput.toJson(matrix))
}
}
-// gradle generateMatrixDiffCoordinates -PbaseCommit= -PnewCommit=
-Provider generateMatrixDiffCoordinates = tasks.register("generateMatrixDiffCoordinates", DefaultTask) { task ->
+// gradle generateChangedCoordinatesMatrix -PbaseCommit= -PnewCommit=
+Provider generateChangedCoordinatesMatrix = tasks.register("generateChangedCoordinatesMatrix", DefaultTask) { task ->
task.setDescription("Returns matrix definition populated with coordinates of changed libraries")
task.setGroup(METADATA_GROUP)
task.doFirst {
@@ -182,40 +189,84 @@ Provider generateMatrixDiffCoordinates = tasks.register("generateMatrixDif
throw new GradleException("Missing 'baseCommit' property! Rerun Gradle with '-PbaseCommit='")
}
- if (diffCoordinates.isEmpty()) {
- def matrix = [
- "coordinates": ["No matches found!"]
- ]
-
- matrix.putAll(matrixDefault)
+ boolean noneFound = diffCoordinates.isEmpty()
+ def matrix = [
+ "coordinates": noneFound ? [] : diffCoordinates
+ ]
+ matrix.putAll(matrixDefault)
+ if (noneFound) {
println "No changed coordinates were found!"
- new File(System.getenv("GITHUB_OUTPUT")).append("matrix=${JsonOutput.toJson(matrix)}\n")
- new File(System.getenv("GITHUB_OUTPUT")).append("none-found=true\n")
- } else {
- def matrix = [
- "coordinates": diffCoordinates
+ }
+ writeGithubOutput("matrix", JsonOutput.toJson(matrix))
+ writeGithubOutput("none-found", noneFound.toString())
+ }
+}
+
+// gradle generateInfrastructureChangedCoordinatesMatrix -PbaseCommit= -PnewCommit=
+Provider generateInfrastructureChangedCoordinatesMatrix = tasks.register("generateInfrastructureChangedCoordinatesMatrix", DefaultTask) { task ->
+ task.setDescription("Returns matrix definition populated with pre-selected coordinates when test infrastructure has changed")
+ task.setGroup(METADATA_GROUP)
+ task.doFirst {
+ if (!project.hasProperty("baseCommit")) {
+ throw new GradleException("Missing 'baseCommit' property! Rerun Gradle with '-PbaseCommit='")
+ }
+ String baseCommit = project.findProperty("baseCommit")
+ String newCommit = Objects.requireNonNullElse(project.findProperty("newCommit"), "HEAD")
+
+ // Detect changes in test infrastructure (build logic and workflows)
+ def baos = new ByteArrayOutputStream()
+ project.exec {
+ standardOutput = baos
+ commandLine 'git', 'diff', '--name-only', '--diff-filter=ACMRT', baseCommit, newCommit
+ }
+ List changedFiles = baos.toString("UTF-8").split("\\r?\\n") as List
+ boolean infraChanged = changedFiles.any { it.startsWith('tests/tck-build-logic') || it.startsWith('.github/workflows') }
+
+ List selected = []
+ if (infraChanged) {
+ // Pre-selected modules; keep stable for infra verification
+ List preselectedModules = [
+ 'org.bouncycastle:bcpkix-jdk15on',
+ 'org.bouncycastle:bcpkix-jdk18on',
+ 'io.netty:netty-common',
+ 'io.grpc:grpc-core',
+ 'org.postgresql:postgresql',
+ 'org.apache.kafka:kafka-clients',
+ 'com.zaxxer:HikariCP',
+ 'org.hibernate.validator:hibernate-validator',
+ 'io.undertow:undertow-core',
+ 'com.hazelcast:hazelcast'
]
- matrix.putAll(matrixDefault)
-
- /**
- * if we changed some files from tck-build-logic or github workflows, we must run all tests
- * to check if we accidentally broke something. In this case, we will have a lots of tests, so we can't
- * run them with all possible JDK versions, because we will hit the following error:
- * Strategy expansion exceeded 256 results for job 'test-changed-metadata'
- */
- if (!testAll) {
- /**
- * when we are introducing a new metadata, we should test it against all versions,
- * not just the oldest and the newest one (which we are testing by default)
- */
- matrix.version.add("21")
- matrix.version.add("25")
- matrix.version.add("latest-ea")
+ preselectedModules.each { module ->
+ List matches = tck.getMatchingCoordinates(module)
+ if (!matches.isEmpty()) {
+ def withVersions = matches.collect { c ->
+ def v = c.substring(c.lastIndexOf(':') + 1)
+ [coord: c, ver: v]
+ }
+ def latest = withVersions.max { a, b -> VersionNumber.parse(a.ver) <=> VersionNumber.parse(b.ver) }
+ selected.add(latest.coord)
+ } else {
+ logger.lifecycle("No tested versions found for ${module}, skipping")
+ }
+ }
+ }
+
+ boolean noneFound = !infraChanged || selected.isEmpty()
+ def matrix = [
+ "coordinates": noneFound ? [] : selected
+ ]
+ matrix.putAll(matrixDefault)
+ if (noneFound) {
+ if (!infraChanged) {
+ println "No test infrastructure changes detected."
+ } else {
+ println "Test infrastructure changed, but no pre-selected coordinates could be resolved."
}
- new File(System.getenv("GITHUB_OUTPUT")).append("matrix=${JsonOutput.toJson(matrix)}\n")
- new File(System.getenv("GITHUB_OUTPUT")).append("none-found=false\n")
}
+ writeGithubOutput("matrix", JsonOutput.toJson(matrix))
+ writeGithubOutput("none-found", noneFound.toString())
}
}
diff --git a/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/TckExtension.java b/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/TckExtension.java
index eb31d97c4..8937516cb 100644
--- a/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/TckExtension.java
+++ b/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/TckExtension.java
@@ -119,12 +119,6 @@ Path getTestDir(String coordinates) {
throw new RuntimeException("Missing test-directory for coordinates `" + coordinates + "`");
}
- private boolean shouldTestAll = false;
-
- public boolean shouldTestAll() {
- return shouldTestAll;
- }
-
/**
* Returns a list of coordinates that match changed files between baseCommit and newCommit.
*
@@ -142,13 +136,11 @@ List diffCoordinates(String baseCommit, String newCommit) {
List diffFiles = Arrays.asList(output.split("\\r?\\n"));
Path workflowsRoot = repoRoot().resolve(".github").resolve("workflows");
- AtomicBoolean testAll = new AtomicBoolean(false);
// Group files by if they belong to 'metadata' or 'test' directory structures.
Map> changed = diffFiles.stream()
.map(line -> repoRoot().resolve(line))
.collect(Collectors.groupingBy((Path path) -> {
if (path.startsWith(tckRoot()) || path.startsWith(workflowsRoot)) {
- testAll.set(true);
return "logic";
} else if (path.startsWith(testRoot())) {
return "test";
@@ -159,12 +151,6 @@ List diffCoordinates(String baseCommit, String newCommit) {
}
}));
- if (testAll.get()) {
- shouldTestAll = true;
- // If tck was changed we should retest everything, just to be safe.
- return getMatchingCoordinates("");
- }
-
// if we didn't change any of metadata, tests or logic we don't need to test anything
if (changed.get("metadata") != null && changed.get("metadata").isEmpty()
&& changed.get("test") != null && changed.get("test").isEmpty()
From ded35092dbb774db75171b4c8569fc259d3c005f Mon Sep 17 00:00:00 2001
From: Vojin Jovanovic
Date: Sat, 15 Nov 2025 20:06:58 +0100
Subject: [PATCH 2/9] Add infrastructure-changed matrix
---
.../org.graalvm.internal.tck-harness.gradle | 67 +++++++------------
1 file changed, 25 insertions(+), 42 deletions(-)
diff --git a/tests/tck-build-logic/src/main/groovy/org.graalvm.internal.tck-harness.gradle b/tests/tck-build-logic/src/main/groovy/org.graalvm.internal.tck-harness.gradle
index 6edc8d8e6..644c96024 100644
--- a/tests/tck-build-logic/src/main/groovy/org.graalvm.internal.tck-harness.gradle
+++ b/tests/tck-build-logic/src/main/groovy/org.graalvm.internal.tck-harness.gradle
@@ -10,7 +10,7 @@ plugins {
}
import groovy.json.JsonOutput
-import org.graalvm.internal.tck. ContributionTask
+import org.graalvm.internal.tck.ContributionTask
import org.graalvm.internal.tck.DockerTask
import org.graalvm.internal.tck.ConfigFilesChecker
import org.graalvm.internal.tck.ScaffoldTask
@@ -197,6 +197,10 @@ Provider generateChangedCoordinatesMatrix = tasks.register("generateChange
if (noneFound) {
println "No changed coordinates were found!"
}
+
+ matrix.version.add("21")
+ matrix.version.add("25")
+
writeGithubOutput("matrix", JsonOutput.toJson(matrix))
writeGithubOutput("none-found", noneFound.toString())
}
@@ -207,25 +211,10 @@ Provider generateInfrastructureChangedCoordinatesMatrix = tasks.register("
task.setDescription("Returns matrix definition populated with pre-selected coordinates when test infrastructure has changed")
task.setGroup(METADATA_GROUP)
task.doFirst {
- if (!project.hasProperty("baseCommit")) {
- throw new GradleException("Missing 'baseCommit' property! Rerun Gradle with '-PbaseCommit='")
- }
- String baseCommit = project.findProperty("baseCommit")
- String newCommit = Objects.requireNonNullElse(project.findProperty("newCommit"), "HEAD")
-
- // Detect changes in test infrastructure (build logic and workflows)
- def baos = new ByteArrayOutputStream()
- project.exec {
- standardOutput = baos
- commandLine 'git', 'diff', '--name-only', '--diff-filter=ACMRT', baseCommit, newCommit
- }
- List changedFiles = baos.toString("UTF-8").split("\\r?\\n") as List
- boolean infraChanged = changedFiles.any { it.startsWith('tests/tck-build-logic') || it.startsWith('.github/workflows') }
-
List selected = []
- if (infraChanged) {
- // Pre-selected modules; keep stable for infra verification
- List preselectedModules = [
+ boolean infraChanged = true
+ // Pre-selected modules; keep stable for infra verification
+ List preselectedModules = [
'org.bouncycastle:bcpkix-jdk15on',
'org.bouncycastle:bcpkix-jdk18on',
'io.netty:netty-common',
@@ -236,37 +225,31 @@ Provider generateInfrastructureChangedCoordinatesMatrix = tasks.register("
'org.hibernate.validator:hibernate-validator',
'io.undertow:undertow-core',
'com.hazelcast:hazelcast'
- ]
-
- preselectedModules.each { module ->
- List matches = tck.getMatchingCoordinates(module)
- if (!matches.isEmpty()) {
- def withVersions = matches.collect { c ->
- def v = c.substring(c.lastIndexOf(':') + 1)
- [coord: c, ver: v]
- }
- def latest = withVersions.max { a, b -> VersionNumber.parse(a.ver) <=> VersionNumber.parse(b.ver) }
- selected.add(latest.coord)
- } else {
- logger.lifecycle("No tested versions found for ${module}, skipping")
+ ]
+ preselectedModules.each { module ->
+ List matches = tck.getMatchingCoordinates(module)
+ if (!matches.isEmpty()) {
+ def withVersions = matches.collect { c ->
+ def v = c.substring(c.lastIndexOf(':') + 1)
+ [coord: c, ver: v]
}
+ def latest = withVersions.max { a, b -> VersionNumber.parse(a.ver) <=> VersionNumber.parse(b.ver) }
+ selected.add(latest.coord)
+ } else {
+ throw new GradleException("No tested versions found for ${module}, skipping")
}
}
- boolean noneFound = !infraChanged || selected.isEmpty()
def matrix = [
- "coordinates": noneFound ? [] : selected
+ "coordinates": selected
]
matrix.putAll(matrixDefault)
- if (noneFound) {
- if (!infraChanged) {
- println "No test infrastructure changes detected."
- } else {
- println "Test infrastructure changed, but no pre-selected coordinates could be resolved."
- }
- }
+
+ matrix.version.add("21")
+ matrix.version.add("25")
+
writeGithubOutput("matrix", JsonOutput.toJson(matrix))
- writeGithubOutput("none-found", noneFound.toString())
+ writeGithubOutput("none-found", "false")
}
}
From d3a07fa3780e1408d27bfffdb7791637f35195e6 Mon Sep 17 00:00:00 2001
From: Vojin Jovanovic
Date: Sat, 15 Nov 2025 22:09:52 +0100
Subject: [PATCH 3/9] Add separate tests for changed infrastructure
---
.github/CODEOWNERS | 3 +-
.../test-changed-infrastructure-skip.yml | 25 +++++
.../workflows/test-changed-infrastructure.yml | 101 ++++++++++++++++++
.../workflows/test-changed-metadata-skip.yml | 2 +-
.github/workflows/test-changed-metadata.yml | 2 +-
5 files changed, 130 insertions(+), 3 deletions(-)
create mode 100644 .github/workflows/test-changed-infrastructure-skip.yml
create mode 100644 .github/workflows/test-changed-infrastructure.yml
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index ca70f2617..d3c37ebb6 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1,5 +1,6 @@
metadata/* @oracle/graalvm-reachability-maintainer
-tests/* @oracle/graalvm-reachability-maintainer
+tests/src/* @oracle/graalvm-reachability-maintainer
+tests/tck-build-logic/* @vjovanov
tests/tck-build-logic/src/main/resources/allowed-docker-images/* @matneu
library-and-framework-list.json @fniephaus
.github/* @vjovanov
diff --git a/.github/workflows/test-changed-infrastructure-skip.yml b/.github/workflows/test-changed-infrastructure-skip.yml
new file mode 100644
index 000000000..e85f2aa23
--- /dev/null
+++ b/.github/workflows/test-changed-infrastructure-skip.yml
@@ -0,0 +1,25 @@
+name: "Test changed build logic"
+
+on:
+ pull_request:
+ branches:
+ - master
+ paths-ignore:
+ - "tests/tck-build-logic/**"
+ - "gradle/**"
+ - "build.gradle"
+ - "settings.gradle"
+ - "gradle.properties"
+
+jobs:
+ get-changed-infrastructure:
+ name: "π Get a list of libraries to test for build-logic changes"
+ runs-on: ubuntu-latest
+ steps:
+ - run: 'echo "No build required"'
+
+ all-infrastructure-passed:
+ name: "π§ͺ All build-logic triggered tests have passed"
+ runs-on: ubuntu-latest
+ steps:
+ - run: 'echo "No build required"'
diff --git a/.github/workflows/test-changed-infrastructure.yml b/.github/workflows/test-changed-infrastructure.yml
new file mode 100644
index 000000000..539161917
--- /dev/null
+++ b/.github/workflows/test-changed-infrastructure.yml
@@ -0,0 +1,101 @@
+name: "Test changed build logic"
+
+on:
+ pull_request:
+ branches:
+ - master
+ paths:
+ - "tests/tck-build-logic/**"
+ - "gradle/**"
+ - "build.gradle"
+ - "settings.gradle"
+ - "gradle.properties"
+
+concurrency:
+ group: "workflow = ${{ github.workflow }}, ref = ${{ github.event.ref }}, pr = ${{ github.event.pull_request.id }}"
+ cancel-in-progress: true
+
+jobs:
+ get-changed-infrastructure:
+ if: github.repository == 'oracle/graalvm-reachability-metadata'
+ name: "π Get a list of libraries to test for build-logic changes"
+ runs-on: "ubuntu-22.04"
+ timeout-minutes: 5
+ outputs:
+ matrix: ${{ steps.set-matrix.outputs.matrix }}
+ none-found: ${{ steps.set-matrix.outputs.none-found }}
+ steps:
+ - name: "βοΈ Checkout repository"
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+ - name: "π§ Prepare environment"
+ uses: graalvm/setup-graalvm@v1
+ with:
+ java-version: "17"
+ distribution: "graalvm"
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ - name: "πΈοΈ Populate matrix"
+ id: set-matrix
+ run: |
+ ./gradlew generateInfrastructureChangedCoordinatesMatrix -PbaseCommit=${{ github.event.pull_request.base.sha }} -PnewCommit=${{ github.event.pull_request.head.sha }}
+
+ test-changed-infrastructure:
+ name: "π§ͺ ${{ matrix.coordinates }} (GraalVM for JDK ${{ matrix.version }} @ ${{ matrix.os }})"
+ if: needs.get-changed-infrastructure.result == 'success' && needs.get-changed-infrastructure.outputs.none-found != 'true' && github.repository == 'oracle/graalvm-reachability-metadata'
+ runs-on: ${{ matrix.os }}
+ timeout-minutes: 20
+ needs: get-changed-infrastructure
+
+ strategy:
+ fail-fast: false
+ matrix: ${{ fromJson(needs.get-changed-infrastructure.outputs.matrix) }}
+
+ steps:
+ - name: "βοΈ Checkout repository"
+ uses: actions/checkout@v4
+
+ - name: "π§ Setup java"
+ uses: actions/setup-java@v4
+ with:
+ distribution: "oracle"
+ java-version: "17"
+
+ - name: "π§ Prepare environment"
+ uses: graalvm/setup-graalvm@v1
+ with:
+ set-java-home: "false"
+ java-version: ${{ matrix.version }}
+ distribution: "graalvm"
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ native-image-job-reports: "true"
+
+ - name: "Pull allowed docker images"
+ run: |
+ ./gradlew pullAllowedDockerImages --coordinates=${{ matrix.coordinates }}
+
+ - name: "Disable docker networking"
+ run: bash ./.github/workflows/disable-docker.sh
+
+ - name: "π Check metadata config files content"
+ run: |
+ ./gradlew checkConfigFiles --coordinates=${{ matrix.coordinates }}
+
+ - name: "π§ͺ Run '${{ matrix.coordinates }}' tests"
+ run: |
+ ./gradlew test -Pcoordinates=${{ matrix.coordinates }}
+
+ all-infrastructure-passed:
+ name: "π§ͺ All build-logic triggered tests have passed"
+ runs-on: "ubuntu-22.04"
+ timeout-minutes: 1
+ if: ${{ always() }} && github.repository == 'oracle/graalvm-reachability-metadata'
+ needs: test-changed-infrastructure
+ steps:
+ - name: "All tests passed"
+ if: needs.test-changed-infrastructure.result == 'success'
+ run: exit 0
+
+ - name: "Some tests failed"
+ if: needs.test-changed-infrastructure.result == 'failure'
+ run: exit 1
diff --git a/.github/workflows/test-changed-metadata-skip.yml b/.github/workflows/test-changed-metadata-skip.yml
index 94cedf047..82d07a247 100644
--- a/.github/workflows/test-changed-metadata-skip.yml
+++ b/.github/workflows/test-changed-metadata-skip.yml
@@ -6,7 +6,7 @@ on:
- master
paths-ignore:
- 'metadata/*'
- - 'tests/*'
+ - 'tests/src/*'
jobs:
get-changed-metadata:
diff --git a/.github/workflows/test-changed-metadata.yml b/.github/workflows/test-changed-metadata.yml
index b8d5e4b94..31c93eee5 100644
--- a/.github/workflows/test-changed-metadata.yml
+++ b/.github/workflows/test-changed-metadata.yml
@@ -6,7 +6,7 @@ on:
- master
paths:
- 'metadata/*'
- - 'tests/*'
+ - 'tests/src/*'
concurrency:
group: "workflow = ${{ github.workflow }}, ref = ${{ github.event.ref }}, pr = ${{ github.event.pull_request.id }}"
From 59c47656259bbc479d898cf886e629236b344269 Mon Sep 17 00:00:00 2001
From: Vojin Jovanovic
Date: Sat, 15 Nov 2025 22:21:33 +0100
Subject: [PATCH 4/9] Move the pull request template to .github
---
pull_request_template.md => .github/pull_request_template.md | 0
CONTRIBUTING.md | 2 +-
REVIEWING.md | 4 ++--
3 files changed, 3 insertions(+), 3 deletions(-)
rename pull_request_template.md => .github/pull_request_template.md (100%)
diff --git a/pull_request_template.md b/.github/pull_request_template.md
similarity index 100%
rename from pull_request_template.md
rename to .github/pull_request_template.md
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index b01c8db88..128c671d1 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -52,7 +52,7 @@ not be included as it does not compose and can break code in unpredictable ways.
* Make sure that you are using [Conditional Configuration](https://www.graalvm.org/latest/reference-manual/native-image/metadata/#specifying-reflection-metadata-in-json)
in order to precisely define the metadata scope. This is a hard requirement as it prevents unnecessary bloating of
images.
-* Once you want to create a pull request, you will be asked to fill out the [following list](./pull_request_template.md).
+* Once you want to create a pull request, you will be asked to fill out the [following list](.github/pull_request_template.md).
βΉοΈ To learn more about collecting metadata, see [How To Collect Metadata](docs/CollectingMetadata.md).
diff --git a/REVIEWING.md b/REVIEWING.md
index e8156c64a..194d824d9 100644
--- a/REVIEWING.md
+++ b/REVIEWING.md
@@ -6,7 +6,7 @@ This document should serve as a guideline for reviewers to simplify and harmoniz
## Checklist
First step of every review is to verify the checklist from the pull request description.
-Once the contributor wants to open a pull request [this checklist](pull_request_template.md) will be automatically added to the pull request description.
+Once the contributor wants to open a pull request [this checklist](.github/pull_request_template.md) will be automatically added to the pull request description.
* If the PR does not contain such a list, it **should not be reviewed**
* If any of the items is not checked, the reviewer should ask for an explanation from the contributor
@@ -61,4 +61,4 @@ All metadata files **must** be covered by the tests. Every metadata file should:
There are various tools that could help checking the content of all json files we are collecting.
To run these checks automatically, top-level metadata index file must contain `allowed-packages` properly set ([see this](./CONTRIBUTING.md#metadata-structure)).
-If this field is properly configured, our GitHub workflows will automatically check `typeReachable` and origin of all entries in all config files.
\ No newline at end of file
+If this field is properly configured, our GitHub workflows will automatically check `typeReachable` and origin of all entries in all config files.
From 06761484d3c92860fb39af473fc78a0e307fd9a5 Mon Sep 17 00:00:00 2001
From: Vojin Jovanovic
Date: Sun, 16 Nov 2025 11:04:19 +0100
Subject: [PATCH 5/9] Add ci.json for matrix specs
---
ci.json | 14 ++++++++++++++
1 file changed, 14 insertions(+)
create mode 100644 ci.json
diff --git a/ci.json b/ci.json
new file mode 100644
index 000000000..d941c44df
--- /dev/null
+++ b/ci.json
@@ -0,0 +1,14 @@
+{
+ "generateMatrixMatchingCoordinates": {
+ "java": ["17", "latest-ea"],
+ "os": ["ubuntu-latest"]
+ },
+ "generateChangedCoordinatesMatrix": {
+ "java": ["17", "21", "25", "latest-ea"],
+ "os": ["ubuntu-latest"]
+ },
+ "generateInfrastructureChangedCoordinatesMatrix": {
+ "java": ["17", "21", "25", "latest-ea"],
+ "os": ["ubuntu-latest"]
+ }
+}
From d1b88d029050af8ad9ddba228c1c2969fc22cc48 Mon Sep 17 00:00:00 2001
From: Vojin Jovanovic
Date: Sun, 16 Nov 2025 10:58:44 +0100
Subject: [PATCH 6/9] Test all in batches
---
.github/workflows/test-all-metadata.yml | 6 +-
ci.json | 8 +-
.../org.graalvm.internal.tck-harness.gradle | 179 ++++++++++++++++--
.../internal/tck/PullImagesFromFileTask.java | 53 ++++++
4 files changed, 224 insertions(+), 22 deletions(-)
create mode 100644 tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/PullImagesFromFileTask.java
diff --git a/.github/workflows/test-all-metadata.yml b/.github/workflows/test-all-metadata.yml
index 3c7e003ec..3c0fdf61e 100644
--- a/.github/workflows/test-all-metadata.yml
+++ b/.github/workflows/test-all-metadata.yml
@@ -27,13 +27,13 @@ jobs:
- name: "πΈοΈ Populate matrix"
id: set-matrix
run: |
- ./gradlew generateMatrixMatchingCoordinates -Pcoordinates=all
+ ./gradlew generateMatrixBatchedCoordinates -Pbatches=16
test-all-metadata:
if: github.repository == 'oracle/graalvm-reachability-metadata'
name: "π§ͺ ${{ matrix.coordinates }} (GraalVM for JDK ${{ matrix.version }} @ ${{ matrix.os }})"
runs-on: ${{ matrix.os }}
- timeout-minutes: 20
+ timeout-minutes: 120
needs: get-all-metadata
strategy:
fail-fast: false
@@ -56,7 +56,7 @@ jobs:
native-image-job-reports: 'true'
- name: "Pull allowed docker images"
run: |
- ./gradlew pullAllowedDockerImages --coordinates=${{ matrix.coordinates }}
+ ./gradlew pullAllowedDockerImagesMatching -Pcoordinates=${{ matrix.coordinates }}
- name: "Disable docker networking"
run: bash ./.github/workflows/disable-docker.sh
- name: "π§ͺ Run '${{ matrix.coordinates }}' tests"
diff --git a/ci.json b/ci.json
index d941c44df..6c088ad84 100644
--- a/ci.json
+++ b/ci.json
@@ -1,6 +1,6 @@
{
- "generateMatrixMatchingCoordinates": {
- "java": ["17", "latest-ea"],
+ "generateMatrixBatchedCoordinates": {
+ "java": ["17", "21", "25", "latest-ea"],
"os": ["ubuntu-latest"]
},
"generateChangedCoordinatesMatrix": {
@@ -10,5 +10,9 @@
"generateInfrastructureChangedCoordinatesMatrix": {
"java": ["17", "21", "25", "latest-ea"],
"os": ["ubuntu-latest"]
+ },
+ "generateMatrixMatchingCoordinates": {
+ "java": ["17", "latest-ea"],
+ "os": ["ubuntu-latest"]
}
}
diff --git a/tests/tck-build-logic/src/main/groovy/org.graalvm.internal.tck-harness.gradle b/tests/tck-build-logic/src/main/groovy/org.graalvm.internal.tck-harness.gradle
index 644c96024..a838e5a46 100644
--- a/tests/tck-build-logic/src/main/groovy/org.graalvm.internal.tck-harness.gradle
+++ b/tests/tck-build-logic/src/main/groovy/org.graalvm.internal.tck-harness.gradle
@@ -10,9 +10,12 @@ plugins {
}
import groovy.json.JsonOutput
+import groovy.json.JsonSlurper
import org.graalvm.internal.tck.ContributionTask
import org.graalvm.internal.tck.DockerTask
import org.graalvm.internal.tck.ConfigFilesChecker
+import org.graalvm.internal.tck.DockerUtils
+import org.graalvm.internal.tck.PullImagesFromFileTask
import org.graalvm.internal.tck.ScaffoldTask
import org.graalvm.internal.tck.GrypeTask
import org.graalvm.internal.tck.TestedVersionUpdaterTask
@@ -42,7 +45,47 @@ def writeGithubOutput(String key, String value) {
}
String coordinateFilter = Objects.requireNonNullElse(project.findProperty("coordinates"), "")
-List matchingCoordinates = tck.getMatchingCoordinates(coordinateFilter)
+
+// Support fractional batching coordinates in the form "k/n" (e.g., "1/16")
+boolean isFractionalBatch(String s) {
+ return s != null && (s ==~ /\d+\/\d+/)
+}
+
+List parseFraction(String s) {
+ def m = s =~ /(\d+)\/(\d+)/
+ if (!m.matches()) return null
+ int k = (m[0][1] as int)
+ int n = (m[0][2] as int)
+ return [k, n]
+}
+
+List computeBatchedCoordinates(List allCoords, int k, int n) {
+ if (n <= 0) throw new GradleException("Invalid batches denominator: ${n}")
+ if (k < 1 || k > n) throw new GradleException("Invalid batch index: ${k}/${n}")
+ def sorted = new ArrayList(allCoords)
+ java.util.Collections.sort(sorted)
+ int target = (k - 1)
+ def result = []
+ int i = 0
+ for (String c : sorted) {
+ if ((i % n) == target) {
+ result.add(c)
+ }
+ i++
+ }
+ return result
+}
+
+List matchingCoordinates
+if (isFractionalBatch(coordinateFilter)) {
+ def frac = parseFraction(coordinateFilter)
+ int k = frac[0]
+ int n = frac[1]
+ List all = tck.getMatchingCoordinates("all")
+ matchingCoordinates = computeBatchedCoordinates(all, k, n)
+} else {
+ matchingCoordinates = tck.getMatchingCoordinates(coordinateFilter)
+}
// gradle test -Pcoordinates=
Provider test = tasks.register("test", DefaultTask) { task ->
@@ -78,6 +121,79 @@ tasks.named("check").configure {
dependsOn(checkstyle)
}
+final String METADATA_GROUP = "Metadata"
+
+Provider pullAllowedDockerImagesMatching = tasks.register("pullAllowedDockerImagesMatching", DefaultTask) { task ->
+ task.setDescription("Pull allowed docker images for all matching coordinates")
+ task.setGroup(METADATA_GROUP)
+ task.doFirst {
+ if (matchingCoordinates == null || matchingCoordinates.isEmpty()) {
+ throw new GradleException("No matching coordinates found for property 'coordinates'. Provide -Pcoordinates= or a fractional batch 'k/n'.")
+ }
+ println "Pulling allowed docker images for ${matchingCoordinates.size()} coordinate(s):"
+ matchingCoordinates.each { c -> println(" - ${c}") }
+ }
+}
+
+// Collect unique required images across matching coordinates and filter by allowed list
+tasks.register("collectRequiredAllowedDockerImagesMatching", DefaultTask) { task ->
+ task.setDescription("Collect unique allowed docker images required by matching coordinates into a file")
+ task.setGroup(METADATA_GROUP)
+ File out = new File(buildDir, "required-docker-images-union.txt")
+ // Declare the output so Gradle can track it
+ task.outputs.file(out)
+ task.doFirst {
+ if (matchingCoordinates == null || matchingCoordinates.isEmpty()) {
+ throw new GradleException("No matching coordinates found for property 'coordinates'. Provide -Pcoordinates= or a fractional batch 'k/n'.")
+ }
+ Set unionRequired = new LinkedHashSet<>()
+ matchingCoordinates.each { c ->
+ def parts = c.split(":")
+ if (parts.length < 3) {
+ logger.warn("Skipping invalid coordinates: ${c}")
+ return
+ }
+ def group = parts[0]
+ def artifact = parts[1]
+ def version = parts[2]
+ File f = project.file("tests/src/${group}/${artifact}/${version}/required-docker-images.txt")
+ if (f.exists()) {
+ f.readLines()
+ .collect { it?.trim() }
+ .findAll { it && !it.startsWith("#") }
+ .each { unionRequired.add(it) }
+ }
+ }
+
+ Set allowed = DockerUtils.getAllAllowedImages()
+ def notAllowed = unionRequired.findAll { !allowed.contains(it) }
+ if (!notAllowed.isEmpty()) {
+ throw new GradleException("The following images are not in the allowed list: ${notAllowed}. " +
+ "If you need them, add Dockerfiles under tests/tck-build-logic/src/main/resources/allowed-docker-images " +
+ "per CONTRIBUTING.md, or adjust required-docker-images.txt files.")
+ }
+
+ out.parentFile.mkdirs()
+ def finalList = unionRequired.findAll { allowed.contains(it) }.toList()
+ out.text = finalList.join(System.lineSeparator())
+ println "Collected ${finalList.size()} required allowed image(s):"
+ finalList.each { println(" - ${it}") }
+ }
+}
+
+// Pull the collected unique images (once)
+tasks.register("pullRequiredAllowedDockerImagesMatching", PullImagesFromFileTask.class) { task ->
+ task.setDescription("Pull unique allowed docker images required by matching coordinates")
+ task.setGroup(METADATA_GROUP)
+ task.dependsOn("collectRequiredAllowedDockerImagesMatching")
+ task.imagesFile.set(new File(buildDir, "required-docker-images-union.txt"))
+}
+
+// Rewire the aggregate to depend on the unique pull task
+pullAllowedDockerImagesMatching.configure {
+ dependsOn("pullRequiredAllowedDockerImagesMatching")
+}
+
// Here we want to configure all test and checkstyle tasks for all filtered subprojects
for (String coordinates in matchingCoordinates) {
String testTaskName = generateTaskName("test", coordinates)
@@ -127,6 +243,13 @@ for (String coordinates in matchingCoordinates) {
javaTest.configure {
dependsOn(javaTestTaskName)
}
+
+ String pullDockerTaskName = generateTaskName("pullAllowedDockerImages", coordinates)
+ if ((!tasks.getNames().contains(pullDockerTaskName))) {
+ tasks.register(pullDockerTaskName, DockerTask.class) { t ->
+ t.setCoordinates(coordinates)
+ }
+ }
}
// gradle diff -PbaseCommit= -PnewCommit=
@@ -157,15 +280,23 @@ if (project.hasProperty("baseCommit")) {
}
}
-def matrixDefault = [
- "version": [
- "17",
- "latest-ea"
- ],
- "os" : ["ubuntu-latest"]
-]
+Map loadCi() {
+ File f = project.file("ci.json")
+ if (!f.exists()) {
+ throw new GradleException("Missing ci.json in repo root")
+ }
+ new JsonSlurper().parse(f) as Map
+}
-final String METADATA_GROUP = "Metadata"
+Map> matrixDefaultsFor(String section) {
+ def ci = loadCi()
+ def sec = ci[section]
+ if (sec == null) throw new GradleException("Missing '${section}' in ci.json")
+ [
+ "version": (sec["java"] as List),
+ "os": (sec["os"] as List)
+ ]
+}
// gradle generateMatrixMatchingCoordinates -Pcoordinates=
Provider generateMatrixMatchingCoordinates = tasks.register("generateMatrixMatchingCoordinates", DefaultTask) { task ->
@@ -175,7 +306,25 @@ Provider generateMatrixMatchingCoordinates = tasks.register("generateMatri
def matrix = [
"coordinates": matchingCoordinates
]
- matrix.putAll(matrixDefault)
+ matrix.putAll(matrixDefaultsFor("generateMatrixMatchingCoordinates"))
+ writeGithubOutput("matrix", JsonOutput.toJson(matrix))
+ }
+}
+
+ // gradle generateMatrixBatchedCoordinates [-Pbatches=]
+Provider generateMatrixBatchedCoordinates = tasks.register("generateMatrixBatchedCoordinates", DefaultTask) { task ->
+ task.setDescription("Returns matrix definition populated with fractional batch coordinates (k/n)")
+ task.setGroup(METADATA_GROUP)
+ task.doFirst {
+ int batches = project.hasProperty("batches") ? Integer.parseInt(project.findProperty("batches").toString()) : 16
+ if (batches <= 0) {
+ throw new GradleException("Invalid 'batches' value: ${batches}")
+ }
+ List coords = (1..batches).collect { i -> "${i}/${batches}" }
+ def matrix = [
+ "coordinates": coords
+ ]
+ matrix.putAll(matrixDefaultsFor("generateMatrixBatchedCoordinates"))
writeGithubOutput("matrix", JsonOutput.toJson(matrix))
}
}
@@ -193,13 +342,11 @@ Provider generateChangedCoordinatesMatrix = tasks.register("generateChange
def matrix = [
"coordinates": noneFound ? [] : diffCoordinates
]
- matrix.putAll(matrixDefault)
+ matrix.putAll(matrixDefaultsFor("generateChangedCoordinatesMatrix"))
if (noneFound) {
println "No changed coordinates were found!"
}
- matrix.version.add("21")
- matrix.version.add("25")
writeGithubOutput("matrix", JsonOutput.toJson(matrix))
writeGithubOutput("none-found", noneFound.toString())
@@ -215,7 +362,7 @@ Provider generateInfrastructureChangedCoordinatesMatrix = tasks.register("
boolean infraChanged = true
// Pre-selected modules; keep stable for infra verification
List preselectedModules = [
- 'org.bouncycastle:bcpkix-jdk15on',
+ 'ch.qos.logback:logback-classic',
'org.bouncycastle:bcpkix-jdk18on',
'io.netty:netty-common',
'io.grpc:grpc-core',
@@ -243,10 +390,8 @@ Provider generateInfrastructureChangedCoordinatesMatrix = tasks.register("
def matrix = [
"coordinates": selected
]
- matrix.putAll(matrixDefault)
+ matrix.putAll(matrixDefaultsFor("generateInfrastructureChangedCoordinatesMatrix"))
- matrix.version.add("21")
- matrix.version.add("25")
writeGithubOutput("matrix", JsonOutput.toJson(matrix))
writeGithubOutput("none-found", "false")
diff --git a/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/PullImagesFromFileTask.java b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/PullImagesFromFileTask.java
new file mode 100644
index 000000000..7b2d84751
--- /dev/null
+++ b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/PullImagesFromFileTask.java
@@ -0,0 +1,53 @@
+package org.graalvm.internal.tck;
+
+import org.gradle.api.DefaultTask;
+import org.gradle.api.file.RegularFileProperty;
+import org.gradle.api.tasks.InputFile;
+import org.gradle.api.tasks.TaskAction;
+import org.gradle.process.ExecOperations;
+import org.gradle.api.GradleException;
+
+import javax.inject.Inject;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.List;
+
+/**
+ * Pulls docker images listed in a text file (one image per line).
+ * Fails the task immediately if any image pull fails to ensure batch execution fails on single error.
+ */
+public abstract class PullImagesFromFileTask extends DefaultTask {
+
+ @InputFile
+ public abstract RegularFileProperty getImagesFile();
+
+ @Inject
+ protected abstract ExecOperations getExecOperations();
+
+ @TaskAction
+ public void run() throws IOException {
+ File inFile = getImagesFile().get().getAsFile();
+ if (!inFile.exists()) {
+ getLogger().lifecycle("No required docker images collected: {}", inFile.getAbsolutePath());
+ return;
+ }
+
+ List images = Files.readAllLines(inFile.toPath()).stream()
+ .map(String::trim)
+ .filter(s -> !s.isEmpty() && !s.startsWith("#"))
+ .toList();
+
+ for (String image : images) {
+ getLogger().lifecycle("Pulling image {}...", image);
+ try {
+ getExecOperations().exec(spec -> {
+ spec.setExecutable("docker");
+ spec.args("pull", image);
+ });
+ } catch (Exception e) {
+ throw new GradleException("Failed to pull image " + image + ": " + e.getMessage(), e);
+ }
+ }
+ }
+}
From f467d3733bfe4ce8dc5dc76622941eb6808f6e3d Mon Sep 17 00:00:00 2001
From: Vojin Jovanovic
Date: Mon, 17 Nov 2025 13:28:07 +0100
Subject: [PATCH 7/9] Add build arguments to ci.json
---
.github/workflows/test-all-metadata.yml | 7 +-
ci.json | 1 +
.../org.graalvm.internal.tck-harness.gradle | 144 ++++++++----------
.../groovy/org.graalvm.internal.tck.gradle | 25 ++-
4 files changed, 91 insertions(+), 86 deletions(-)
diff --git a/.github/workflows/test-all-metadata.yml b/.github/workflows/test-all-metadata.yml
index 3c0fdf61e..2b1c2eda5 100644
--- a/.github/workflows/test-all-metadata.yml
+++ b/.github/workflows/test-all-metadata.yml
@@ -2,6 +2,11 @@ name: "Test all metadata"
on:
workflow_dispatch:
+ pull_request:
+ branches:
+ - master
+ paths:
+ - 'ci.json'
concurrency:
group: "workflow = ${{ github.workflow }}, ref = ${{ github.event.ref }}, pr = ${{ github.event.pull_request.id }}"
@@ -56,7 +61,7 @@ jobs:
native-image-job-reports: 'true'
- name: "Pull allowed docker images"
run: |
- ./gradlew pullAllowedDockerImagesMatching -Pcoordinates=${{ matrix.coordinates }}
+ ./gradlew pullAllowedDockerImages -Pcoordinates=${{ matrix.coordinates }}
- name: "Disable docker networking"
run: bash ./.github/workflows/disable-docker.sh
- name: "π§ͺ Run '${{ matrix.coordinates }}' tests"
diff --git a/ci.json b/ci.json
index 6c088ad84..9e50fe296 100644
--- a/ci.json
+++ b/ci.json
@@ -1,4 +1,5 @@
{
+ "buildArgs": ["-verbose", "-Ob"],
"generateMatrixBatchedCoordinates": {
"java": ["17", "21", "25", "latest-ea"],
"os": ["ubuntu-latest"]
diff --git a/tests/tck-build-logic/src/main/groovy/org.graalvm.internal.tck-harness.gradle b/tests/tck-build-logic/src/main/groovy/org.graalvm.internal.tck-harness.gradle
index a838e5a46..d6485e38a 100644
--- a/tests/tck-build-logic/src/main/groovy/org.graalvm.internal.tck-harness.gradle
+++ b/tests/tck-build-logic/src/main/groovy/org.graalvm.internal.tck-harness.gradle
@@ -15,7 +15,6 @@ import org.graalvm.internal.tck.ContributionTask
import org.graalvm.internal.tck.DockerTask
import org.graalvm.internal.tck.ConfigFilesChecker
import org.graalvm.internal.tck.DockerUtils
-import org.graalvm.internal.tck.PullImagesFromFileTask
import org.graalvm.internal.tck.ScaffoldTask
import org.graalvm.internal.tck.GrypeTask
import org.graalvm.internal.tck.TestedVersionUpdaterTask
@@ -28,6 +27,7 @@ import org.graalvm.internal.tck.harness.tasks.NativeTestCompileInvocationTask
import org.graalvm.internal.tck.updaters.FetchExistingLibrariesWithNewerVersionsTask
import org.graalvm.internal.tck.updaters.GroupUnsupportedLibraries
import org.gradle.util.internal.VersionNumber
+import org.graalvm.internal.tck.PullImagesFromFileTask
import static org.graalvm.internal.tck.Utils.generateTaskName
@@ -47,11 +47,11 @@ def writeGithubOutput(String key, String value) {
String coordinateFilter = Objects.requireNonNullElse(project.findProperty("coordinates"), "")
// Support fractional batching coordinates in the form "k/n" (e.g., "1/16")
-boolean isFractionalBatch(String s) {
+static boolean isFractionalBatch(String s) {
return s != null && (s ==~ /\d+\/\d+/)
}
-List parseFraction(String s) {
+static List parseFraction(String s) {
def m = s =~ /(\d+)\/(\d+)/
if (!m.matches()) return null
int k = (m[0][1] as int)
@@ -59,16 +59,16 @@ List parseFraction(String s) {
return [k, n]
}
-List computeBatchedCoordinates(List allCoords, int k, int n) {
- if (n <= 0) throw new GradleException("Invalid batches denominator: ${n}")
- if (k < 1 || k > n) throw new GradleException("Invalid batch index: ${k}/${n}")
- def sorted = new ArrayList(allCoords)
- java.util.Collections.sort(sorted)
- int target = (k - 1)
+static List computeBatchedCoordinates(List coordinates, int index, int batches) {
+ if (batches <= 0) throw new GradleException("Invalid batches denominator: ${batches}")
+ if (index < 1 || index > batches) throw new GradleException("Invalid batch index: ${index}/${batches}")
+ def sorted = new ArrayList(coordinates)
+ Collections.sort(sorted)
+ int target = (index - 1)
def result = []
int i = 0
for (String c : sorted) {
- if ((i % n) == target) {
+ if ((i % batches) == target) {
result.add(c)
}
i++
@@ -79,10 +79,8 @@ List computeBatchedCoordinates(List allCoords, int k, int n) {
List matchingCoordinates
if (isFractionalBatch(coordinateFilter)) {
def frac = parseFraction(coordinateFilter)
- int k = frac[0]
- int n = frac[1]
List all = tck.getMatchingCoordinates("all")
- matchingCoordinates = computeBatchedCoordinates(all, k, n)
+ matchingCoordinates = computeBatchedCoordinates(all, frac[0], frac[1])
} else {
matchingCoordinates = tck.getMatchingCoordinates(coordinateFilter)
}
@@ -123,76 +121,8 @@ tasks.named("check").configure {
final String METADATA_GROUP = "Metadata"
-Provider pullAllowedDockerImagesMatching = tasks.register("pullAllowedDockerImagesMatching", DefaultTask) { task ->
- task.setDescription("Pull allowed docker images for all matching coordinates")
- task.setGroup(METADATA_GROUP)
- task.doFirst {
- if (matchingCoordinates == null || matchingCoordinates.isEmpty()) {
- throw new GradleException("No matching coordinates found for property 'coordinates'. Provide -Pcoordinates= or a fractional batch 'k/n'.")
- }
- println "Pulling allowed docker images for ${matchingCoordinates.size()} coordinate(s):"
- matchingCoordinates.each { c -> println(" - ${c}") }
- }
-}
-// Collect unique required images across matching coordinates and filter by allowed list
-tasks.register("collectRequiredAllowedDockerImagesMatching", DefaultTask) { task ->
- task.setDescription("Collect unique allowed docker images required by matching coordinates into a file")
- task.setGroup(METADATA_GROUP)
- File out = new File(buildDir, "required-docker-images-union.txt")
- // Declare the output so Gradle can track it
- task.outputs.file(out)
- task.doFirst {
- if (matchingCoordinates == null || matchingCoordinates.isEmpty()) {
- throw new GradleException("No matching coordinates found for property 'coordinates'. Provide -Pcoordinates= or a fractional batch 'k/n'.")
- }
- Set unionRequired = new LinkedHashSet<>()
- matchingCoordinates.each { c ->
- def parts = c.split(":")
- if (parts.length < 3) {
- logger.warn("Skipping invalid coordinates: ${c}")
- return
- }
- def group = parts[0]
- def artifact = parts[1]
- def version = parts[2]
- File f = project.file("tests/src/${group}/${artifact}/${version}/required-docker-images.txt")
- if (f.exists()) {
- f.readLines()
- .collect { it?.trim() }
- .findAll { it && !it.startsWith("#") }
- .each { unionRequired.add(it) }
- }
- }
- Set allowed = DockerUtils.getAllAllowedImages()
- def notAllowed = unionRequired.findAll { !allowed.contains(it) }
- if (!notAllowed.isEmpty()) {
- throw new GradleException("The following images are not in the allowed list: ${notAllowed}. " +
- "If you need them, add Dockerfiles under tests/tck-build-logic/src/main/resources/allowed-docker-images " +
- "per CONTRIBUTING.md, or adjust required-docker-images.txt files.")
- }
-
- out.parentFile.mkdirs()
- def finalList = unionRequired.findAll { allowed.contains(it) }.toList()
- out.text = finalList.join(System.lineSeparator())
- println "Collected ${finalList.size()} required allowed image(s):"
- finalList.each { println(" - ${it}") }
- }
-}
-
-// Pull the collected unique images (once)
-tasks.register("pullRequiredAllowedDockerImagesMatching", PullImagesFromFileTask.class) { task ->
- task.setDescription("Pull unique allowed docker images required by matching coordinates")
- task.setGroup(METADATA_GROUP)
- task.dependsOn("collectRequiredAllowedDockerImagesMatching")
- task.imagesFile.set(new File(buildDir, "required-docker-images-union.txt"))
-}
-
-// Rewire the aggregate to depend on the unique pull task
-pullAllowedDockerImagesMatching.configure {
- dependsOn("pullRequiredAllowedDockerImagesMatching")
-}
// Here we want to configure all test and checkstyle tasks for all filtered subprojects
for (String coordinates in matchingCoordinates) {
@@ -422,9 +352,57 @@ tasks.register("checkAllowedDockerImages", GrypeTask.class) { task ->
task.setGroup(METADATA_GROUP)
}
-tasks.register("pullAllowedDockerImages", DockerTask.class) { task ->
- task.setDescription("Pull allowed docker images from list.")
+def imagesFileProvider = project.layout.buildDirectory.file("tck/required-docker-images.txt")
+
+def computeImages = tasks.register("computeAllowedDockerImagesFile", DefaultTask) { task ->
+ task.setDescription("Computes allowed docker images required by matching coordinates and writes them to a file")
+ task.setGroup(METADATA_GROUP)
+ task.outputs.file(imagesFileProvider)
+ task.doFirst {
+ if (matchingCoordinates == null || matchingCoordinates.isEmpty()) {
+ throw new GradleException("No matching coordinates found for property 'coordinates'. Provide -Pcoordinates= or a fractional batch 'k/n'.")
+ }
+ Set unionRequired = new LinkedHashSet<>()
+ matchingCoordinates.each { c ->
+ def parts = c.split(":")
+ if (parts.length < 3) {
+ logger.warn("Skipping invalid coordinates: ${c}")
+ return
+ }
+ def group = parts[0]
+ def artifact = parts[1]
+ def version = parts[2]
+ File f = project.file("tests/src/${group}/${artifact}/${version}/required-docker-images.txt")
+ if (f.exists()) {
+ f.readLines()
+ .collect { it?.trim() }
+ .findAll { it && !it.startsWith("#") }
+ .each { unionRequired.add(it) }
+ }
+ }
+
+ Set allowed = DockerUtils.getAllAllowedImages()
+ def notAllowed = unionRequired.findAll { !allowed.contains(it) }
+ if (!notAllowed.isEmpty()) {
+ throw new GradleException("The following images are not in the allowed list: ${notAllowed}. " +
+ "If you need them, add Dockerfiles under tests/tck-build-logic/src/main/resources/allowed-docker-images " +
+ "per CONTRIBUTING.md, or adjust required-docker-images.txt files.")
+ }
+
+ def finalList = unionRequired.findAll { allowed.contains(it) }.toList()
+ println "Collected ${finalList.size()} required allowed image(s)"
+ File outFile = imagesFileProvider.get().asFile
+ outFile.parentFile.mkdirs()
+ outFile.text = finalList.join(System.lineSeparator())
+ }
+}
+
+tasks.register("pullAllowedDockerImages", PullImagesFromFileTask.class) { task ->
+ task.setDescription("Pull allowed docker images required by matching coordinates")
task.setGroup(METADATA_GROUP)
+ task.getImagesFile().set(imagesFileProvider)
+}.configure { t ->
+ t.dependsOn(computeImages)
}
diff --git a/tests/tck-build-logic/src/main/groovy/org.graalvm.internal.tck.gradle b/tests/tck-build-logic/src/main/groovy/org.graalvm.internal.tck.gradle
index d0b443eba..35178718b 100644
--- a/tests/tck-build-logic/src/main/groovy/org.graalvm.internal.tck.gradle
+++ b/tests/tck-build-logic/src/main/groovy/org.graalvm.internal.tck.gradle
@@ -6,6 +6,8 @@
*/
+import groovy.json.JsonSlurper
+
plugins {
id 'org.graalvm.internal.tck-base'
id 'checkstyle'
@@ -51,6 +53,26 @@ String overrideVal = System.getenv("GVM_TCK_EXCLUDE") ?: providers.gradlePropert
overrideVal = overrideVal ?: "false"
boolean override = overrideVal.toBoolean()
+// Determine native-image build arguments from ci.json.
+def ciJsonFile = rootProject.file("ci.json")
+def nativeImageArgs = []
+if (ciJsonFile.exists()) {
+ try {
+ def parsed = new JsonSlurper().parse(ciJsonFile)
+ def argsFromCi = parsed?.buildArgs
+ if (argsFromCi instanceof Collection && !argsFromCi.isEmpty()) {
+ nativeImageArgs = argsFromCi.collect { it.toString() }
+ // Post-process placeholders in args
+ nativeImageArgs = nativeImageArgs.collect { arg ->
+ arg.replace('{{library.version}}', libraryVersion)
+ .replace('{{library.coordinates}}', libraryGAV)
+ }
+ }
+ } catch (Exception ignored) {
+ throw new GradleException("ci.json must contain the buildArgs")
+ }
+}
+
tck.testedLibraryVersion = libraryVersion
// This value can be used to request specific library version to test with.
@@ -78,8 +100,7 @@ graalvmNative {
if (override) {
excludeConfig.put(libraryGAV, [".*"])
}
- verbose = true
- quickBuild = true
+ buildArgs.addAll(nativeImageArgs)
}
}
}
From 8cc7affd70704e3668dfa1cdd901b6504563c599 Mon Sep 17 00:00:00 2001
From: Vojin Jovanovic
Date: Mon, 17 Nov 2025 18:13:41 +0100
Subject: [PATCH 8/9] =?UTF-8?q?Give=20this=20repo=20the=20=E2=9D=A4?=
=?UTF-8?q?=EF=B8=8F=20it=20deserves?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- All commands now support a -Pcoordinates=k/n mode for batched execution.
- One stop shop testing command: ./gradlew testAllParallel -Pparallelism=n
- Documentation and structure cleanup (docs).
- CLine support.
- Complete command cleanup and simplification.
---
.github/CODEOWNERS | 3 +-
.github/workflows/checkstyle-skip.yml | 2 +-
.github/workflows/checkstyle.yml | 13 +-
.../workflows/create-scheduled-release.yml | 10 +
.../library-and-framework-list-validation.yml | 4 +-
.github/workflows/scan-docker-images.yml | 12 +-
.../workflows/{ => scripts}/disable-docker.sh | 0
.../workflows/{ => scripts}/discard-port.conf | 0
.../workflows/{ => scripts}/dockerd.service | 0
.../{ => scripts}/run-consecutive-tests.sh | 2 +-
.github/workflows/test-all-metadata.yml | 34 +--
.../workflows/test-changed-infrastructure.yml | 31 ++-
.github/workflows/test-changed-metadata.yml | 38 +--
...rify-new-library-version-compatibility.yml | 26 +-
AGENTS.md | 64 +++++
README.md | 10 +-
build.gradle | 158 +++++++++++-
docs/CI.md | 37 +++
CONTRIBUTING.md => docs/CONTRIBUTING.md | 4 +-
docs/CollectingMetadata.md | 2 +-
docs/DEVELOPING.md | 138 ++++++++++
.../check-new-versions-of-libraries.md | 51 ----
REVIEWING.md => docs/REVIEWING.md | 4 +-
SECURITY.md => docs/SECURITY.md | 0
.../3.1.0.M1/build.gradle | 2 +-
.../thymeleaf-spring6/3.1.0.M2/build.gradle | 2 +-
.../org.graalvm.internal.tck-harness.gradle | 235 +++++-------------
.../groovy/org.graalvm.internal.tck.gradle | 2 +-
.../internal/tck/harness/TckExtension.java | 47 ++--
.../tasks/AbstractSubprojectTask.groovy | 1 -
.../harness/tasks/CleanInvocationTask.groovy | 8 +
...y => CompileTestJavaInvocationTask.groovy} | 4 +-
...ComputeAndPullAllowedDockerImagesTask.java | 138 ++++++++++
...stingLibrariesWithNewerVersionsTask.groovy | 6 +-
.../tck/harness/tasks/TeeOutputStream.java | 6 +-
.../updaters/GroupUnsupportedLibraries.groovy | 53 ----
.../internal/tck/ContributionTask.java | 1 +
.../graalvm/internal/tck/CoordinateUtils.java | 27 --
.../org/graalvm/internal/tck/Coordinates.java | 14 +-
.../org/graalvm/internal/tck/DockerTask.java | 2 +
.../org/graalvm/internal/tck/GrypeTask.java | 8 +-
...ker.java => MetadataFilesCheckerTask.java} | 49 ++--
.../internal/tck/PullImagesFromFileTask.java | 53 ----
.../graalvm/internal/tck/ScaffoldTask.java | 4 +-
.../tck/TestedVersionUpdaterTask.java | 7 +-
.../internal/tck/utils/CoordinateUtils.java | 95 +++++++
46 files changed, 889 insertions(+), 518 deletions(-)
rename .github/workflows/{ => scripts}/disable-docker.sh (100%)
rename .github/workflows/{ => scripts}/discard-port.conf (100%)
rename .github/workflows/{ => scripts}/dockerd.service (100%)
rename .github/workflows/{ => scripts}/run-consecutive-tests.sh (96%)
create mode 100644 AGENTS.md
create mode 100644 docs/CI.md
rename CONTRIBUTING.md => docs/CONTRIBUTING.md (99%)
create mode 100644 docs/DEVELOPING.md
delete mode 100644 docs/Infrastructure/check-new-versions-of-libraries.md
rename REVIEWING.md => docs/REVIEWING.md (95%)
rename SECURITY.md => docs/SECURITY.md (100%)
rename tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/tasks/{JavacInvocationTask.groovy => CompileTestJavaInvocationTask.groovy} (84%)
create mode 100644 tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/tasks/ComputeAndPullAllowedDockerImagesTask.java
rename tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/{updaters => harness/tasks}/FetchExistingLibrariesWithNewerVersionsTask.groovy (97%)
delete mode 100644 tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/updaters/GroupUnsupportedLibraries.groovy
delete mode 100644 tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/CoordinateUtils.java
rename tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/{ConfigFilesChecker.java => MetadataFilesCheckerTask.java} (92%)
delete mode 100644 tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/PullImagesFromFileTask.java
create mode 100644 tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/utils/CoordinateUtils.java
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index d3c37ebb6..0bc4ad10e 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -4,6 +4,7 @@ tests/tck-build-logic/* @vjovanov
tests/tck-build-logic/src/main/resources/allowed-docker-images/* @matneu
library-and-framework-list.json @fniephaus
.github/* @vjovanov
-docs/* @vjovanov
+docs/* @vjovanov @ban-mi
+README.md @vjovanov @ban-mi
gradle/* @vjovanov
/* @vjovanov
diff --git a/.github/workflows/checkstyle-skip.yml b/.github/workflows/checkstyle-skip.yml
index 365b82c9c..2ae60e70b 100644
--- a/.github/workflows/checkstyle-skip.yml
+++ b/.github/workflows/checkstyle-skip.yml
@@ -3,7 +3,7 @@ name: "Check code style"
on:
pull_request:
paths:
- - 'docs/*'
+ - 'docs/**'
- '**.md'
- 'library-and-framework-list*.json'
diff --git a/.github/workflows/checkstyle.yml b/.github/workflows/checkstyle.yml
index a299a3e40..9fcef7915 100644
--- a/.github/workflows/checkstyle.yml
+++ b/.github/workflows/checkstyle.yml
@@ -3,24 +3,25 @@ name: "Check code style"
on:
pull_request:
paths-ignore:
- - 'docs/*'
+ - 'docs/**'
- '**.md'
- 'library-and-framework-list*.json'
jobs:
checkstyle:
- if: github.repository == 'oracle/graalvm-reachability-metadata'
name: "π Check style according to checkstyle.xml"
runs-on: "ubuntu-22.04"
timeout-minutes: 15
steps:
- name: "βοΈ Checkout repository"
uses: actions/checkout@v4
+
- uses: actions/setup-python@v4
- - name: "π§ Prepare environment"
- uses: graalvm/setup-graalvm@v1
+
+ - name: "π§ Setup java"
+ uses: actions/setup-java@v4
with:
- java-version: '17'
distribution: 'graalvm'
- github-token: ${{ secrets.GITHUB_TOKEN }}
+ java-version: '21'
+
- run: ./gradlew checkstyle
diff --git a/.github/workflows/create-scheduled-release.yml b/.github/workflows/create-scheduled-release.yml
index 7c465d613..a26e59e32 100644
--- a/.github/workflows/create-scheduled-release.yml
+++ b/.github/workflows/create-scheduled-release.yml
@@ -12,6 +12,7 @@ permissions:
jobs:
get-changed-metadata:
name: "π Get a list of changed metadata"
+ if: github.repository == 'oracle/graalvm-reachability-metadata'
runs-on: "ubuntu-22.04"
timeout-minutes: 5
outputs:
@@ -22,11 +23,13 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: 0
+
- name: "π§ Setup java"
uses: actions/setup-java@v4
with:
distribution: 'graalvm'
java-version: '21'
+
- name: "πΈοΈ Get changed metadata matrix"
id: set-matrix
run: |
@@ -45,11 +48,13 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: 0
+
- name: "π§ Setup java"
uses: actions/setup-java@v4
with:
distribution: 'graalvm'
java-version: '21'
+
- name: "Get tags"
run: |
PREVIOUS_RELEASE_TAG=$(git tag --list | sort -V | tail -1)
@@ -57,15 +62,19 @@ jobs:
CURRENT_RELEASE_TAG=$(sed -E 's/^([0-9]+\.)([0-9]+\.)([0-9]+)/echo \1\2$((\3+1))/e' <<< $PREVIOUS_RELEASE_TAG)
echo "CURRENT_RELEASE_TAG=$CURRENT_RELEASE_TAG" >> ${GITHUB_ENV}
+
- name: "β¬οΈ Update version"
run: |
sed -i "s/project.version(\"1.0.0-SNAPSHOT\")/project.version(\"${{ env.CURRENT_RELEASE_TAG }}\")/g" build.gradle
+
- name: "π Run spotless check"
run: |
./gradlew spotlessCheck
+
- name: "π Generate release artifacts"
run: |
./gradlew package
+
- name: "π Commit changes"
run: |
git config --local user.email "actions@github.com"
@@ -74,6 +83,7 @@ jobs:
git commit -m "Release version ${{ env.CURRENT_RELEASE_TAG }}"
git tag ${{ env.CURRENT_RELEASE_TAG }}
git push origin ${{ env.CURRENT_RELEASE_TAG }}
+
- name: "π Publish a release"
run: |
gh release create ${{ env.CURRENT_RELEASE_TAG }} build/graalvm-reachability-metadata-*.zip --generate-notes --notes-start-tag ${{ env.PREVIOUS_RELEASE_TAG }}
diff --git a/.github/workflows/library-and-framework-list-validation.yml b/.github/workflows/library-and-framework-list-validation.yml
index bec665690..a146b16fa 100644
--- a/.github/workflows/library-and-framework-list-validation.yml
+++ b/.github/workflows/library-and-framework-list-validation.yml
@@ -7,16 +7,17 @@ on:
jobs:
validate-library-and-framework-list-json:
- if: github.repository == 'oracle/graalvm-reachability-metadata'
name: "π Validate the JSON file"
runs-on: "ubuntu-22.04"
timeout-minutes: 5
steps:
- name: "βοΈ Checkout repository"
uses: actions/checkout@v4
+
- uses: actions/setup-python@v4
with:
python-version: '3.10'
+
- name: Check that the JSON file is well-formatted and sorted by artifact
run: |
JSON="library-and-framework-list.json"
@@ -29,6 +30,7 @@ jobs:
echo "'${JSON}' is no longer sorted by artifact key. You can use 'jq' to sort it: 'sorted="$(jq -s '.[] | sort_by(.artifact)' ${JSON})" && echo -E "${sorted}" > ${JSON}"
exit 8
fi
+
- name: Check that the JSON file conforms to the schema
run: |
pip install check-jsonschema
diff --git a/.github/workflows/scan-docker-images.yml b/.github/workflows/scan-docker-images.yml
index 21a7c11a8..14d8c9117 100644
--- a/.github/workflows/scan-docker-images.yml
+++ b/.github/workflows/scan-docker-images.yml
@@ -18,18 +18,22 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: 0
- - uses: graalvm/setup-graalvm@v1
+
+ - uses: actions/setup-java@v4
with:
- java-version: '17'
distribution: 'graalvm'
+ java-version: '21'
github-token: ${{ secrets.GITHUB_TOKEN }}
+
- name: "Install required tools"
run: |
- curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sudo sh -s -- -b /usr/local/bin
+ curl -sSfL https://get.anchore.io/grype/v0.104.0/install.sh | sudo sh -s -- -b /usr/local/bin
sudo apt-get install jq
+
- name: "π Check changed docker images"
if: github.event_name == 'pull_request'
run: ./gradlew checkAllowedDockerImages --baseCommit=${{ github.event.pull_request.base.sha }} --newCommit=${{ github.event.pull_request.head.sha }}
+
- name: "π Check all docker images"
- if: github.event_name != 'pull_request' && github.repository == 'oracle/graalvm-reachability-metadata'
+ if: github.event_name == 'schedule' && github.repository == 'oracle/graalvm-reachability-metadata'
run: ./gradlew checkAllowedDockerImages
diff --git a/.github/workflows/disable-docker.sh b/.github/workflows/scripts/disable-docker.sh
similarity index 100%
rename from .github/workflows/disable-docker.sh
rename to .github/workflows/scripts/disable-docker.sh
diff --git a/.github/workflows/discard-port.conf b/.github/workflows/scripts/discard-port.conf
similarity index 100%
rename from .github/workflows/discard-port.conf
rename to .github/workflows/scripts/discard-port.conf
diff --git a/.github/workflows/dockerd.service b/.github/workflows/scripts/dockerd.service
similarity index 100%
rename from .github/workflows/dockerd.service
rename to .github/workflows/scripts/dockerd.service
diff --git a/.github/workflows/run-consecutive-tests.sh b/.github/workflows/scripts/run-consecutive-tests.sh
similarity index 96%
rename from .github/workflows/run-consecutive-tests.sh
rename to .github/workflows/scripts/run-consecutive-tests.sh
index beaac23a7..26036a4aa 100644
--- a/.github/workflows/run-consecutive-tests.sh
+++ b/.github/workflows/scripts/run-consecutive-tests.sh
@@ -62,7 +62,7 @@ for VERSION in "${VERSIONS[@]}"; do
echo "$DELIMITER"
- if ! run_multiple_attempts "javac compile" 1 javac; then
+ if ! run_multiple_attempts "javac compile" 1 compileTestJava; then
break
fi
diff --git a/.github/workflows/test-all-metadata.yml b/.github/workflows/test-all-metadata.yml
index 2b1c2eda5..4a87c9d71 100644
--- a/.github/workflows/test-all-metadata.yml
+++ b/.github/workflows/test-all-metadata.yml
@@ -1,4 +1,4 @@
-name: "Test all metadata"
+name: "Test all metadata (one version per test suite)"
on:
workflow_dispatch:
@@ -14,7 +14,7 @@ concurrency:
jobs:
get-all-metadata:
- if: github.repository == 'oracle/graalvm-reachability-metadata'
+ if: github.event_name == 'workflow_dispatch' || github.repository == 'oracle/graalvm-reachability-metadata'
name: "π Get list of all supported libraries"
runs-on: "ubuntu-22.04"
timeout-minutes: 5
@@ -23,19 +23,19 @@ jobs:
steps:
- name: "βοΈ Checkout repository"
uses: actions/checkout@v4
- - name: "π§ Prepare environment"
- uses: graalvm/setup-graalvm@v1
+
+ - name: "π§ Setup java"
+ uses: actions/setup-java@v4
with:
- java-version: '17'
distribution: 'graalvm'
- github-token: ${{ secrets.GITHUB_TOKEN }}
+ java-version: '21'
+
- name: "πΈοΈ Populate matrix"
id: set-matrix
run: |
./gradlew generateMatrixBatchedCoordinates -Pbatches=16
test-all-metadata:
- if: github.repository == 'oracle/graalvm-reachability-metadata'
name: "π§ͺ ${{ matrix.coordinates }} (GraalVM for JDK ${{ matrix.version }} @ ${{ matrix.os }})"
runs-on: ${{ matrix.os }}
timeout-minutes: 120
@@ -46,24 +46,29 @@ jobs:
steps:
- name: "βοΈ Checkout repository"
uses: actions/checkout@v4
+
- name: "π§ Setup java"
uses: actions/setup-java@v4
with:
- distribution: 'oracle'
- java-version: '17'
- - name: "π§ Prepare environment"
+ distribution: 'graalvm'
+ java-version: '21'
+
+ - name: "π§ Download GraalVM for metadata testing"
uses: graalvm/setup-graalvm@v1
with:
- set-java-home: 'false'
- java-version: ${{ matrix.version }}
distribution: 'graalvm'
- github-token: ${{ secrets.GITHUB_TOKEN }}
+ java-version: ${{ matrix.version }}
+ set-java-home: 'false'
native-image-job-reports: 'true'
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+
- name: "Pull allowed docker images"
run: |
./gradlew pullAllowedDockerImages -Pcoordinates=${{ matrix.coordinates }}
+
- name: "Disable docker networking"
- run: bash ./.github/workflows/disable-docker.sh
+ run: bash ./.github/workflows/scripts/disable-docker.sh
+
- name: "π§ͺ Run '${{ matrix.coordinates }}' tests"
run: |
./gradlew test -Pcoordinates=${{ matrix.coordinates }}
@@ -72,7 +77,6 @@ jobs:
name: "π§ͺ All metadata tests have passed"
runs-on: "ubuntu-22.04"
timeout-minutes: 1
- if: ${{ always() }} && github.repository == 'oracle/graalvm-reachability-metadata'
needs: test-all-metadata
steps:
- name: "All tests passed"
diff --git a/.github/workflows/test-changed-infrastructure.yml b/.github/workflows/test-changed-infrastructure.yml
index 539161917..5eac2ed13 100644
--- a/.github/workflows/test-changed-infrastructure.yml
+++ b/.github/workflows/test-changed-infrastructure.yml
@@ -17,7 +17,6 @@ concurrency:
jobs:
get-changed-infrastructure:
- if: github.repository == 'oracle/graalvm-reachability-metadata'
name: "π Get a list of libraries to test for build-logic changes"
runs-on: "ubuntu-22.04"
timeout-minutes: 5
@@ -29,12 +28,13 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: 0
- - name: "π§ Prepare environment"
- uses: graalvm/setup-graalvm@v1
+
+ - name: "π§ Setup java"
+ uses: actions/setup-java@v4
with:
- java-version: "17"
- distribution: "graalvm"
- github-token: ${{ secrets.GITHUB_TOKEN }}
+ distribution: 'graalvm'
+ java-version: '21'
+
- name: "πΈοΈ Populate matrix"
id: set-matrix
run: |
@@ -58,28 +58,28 @@ jobs:
- name: "π§ Setup java"
uses: actions/setup-java@v4
with:
- distribution: "oracle"
- java-version: "17"
+ distribution: 'graalvm'
+ java-version: '21'
- - name: "π§ Prepare environment"
+ - name: "π§ Download GraalVM for metadata testing"
uses: graalvm/setup-graalvm@v1
with:
- set-java-home: "false"
- java-version: ${{ matrix.version }}
distribution: "graalvm"
+ java-version: ${{ matrix.version }}
+ set-java-home: "false"
github-token: ${{ secrets.GITHUB_TOKEN }}
native-image-job-reports: "true"
- name: "Pull allowed docker images"
run: |
- ./gradlew pullAllowedDockerImages --coordinates=${{ matrix.coordinates }}
+ ./gradlew pullAllowedDockerImages -Pcoordinates=${{ matrix.coordinates }}
- name: "Disable docker networking"
- run: bash ./.github/workflows/disable-docker.sh
+ run: bash ./.github/workflows/scripts/disable-docker.sh
- - name: "π Check metadata config files content"
+ - name: "π Check metadata files content"
run: |
- ./gradlew checkConfigFiles --coordinates=${{ matrix.coordinates }}
+ ./gradlew checkMetadataFiles -Pcoordinates=${{ matrix.coordinates }}
- name: "π§ͺ Run '${{ matrix.coordinates }}' tests"
run: |
@@ -89,7 +89,6 @@ jobs:
name: "π§ͺ All build-logic triggered tests have passed"
runs-on: "ubuntu-22.04"
timeout-minutes: 1
- if: ${{ always() }} && github.repository == 'oracle/graalvm-reachability-metadata'
needs: test-changed-infrastructure
steps:
- name: "All tests passed"
diff --git a/.github/workflows/test-changed-metadata.yml b/.github/workflows/test-changed-metadata.yml
index 31c93eee5..3e104005e 100644
--- a/.github/workflows/test-changed-metadata.yml
+++ b/.github/workflows/test-changed-metadata.yml
@@ -5,8 +5,8 @@ on:
branches:
- master
paths:
- - 'metadata/*'
- - 'tests/src/*'
+ - 'metadata/**'
+ - 'tests/src/**'
concurrency:
group: "workflow = ${{ github.workflow }}, ref = ${{ github.event.ref }}, pr = ${{ github.event.pull_request.id }}"
@@ -14,7 +14,6 @@ concurrency:
jobs:
get-changed-metadata:
- if: github.repository == 'oracle/graalvm-reachability-metadata'
name: "π Get a list of all changed libraries"
runs-on: "ubuntu-22.04"
timeout-minutes: 5
@@ -26,11 +25,11 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: 0
- - name: "π§ Prepare environment"
- uses: graalvm/setup-graalvm@v1
+ - name: "π§ Setup Java"
+ uses: actions/setup-java@v4
with:
- java-version: '17'
distribution: 'graalvm'
+ java-version: '21'
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: "πΈοΈ Populate matrix"
id: set-matrix
@@ -50,27 +49,33 @@ jobs:
steps:
- name: "βοΈ Checkout repository"
uses: actions/checkout@v4
+
- name: "π§ Setup java"
uses: actions/setup-java@v4
with:
- distribution: 'oracle'
- java-version: '17'
- - name: "π§ Prepare environment"
+ distribution: 'graalvm'
+ java-version: '21'
+
+ - name: "π§ Download GraalVM for metadata testing"
uses: graalvm/setup-graalvm@v1
with:
- set-java-home: 'false'
- java-version: ${{ matrix.version }}
distribution: 'graalvm'
- github-token: ${{ secrets.GITHUB_TOKEN }}
+ java-version: ${{ matrix.version }}
+ set-java-home: 'false'
native-image-job-reports: 'true'
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+
- name: "Pull allowed docker images"
run: |
- ./gradlew pullAllowedDockerImages --coordinates=${{ matrix.coordinates }}
+ ./gradlew pullAllowedDockerImages -Pcoordinates=${{ matrix.coordinates }}
+
- name: "Disable docker networking"
- run: bash ./.github/workflows/disable-docker.sh
- - name: "π Check metadata config files content"
+ run: bash ./.github/workflows/scripts/disable-docker.sh
+
+ - name: "π Check metadata files content"
run: |
- ./gradlew checkConfigFiles --coordinates=${{ matrix.coordinates }}
+ ./gradlew checkMetadataFiles -Pcoordinates=${{ matrix.coordinates }}
+
- name: "π§ͺ Run '${{ matrix.coordinates }}' tests"
run: |
./gradlew test -Pcoordinates=${{ matrix.coordinates }}
@@ -79,7 +84,6 @@ jobs:
name: "π§ͺ All metadata tests have passed"
runs-on: "ubuntu-22.04"
timeout-minutes: 1
- if: ${{ always() }} && github.repository == 'oracle/graalvm-reachability-metadata'
needs: test-changed-metadata
steps:
- name: "All tests passed"
diff --git a/.github/workflows/verify-new-library-version-compatibility.yml b/.github/workflows/verify-new-library-version-compatibility.yml
index 46e6e90e5..652f56fc8 100644
--- a/.github/workflows/verify-new-library-version-compatibility.yml
+++ b/.github/workflows/verify-new-library-version-compatibility.yml
@@ -16,6 +16,7 @@ concurrency:
jobs:
get-all-libraries:
name: "π Get list of all supported libraries with newer versions"
+ # Opens PRs, with labels and assignees. Works only on the main repo.
if: github.repository == 'oracle/graalvm-reachability-metadata'
runs-on: ubuntu-22.04
timeout-minutes: 5
@@ -27,12 +28,11 @@ jobs:
- name: "βοΈ Checkout repository"
uses: actions/checkout@v4
- - name: "π§ Prepare environment"
- uses: graalvm/setup-graalvm@v1
+ - name: "π§ Setup java"
+ uses: actions/setup-java@v4
with:
- java-version: '21'
distribution: 'graalvm'
- github-token: ${{ secrets.GITHUB_TOKEN }}
+ java-version: '21'
- name: "π
Set branch name"
id: set-branch-name
@@ -74,17 +74,17 @@ jobs:
- name: "π§ Setup java"
uses: actions/setup-java@v4
with:
- distribution: 'oracle'
+ distribution: 'graalvm'
java-version: '21'
- - name: "π§ Prepare environment"
+ - name: "π§ Download GraalVM for metadata testing"
uses: graalvm/setup-graalvm@v1
with:
- set-java-home: 'false'
- java-version: 21
distribution: 'graalvm'
- github-token: ${{ secrets.GITHUB_TOKEN }}
+ java-version: 25
+ set-java-home: 'false'
native-image-job-reports: 'true'
+ github-token: ${{ secrets.GITHUB_TOKEN }}
- name: "Check for an existing issue and skip further testing if found"
id: check_existing_issue
@@ -122,17 +122,17 @@ jobs:
- name: "Pull allowed docker images"
if: steps.check_existing_issue.outputs.skip != 'true'
- run: ./gradlew pullAllowedDockerImages --coordinates="${{ env.TEST_COORDINATES }}"
+ run: ./gradlew pullAllowedDockerImages -Pcoordinates="${{ env.TEST_COORDINATES }}"
- name: "Disable docker networking"
if: steps.check_existing_issue.outputs.skip != 'true'
- run: bash ./.github/workflows/disable-docker.sh
+ run: bash ./.github/workflows/scripts/disable-docker.sh
- name: "π§ͺ Run '${{ env.TEST_COORDINATES }}' tests"
if: steps.check_existing_issue.outputs.skip != 'true'
id: runtests
run: |
- bash ./.github/workflows/run-consecutive-tests.sh "${{ env.TEST_COORDINATES }}" '${{ toJson(matrix.item.versions) }}' 2>&1 | tee test_results.txt || true
+ bash ./.github/workflows/scripts/run-consecutive-tests.sh "${{ env.TEST_COORDINATES }}" '${{ toJson(matrix.item.versions) }}' 2>&1 | tee test_results.txt || true
# Extract successful versions
grep "^PASSED:" test_results.txt | sed 's/PASSED://g' > successful_versions.txt
@@ -174,7 +174,7 @@ jobs:
update_new_versions() {
while read version; do
if [ -n "$version" ]; then
- ./gradlew addTestedVersion --coordinates="${{ matrix.item.name }}:$version" --lastSupportedVersion="${{ env.LATEST_VERSION }}"
+ ./gradlew addTestedVersion -Pcoordinates="${{ matrix.item.name }}:$version" --lastSupportedVersion="${{ env.LATEST_VERSION }}"
fi
done < successful_versions.txt
}
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 000000000..62a30bd90
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,64 @@
+# Development Cheat Sheet
+
+## Prerequisites (assume exists)
+- JAVA_HOME set to JDK 21 (GraalVM recommended to match CI)
+- Docker
+- grype v0.104.0 (install: curl -sSfL https://get.anchore.io/grype/v0.104.0/install.sh | sudo sh -s -- -b /usr/local/bin)
+
+## Setup
+- Always use Gradle wrapper from repo root:
+ - Unix: ./gradlew [options]
+ - Windows: gradlew.bat [options]
+- Tip: add --stacktrace for debugging
+
+## One command for complete testing (use at the end of the task to verify)
+./gradlew testAllParallel -Pparallelism=4
+
+## Code Style
+- Always try to reuse existing code.
+- Be assertive in code.
+- Write type annotations in all functions and most variables.
+- Document code without being too verbose.
+- In java, always import classes and use them without qualified names.
+
+## Testing individual components
+
+- Clean previous build outputs for the selected coordinates: ./gradlew clean -Pcoordinates=[group:artifact:version|k/n|all]
+- Pre-fetch Docker images allowed by metadata (used in tests) for the selected coordinates: ./gradlew pullAllowedDockerImages -Pcoordinates=[group:artifact:version|k/n|all]
+- Validate reachability metadata files for the selected coordinates: ./gradlew checkMetadataFiles -Pcoordinates=[group:artifact:version|k/n|all]
+- Run Checkstyle for the selected coordinates: ./gradlew checkstyle -Pcoordinates=[group:artifact:version|k/n|all]
+- Compile test sources for the selected coordinates: ./gradlew compileTestJava -Pcoordinates=[group:artifact:version|k/n|all]
+- Run JVM-based tests for the selected coordinates: ./gradlew javaTest -Pcoordinates=[group:artifact:version|k/n|all]
+- Build native images used by native tests (compile-only) for the selected coordinates: ./gradlew nativeTestCompile -Pcoordinates=[group:artifact:version|k/n|all]
+- Run all tests for the selected coordinates: ./gradlew test -Pcoordinates=[group:artifact:version|k/n|all]
+
+
+## Check style and formatting
+- Style check: ./gradlew checkstyle
+- Format check: ./gradlew spotlessCheck
+
+## Testing the metadata
+- Single library (replace with group:artifact:version):
+ - ./gradlew pullAllowedDockerImages -Pcoordinates=group:artifact:version
+ - ./gradlew checkMetadataFiles -Pcoordinates=group:artifact:version
+ - ./gradlew test -Pcoordinates=group:artifact:version
+- Sharded example (1/64):
+ - ./gradlew pullAllowedDockerImages -Pcoordinates=1/64
+ - ./gradlew checkMetadataFiles -Pcoordinates=1/64
+ - ./gradlew test -Pcoordinates=1/64
+
+## Docker Image Vulnerability Scanning
+- Changed images between commits:
+ - ./gradlew checkAllowedDockerImages --baseCommit=$(git rev-parse origin/master) --newCommit=$(git rev-parse HEAD)
+- All allowed images:
+ - ./gradlew checkAllowedDockerImages
+
+##s Compatibility Automation (latest library versions)
+- List libs with newer upstream versions:
+ - ./gradlew fetchExistingLibrariesWithNewerVersions --quiet
+- Record a newly tested version:
+ - ./gradlew addTestedVersion -Pcoordinates="group:artifact:newVersion" --lastSupportedVersion="oldVersion"
+ - Example: ./gradlew addTestedVersion -Pcoordinates="org.postgresql:postgresql:42.7.4" --lastSupportedVersion="42.7.3"
+
+## Releases and Packaging
+- Package artifacts: ./gradlew package
diff --git a/README.md b/README.md
index f87d710fe..894fe49cc 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@ you can enable automatic use of the metadata repository for [Gradle projects](ht
[This web page](https://www.graalvm.org/native-image/libraries-and-frameworks/) provides an overview of libraries and frameworks that are tested and thus ready for GraalVM Native Image.
If you would like to see your library or framework in the list too, please open a pull request and extend [this JSON file](https://github.com/oracle/graalvm-reachability-metadata/blob/master/library-and-framework-list.json).
-Before submitting a pull request, please read [this guide](./CONTRIBUTING.md#tested-libraries-and-frameworks).
+Before submitting a pull request, please read [this guide](docs/CONTRIBUTING.md#tested-libraries-and-frameworks).
## Rationale
@@ -25,4 +25,10 @@ Please visit [this web page](https://www.graalvm.org/latest/reference-manual/nat
## Contributing
We welcome contributions from the community.
-Before submitting a pull request, please [review our contribution guide](./CONTRIBUTING.md).
+Before submitting a pull request, please [review our contribution guide](docs/CONTRIBUTING.md).
+
+## Further Information
+
+1. Continuous integration is described in [CI.md](docs/CI.md).
+2. PR Reviewing guides are described in [REVIEWING.md](docs/REVIEWING.md).
+3. Development is described in [DEVELOPING.md](docs/DEVELOPING.md).
diff --git a/build.gradle b/build.gradle
index d043c1cff..ee694bc4c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,3 +1,6 @@
+import java.util.concurrent.Executors
+import java.util.concurrent.TimeUnit
+
/*
* Copyright and related rights waived via CC0
*
@@ -8,7 +11,7 @@
plugins {
id 'base'
id "com.diffplug.spotless" version "6.3.0"
- id "org.graalvm.internal.tck-harness"
+ id "org.graalvm.internal.tck-base"
}
allprojects {
@@ -25,17 +28,17 @@ project.version("1.0.0-SNAPSHOT")
spotless {
json {
target(
- tck.metadataRoot.map { it.toString() + '/**/*.json' }.get(),
+ tck.metadataRoot.map { it.toString() + '/**/*.json' }.get(),
tck.testRoot.map { it.toString() + '/**/*.json' }
)
targetExclude(
- tck.testRoot.map { it.toString() + '/**/build/**/*.json' },
+ tck.testRoot.map { it.toString() + '/**/build/**/*.json' },
tck.repoRoot.map { it.toString() + '/.github/**/*.json' }
)
gson()
- .indentWithSpaces(2)
- .sortByKeys()
- .version("2.9.0")
+ .indentWithSpaces(2)
+ .sortByKeys()
+ .version("2.9.0")
}
}
@@ -54,3 +57,146 @@ tasks.register('package', Zip) { task ->
include("library-and-framework-list.json")
}
}
+
+tasks.register('test') { t ->
+ t.setDescription("Aggregates tests configured by the TCK harness")
+ t.setGroup("verification")
+}
+
+// Apply the harness after creating the 'test' aggregator to avoid missing property,
+// and without applying the 'java' plugin to avoid task name conflicts.
+apply plugin: "org.graalvm.internal.tck-harness"
+
+ext.runLoggedCommand = { List args, String label, File logFile, File workingDir ->
+ def header = "==== BEGIN ${label}"
+ println(header)
+ logFile.text = header + System.lineSeparator()
+
+ def pb = new ProcessBuilder(args as String[])
+ pb.directory(workingDir)
+ pb.redirectErrorStream(true)
+ pb.redirectOutput(ProcessBuilder.Redirect.appendTo(logFile))
+ def proc = pb.start()
+ int exit = proc.waitFor()
+
+ def footer = exit != 0
+ ? "==== END ${label} FAILURE (exit ${exit})"
+ : "==== END ${label} SUCCESS"
+ logFile.append(footer + System.lineSeparator())
+ println(footer)
+ return exit
+}
+
+static List
+ * Coordinates can be provided via:
+ * - -Pcoordinates= (preferred)
+ * - --coordinates=
+ * The filter can be group:artifact:version or a fractional batch in the form k/n (e.g., 1/16), or 'all'.
+ */
+public abstract class ComputeAndPullAllowedDockerImagesTask extends DefaultTask {
+
+ @Input
+ @Optional
+ public abstract Property<@NotNull String> getCoordinates();
+
+ @Option(option = "coordinates", description = "Coordinate filter (group[:artifact[:version]] or k/n fractional batch)")
+ public void setCoordinatesOption(String value) {
+ getCoordinates().set(value);
+ }
+
+ @Inject
+ protected abstract ExecOperations getExecOperations();
+
+ protected String effectiveCoordinateFilter() {
+ // Prefer task option, fallback to -Pcoordinates, then empty string (all)
+ String opt = getCoordinates().getOrNull();
+ if (opt != null) {
+ return opt;
+ }
+ Object prop = getProject().findProperty("coordinates");
+ return prop == null ? "" : prop.toString();
+ }
+
+ @TaskAction
+ public void run() throws IOException {
+ TckExtension tck = Objects.requireNonNull(getProject().getExtensions().findByType(TckExtension.class));
+
+ // Resolve coordinates
+ String filter = effectiveCoordinateFilter();
+
+ List matching;
+ if (CoordinateUtils.isFractionalBatch(filter)) {
+ int[] frac = CoordinateUtils.parseFraction(filter);
+ assert frac != null : "Already checked";
+ List all = tck.getMatchingCoordinates("all");
+ matching = CoordinateUtils.computeBatchedCoordinates(all, frac[0], frac[1]);
+ } else {
+ matching = tck.getMatchingCoordinates(filter);
+ }
+
+ if (matching == null || matching.isEmpty()) {
+ throw new GradleException("No matching coordinates found. Provide --coordinates= (preferred) or -Pcoordinates=, or a fractional batch 'k/n'.");
+ }
+
+ // Collect union of required docker images
+ Set requiredImages = new LinkedHashSet<>();
+ for (String c : matching) {
+ String[] parts = c.split(":");
+ if (parts.length < 3) {
+ throw new GradleException("Invalid coordinates: " + c);
+ }
+ String group = parts[0];
+ String artifact = parts[1];
+ String version = parts[2];
+ File f = getProject().file("tests/src/" + group + "/" + artifact + "/" + version + "/required-docker-images.txt");
+ if (f.exists()) {
+ Files.readAllLines(f.toPath()).stream()
+ .map(String::trim)
+ .filter(s -> !s.isEmpty())
+ .filter(s -> !s.startsWith("#"))
+ .forEach(requiredImages::add);
+ }
+ }
+
+ // Validate against allowed images
+ validateRequiredImages(requiredImages);
+
+ // Pull images immediately
+ for (String image : requiredImages) {
+ getLogger().lifecycle("Pulling docker image {}", image);
+ try {
+ getExecOperations().exec(spec -> {
+ spec.setExecutable("docker");
+ spec.args("pull", image);
+ });
+ } catch (Exception e) {
+ throw new GradleException("Failed to pull image " + image + ": " + e.getMessage(), e);
+ }
+ }
+
+ if (requiredImages.isEmpty()) {
+ getLogger().lifecycle("No required docker images found for coordinates filter '{}'. If your tests use docker, please read: {}", filter,
+ URI.create("https://github.com/oracle/graalvm-reachability-metadata/blob/master/CONTRIBUTING.md#providing-the-tests-that-use-docker"));
+ }
+ }
+
+ private static void validateRequiredImages(Set requiredImages) {
+ Set allowed = DockerUtils.getAllAllowedImages();
+ List notAllowed = new ArrayList<>();
+ for (String img : requiredImages) {
+ if (!allowed.contains(img)) {
+ notAllowed.add(img);
+ }
+ }
+ if (!notAllowed.isEmpty()) {
+ throw new GradleException("""
+ The following images are not in the allowed list: %s. \
+ If you need them, add Dockerfiles under tests/tck-build-logic/src/main/resources/allowed-docker-images \
+ per docs/CONTRIBUTING.md, or adjust required-docker-images.txt files.
+ """.formatted(notAllowed));
+ }
+ }
+}
diff --git a/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/updaters/FetchExistingLibrariesWithNewerVersionsTask.groovy b/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/tasks/FetchExistingLibrariesWithNewerVersionsTask.groovy
similarity index 97%
rename from tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/updaters/FetchExistingLibrariesWithNewerVersionsTask.groovy
rename to tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/tasks/FetchExistingLibrariesWithNewerVersionsTask.groovy
index c230a5693..4982b9610 100644
--- a/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/updaters/FetchExistingLibrariesWithNewerVersionsTask.groovy
+++ b/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/tasks/FetchExistingLibrariesWithNewerVersionsTask.groovy
@@ -1,4 +1,4 @@
-package org.graalvm.internal.tck.updaters
+package org.graalvm.internal.tck.harness.tasks
import com.fasterxml.jackson.annotation.JsonInclude
@@ -9,16 +9,14 @@ import groovy.json.JsonOutput
import org.graalvm.internal.tck.model.MetadataVersionsIndexEntry
import org.gradle.api.DefaultTask
import org.gradle.api.provider.ListProperty
-import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.TaskAction
-import org.gradle.api.tasks.options.Option
import org.gradle.util.internal.VersionNumber
import java.util.regex.Matcher
import java.util.regex.Pattern
-
+@SuppressWarnings("unused")
abstract class FetchExistingLibrariesWithNewerVersionsTask extends DefaultTask {
@Input
diff --git a/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/tasks/TeeOutputStream.java b/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/tasks/TeeOutputStream.java
index dd296db7e..ffc6273b6 100644
--- a/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/tasks/TeeOutputStream.java
+++ b/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/tasks/TeeOutputStream.java
@@ -7,6 +7,8 @@
package org.graalvm.internal.tck.harness.tasks;
+import org.jetbrains.annotations.NotNull;
+
import java.io.IOException;
import java.io.OutputStream;
@@ -26,13 +28,13 @@ public void write(int b) throws IOException {
}
@Override
- public void write(byte[] b) throws IOException {
+ public void write(byte @NotNull [] b) throws IOException {
out1.write(b);
out2.write(b);
}
@Override
- public void write(byte[] b, int off, int len) throws IOException {
+ public void write(byte @NotNull [] b, int off, int len) throws IOException {
out1.write(b, off, len);
out2.write(b, off, len);
}
diff --git a/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/updaters/GroupUnsupportedLibraries.groovy b/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/updaters/GroupUnsupportedLibraries.groovy
deleted file mode 100644
index edf3874f7..000000000
--- a/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/updaters/GroupUnsupportedLibraries.groovy
+++ /dev/null
@@ -1,53 +0,0 @@
-package org.graalvm.internal.tck.updaters
-
-import org.gradle.api.DefaultTask
-import org.gradle.api.provider.Property
-import org.gradle.api.tasks.Input
-import org.gradle.api.tasks.TaskAction
-import org.gradle.api.tasks.options.Option
-import org.gradle.util.internal.VersionNumber
-
-abstract class GroupUnsupportedLibraries extends DefaultTask {
-
- @Input
- @Option(option = "libraries", description = "Provides list of libraries that should be grouped.")
- abstract Property getLibraries()
-
- @TaskAction
- void action() {
- def libraries = getLibraries().get().split("\n")
-
- Map> libraryGroups = new HashMap>()
- for (def library : libraries) {
- def coordinatesPart = library.split("_")
- def artifactKey = coordinatesPart[0] + ":" + coordinatesPart[1]
- def version = coordinatesPart[2]
-
- if (libraryGroups.get(artifactKey) == null) {
- libraryGroups.put(artifactKey, new ArrayList())
- }
-
- libraryGroups.get(artifactKey).add(version)
- libraryGroups.get(artifactKey).sort(Comparator.comparing(VersionNumber::parse))
- }
-
- print generateGroupedComment(libraryGroups)
- }
-
- private static String generateGroupedComment(Map> groups) {
- def sb = new StringBuilder("List of all unsupported libraries:\n")
-
- for (String library : groups.keySet()) {
- sb.append("- ").append(library).append(":\n")
-
- for (String version : groups.get(library)) {
- sb.append("\t").append("- ").append(version).append("\n")
- }
-
- sb.append("\n")
- }
-
- return sb.toString()
- }
-
-}
diff --git a/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/ContributionTask.java b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/ContributionTask.java
index c0b76b306..dbb687b1a 100644
--- a/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/ContributionTask.java
+++ b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/ContributionTask.java
@@ -10,6 +10,7 @@
import org.graalvm.internal.tck.model.MetadataIndexEntry;
import org.graalvm.internal.tck.model.contributing.Question;
import org.graalvm.internal.tck.utils.ConfigurationStringBuilder;
+import org.graalvm.internal.tck.utils.CoordinateUtils;
import org.graalvm.internal.tck.utils.FilesUtils;
import org.graalvm.internal.tck.utils.InteractiveTaskUtils;
import org.gradle.api.DefaultTask;
diff --git a/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/CoordinateUtils.java b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/CoordinateUtils.java
deleted file mode 100644
index e71173e06..000000000
--- a/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/CoordinateUtils.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package org.graalvm.internal.tck;
-
-
-public abstract class CoordinateUtils {
- public static String replace(String template, Coordinates coordinates) {
- return template
- .replace("$group$", coordinates.group())
- .replace("$sanitizedGroup$", coordinates.sanitizedGroup())
- .replace("$artifact$", coordinates.artifact())
- .replace("$sanitizedArtifact$", coordinates.sanitizedArtifact())
- .replace("$capitalizedSanitizedArtifact$", coordinates.capitalizedSanitizedArtifact())
- .replace("$version$", coordinates.version());
- }
-
- public static Coordinates fromString(String coordinates) throws IllegalArgumentException {
- String[] coordinatesParts = coordinates.split(":");
- if (coordinatesParts.length != 3) {
- throw new IllegalArgumentException("Maven coordinates not provided in the correct format.");
- }
-
- String group = coordinatesParts[0];
- String artifact = coordinatesParts[1];
- String version = coordinatesParts[2];
- return new Coordinates(group, artifact, version);
- }
-
-}
diff --git a/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/Coordinates.java b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/Coordinates.java
index 83e90604b..e14a421ee 100644
--- a/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/Coordinates.java
+++ b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/Coordinates.java
@@ -1,16 +1,18 @@
package org.graalvm.internal.tck;
+import org.jetbrains.annotations.NotNull;
+
import java.util.Set;
/**
* Dependency coordinates in the form 'group:artifact:version'.
*/
-record Coordinates(String group, String artifact, String version) {
+public record Coordinates(String group, String artifact, String version) {
private static final Set FORBIDDEN_CHARS = Set.of(
':', '-', '.'
);
- Coordinates {
+ public Coordinates {
if (group == null || group.isEmpty()) {
throw new IllegalArgumentException("group must not be empty");
}
@@ -22,15 +24,15 @@ record Coordinates(String group, String artifact, String version) {
}
}
- String sanitizedGroup() {
+ public String sanitizedGroup() {
return sanitize(group);
}
- String sanitizedArtifact() {
+ public String sanitizedArtifact() {
return sanitize(artifact);
}
- String capitalizedSanitizedArtifact() {
+ public String capitalizedSanitizedArtifact() {
String sanitizedArtifact = sanitizedArtifact();
if (sanitizedArtifact.isEmpty()) {
return sanitizedArtifact;
@@ -39,7 +41,7 @@ String capitalizedSanitizedArtifact() {
}
@Override
- public String toString() {
+ public @NotNull String toString() {
return group + ":" + artifact + ":" + version;
}
diff --git a/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/DockerTask.java b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/DockerTask.java
index b7321bd4f..ad07c5db9 100644
--- a/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/DockerTask.java
+++ b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/DockerTask.java
@@ -1,5 +1,6 @@
package org.graalvm.internal.tck;
+import org.graalvm.internal.tck.utils.CoordinateUtils;
import org.gradle.api.DefaultTask;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.tasks.InputFiles;
@@ -20,6 +21,7 @@
import static org.graalvm.internal.tck.DockerUtils.getAllAllowedImages;
+@SuppressWarnings("unused")
public abstract class DockerTask extends DefaultTask {
@InputFiles
diff --git a/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/GrypeTask.java b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/GrypeTask.java
index 3d53fd987..8a6ffab66 100644
--- a/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/GrypeTask.java
+++ b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/GrypeTask.java
@@ -21,7 +21,7 @@
import java.util.*;
import java.util.stream.Collectors;
-
+@SuppressWarnings("unused")
public abstract class GrypeTask extends DefaultTask {
@Inject
@@ -181,13 +181,13 @@ private Vulnerabilities getVulnerabilities(String image) throws IOException {
* Get all docker images introduced between two commits
*/
private Set getChangedImages() throws IOException, URISyntaxException {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
getExecOperations().exec(spec -> {
- spec.setStandardOutput(baos);
+ spec.setStandardOutput(outputStream);
spec.commandLine("git", "diff", "--name-only", "--diff-filter=ACMRT", baseCommit, newCommit);
});
- String output = baos.toString(StandardCharsets.UTF_8);
+ String output = outputStream.toString(StandardCharsets.UTF_8);
List diffFiles = Arrays.stream(output.split("\\r?\\n"))
.filter(path -> path.contains(DOCKERFILE_DIRECTORY))
.map(path -> path.substring(path.lastIndexOf("/") + 1))
diff --git a/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/ConfigFilesChecker.java b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/MetadataFilesCheckerTask.java
similarity index 92%
rename from tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/ConfigFilesChecker.java
rename to tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/MetadataFilesCheckerTask.java
index b68e4e1ec..db2302d4e 100644
--- a/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/ConfigFilesChecker.java
+++ b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/MetadataFilesCheckerTask.java
@@ -1,30 +1,25 @@
package org.graalvm.internal.tck;
import groovy.json.JsonSlurper;
+import org.graalvm.internal.tck.utils.CoordinateUtils;
import org.gradle.api.DefaultTask;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.TaskAction;
import org.gradle.api.tasks.options.Option;
-import java.util.Scanner;
import java.io.File;
import java.io.FileNotFoundException;
-import java.util.Arrays;
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Map;
-import java.util.HashMap;
-import java.util.Set;
-import java.util.HashSet;
+import java.util.*;
import java.util.stream.Collectors;
/**
* Checks content of config files for a new library.
*
- * Run with {@code gradle checkConfigFiles --coordinates com.example:library:1.0.0}.
+ * Run with {@code gradle checkMetadataFiles -Pcoordinates com.example:library:1.0.0}.
*/
-public abstract class ConfigFilesChecker extends DefaultTask {
+@SuppressWarnings("unused")
+public abstract class MetadataFilesCheckerTask extends DefaultTask {
@InputFiles
protected abstract RegularFileProperty getMetadataRoot();
@@ -32,12 +27,17 @@ public abstract class ConfigFilesChecker extends DefaultTask {
@InputFiles
protected abstract RegularFileProperty getIndexFile();
- private final Set EXPECTED_FILES = new HashSet<>(Arrays.asList("index.json", "reflect-config.json", "resource-config.json", "serialization-config.json",
- "jni-config.json", "proxy-config.json", "predefined-classes-config.json"));
+ private final Set EXPECTED_FILES = new HashSet<>(List.of(
+ "index.json",
+ "reflect-config.json",
+ "resource-config.json",
+ "serialization-config.json",
+ "jni-config.json",
+ "proxy-config.json"));
private final Set ILLEGAL_TYPE_VALUES = new HashSet<>(List.of("java.lang"));
- private final Set PREDEFINED_ALLOWED_PACKAGES = new HashSet<>(Arrays.asList("java.lang", "java.util"));
+ private final Set PREDEFINED_ALLOWED_PACKAGES = new HashSet<>(List.of("java.lang", "java.util"));
Coordinates coordinates;
List allowedPackages;
@@ -98,7 +98,7 @@ void run() throws IllegalArgumentException, FileNotFoundException {
private List getConfigFilesForMetadataDir(File root) throws RuntimeException {
List files = new ArrayList<>();
- File [] content = root.listFiles();
+ File[] content = root.listFiles();
if (content == null) {
throw new RuntimeException("ERROR: Failed to load content of " + root.toURI());
@@ -121,7 +121,7 @@ private List> getConfigEntries(File file) {
return ((List