diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 2c9f1954e..5a3e53a24 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1,3 +1,4 @@
* @oracle/graalvm-reachability-maintainer
tests/tck-build-logic/src/main/resources/allowed-docker-images/* @matneu @matteoldani
library-and-framework-list.json @fniephaus
+.github/* @vjovanov
diff --git a/.github/workflows/check-new-library-versions.yml b/.github/workflows/check-new-library-versions.yml
deleted file mode 100644
index e012911d4..000000000
--- a/.github/workflows/check-new-library-versions.yml
+++ /dev/null
@@ -1,168 +0,0 @@
-name: "Check new library versions"
-
-# The workflow runs bi-weekly alternating with the scheduled release workflow. This way we have enough time to provide metadata for failing tests.
-# In case we need more scans, there is a possibility to trigger the workflow manually.
-on:
- schedule:
- - cron: "0 0 8 * *"
- - cron: "0 0 22 * *"
- workflow_dispatch:
-
-permissions:
- contents: write
- actions: write
-
-concurrency:
- group: "workflow = ${{ github.workflow }}, ref = ${{ github.event.ref }}, pr = ${{ github.event.pull_request.id }}"
- cancel-in-progress: true
-
-jobs:
- get-all-libraries:
- if: github.repository == 'oracle/graalvm-reachability-metadata'
- name: "π Get list of all supported libraries with newer versions"
- permissions: write-all
- runs-on: "ubuntu-22.04"
- timeout-minutes: 5
- env:
- GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- outputs:
- matrix: ${{ steps.set-matrix.outputs.matrix }}
- steps:
- - name: "βοΈ Checkout repository"
- uses: actions/checkout@v4
- - name: "π§ Prepare environment"
- uses: graalvm/setup-graalvm@v1
- with:
- java-version: '21'
- distribution: 'graalvm'
- github-token: ${{ secrets.GITHUB_TOKEN }}
- - name: "πΈοΈ Populate matrix"
- id: set-matrix
- run: |
- ./gradlew fetchExistingLibrariesWithNewerVersions --matrixLimit=200
- - name: "π¨ Create branch"
- run: |
- git config --local user.email "actions@github.com"
- git config --local user.name "Github Actions"
- git switch -C check-new-library-versions/$(date '+%Y-%m-%d')
- git push origin check-new-library-versions/$(date '+%Y-%m-%d')
-
- test-all-metadata:
- name: "π§ͺ ${{ matrix.coordinates }} (GraalVM for JDK ${{ matrix.version }} @ ${{ matrix.os }})"
- permissions: write-all
- runs-on: ${{ matrix.os }}
- timeout-minutes: 20
- env:
- GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- needs: get-all-libraries
- strategy:
- fail-fast: false
- matrix: ${{ fromJson(needs.get-all-libraries.outputs.matrix) }}
- steps:
- - name: "βοΈ Checkout repository"
- uses: actions/checkout@v4
- - name: "π§ Setup java"
- uses: actions/setup-java@v4
- with:
- distribution: 'oracle'
- java-version: '21'
- - 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: "Extract test path and library version"
- run: |
- LIBRARY_PATH=$(echo ${{ matrix.coordinates }} | cut -d ':' -f1-2 | sed 's/:/\//g')
- LATEST_VERSION=$(find tests/src/$LIBRARY_PATH/* -maxdepth 1 -type d | sort -V | tail -1 | cut -d '/' -f5)
- TEST_PATH="$LIBRARY_PATH/$LATEST_VERSION"
- TEST_COORDINATES=$(echo "$TEST_PATH" | tr / :)
-
- echo "LATEST_VERSION=$LATEST_VERSION" >> ${GITHUB_ENV}
- echo "TEST_PATH=$TEST_PATH" >> ${GITHUB_ENV}
- echo "TEST_COORDINATES=$TEST_COORDINATES" >> ${GITHUB_ENV}
- - name: "Pull allowed docker images"
- run: |
- ./gradlew pullAllowedDockerImages --coordinates=${{ env.TEST_COORDINATES }}
- - name: "Disable docker"
- run: |
- sudo apt-get install openbsd-inetd
- sudo bash -c "cat ./.github/workflows/discard-port.conf >> /etc/inetd.conf"
- sudo systemctl start inetd
- sudo mkdir /etc/systemd/system/docker.service.d
- sudo bash -c "cat ./.github/workflows/dockerd.service > /etc/systemd/system/docker.service.d/http-proxy.conf"
- sudo systemctl daemon-reload
- sudo systemctl restart docker
- - name: "π§ͺ Run '${{ env.TEST_COORDINATES }}' tests"
- run: |
- TESTING_VERSION=$(echo ${{ matrix.coordinates }} | cut -d ":" -f3)
- export GVM_TCK_LV=$TESTING_VERSION
-
- ./gradlew test -Pcoordinates=${{ env.TEST_COORDINATES }}
- - name: "βοΈ New library is supported"
- if: success()
- run: |
- bash ./.github/workflows/tryPushVersionsUpdate.sh ${{ matrix.coordinates }} ${{ env.LATEST_VERSION }}
- - name: "β New library is not supported"
- if: failure()
- run: |
- LIB=$(echo "${{ matrix.coordinates }}" | sed 's/:/_/g')
- touch $LIB
- echo "UNSUPPORTED_LIB=$LIB" >> $GITHUB_ENV
- - name: "Upload artifacts"
- if: failure()
- id: upload
- continue-on-error: true
- uses: actions/upload-artifact@v4
- with:
- name: ${{ env.UNSUPPORTED_LIB }}
- path: ${{ env.UNSUPPORTED_LIB }}
- retention-days: 1
-
- process-results:
- name: "π§ͺ Process results"
- runs-on: "ubuntu-22.04"
- if: ${{ always() }}
- needs:
- - get-all-libraries
- - test-all-metadata
- permissions: write-all
- env:
- GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- steps:
- - name: "βοΈ Checkout repository"
- uses: actions/checkout@v4
- - name: "π§ Setup java"
- uses: actions/setup-java@v4
- with:
- distribution: 'oracle'
- java-version: '21'
- - name: "βοΈ PR for supported versions"
- run: |
- git config --local user.email "actions@github.com"
- git config --local user.name "Github Actions"
- git fetch origin check-new-library-versions/$(date '+%Y-%m-%d')
- git checkout check-new-library-versions/$(date '+%Y-%m-%d')
- gh pr create --title "Update supported library versions" --body "This pull request updates supported versions of the existing libraries in the repo"
- - name: "Download artifacts for unsupported versions"
- uses: actions/download-artifact@v4
- with:
- path: ./unsupported
- - name: "βοΈ Issue for unsupported versions"
- run: |
- git config --local user.email "actions@github.com"
- git config --local user.name "Github Actions"
-
- LABEL="library-update"
- ALL_LIBRARIES=$(ls unsupported)
- FORMATTED_BODY=$(./gradlew -q groupLibrariesByName --libraries="$ALL_LIBRARIES")
-
- EXISTING_ISSUE=$(gh issue list --label "$LABEL" --state open --limit 1 --json url | jq -r '.[0].url')
- if [ $EXISTING_ISSUE != "null" ]; then
- gh issue edit $EXISTING_ISSUE --body "$FORMATTED_BODY"
- else
- gh issue create --title "List unsupported libraries versions" --body "$FORMATTED_BODY" --label $LABEL
- fi
diff --git a/.github/workflows/disable-docker.sh b/.github/workflows/disable-docker.sh
new file mode 100644
index 000000000..4387fabf1
--- /dev/null
+++ b/.github/workflows/disable-docker.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+# Copyright and related rights waived via CC0
+#
+# You should have received a copy of the CC0 legalcode along with this
+# work. If not, see .
+
+# Purpose:
+# Make Docker unable to access the network during tests by:
+# 1) Enabling the discard service on localhost:9 (TCP/UDP) via inetd to accept and immediately discard traffic.
+# 2) Pointing Docker's HTTP(S) proxy environment variables to http(s)://localhost:9 using a systemd drop-in.
+#
+# Why:
+# - Tests may only use pre-pulled/allowed Docker images. This prevents Docker from downloading anything else.
+# - Using the discard service avoids long TCP connection timeouts: the local port accepts connections and discards
+# data quickly, causing Docker's proxy connections to fail fast.
+#
+# Notes:
+# - This script is designed for GitHub Actions Ubuntu runners with sudo.
+# - It is idempotent: re-running it won't duplicate config lines or unnecessarily restart Docker.
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
+sudo apt-get install openbsd-inetd
+sudo bash -c "cat ${SCRIPT_DIR}/discard-port.conf >> /etc/inetd.conf"
+sudo systemctl start inetd
+sudo mkdir /etc/systemd/system/docker.service.d
+sudo bash -c "cat ${SCRIPT_DIR}/dockerd.service > /etc/systemd/system/docker.service.d/http-proxy.conf"
+sudo systemctl daemon-reload
+sudo systemctl restart docker
+echo "Docker outbound network effectively disabled via proxy=http(s)://localhost:9 backed by inetd discard service."
diff --git a/.github/workflows/run-consecutive-tests.sh b/.github/workflows/run-consecutive-tests.sh
new file mode 100644
index 000000000..beaac23a7
--- /dev/null
+++ b/.github/workflows/run-consecutive-tests.sh
@@ -0,0 +1,80 @@
+#!/bin/bash
+
+# Copyright and related rights waived via CC0
+#
+# You should have received a copy of the CC0 legalcode along with this
+# work. If not, see .
+
+set -u
+
+if [ $# -ne 2 ]; then
+ echo "Usage: $0 "
+ exit 1
+fi
+
+# Input parameters
+TEST_COORDINATES="$1"
+VERSIONS_JSON="$2"
+
+# Remove surrounding single quotes if present (when called from workflow)
+VERSIONS_JSON="${VERSIONS_JSON#"${VERSIONS_JSON%%[!\']*}"}"
+VERSIONS_JSON="${VERSIONS_JSON%"${VERSIONS_JSON##*[!\']}"}"
+
+# Parse versions with jq
+readarray -t VERSIONS < <(echo "$VERSIONS_JSON" | jq -r '.[]')
+export DELIMITER="========================================================================================"
+
+run_multiple_attempts() {
+ local stage="$1"
+ local max_attempts="$2"
+ local gradle_command="$3"
+
+ echo "$DELIMITER"
+ echo " $TEST_COORDINATES:$VERSION stage $stage"
+ echo "$DELIMITER"
+
+ local attempt=0
+ local result=0
+
+ while [ $attempt -lt "$max_attempts" ]; do
+ local cmd_str="GVM_TCK_LV=\"$VERSION\" ./gradlew clean $gradle_command -Pcoordinates=\"$TEST_COORDINATES\""
+ if [ $attempt -gt 0 ]; then
+ echo "Re-running stage '$stage' (attempt $((attempt + 1))/$max_attempts)"
+ fi
+
+ eval "$cmd_str"
+ result=$?
+
+ if [ "$result" -eq 0 ]; then
+ return 0
+ fi
+
+ attempt=$((attempt + 1))
+ done
+
+ echo "FAILED [$stage][$VERSION][$cmd_str]"
+ return $result
+}
+
+for VERSION in "${VERSIONS[@]}"; do
+ echo "$DELIMITER"
+ echo " Testing $TEST_COORDINATES:$VERSION"
+ echo "$DELIMITER"
+
+
+ if ! run_multiple_attempts "javac compile" 1 javac; then
+ break
+ fi
+
+ if ! run_multiple_attempts "native-image build" 1 nativeTestCompile; then
+ break
+ fi
+
+ if ! run_multiple_attempts "native-image run" 3 test; then
+ break
+ fi
+
+ echo "PASSED:$VERSION"
+done
+
+exit 0
diff --git a/.github/workflows/test-all-metadata.yml b/.github/workflows/test-all-metadata.yml
index 5b8dae16c..9c4490e11 100644
--- a/.github/workflows/test-all-metadata.yml
+++ b/.github/workflows/test-all-metadata.yml
@@ -63,15 +63,8 @@ jobs:
- name: "Pull allowed docker images"
run: |
./gradlew pullAllowedDockerImages --coordinates=${{ matrix.coordinates }}
- - name: "Disable docker"
- run: |
- sudo apt-get install openbsd-inetd
- sudo bash -c "cat ./.github/workflows/discard-port.conf >> /etc/inetd.conf"
- sudo systemctl start inetd
- sudo mkdir /etc/systemd/system/docker.service.d
- sudo bash -c "cat ./.github/workflows/dockerd.service > /etc/systemd/system/docker.service.d/http-proxy.conf"
- sudo systemctl daemon-reload
- sudo systemctl restart docker
+ - name: "Disable docker networking"
+ run: bash ./.github/workflows/disable-docker.sh
- name: "π§ͺ Run '${{ matrix.coordinates }}' tests"
run: |
./gradlew test -Pcoordinates=${{ matrix.coordinates }}
diff --git a/.github/workflows/test-changed-metadata.yml b/.github/workflows/test-changed-metadata.yml
index df7e33a2c..d29dceebb 100644
--- a/.github/workflows/test-changed-metadata.yml
+++ b/.github/workflows/test-changed-metadata.yml
@@ -66,15 +66,8 @@ jobs:
- name: "Pull allowed docker images"
run: |
./gradlew pullAllowedDockerImages --coordinates=${{ matrix.coordinates }}
- - name: "Disable docker"
- run: |
- sudo apt-get install openbsd-inetd
- sudo bash -c "cat ./.github/workflows/discard-port.conf >> /etc/inetd.conf"
- sudo systemctl start inetd
- sudo mkdir /etc/systemd/system/docker.service.d
- sudo bash -c "cat ./.github/workflows/dockerd.service > /etc/systemd/system/docker.service.d/http-proxy.conf"
- sudo systemctl daemon-reload
- sudo systemctl restart docker
+ - name: "Disable docker networking"
+ run: bash ./.github/workflows/disable-docker.sh
- name: "π Check metadata config files content"
run: |
./gradlew checkConfigFiles --coordinates=${{ matrix.coordinates }}
diff --git a/.github/workflows/tryPushVersionsUpdate.sh b/.github/workflows/tryPushVersionsUpdate.sh
deleted file mode 100644
index 4d807c3bd..000000000
--- a/.github/workflows/tryPushVersionsUpdate.sh
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/bin/bash
-:' This script tries to run addTestedVersion gradle task which adds new version in the tested-versions list of the proper index.json file.
-Since the script could be executed from multiple parallel jobs, we want to avoid two things here: overwriting of previous changes and merge conflicts.
-To prevent overwriting of changes that some job already created, we only push changes from the current job if we are 0 commits behind the origin branch.
-Once that is achieved, we can try to push changes.
-If the push was rejected because of a merge conflict, we are: removing changes of the current job, rebasing, and doing the process again until it succeeds.
-'
-
-set -x
-
-git config --local user.email "actions@github.com"
-git config --local user.name "Github Actions"
-
-BRANCH="check-new-library-versions/$(date '+%Y-%m-%d')"
-git fetch origin "$BRANCH"
-git checkout "$BRANCH"
-
-while [ true ]
-do
- # update the list of tested versions
- ./gradlew addTestedVersion --coordinates="$1" --lastSupportedVersion="$2"
-
- # commit changes
- git add -u
- git commit -m "$1"
-
- # only push changes if we are not behind the remote branch
- if [ "$(git rev-list --count origin/$BRANCH --not $BRANCH)" -eq 0 ]
- then
- # try to push changes
- git push origin "$BRANCH"
- PUSH_RETVAL=$?
- if [ "$PUSH_RETVAL" -eq 0 ]
- then
- # if the push was successful, we can exit the loop
- break
- fi
- fi
-
- # we are either behind the remote branch or we have a merge conflict => remove changes and rebase accepting incoming changes
- git reset --hard HEAD~1
- git fetch origin "$BRANCH"
- git rebase -X theirs "origin/$BRANCH"
-done
-
-
diff --git a/.github/workflows/verify-new-library-version-compatibility.yml b/.github/workflows/verify-new-library-version-compatibility.yml
new file mode 100644
index 000000000..46e6e90e5
--- /dev/null
+++ b/.github/workflows/verify-new-library-version-compatibility.yml
@@ -0,0 +1,266 @@
+name: "Verify compatibility with latest library versions"
+
+on:
+ schedule:
+ - cron: '0 0 * * 0'
+ workflow_dispatch:
+
+permissions:
+ contents: write
+ actions: write
+
+concurrency:
+ group: "workflow=${{ github.workflow }},ref=${{ github.event.ref }},pr=${{ github.event.pull_request.id }}"
+ cancel-in-progress: true
+
+jobs:
+ get-all-libraries:
+ name: "π Get list of all supported libraries with newer versions"
+ if: github.repository == 'oracle/graalvm-reachability-metadata'
+ runs-on: ubuntu-22.04
+ timeout-minutes: 5
+ permissions: write-all
+ outputs:
+ matrix: ${{ steps.set-matrix.outputs.matrix }}
+ branch: ${{ steps.set-branch-name.outputs.branch }}
+ steps:
+ - name: "βοΈ Checkout repository"
+ uses: actions/checkout@v4
+
+ - name: "π§ Prepare environment"
+ uses: graalvm/setup-graalvm@v1
+ with:
+ java-version: '21'
+ distribution: 'graalvm'
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: "π
Set branch name"
+ id: set-branch-name
+ run: |
+ BRANCH_NAME="check-new-library-versions/$(date '+%Y-%m-%dT%H-%M')"
+ echo "branch=$BRANCH_NAME" >> $GITHUB_OUTPUT
+
+ - name: "πΈοΈ Populate matrix"
+ id: set-matrix
+ run: |
+ echo "matrix=$(./gradlew fetchExistingLibrariesWithNewerVersions --quiet | sed -n '/\[/,$p')" >> $GITHUB_OUTPUT
+
+ - name: "π¨ Create branch"
+ run: |
+ git config --local user.email "actions@github.com"
+ git config --local user.name "Github Actions"
+ git checkout -b "${{ steps.set-branch-name.outputs.branch }}"
+ git push origin "${{ steps.set-branch-name.outputs.branch }}"
+
+ test-all-metadata:
+ name: "π§ͺ ${{ matrix.item.name }}"
+ runs-on: ubuntu-22.04
+ needs: get-all-libraries
+ permissions: write-all
+ env:
+ CURRENT_JOB_NAME: "π§ͺ ${{ matrix.item.name }}"
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ ISSUE_TITLE_PREFIX: "[Automation] "
+ ISSUE_TITLE_MIDDLE: " fails for "
+ LOG_LINES: "300"
+ strategy:
+ fail-fast: false
+ matrix:
+ item: ${{ fromJson(needs.get-all-libraries.outputs.matrix) }}
+ steps:
+ - name: "βοΈ Checkout repository"
+ uses: actions/checkout@v4
+
+ - name: "π§ Setup java"
+ uses: actions/setup-java@v4
+ with:
+ distribution: 'oracle'
+ java-version: '21'
+
+ - name: "π§ Prepare environment"
+ uses: graalvm/setup-graalvm@v1
+ with:
+ set-java-home: 'false'
+ java-version: 21
+ distribution: 'graalvm'
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ native-image-job-reports: 'true'
+
+ - name: "Check for an existing issue and skip further testing if found"
+ id: check_existing_issue
+ run: |
+ GROUP_ID="$(echo "${{ matrix.item.name }}" | cut -d: -f1)"
+ ARTIFACT_ID="$(echo "${{ matrix.item.name }}" | cut -d: -f2)"
+
+ readarray -t VERSIONS < <(echo '${{ toJson(matrix.item.versions) }}' | jq -r '.[]')
+ FIRST_TESTING_VERSION="${VERSIONS[0]}"
+
+ TITLE_SEARCH="${{ env.ISSUE_TITLE_MIDDLE }}$GROUP_ID:$ARTIFACT_ID:$FIRST_TESTING_VERSION"
+
+ ISSUE_NUMBER=$(gh issue list --repo "${{ github.repository }}" --state open --search "in:title $TITLE_SEARCH" --json number,title --jq \
+ '.[] | select(.title | endswith("'"$TITLE_SEARCH"'")) | .number')
+
+ if [[ -n "$ISSUE_NUMBER" ]]; then
+ echo "skip=true" >> "$GITHUB_OUTPUT"
+ echo "There is no progress since last time this version was tested. Skipping further steps."
+ else
+ echo "skip=false" >> "$GITHUB_OUTPUT"
+ fi
+
+ - name: "Extract test path and library version"
+ if: steps.check_existing_issue.outputs.skip != 'true'
+ id: extract-params
+ run: |
+ LIBRARY_PATH=$(echo "${{ matrix.item.name }}" | sed 's/:/\//g')
+ LATEST_VERSION=$(find tests/src/$LIBRARY_PATH/* -maxdepth 1 -type d | sort -V | tail -1 | cut -d '/' -f5)
+ TEST_PATH="$LIBRARY_PATH/$LATEST_VERSION"
+ TEST_COORDINATES=$(echo "$TEST_PATH" | tr / :)
+
+ echo "LATEST_VERSION=$LATEST_VERSION" >> ${GITHUB_ENV}
+ echo "TEST_PATH=$TEST_PATH" >> ${GITHUB_ENV}
+ echo "TEST_COORDINATES=$TEST_COORDINATES" >> ${GITHUB_ENV}
+
+ - name: "Pull allowed docker images"
+ if: steps.check_existing_issue.outputs.skip != 'true'
+ run: ./gradlew pullAllowedDockerImages --coordinates="${{ env.TEST_COORDINATES }}"
+
+ - name: "Disable docker networking"
+ if: steps.check_existing_issue.outputs.skip != 'true'
+ run: bash ./.github/workflows/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
+
+ # Extract successful versions
+ grep "^PASSED:" test_results.txt | sed 's/PASSED://g' > successful_versions.txt
+ echo "successful_versions<> $GITHUB_OUTPUT
+ cat successful_versions.txt >> $GITHUB_OUTPUT
+ echo "EOF" >> $GITHUB_OUTPUT
+
+ # Extract failure type and failed version
+ awk -F'[][]' '/^FAILED/ {print "failure_type="$2; print "failed_version="$4; print "failed_command="$6}' test_results.txt >> $GITHUB_OUTPUT
+
+ # Fetch the job URL
+ JOB_ID=$(
+ gh run view "${{ github.run_id }}" --repo "${{ github.repository }}" --json jobs \
+ | jq -r --arg name "$CURRENT_JOB_NAME" '.jobs[] | select(.name | startswith($name)) | .databaseId' \
+ | head -n1
+ )
+ if [ -z "$JOB_ID" ] || [ "$JOB_ID" = "null" ]; then
+ # Fallback to run-level URL if job lookup fails
+ echo "runner_log_url=https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" >> $GITHUB_OUTPUT
+ else
+ echo "runner_log_url=https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}/job/$JOB_ID" >> $GITHUB_OUTPUT
+ fi
+
+ # Extract log tail
+ echo "log_tail<> $GITHUB_OUTPUT
+ tail "-n${{ env.LOG_LINES }}" test_results.txt | head -c 900000 >> $GITHUB_OUTPUT
+ echo "" >> $GITHUB_OUTPUT
+ echo "EOF" >> $GITHUB_OUTPUT
+
+ - name: "βοΈ New library versions are supported (with locks, waiting and retries)"
+ if: steps.check_existing_issue.outputs.skip != 'true' && steps.runtests.outputs.successful_versions != ''
+ env:
+ BRANCH: ${{ needs.get-all-libraries.outputs.branch }}
+ run: |
+ set -euo pipefail
+ git config --local user.email "actions@github.com"
+ git config --local user.name "Github Actions"
+
+ update_new_versions() {
+ while read version; do
+ if [ -n "$version" ]; then
+ ./gradlew addTestedVersion --coordinates="${{ matrix.item.name }}:$version" --lastSupportedVersion="${{ env.LATEST_VERSION }}"
+ fi
+ done < successful_versions.txt
+ }
+
+ # Small jitter to reduce contention start
+ sleep $((RANDOM % 5 + 1))
+
+ for i in {1..10}; do
+ # Always start from the latest remote state
+ git fetch origin "$BRANCH"
+ git checkout -B "$BRANCH" "origin/$BRANCH"
+
+ update_new_versions
+
+ # If nothing changed, exit early
+ if git status --porcelain | grep -q .; then
+ git add -u
+ git commit -m "Update tested versions for ${{ matrix.item.name }}"
+ else
+ echo "No changes to commit for ${{ matrix.item.name }}."
+ exit 0
+ fi
+
+ if git push origin "$BRANCH"; then
+ echo "Pushed successfully."
+ exit 0
+ fi
+
+ echo "Push failed (likely concurrent update). Waiting and retrying..."
+ sleep 5
+ done
+
+ echo "Timed out waiting to push updates after concurrent jobs."
+ exit 1
+
+ - name: "β New library version is not supported"
+ if: steps.check_existing_issue.outputs.skip != 'true' && steps.runtests.outputs.failed_version != ''
+ run: |
+ git config --local user.email "actions@github.com"
+ git config --local user.name "Github Actions"
+
+ FAILED_VERSION="${{ steps.runtests.outputs.failed_version }}"
+ REPO="${{ github.repository }}"
+ TITLE="${{ env.ISSUE_TITLE_PREFIX }}${{ steps.runtests.outputs.failure_type }}${{ env.ISSUE_TITLE_MIDDLE }}${{ matrix.item.name }}:$FAILED_VERSION"
+
+ BODY_FILE=$(mktemp)
+ # Use single-quoted here-doc to disable any shell expansion of log content
+ cat > "$BODY_FILE" <<'EOF'
+ Failure kind: ${{ steps.runtests.outputs.failure_type }}
+ Reproducer: `${{ steps.runtests.outputs.failed_command }}`
+ Runner log: ${{ steps.runtests.outputs.runner_log_url }}
+ Last ${{ env.LOG_LINES }} lines of the log:
+ ```console
+ ${{ steps.runtests.outputs.log_tail }}
+ ```
+ EOF
+
+ ISSUE_NUMBER=$(gh issue list --repo "$REPO" --state open --search "$TITLE" --json number,title --jq '.[] | select(.title | startswith("'"$TITLE"'")) | .number')
+ if [ -n "$ISSUE_NUMBER" ]; then
+ echo "Updating existing issue #$ISSUE_NUMBER"
+ gh issue edit "$ISSUE_NUMBER" --repo "$REPO" --body-file "$BODY_FILE"
+ else
+ echo "Creating new issue"
+ gh issue create --repo "$REPO" --title "$TITLE" --body-file "$BODY_FILE"
+ fi
+
+ rm "$BODY_FILE"
+
+ process-results:
+ name: "π§ͺ Process results"
+ runs-on: ubuntu-22.04
+ permissions: write-all
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ if: ${{ always() }}
+ needs:
+ - get-all-libraries
+ - test-all-metadata
+ steps:
+ - name: "βοΈ Checkout repository"
+ uses: actions/checkout@v4
+
+ - name: "βοΈ PR for supported versions"
+ run: |
+ git config --local user.email "actions@github.com"
+ git config --local user.name "Github Actions"
+ git fetch origin ${{ needs.get-all-libraries.outputs.branch }}
+ git checkout ${{ needs.get-all-libraries.outputs.branch }}
+ gh pr create --title "[Automation] Update supported library versions $(date '+%Y-%m-%dT%H:%M')" --body "This pull request updates supported versions of the existing libraries in the repo"
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 14ab8cd4a..6875361b0 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
@@ -19,6 +19,9 @@ import org.graalvm.internal.tck.TestedVersionUpdaterTask
import org.graalvm.internal.tck.harness.tasks.TestInvocationTask
import org.graalvm.internal.tck.harness.tasks.CheckstyleInvocationTask
import org.graalvm.internal.tck.harness.tasks.CleanInvocationTask
+import org.graalvm.internal.tck.harness.tasks.JavacInvocationTask
+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
@@ -43,6 +46,24 @@ Provider checkstyle = tasks.register("checkstyle") { task ->
task.setGroup(JavaBasePlugin.VERIFICATION_GROUP)
}
+ // gradle javac -Pcoordinates=
+Provider javac = tasks.register("javac") { task ->
+ task.setDescription("Compiles sources (javac) for all subprojects")
+ task.setGroup(LifecycleBasePlugin.BUILD_GROUP)
+}
+
+ // gradle nativeTestCompile -Pcoordinates=
+Provider nativeTestCompile = tasks.register("nativeTestCompile") { task ->
+ task.setDescription("Compiles native tests (nativeTestCompile) for all subprojects")
+ task.setGroup(LifecycleBasePlugin.BUILD_GROUP)
+}
+
+ // gradle javaTest -Pcoordinates=
+Provider javaTest = tasks.register("javaTest") { task ->
+ task.setDescription("Runs JVM tests (Gradle 'test') for all subprojects")
+ task.setGroup(JavaBasePlugin.VERIFICATION_GROUP)
+}
+
tasks.named("check").configure {
dependsOn(checkstyle)
}
@@ -72,6 +93,30 @@ for (String coordinates in matchingCoordinates) {
clean.configure {
dependsOn(cleanTaskName)
}
+
+ String javacTaskName = generateTaskName("javac", coordinates)
+ if ((!tasks.getNames().contains(javacTaskName))) {
+ tasks.register(javacTaskName, JavacInvocationTask, coordinates)
+ }
+ javac.configure {
+ dependsOn(javacTaskName)
+ }
+
+ String nativeTestCompileTaskName = generateTaskName("nativeTestCompile", coordinates)
+ if ((!tasks.getNames().contains(nativeTestCompileTaskName))) {
+ tasks.register(nativeTestCompileTaskName, NativeTestCompileInvocationTask, coordinates)
+ }
+ nativeTestCompile.configure {
+ dependsOn(nativeTestCompileTaskName)
+ }
+
+ String javaTestTaskName = generateTaskName("javaTest", coordinates)
+ if ((!tasks.getNames().contains(javaTestTaskName))) {
+ tasks.register(javaTestTaskName, JavaTestInvocationTask, coordinates)
+ }
+ javaTest.configure {
+ dependsOn(javaTestTaskName)
+ }
}
// gradle diff -PbaseCommit= -PnewCommit=
diff --git a/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/tasks/JavaTestInvocationTask.groovy b/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/tasks/JavaTestInvocationTask.groovy
new file mode 100644
index 000000000..efcf472f5
--- /dev/null
+++ b/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/tasks/JavaTestInvocationTask.groovy
@@ -0,0 +1,35 @@
+/*
+ * Copyright and related rights waived via CC0
+ *
+ * You should have received a copy of the CC0 legalcode along with this
+ * work. If not, see .
+ */
+
+package org.graalvm.internal.tck.harness.tasks
+
+import org.gradle.api.tasks.Input
+
+import javax.inject.Inject
+/**
+ * Task that is used to run JVM tests (Gradle 'test') on subprojects.
+ */
+@SuppressWarnings("unused")
+abstract class JavaTestInvocationTask extends AbstractSubprojectTask {
+
+ @Inject
+ JavaTestInvocationTask(String coordinates) {
+ super(coordinates)
+ }
+
+ @Override
+ @Input
+ List getCommand() {
+ return [tckExtension.repoRoot.get().asFile.toPath().resolve("gradlew").toString(), "test"]
+ }
+
+ @Override
+ protected String getErrorMessage(int exitCode) {
+ "Java tests failed"
+ }
+
+}
diff --git a/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/tasks/JavacInvocationTask.groovy b/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/tasks/JavacInvocationTask.groovy
new file mode 100644
index 000000000..63434e2eb
--- /dev/null
+++ b/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/tasks/JavacInvocationTask.groovy
@@ -0,0 +1,35 @@
+/*
+ * Copyright and related rights waived via CC0
+ *
+ * You should have received a copy of the CC0 legalcode along with this
+ * work. If not, see .
+ */
+
+package org.graalvm.internal.tck.harness.tasks
+
+import org.gradle.api.tasks.Input
+
+import javax.inject.Inject
+/**
+ * Task that is used to compile subprojects with javac.
+ */
+@SuppressWarnings("unused")
+abstract class JavacInvocationTask extends AbstractSubprojectTask {
+
+ @Inject
+ JavacInvocationTask(String coordinates) {
+ super(coordinates)
+ }
+
+ @Override
+ @Input
+ List getCommand() {
+ return [tckExtension.repoRoot.get().asFile.toPath().resolve("gradlew").toString(), "compileTestJava"]
+ }
+
+ @Override
+ protected String getErrorMessage(int exitCode) {
+ "Compilation failed"
+ }
+
+}
diff --git a/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/tasks/NativeTestCompileInvocationTask.groovy b/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/tasks/NativeTestCompileInvocationTask.groovy
new file mode 100644
index 000000000..158b2dfbd
--- /dev/null
+++ b/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/tasks/NativeTestCompileInvocationTask.groovy
@@ -0,0 +1,35 @@
+/*
+ * Copyright and related rights waived via CC0
+ *
+ * You should have received a copy of the CC0 legalcode along with this
+ * work. If not, see .
+ */
+
+package org.graalvm.internal.tck.harness.tasks
+
+import org.gradle.api.tasks.Input
+
+import javax.inject.Inject
+/**
+ * Task that is used to compile native tests (Gradle 'nativeTestCompile') on subprojects.
+ */
+@SuppressWarnings("unused")
+abstract class NativeTestCompileInvocationTask extends AbstractSubprojectTask {
+
+ @Inject
+ NativeTestCompileInvocationTask(String coordinates) {
+ super(coordinates)
+ }
+
+ @Override
+ @Input
+ List getCommand() {
+ return [tckExtension.repoRoot.get().asFile.toPath().resolve("gradlew").toString(), "nativeTestCompile"]
+ }
+
+ @Override
+ protected String getErrorMessage(int exitCode) {
+ "Native test compilation failed"
+ }
+
+}
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/updaters/FetchExistingLibrariesWithNewerVersionsTask.groovy
index 23197c1b7..c230a5693 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/updaters/FetchExistingLibrariesWithNewerVersionsTask.groovy
@@ -24,10 +24,6 @@ abstract class FetchExistingLibrariesWithNewerVersionsTask extends DefaultTask {
@Input
abstract ListProperty getAllLibraryCoordinates()
- @Input
- @Option(option = "matrixLimit", description = "Sets the maximum number of coordinates in the final matrix")
- abstract Property getMatrixLimit()
-
private static final List INFRASTRUCTURE_TESTS = List.of("samples", "org.example")
@TaskAction
@@ -50,17 +46,15 @@ abstract class FetchExistingLibrariesWithNewerVersionsTask extends DefaultTask {
}
}
- if (newerVersions.size() > getMatrixLimit().get()) {
- newerVersions = newerVersions.subList(0, getMatrixLimit().get())
+ def map = [:]
+ newerVersions.each { coord ->
+ def (group, artifact, version) = coord.tokenize(':')
+ def key = "${group}:${artifact}"
+ map[key] = (map[key] ?: []) + version
}
+ def pairs = map.collect { k, v -> [name: k, versions: v] }
- def matrix = [
- "coordinates": newerVersions,
- "version" : ["17"],
- "os" : ["ubuntu-latest"]
- ]
-
- new File(System.getenv("GITHUB_OUTPUT")).append("matrix::${JsonOutput.toJson(matrix)}")
+ println JsonOutput.toJson(pairs)
}
static List getNewerVersionsFor(String library, String startingVersion) {
@@ -88,14 +82,10 @@ abstract class FetchExistingLibrariesWithNewerVersionsTask extends DefaultTask {
int indexOfStartingVersion = allVersions.indexOf(startingVersion);
if (indexOfStartingVersion < 0) {
- System.out.println("Cannot find starting version in index file: " + libraryName + " for version " + startingVersion);
return new ArrayList<>();
}
allVersions = allVersions.subList(indexOfStartingVersion, allVersions.size());
- if (allVersions.size() <= 1) {
- System.out.println("Cannot find newer versions for " + libraryName + " after the version " + startingVersion);
- }
return allVersions.subList(1, allVersions.size());
}
diff --git a/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/TestedVersionUpdaterTask.java b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/TestedVersionUpdaterTask.java
index 87163c3bf..1ec9a7346 100644
--- a/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/TestedVersionUpdaterTask.java
+++ b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/TestedVersionUpdaterTask.java
@@ -19,6 +19,7 @@
import java.io.File;
import java.io.IOException;
+import java.nio.file.Files;
import java.util.Comparator;
import java.util.List;
@@ -65,6 +66,11 @@ void run() throws IllegalStateException, IOException {
DefaultPrettyPrinter prettyPrinter = new DefaultPrettyPrinter();
prettyPrinter.indentArraysWith(DefaultIndenter.SYSTEM_LINEFEED_INSTANCE);
- objectMapper.writer(prettyPrinter).writeValue(coordinatesMetadataIndex, entries);
+ // Ensure the JSON file ends with a trailing EOL
+ String json = objectMapper.writer(prettyPrinter).writeValueAsString(entries);
+ if (!json.endsWith("\n")) {
+ json = json + System.lineSeparator();
+ }
+ Files.writeString(coordinatesMetadataIndex.toPath(), json, java.nio.charset.StandardCharsets.UTF_8);
}
}