From 6d740fea7332ab259693a29a500e766221bf3b59 Mon Sep 17 00:00:00 2001 From: David Nestorovic Date: Tue, 12 Nov 2024 14:52:54 +0100 Subject: [PATCH] Scan new versions for existing libraries (#552) * Scan new versions for existing libraries * Remove redudant changes left from testing * Fix function call after refactoring * Fix task registration after refactoring * Reduce number of jobs to pass github limitations * Use simple matrix * Use env variable to specify library version * Find update entry based on the latest supported version * Use jackson to parse index file when fetching latest version * Remove unused import * Improve workflow steps titles * Remove suppress warnings after refactoring * Extract github limitations as parameter of the gradle task * Remove unused suppress * Use different PR branch name * Use bash instead of sh to invoke push script * Add comments into the tryPush script * Always extract coordinates part in the same way * Extract gradle task for fetching newer versions * Properly add Input and Output anotations to the updater task * Rename function that extracts information from provided coordinates * Use abstract getters for properties in the fetching task * Add a doc file that explains how the scan works --- .../workflows/check-new-library-versions.yml | 144 ++++++++++++++++++ .github/workflows/tryPushVersionsUpdate.sh | 46 ++++++ .../check-new-versions-of-libraries.md | 51 +++++++ .../org.graalvm.internal.tck-harness.gradle | 15 ++ .../internal/tck/harness/TckExtension.java | 23 +-- .../tasks/AbstractSubprojectTask.groovy | 5 +- ...stingLibrariesWithNewerVersionsTask.groovy | 133 ++++++++++++++++ .../tck/TestedVersionUpdaterTask.java | 70 +++++++++ .../tck/model/MetadataVersionsIndexEntry.java | 17 +++ 9 files changed, 492 insertions(+), 12 deletions(-) create mode 100644 .github/workflows/check-new-library-versions.yml create mode 100644 .github/workflows/tryPushVersionsUpdate.sh create mode 100644 docs/Infrastructure/check-new-versions-of-libraries.md create mode 100644 tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/tasks/FetchExistingLibrariesWithNewerVersionsTask.groovy create mode 100644 tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/TestedVersionUpdaterTask.java create mode 100644 tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/model/MetadataVersionsIndexEntry.java diff --git a/.github/workflows/check-new-library-versions.yml b/.github/workflows/check-new-library-versions.yml new file mode 100644 index 000000000..d88780c8f --- /dev/null +++ b/.github/workflows/check-new-library-versions.yml @@ -0,0 +1,144 @@ +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-20.04" + timeout-minutes: 5 + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + outputs: + matrix: ${{ steps.set-matrix.outputs.matrix }} + issue: ${{ steps.set-issue.outputs.issue }} + 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') + - name: "πŸ”¨ Create issue" + id: set-issue + run: | + git config --local user.email "actions@github.com" + git config --local user.name "Github Actions" + + issue_url=$(gh issue create --title "List unsupported library versions" --body "This issue lists unsupported versions of the existing libraries in the repo") + echo "::set-output name=issue::$issue_url" + + 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: | + git config --local user.email "actions@github.com" + git config --local user.name "Github Actions" + gh issue comment "${{ needs.get-all-libraries.outputs.issue }}" --body "${{ matrix.coordinates }}" + + process-results: + name: "πŸ§ͺ Process results" + runs-on: "ubuntu-20.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: "✏️ 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" diff --git a/.github/workflows/tryPushVersionsUpdate.sh b/.github/workflows/tryPushVersionsUpdate.sh new file mode 100644 index 000000000..4d807c3bd --- /dev/null +++ b/.github/workflows/tryPushVersionsUpdate.sh @@ -0,0 +1,46 @@ +#!/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/docs/Infrastructure/check-new-versions-of-libraries.md b/docs/Infrastructure/check-new-versions-of-libraries.md new file mode 100644 index 000000000..79c97e54b --- /dev/null +++ b/docs/Infrastructure/check-new-versions-of-libraries.md @@ -0,0 +1,51 @@ +# Check new versions of existing libraries in the repository + +As the number of libraries in the repository grow fast, it is hard to track new library versions for every library manually. +Instead of doing this process manually, we provided a mechanism (through [a GitHub workflow](https://github.com/oracle/graalvm-reachability-metadata/blob/master/.github/workflows/check-new-library-versions.yml)) +that automatically scans MavenCentral repository for new versions of the libraries that we currently have. + +## How it works + +The workflow gets triggered every two weeks automatically (alternating to the automatic release weeks). Besides that, the job can be triggered manually from the GitHub actions. +The whole process consists of the following parts: +* Scanning of the MavenCentral +* Running existing tests with newer versions of the library +* Creating a pull-request that updates `tested-versions` field of the `index.json` file for libraries that passed tests with a new version +* Creating an issue that lists all versions of libraries that failed their existing tests. + +As a preparation for the whole process, we are creating a branch for all successful tests, and a single issue for all failed tests. + +### Scanning the MavenCentral + +At first, the workflow runs gradle task called `fetchExistingLibrariesWithNewerVersions`. +The task itself does the following: +1. Gets the list of all existing libraries in the repository +2. For each library, it searches for the latest tested version in the corresponding library `index.json` file +3. For the given library name, it fetches `maven-metadata.xml` file from the MavenCentral repository +4. In the fetched `maven-metadata.xml` file, it finds the position of the latest tested version (gathered in the step 3) and returns all the versions after it +5. As a last step, the task returns list of maven coordinates of libraries with newer versions (alongside java version and os version required for testing) + +### Running existing tests with newer versions + +Now that we have coordinates list, we are spawning a new job in GitHub workflow for each coordinate in the list. +Each of the spawned jobs: +1. Extracts the following parts from the given maven coordinates: + 1. Latest version that we have tests written for + 2. Path to the latest tests we have + 3. Maven coordinates of the latest tests +2. Sets `GVM_TCK_LV` env variable to the version we want to test. This way the executed tests will use library version specified in the env variable. +3. Run the latest test with `./gradlew test -Pcoordinates=` (with `testCoordinates` calculated in the step 1) + +### Aggregating results of the tests + +Based on the outcome of the test we: +* Update the list of `tested-versions` in the proper library `index.json` file and commit changes to the previously created branch, if the test passed +* Add a comment that explains which library version cannot pass the tests, in the issue we previously created + +Note: since the spawned jobs run tests in parallel, we have to make some kind of synchronization to avoid merge conflicts if two tests are populating the same `index.json` file. +The whole process of synchronization is driven by the [tryPushVersionsUpdate](https://github.com/oracle/graalvm-reachability-metadata/blob/master/.github/workflows/tryPushVersionsUpdate.sh) script. + +At the end, when all jobs have finished their executions, the workflow just creates a pull-request based on a branch the jobs committed to. +As a final result, we have: +* a pull-request with updates of all new tested versions +* an issue with list of all versions that doesn't work with existing metadata 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 e6f86c486..e26864c9b 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 @@ -14,7 +14,9 @@ import org.graalvm.internal.tck.DockerTask import org.graalvm.internal.tck.ConfigFilesChecker import org.graalvm.internal.tck.ScaffoldTask import org.graalvm.internal.tck.GrypeTask +import org.graalvm.internal.tck.TestedVersionUpdaterTask import org.graalvm.internal.tck.harness.tasks.CheckstyleInvocationTask +import org.graalvm.internal.tck.harness.tasks.FetchExistingLibrariesWithNewerVersionsTask import org.graalvm.internal.tck.harness.tasks.TestInvocationTask @@ -161,6 +163,14 @@ Provider generateMatrixDiffCoordinates = tasks.register("generateMatrixDif } } +// groovy tasks +tasks.register("fetchExistingLibrariesWithNewerVersions", FetchExistingLibrariesWithNewerVersionsTask.class) { task -> + task.setGroup(METADATA_GROUP) + task.setDescription("Returns list of all libraries coordinates") + task.setAllLibraryCoordinates(matchingCoordinates) +} + +// java tasks tasks.register("checkAllowedDockerImages", GrypeTask.class) { task -> task.setDescription("Returns list of allowed docker images") task.setGroup(METADATA_GROUP) @@ -182,3 +192,8 @@ tasks.register("checkConfigFiles", ConfigFilesChecker.class) { task -> task.setDescription("Checks content of config files for a new library.") task.setGroup(METADATA_GROUP) } + +tasks.register("addTestedVersion", TestedVersionUpdaterTask.class) { task -> + task.setDescription("Updates list of tested versions.") + task.setGroup(METADATA_GROUP) +} 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 2cff195d9..bf2c4fc38 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 @@ -6,6 +6,11 @@ */ package org.graalvm.internal.tck.harness; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import org.graalvm.internal.tck.model.MetadataVersionsIndexEntry; import org.gradle.api.Project; import org.gradle.api.file.Directory; import org.gradle.api.file.DirectoryProperty; @@ -13,24 +18,21 @@ import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; import org.gradle.process.ExecOperations; +import org.gradle.util.internal.VersionNumber; import javax.inject.Inject; import java.io.ByteArrayOutputStream; +import java.io.File; import java.io.IOException; import java.net.URI; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; +import java.util.*; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -299,9 +301,7 @@ List getMatchingCoordinates(String coordinateFilter) { String artifactId = strings.get(1); String version = strings.get(2); - Set matchingCoordinates = new HashSet<>(); - for (String directory : getMatchingMetadataDirs(groupId, artifactId)) { Path index = metadataRoot().resolve(directory).resolve("index.json"); List> metadataIndex = (List>) extractJsonFile(index); @@ -322,7 +322,8 @@ List getMatchingCoordinates(String coordinateFilter) { } } } - return matchingCoordinates.stream().collect(Collectors.toList()); + + return new ArrayList<>(matchingCoordinates); } /** diff --git a/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/tasks/AbstractSubprojectTask.groovy b/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/tasks/AbstractSubprojectTask.groovy index e41c58761..8940a5ca4 100644 --- a/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/tasks/AbstractSubprojectTask.groovy +++ b/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/tasks/AbstractSubprojectTask.groovy @@ -93,7 +93,10 @@ abstract class AbstractSubprojectTask extends DefaultTask { // Environment variables for setting up TCK env.put("GVM_TCK_LC", coordinates) env.put("GVM_TCK_EXCLUDE", override.toString()) - env.put("GVM_TCK_LV", version) + if (System.getenv("GVM_TCK_LV") == null) { + // we only set this env variable if user didn't specify it manually + env.put("GVM_TCK_LV", version) + } env.put("GVM_TCK_MD", metadataDir.toAbsolutePath().toString()) env.put("GVM_TCK_TCKDIR", tckExtension.getTckRoot().get().getAsFile().toPath().toAbsolutePath().toString()) spec.environment(env) diff --git a/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/tasks/FetchExistingLibrariesWithNewerVersionsTask.groovy b/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/tasks/FetchExistingLibrariesWithNewerVersionsTask.groovy new file mode 100644 index 000000000..fed4c2776 --- /dev/null +++ b/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/tasks/FetchExistingLibrariesWithNewerVersionsTask.groovy @@ -0,0 +1,133 @@ +package org.graalvm.internal.tck.harness.tasks + + +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.core.type.TypeReference +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.databind.SerializationFeature +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 + + +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 + void action() { + // get all existing libraries + Set libraries = [] + getAllLibraryCoordinates().get().forEach { + libraries.add(it.substring(0, it.lastIndexOf(":"))) + } + + // foreach existing library find newer versions than the latest one tested except for infrastructure tests + List newerVersions = new ArrayList<>() + libraries.forEach { + String libraryName = it + if (INFRASTRUCTURE_TESTS.stream().noneMatch(testName -> libraryName.startsWith(testName))) { + List versions = getNewerVersionsFor(libraryName, getLatestLibraryVersion(libraryName)) + versions.forEach { + newerVersions.add(libraryName.concat(":").concat(it)) + } + } + } + + if (newerVersions.size() > getMatrixLimit().get()) { + newerVersions = newerVersions.subList(0, getMatrixLimit().get()) + } + + def matrix = [ + "coordinates": newerVersions, + "version" : ["17"], + "os" : ["ubuntu-latest"] + ] + + println "::set-output name=matrix::${JsonOutput.toJson(matrix)}" + } + + static List getNewerVersionsFor(String library, String startingVersion) { + def baseUrl = "https://repo1.maven.org/maven2" + String[] libraryParts = library.split(":") + String group = libraryParts[0].replace(".", "/") + String artifact = libraryParts[1] + def data = new URL(baseUrl + "/" + group + "/" + artifact + "/" + "maven-metadata.xml").getText() + + return getNewerVersionsFromLibraryIndex(data, startingVersion, library) + } + + static List getNewerVersionsFromLibraryIndex(String index, String startingVersion, String libraryName) { + Pattern pattern = Pattern.compile("(.*)"); + Matcher matcher = pattern.matcher(index); + List allVersions = new ArrayList<>(); + + if (matcher.groupCount() < 1) { + throw new RuntimeException("Cannot find versions in the given index file: " + libraryName); + } + + while (matcher.find()) { + allVersions.add(matcher.group(1)); + } + + 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()); + } + + static String getLatestLibraryVersion(String libraryModule) { + try { + String[] coordinates = libraryModule.split(":"); + String group = coordinates[0]; + String artifact = coordinates[1]; + + File coordinatesMetadataIndex = new File("metadata/" + group + "/" + artifact +"/index.json"); + ObjectMapper objectMapper = new ObjectMapper() + .enable(SerializationFeature.INDENT_OUTPUT) + .setSerializationInclusion(JsonInclude.Include.NON_NULL); + + List entries = objectMapper.readValue(coordinatesMetadataIndex, new TypeReference>() { + }); + + List allTested = new ArrayList<>(); + for (MetadataVersionsIndexEntry entry : entries) { + allTested.addAll(entry.testedVersions()); + } + + if (allTested.isEmpty()) { + throw new IllegalStateException("Cannot find any tested version for: " + libraryModule); + } + + allTested.sort(Comparator.comparing(VersionNumber::parse)); + return allTested.get(allTested.size() - 1); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + +} 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 new file mode 100644 index 000000000..87163c3bf --- /dev/null +++ b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/TestedVersionUpdaterTask.java @@ -0,0 +1,70 @@ +package org.graalvm.internal.tck; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.core.util.DefaultIndenter; +import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import org.graalvm.internal.tck.model.MetadataVersionsIndexEntry; + +import org.gradle.api.DefaultTask; +import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.provider.Property; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.OutputFiles; +import org.gradle.api.tasks.TaskAction; +import org.gradle.api.tasks.options.Option; +import org.gradle.util.internal.VersionNumber; + +import java.io.File; +import java.io.IOException; +import java.util.Comparator; +import java.util.List; + +public abstract class TestedVersionUpdaterTask extends DefaultTask { + + @Option(option = "coordinates", description = "GAV coordinates of the library") + void extractInformationFromCoordinates(String c) { + String[] coordinatesParts = c.split(":"); + if (coordinatesParts.length != 3) { + throw new IllegalArgumentException("Maven coordinates should have 3 parts"); + } + String group = coordinatesParts[0]; + String artifact = coordinatesParts[1]; + String version = coordinatesParts[2]; + Coordinates coordinates = new Coordinates(group, artifact, version); + + getIndexFile().set(getProject().file(CoordinateUtils.replace("metadata/$group$/$artifact$/index.json", coordinates))); + getNewVersion().set(version); + } + + @Input + @Option(option = "lastSupportedVersion", description = "Last version of the library that passed tests") + protected abstract Property getLastSupportedVersion(); + + @Input + protected abstract Property getNewVersion(); + + @OutputFiles + protected abstract RegularFileProperty getIndexFile(); + + @TaskAction + void run() throws IllegalStateException, IOException { + File coordinatesMetadataIndex = getIndexFile().get().getAsFile(); + ObjectMapper objectMapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT).setSerializationInclusion(JsonInclude.Include.NON_NULL); + + List entries = objectMapper.readValue(coordinatesMetadataIndex, new TypeReference<>() {}); + for (MetadataVersionsIndexEntry entry : entries) { + if (entry.testedVersions().contains(getLastSupportedVersion().get())) { + entry.testedVersions().add(getNewVersion().get()); + entry.testedVersions().sort(Comparator.comparing(VersionNumber::parse)); + } + } + + DefaultPrettyPrinter prettyPrinter = new DefaultPrettyPrinter(); + prettyPrinter.indentArraysWith(DefaultIndenter.SYSTEM_LINEFEED_INSTANCE); + + objectMapper.writer(prettyPrinter).writeValue(coordinatesMetadataIndex, entries); + } +} diff --git a/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/model/MetadataVersionsIndexEntry.java b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/model/MetadataVersionsIndexEntry.java new file mode 100644 index 000000000..ce2e28132 --- /dev/null +++ b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/model/MetadataVersionsIndexEntry.java @@ -0,0 +1,17 @@ +package org.graalvm.internal.tck.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +public record MetadataVersionsIndexEntry ( + Boolean latest, + Boolean override, + String module, + @JsonProperty("default-for") + String defaultFor, + @JsonProperty("metadata-version") + String metadataVersion, + @JsonProperty("tested-versions") + List testedVersions +){}