Skip to content

Verify compatibility with latest library versions #548

Verify compatibility with latest library versions

Verify compatibility with latest library versions #548

# Scheduled upstream-version tracker (every 6 hours): discovers newer versions, tests each across
# the matrix, records passing ones via addTestedVersion (§TCK-test-harness.5) and files issues.
# §CI-verify-new-library-version-compatibility implements §FS-library-version-update-automation.
name: "Verify compatibility with latest library versions"
on:
schedule:
- cron: '0 */6 * * *'
workflow_dispatch:
permissions:
contents: read
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"
# 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: 20
permissions:
contents: write
issues: read
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
none-found: ${{ steps.set-matrix.outputs.none-found }}
branch: ${{ steps.set-branch-name.outputs.branch }}
steps:
- name: "☁️ Checkout repository"
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: "🔧 Setup java"
uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4
with:
distribution: 'graalvm'
java-version: '25'
- 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
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -o pipefail
MATRIX_OUTPUT_FILE="$(mktemp)"
RAW_OUTPUT="$(./gradlew fetchExistingLibrariesWithNewerVersions --quiet | sed -n '/\[/,$p')"
JSON_PAYLOAD="$(printf '%s' "$RAW_OUTPUT" | jq -c '.')"
OPEN_ISSUES_JSON="$(
gh issue list \
--repo "${{ github.repository }}" \
--state open \
--limit 1000 \
--json title
)"
FILTERED_JSON_PAYLOAD="$(
printf '%s' "$JSON_PAYLOAD" | jq -c \
--arg issueTitlePrefix "[Automation] " \
--arg issueTitleMiddle " fails for " \
--argjson issues "$OPEN_ISSUES_JSON" '
[
.[]
| . as $library
| ($library.versions[0] // null) as $firstVersion
| if $firstVersion == null then
$library
else
($library.name + ":" + $firstVersion) as $gavCoordinates
| ($issueTitleMiddle + $gavCoordinates) as $titleEnd
| select(
any(
$issues[]?;
.title | (startswith($issueTitlePrefix) and endswith($titleEnd))
) | not
)
end
]
'
)"
TOTAL_CANDIDATES="$(printf '%s' "$JSON_PAYLOAD" | jq 'length')"
FILTERED_CANDIDATES="$(printf '%s' "$FILTERED_JSON_PAYLOAD" | jq 'length')"
SKIPPED_CANDIDATES="$((TOTAL_CANDIDATES - FILTERED_CANDIDATES))"
{
echo "Compatibility candidates discovered: $TOTAL_CANDIDATES"
echo "Filtered because an open automation issue already exists for the first candidate version: $SKIPPED_CANDIDATES"
echo "Libraries scheduled for testing: $FILTERED_CANDIDATES"
} >> "$GITHUB_STEP_SUMMARY"
GITHUB_OUTPUT="$MATRIX_OUTPUT_FILE" ./gradlew generateNewLibraryVersionCompatibilityMatrix -PnewLibraryVersionCandidates="$FILTERED_JSON_PAYLOAD"
{
echo "matrix<<EOF"
cat "$MATRIX_OUTPUT_FILE" | sed -n 's/^matrix=//p'
echo "EOF"
echo "none-found=$(sed -n 's/^none-found=//p' "$MATRIX_OUTPUT_FILE")"
} >> "$GITHUB_OUTPUT"
- name: "🔨 Create branch"
if: steps.set-matrix.outputs.none-found != 'true'
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.name }} [${{ matrix.nativeImageMode }}] (GraalVM for JDK ${{ matrix.version }} @ ${{ matrix.os }})"
if: needs.get-all-libraries.outputs.none-found != 'true'
runs-on: ${{ matrix.os }}
needs: get-all-libraries
permissions:
contents: read
env:
GVM_TCK_NATIVE_IMAGE_MODE: ${{ matrix.nativeImageMode }}
LOG_LINES: "300"
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.get-all-libraries.outputs.matrix) }}
steps:
- name: "☁️ Checkout repository"
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
persist-credentials: false
- name: "🛠️ Setup latest native-build-tools snapshot"
uses: ./.github/actions/setup-native-build-tools
- name: "🔧 Download GraalVM for metadata testing"
uses: graalvm/setup-graalvm@60c26726de13f8b90771df4bc1641a52a3159994 # v1
with:
distribution: 'graalvm'
java-version: ${{ matrix.version }}
set-java-home: 'true'
native-image-job-reports: 'true'
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: "Extract test path and library version"
id: extract-params
run: ./gradlew extractLibraryTestParams -Pcoordinates="${{ matrix.name }}"
- name: "Pull allowed docker images"
run: ./gradlew pullAllowedDockerImages -Pcoordinates="${{ env.TEST_COORDINATES }}"
- name: "Disable docker networking"
run: bash ./.github/workflows/scripts/disable-docker.sh
- name: "🧪 Run '${{ env.TEST_COORDINATES }}' tests"
id: runtests
run: |
bash ./.github/workflows/scripts/run-consecutive-tests.sh "${{ env.TEST_COORDINATES }}" '${{ toJson(matrix.versions) }}' 2>&1 | tee test_results.txt || true
grep -a "^PASSED:" test_results.txt | sed 's/PASSED://g' > successful_versions.txt || true
FAILED_LINE="$(grep -a "^FAILED" test_results.txt | head -n 1 || true)"
FAILURE_TYPE=""
FAILED_VERSION=""
FAILED_COMMAND=""
if [[ -n "$FAILED_LINE" ]]; then
FAILURE_TYPE="$(printf '%s\n' "$FAILED_LINE" | awk -F'[][]' '{print $2}')"
FAILED_VERSION="$(printf '%s\n' "$FAILED_LINE" | awk -F'[][]' '{print $4}')"
FAILED_COMMAND="$(printf '%s\n' "$FAILED_LINE" | awk -F'[][]' '{print $6}')"
fi
RUNNER_LOG_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
SUCCESSFUL_VERSIONS_JSON="$(jq -R -s 'split("\n") | map(select(length > 0))' successful_versions.txt)"
jq -n \
--arg name "${{ matrix.name }}" \
--arg os "${{ matrix.os }}" \
--arg jdk "${{ matrix.version }}" \
--arg nativeImageMode "${{ matrix.nativeImageMode }}" \
--arg latestVersion "${{ env.LATEST_VERSION }}" \
--arg runnerLogUrl "$RUNNER_LOG_URL" \
--arg failureType "$FAILURE_TYPE" \
--arg failedVersion "$FAILED_VERSION" \
--arg failedCommand "$FAILED_COMMAND" \
--arg logLines "${{ env.LOG_LINES }}" \
--argjson successfulVersions "$SUCCESSFUL_VERSIONS_JSON" \
--rawfile logTail test_results.txt \
'{
name: $name,
os: $os,
version: $jdk,
nativeImageMode: $nativeImageMode,
latestVersion: $latestVersion,
runnerLogUrl: $runnerLogUrl,
successfulVersions: $successfulVersions,
failure: (if $failedVersion == "" then null else {
failureType: $failureType,
failedVersion: $failedVersion,
failedCommand: $failedCommand,
logLines: $logLines,
logTail: ($logTail | split("\n") | .[-($logLines | tonumber):] | join("\n"))
} end)
}' > result.json
- name: "📝 Compute artifact names"
id: artifact-name
run: |
SAFE_NAME="$(printf '%s' '${{ matrix.name }}' | tr ':' '-')"
SAFE_MODE="$(printf '%s' '${{ matrix.nativeImageMode }}' | tr ':' '-')"
echo "artifact_name=compatibility-result-$SAFE_NAME-${{ matrix.version }}-${{ matrix.os }}-$SAFE_MODE" >> "$GITHUB_OUTPUT"
echo "result_file=result-$SAFE_NAME-${{ matrix.version }}-${{ matrix.os }}-$SAFE_MODE.json" >> "$GITHUB_OUTPUT"
- name: "📝 Rename result file for merged download"
run: mv result.json "${{ steps.artifact-name.outputs.result_file }}"
- name: "📦 Upload result artifact"
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: ${{ steps.artifact-name.outputs.artifact_name }}
path: ${{ steps.artifact-name.outputs.result_file }}
if-no-files-found: error
process-results:
name: "🧪 Process results"
runs-on: ubuntu-22.04
permissions:
actions: read
contents: write
issues: write
pull-requests: write
env:
ISSUE_TITLE_PREFIX: "[Automation] "
ISSUE_TITLE_MIDDLE: " fails for "
ISSUE_BODY_CHAR_LIMIT: "60000"
LOG_LINES: "300"
needs:
- get-all-libraries
- test-all-metadata
if: needs.get-all-libraries.outputs.none-found != 'true'
steps:
- name: "☁️ Checkout repository"
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: "🔧 Setup java"
uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4
with:
distribution: 'graalvm'
java-version: '25'
- name: "📥 Download matrix results"
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
path: compatibility-results
pattern: compatibility-result-*
merge-multiple: true
- name: "🧮 Aggregate compatibility results"
id: aggregate
run: |
mapfile -t RESULT_FILES < <(find compatibility-results -type f -name 'result-*.json' | sort)
if [[ "${#RESULT_FILES[@]}" -eq 0 ]]; then
echo "No result.json artifacts were found under compatibility-results"
exit 1
fi
jq -s '
def failures_by_library:
map(select(.failure != null))
| group_by(.name)
| map({
name: .[0].name,
latestVersion: .[0].latestVersion,
failures: (
map(.failure + {
os: .os,
jdk: .version,
nativeImageMode: .nativeImageMode,
runnerLogUrl: .runnerLogUrl
})
| group_by(.failedVersion)
| map({
failedVersion: .[0].failedVersion,
failureTypes: (map(.failureType) | unique),
environments: map({
os: .os,
jdk: .jdk,
nativeImageMode: .nativeImageMode,
failureType: .failureType,
failedCommand: .failedCommand,
runnerLogUrl: .runnerLogUrl,
logLines: .logLines,
logTail: .logTail
})
})
)
});
def unique_preserve:
reduce .[] as $item ([]; if index($item) then . else . + [$item] end);
def successes_by_library:
group_by(.name)
| map(
(. | map(select(.skipped != true))) as $active
| if ($active | length) == 0 then empty else {
name: $active[0].name,
latestVersion: $active[0].latestVersion,
successfulVersions: (
($active | map(.successfulVersions | unique_preserve)) as $lists
| if ($lists | length) == 0 then []
else reduce $lists[1:][] as $candidate ($lists[0]; [ .[] | select($candidate | index(.)) ])
end
),
consideredVersions: ($active | map(.successfulVersions + (if .failure == null then [] else [.failure.failedVersion] end)) | add | unique)
}
end
);
{
successes: successes_by_library,
failures: failures_by_library
}
' "${RESULT_FILES[@]}" > aggregate-results.json
jq -r '
.successes[]
| .name as $name
| .latestVersion as $latest
| .successfulVersions as $versions
| range(0; $versions | length) as $i
| ($versions[$i]) as $version
| (if $i == 0 then $latest else $versions[$i - 1] end) as $lastSupported
| "\($name):\($version)|\($lastSupported)"
' aggregate-results.json > successful_updates.txt
if [[ -s successful_updates.txt ]]; then
echo "has-successful-updates=true" >> "$GITHUB_OUTPUT"
else
echo "has-successful-updates=false" >> "$GITHUB_OUTPUT"
fi
if jq -e '.failures | length > 0' aggregate-results.json > /dev/null; then
echo "has-failures=true" >> "$GITHUB_OUTPUT"
else
echo "has-failures=false" >> "$GITHUB_OUTPUT"
fi
- name: "✔️ New library versions are supported (with locks, waiting and retries)"
if: steps.aggregate.outputs.has-successful-updates == 'true'
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 IFS='|' read -r coordinates last_supported_version; do
if [[ -n "$coordinates" && -n "$last_supported_version" ]]; then
./gradlew addTestedVersion -Pcoordinates="$coordinates" --lastSupportedVersion="$last_supported_version"
fi
done < successful_updates.txt
}
update_root_coverage_markdown() {
local coverage_dir="${RUNNER_TEMP}/root-coverage"
rm -rf "$coverage_dir"
mkdir -p "$coverage_dir"
./gradlew generateReadmeBadgeSummary -PreadmeMetricsOutputRoot="$coverage_dir" --stacktrace
cp "$coverage_dir/COVERAGE.md" COVERAGE.md
}
sleep $((RANDOM % 5 + 1))
for i in {1..10}; do
git fetch origin "$BRANCH"
git checkout -B "$BRANCH" "origin/$BRANCH"
update_new_versions
git restore --source=HEAD --staged --worktree gradle/libs.versions.toml || true
update_root_coverage_markdown
if git status --porcelain | grep -q .; then
git add -A -- metadata stats tests/src COVERAGE.md
COMMIT_BODY_FILE="$(mktemp)"
{
printf 'Update tested library versions\n\n'
printf 'Added tested versions:\n'
awk -F'[|]' '
{
split($1, coordinatesParts, ":")
library = coordinatesParts[1] ":" coordinatesParts[2]
testedVersion = coordinatesParts[3]
updates[library] = updates[library] "\n- `" testedVersion "`"
}
END {
n = asorti(updates, libraries)
for (i = 1; i <= n; i++) {
library = libraries[i]
printf "#### `%s`%s\n", library, updates[library]
}
}
' successful_updates.txt
} > "$COMMIT_BODY_FILE"
git commit -F "$COMMIT_BODY_FILE"
rm "$COMMIT_BODY_FILE"
else
echo "No tested version updates to commit."
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: "❗ Create aggregated issues for unsupported library versions"
if: steps.aggregate.outputs.has-failures == 'true'
env:
GH_TOKEN: ${{ secrets.GRAALBOT_PR_TOKEN }}
run: |
set -euo pipefail
git fetch --no-tags --depth=1 origin +master:refs/remotes/origin/master
latest_master_supports_version() {
local name="$1"
local failed_version="$2"
local group="${name%%:*}"
local artifact="${name#*:}"
local index_path="metadata/$group/$artifact/index.json"
if ! git cat-file -e "origin/master:$index_path" 2>/dev/null; then
return 1
fi
git show "origin/master:$index_path" | jq -e --arg version "$failed_version" '
any(.[]?; (."metadata-version" == $version) or ((."tested-versions" // []) | index($version) != null))
' >/dev/null
}
jq -c '.failures[]' aggregate-results.json | while read -r library; do
NAME="$(printf '%s' "$library" | jq -r '.name')"
printf '%s' "$library" | jq -c '.failures[]' | while read -r failure; do
FAILED_VERSION="$(printf '%s' "$failure" | jq -r '.failedVersion')"
GAV_COORDINATES="$NAME:$FAILED_VERSION"
TITLE_END="${{ env.ISSUE_TITLE_MIDDLE }}$GAV_COORDINATES"
FAILURE_TYPE="$(printf '%s' "$failure" | jq -r '.failureTypes | sort | join(", ")')"
PRIMARY_FAILURE_TYPE="$(printf '%s' "$failure" | jq -r '.failureTypes | sort | .[0]')"
TITLE="${{ env.ISSUE_TITLE_PREFIX }}$PRIMARY_FAILURE_TYPE$TITLE_END"
FAILURE_LABEL="fails-$(printf '%s' "$PRIMARY_FAILURE_TYPE" | sed 's/ /-/g')"
if latest_master_supports_version "$NAME" "$FAILED_VERSION"; then
echo "Latest origin/master already supports $GAV_COORDINATES. Skipping stale failure issue."
continue
fi
ISSUE_NUMBER=$(
gh issue list \
--repo "${{ github.repository }}" \
--state open \
--search "\"$TITLE_END\" in:title" \
--json number,title \
--jq ".[] | select(.title | (startswith(\"${{ env.ISSUE_TITLE_PREFIX }}\") and endswith(\"$TITLE_END\"))) | .number"
)
if [[ -n "$ISSUE_NUMBER" ]]; then
echo "Issue already exists: $ISSUE_NUMBER. Skipping creation."
continue
fi
BODY_FILE="$(mktemp)"
BODY_CHAR_LIMIT="${{ env.ISSUE_BODY_CHAR_LIMIT }}"
CODE_BLOCK_PREFIX=$'\n```console\n'
CODE_BLOCK_SUFFIX=$'\n```\n\n'
mapfile -t ENVIRONMENTS < <(printf '%s\n' "$failure" | jq -c '.environments[]')
ENVIRONMENT_COUNT="${#ENVIRONMENTS[@]}"
declare -a NORMAL_PREFIXES
declare -a TRUNCATED_PREFIXES
declare -a LOG_TAILS
declare -a LOG_LENGTHS
FULL_BODY_LENGTH=0
FIXED_TRUNCATED_LENGTH=0
TOTAL_LOG_LENGTH=0
for environment in "${ENVIRONMENTS[@]}"; do
OS="$(printf '%s' "$environment" | jq -r '.os')"
JDK="$(printf '%s' "$environment" | jq -r '.jdk')"
NATIVE_IMAGE_MODE="$(printf '%s' "$environment" | jq -r '.nativeImageMode')"
COMMAND="$(printf '%s' "$environment" | jq -r '.failedCommand')"
RUNNER_LOG_URL="$(printf '%s' "$environment" | jq -r '.runnerLogUrl')"
ENV_FAILURE_TYPE="$(printf '%s' "$environment" | jq -r '.failureType')"
ENV_LOG_LINES="$(printf '%s' "$environment" | jq -r '.logLines')"
LOG_TAIL="$(printf '%s' "$environment" | jq -r '.logTail')"
NORMAL_PREFIX="$(
printf '## %s on %s / JDK %s / mode %s\n\n' "$ENV_FAILURE_TYPE" "$OS" "$JDK" "$NATIVE_IMAGE_MODE"
printf 'Failure kind: %s\n' "$ENV_FAILURE_TYPE"
printf 'OS: %s\n' "$OS"
printf 'JDK: %s\n' "$JDK"
printf 'Native-image mode: %s\n' "$NATIVE_IMAGE_MODE"
printf 'Reproducer: `%s`\n' "$COMMAND"
printf 'Runner log: %s\n' "$RUNNER_LOG_URL"
printf 'Last %s lines of the log:\n' "$ENV_LOG_LINES"
)"
TRUNCATED_PREFIX="$(
printf '## %s on %s / JDK %s / mode %s\n\n' "$ENV_FAILURE_TYPE" "$OS" "$JDK" "$NATIVE_IMAGE_MODE"
printf 'Failure kind: %s\n' "$ENV_FAILURE_TYPE"
printf 'OS: %s\n' "$OS"
printf 'JDK: %s\n' "$JDK"
printf 'Native-image mode: %s\n' "$NATIVE_IMAGE_MODE"
printf 'Reproducer: `%s`\n' "$COMMAND"
printf 'Runner log: %s\n' "$RUNNER_LOG_URL"
printf 'Last %s lines of the log (excerpt truncated to fit the GitHub issue size limit):\n' "$ENV_LOG_LINES"
)"
LOG_LENGTH="$(printf '%s' "$LOG_TAIL" | wc -c)"
NORMAL_PREFIXES+=("$NORMAL_PREFIX")
TRUNCATED_PREFIXES+=("$TRUNCATED_PREFIX")
LOG_TAILS+=("$LOG_TAIL")
LOG_LENGTHS+=("$LOG_LENGTH")
FULL_BODY_LENGTH=$((FULL_BODY_LENGTH + $(printf '%s' "$NORMAL_PREFIX" | wc -c) + $(printf '%s' "$CODE_BLOCK_PREFIX" | wc -c) + LOG_LENGTH + $(printf '%s' "$CODE_BLOCK_SUFFIX" | wc -c)))
FIXED_TRUNCATED_LENGTH=$((FIXED_TRUNCATED_LENGTH + $(printf '%s' "$TRUNCATED_PREFIX" | wc -c) + $(printf '%s' "$CODE_BLOCK_PREFIX" | wc -c) + $(printf '%s' "$CODE_BLOCK_SUFFIX" | wc -c)))
TOTAL_LOG_LENGTH=$((TOTAL_LOG_LENGTH + LOG_LENGTH))
done
: > "$BODY_FILE"
if (( FULL_BODY_LENGTH <= BODY_CHAR_LIMIT )); then
for i in "${!ENVIRONMENTS[@]}"; do
printf '%s' "${NORMAL_PREFIXES[$i]}" >> "$BODY_FILE"
printf '%s' "$CODE_BLOCK_PREFIX" >> "$BODY_FILE"
printf '%s' "${LOG_TAILS[$i]}" >> "$BODY_FILE"
printf '%s' "$CODE_BLOCK_SUFFIX" >> "$BODY_FILE"
done
else
REMAINING_LOG_BUDGET=$((BODY_CHAR_LIMIT - FIXED_TRUNCATED_LENGTH))
if (( REMAINING_LOG_BUDGET < 0 )); then
echo "Issue metadata exceeds the configured issue body size limit."
exit 1
fi
declare -a LOG_BUDGETS
ASSIGNED_LOG_BUDGET=0
for i in "${!ENVIRONMENTS[@]}"; do
if (( TOTAL_LOG_LENGTH == 0 )); then
LOG_BUDGET=0
else
LOG_BUDGET=$((LOG_LENGTHS[$i] * REMAINING_LOG_BUDGET / TOTAL_LOG_LENGTH))
fi
LOG_BUDGETS+=("$LOG_BUDGET")
ASSIGNED_LOG_BUDGET=$((ASSIGNED_LOG_BUDGET + LOG_BUDGET))
done
EXTRA_BYTES=$((REMAINING_LOG_BUDGET - ASSIGNED_LOG_BUDGET))
NEXT_INDEX=0
while (( EXTRA_BYTES > 0 && ENVIRONMENT_COUNT > 0 )); do
LOG_BUDGETS[$NEXT_INDEX]=$((LOG_BUDGETS[$NEXT_INDEX] + 1))
EXTRA_BYTES=$((EXTRA_BYTES - 1))
NEXT_INDEX=$(((NEXT_INDEX + 1) % ENVIRONMENT_COUNT))
done
for i in "${!ENVIRONMENTS[@]}"; do
printf '%s' "${TRUNCATED_PREFIXES[$i]}" >> "$BODY_FILE"
printf '%s' "$CODE_BLOCK_PREFIX" >> "$BODY_FILE"
if (( LOG_BUDGETS[$i] > 0 )); then
if (( LOG_BUDGETS[$i] >= LOG_LENGTHS[$i] )); then
printf '%s' "${LOG_TAILS[$i]}" >> "$BODY_FILE"
else
printf '%s' "${LOG_TAILS[$i]}" | tail -c "${LOG_BUDGETS[$i]}" >> "$BODY_FILE"
fi
fi
printf '%s' "$CODE_BLOCK_SUFFIX" >> "$BODY_FILE"
done
fi
ASSIGNEE_ARGS=()
if [[ "$FAILURE_LABEL" == "fails-native-image-build" ]]; then
ASSIGNEE_ARGS=(--assignee "vjovanov")
fi
gh issue create \
--repo "${{ github.repository }}" \
--title "$TITLE" \
--body-file "$BODY_FILE" \
--label "library-unsupported-version" \
--label "$FAILURE_LABEL" \
"${ASSIGNEE_ARGS[@]}"
rm "$BODY_FILE"
done
done
- name: "🧹 Close old pre-release issues for tested versions"
if: steps.aggregate.outputs.has-successful-updates == 'true' || steps.aggregate.outputs.has-failures == 'true'
env:
GH_TOKEN: ${{ secrets.GRAALBOT_PR_TOKEN }}
REPO: ${{ github.repository }}
PRE_RELEASE_SUFFIX: "(alpha[0-9]*|beta[0-9]*|rc[0-9]*|cr[0-9]*|m[0-9]+|ea[0-9]*|b[0-9]+|[0-9]+|preview)"
run: |
set -euo pipefail
LIBRARY_VERSIONS_FILE="$(mktemp)"
jq -r '.successes[]? | .name as $name | .successfulVersions[]? | "\($name)|\(.)"' aggregate-results.json >> "$LIBRARY_VERSIONS_FILE"
jq -r '.failures[]? | .name as $name | .failures[]?.failedVersion | "\($name)|\(.)"' aggregate-results.json >> "$LIBRARY_VERSIONS_FILE"
sort -u "$LIBRARY_VERSIONS_FILE" -o "$LIBRARY_VERSIONS_FILE"
while IFS='|' read -r LIBRARY_NAME VERSION; do
if [[ -z "$LIBRARY_NAME" || -z "$VERSION" ]]; then
continue
fi
VERSION_REGEX="^([0-9]+(\.[0-9]+)*)(\.Final|\.RELEASE)?([-.]$PRE_RELEASE_SUFFIX([-.].*)?)?$"
if [[ "$VERSION" =~ $VERSION_REGEX ]]; then
BASE_VERSION="${BASH_REMATCH[1]}"
PRE_RELEASE_TAG="${BASH_REMATCH[4]-}"
else
echo "Skipping invalid version: $VERSION"
continue
fi
if [[ -n "$PRE_RELEASE_TAG" ]]; then
echo "$VERSION is a pre-release, skipping issue closing."
continue
fi
PRE_RELEASE_REGEX="$BASE_VERSION[-.]$PRE_RELEASE_SUFFIX"
GROUP_ID="$(echo "$LIBRARY_NAME" | cut -d: -f1)"
ARTIFACT_ID="$(echo "$LIBRARY_NAME" | cut -d: -f2)"
GAV_COORDINATES_VERSIONLESS="$GROUP_ID:$ARTIFACT_ID"
TITLE_END_VERSIONLESS="${{ env.ISSUE_TITLE_MIDDLE }}$GAV_COORDINATES_VERSIONLESS"
PRE_RELEASE_ISSUES=$(gh issue list \
--repo "$REPO" \
--state open \
--search "\"$TITLE_END_VERSIONLESS\" in:title" \
--json number,title \
--jq ".[] | select(.title | startswith(\"${{ env.ISSUE_TITLE_PREFIX }}\") and test(\"$TITLE_END_VERSIONLESS:$PRE_RELEASE_REGEX\"; \"i\")) | .number")
if [[ -n "$PRE_RELEASE_ISSUES" ]]; then
echo "Closing pre-release issues for $LIBRARY_NAME version $BASE_VERSION:"
for ISSUE in $PRE_RELEASE_ISSUES; do
echo "Closing issue #$ISSUE"
gh issue close "$ISSUE" --repo "$REPO" \
-c "Closing this pre-release issue because a full release is now available and/or builds successfully." \
-r "not planned"
done
else
echo "No pre-release issues found for $LIBRARY_NAME version $BASE_VERSION"
fi
done < "$LIBRARY_VERSIONS_FILE"
rm "$LIBRARY_VERSIONS_FILE"
- name: "✏️ PR for supported versions"
if: steps.aggregate.outputs.has-successful-updates == 'true'
env:
GH_TOKEN: ${{ secrets.GRAALBOT_PR_TOKEN }}
run: |
git fetch origin "${{ needs.get-all-libraries.outputs.branch }}"
git checkout "${{ needs.get-all-libraries.outputs.branch }}"
if git rev-parse --verify HEAD >/dev/null 2>&1 && ! git diff --quiet "origin/master...HEAD"; then
PR_BODY_FILE="$(mktemp)"
{
printf 'This pull request updates supported versions of the existing libraries in the repo.\n\n'
printf 'Added tested versions:\n'
awk -F'[|]' '
{
split($1, coordinatesParts, ":")
library = coordinatesParts[1] ":" coordinatesParts[2]
testedVersion = coordinatesParts[3]
updates[library] = updates[library] "\n- `" testedVersion "`"
}
END {
n = asorti(updates, libraries)
for (i = 1; i <= n; i++) {
library = libraries[i]
printf "#### `%s`%s\n", library, updates[library]
}
}
' successful_updates.txt
} > "$PR_BODY_FILE"
gh pr create \
--title "${{ env.ISSUE_TITLE_PREFIX }}Update supported library versions $(date '+%Y-%m-%dT%H:%M')" \
--body-file "$PR_BODY_FILE" \
--reviewer "kimeta,vjovanov,jormundur00" \
--assignee "vjovanov" \
--label "library-bulk-update"
rm "$PR_BODY_FILE"
else
echo "No branch changes available for PR creation."
fi