Skip to content

Commit c965eda

Browse files
committed
Merge branch 'master' into jormundur00/gh-791
2 parents aacb7d2 + 7e9e33b commit c965eda

File tree

96 files changed

+15146
-200
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

96 files changed

+15146
-200
lines changed

.github/CODEOWNERS

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ tests/tck-build-logic/* @vjovanov
44
tests/tck-build-logic/src/main/resources/allowed-docker-images/* @matneu
55
library-and-framework-list.json @fniephaus
66
.github/* @vjovanov
7-
docs/* @vjovanov @ban-mi
8-
README.md @vjovanov @ban-mi
7+
docs/* @vjovanov
8+
README.md @vjovanov
99
gradle/* @vjovanov
1010
/* @vjovanov

.github/workflows/checkstyle.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,4 @@ jobs:
3333

3434
- name: "Run Checkstyle"
3535
if: steps.filter.outputs.changed == 'true'
36-
run: ./gradlew checkstyle
36+
run: ./gradlew spotlessCheck checkstyle

.github/workflows/test-all-metadata.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ on:
77
- master
88
paths:
99
- 'ci.json'
10+
- 'java/org/graalvm/internal/tck/MetadataFilesCheckerTask.java'
1011

1112
concurrency:
1213
group: "workflow = ${{ github.workflow }}, ref = ${{ github.event.ref }}, pr = ${{ github.event.pull_request.id }}"

.github/workflows/test-changed-infrastructure.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ jobs:
5050
5151
test-changed-infrastructure:
5252
name: "🧪 ${{ matrix.coordinates }} (GraalVM for JDK ${{ matrix.version }} @ ${{ matrix.os }})"
53-
if: needs.get-changed-infrastructure.outputs.relevant-files-changed == 'true' && needs.get-changed-infrastructure.result == 'success' && needs.get-changed-infrastructure.outputs.none-found != 'true' && github.repository == 'jormundur00/graalvm-reachability-metadata'
53+
if: needs.get-changed-infrastructure.outputs.relevant-files-changed == 'true' && needs.get-changed-infrastructure.result == 'success' && needs.get-changed-infrastructure.outputs.none-found != 'true' && github.repository == 'oracle/graalvm-reachability-metadata'
5454
runs-on: ${{ matrix.os }}
5555
timeout-minutes: 20
5656
needs: get-changed-infrastructure

.github/workflows/test-changed-metadata.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ jobs:
4949
5050
test-changed-metadata:
5151
name: "🧪 ${{ matrix.coordinates }} (GraalVM for JDK ${{ matrix.version }} @ ${{ matrix.os }})"
52-
if: needs.get-changed-metadata.outputs.relevant-files-changed == 'true' && needs.get-changed-metadata.result == 'success' && needs.get-changed-metadata.outputs.none-found != 'true' && github.repository == 'jormundur00/graalvm-reachability-metadata'
52+
if: needs.get-changed-metadata.outputs.relevant-files-changed == 'true' && needs.get-changed-metadata.result == 'success' && needs.get-changed-metadata.outputs.none-found != 'true' && github.repository == 'oracle/graalvm-reachability-metadata'
5353
runs-on: ${{ matrix.os }}
5454
timeout-minutes: 20
5555
needs: get-changed-metadata

AGENTS.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
- Be assertive in code.
2020
- Write type annotations in all functions and most variables.
2121
- Document code without being too verbose.
22-
- In java, always import classes and use them without qualified names.
22+
- In Java and Groovy, always import classes and use them without qualified names.
2323

2424
## Testing individual components
2525

@@ -47,6 +47,17 @@
4747
- ./gradlew checkMetadataFiles -Pcoordinates=1/64
4848
- ./gradlew test -Pcoordinates=1/64
4949

50+
### Generating Metadata
51+
- Generate metadata for a certain library version:
52+
- ./gradlew generateMetadata -Pcoordinates=com.hazelcast:hazelcast:5.2.1
53+
- Generate metadata for a certain library version and create or update the user-code-filter.json:
54+
- ./gradlew generateMetadata -Pcoordinates=org.postgresql:postgresql:42.7.3 --agentAllowedPackages=org.example.app,com.acme.service
55+
56+
### Fix failing tasks
57+
58+
- Generates new metadata for library's new version which is failing native-image run:
59+
- ./gradlew fixTestNativeImageRun -PtestLibraryCoordinates=org.postgresql:postgresql:42.7.3 -PnewLibraryVersion=42.7.4
60+
5061
## Docker Image Vulnerability Scanning
5162
- Changed images between commits:
5263
- ./gradlew checkAllowedDockerImages --baseCommit=$(git rev-parse origin/master) --newCommit=$(git rev-parse HEAD)

build.gradle

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
/*
2+
* Copyright and related rights waived via CC0
3+
*
4+
* You should have received a copy of the CC0 legalcode along with this
5+
* work. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
6+
*/
7+
import groovy.json.JsonSlurper
8+
19
import java.util.concurrent.Executors
210
import java.util.concurrent.TimeUnit
311

@@ -40,6 +48,50 @@ spotless {
4048
.sortByKeys()
4149
.version("2.9.0")
4250
}
51+
java {
52+
target('**/*.java')
53+
targetExclude(
54+
'metadata/**', // only JSON there
55+
'**/build/**',
56+
'gradle/header.java')
57+
// Place header before package/import/module
58+
licenseHeaderFile("$rootDir/gradle/header.java", "package |import |module ")
59+
}
60+
61+
String[] noHeaderDirs = [
62+
'docs/**', // only .md files
63+
'metadata/**', // only .json files
64+
'**/build/**', // not relevant
65+
'gradle/wrapper/**', // not relevant
66+
]
67+
groovy {
68+
target('**/*.groovy')
69+
targetExclude(noHeaderDirs)
70+
// Place header before package/import
71+
licenseHeaderFile("$rootDir/gradle/header.java", "package |import ")
72+
}
73+
groovyGradle {
74+
// Build scripts (*.gradle)
75+
target('**/*.gradle')
76+
targetExclude(noHeaderDirs)
77+
targetExclude('tests/**')
78+
// Insert header at file start (works for any Gradle script layout)
79+
licenseHeaderFile("$rootDir/gradle/header.java", "(?m)^(import\\b|plugins\\b|buildscript\\b|apply\\b|rootProject\\b|pluginManagement\\b|dependencyResolutionManagement\\b)")
80+
}
81+
format('shell') {
82+
target('**/*.sh')
83+
targetExclude(noHeaderDirs)
84+
// Ensure header appears after shebang if present, else at the very top.
85+
def shHeader = file("$rootDir/gradle/header.sh").text
86+
// If file starts with a shebang and is missing the header, insert it after the shebang
87+
replaceRegex('insert-license-after-shebang',
88+
'(?s)\\A(#!.*\\n)(?!# Copyright and related rights waived via CC0\\n)',
89+
'$1' + shHeader + "\n")
90+
// If file has no shebang and is missing the header, insert it at the start
91+
replaceRegex('insert-license-at-start',
92+
'(?s)\\A(?!#!)(?!# Copyright and related rights waived via CC0\\n)',
93+
shHeader + "\n")
94+
}
4395
}
4496

4597
// gradle package
@@ -100,6 +152,157 @@ static List<Map> testAllCommands(String gradleCmd, String target) {
100152
}
101153
}
102154

155+
/*
156+
* Helper utilities for environment setup, and backup/restore
157+
* used by testMetadataGeneration.
158+
*/
159+
def withUnsetTckDir(List<String> baseArgs) {
160+
if (System.getProperty("os.name").toLowerCase().contains("windows")) {
161+
["cmd.exe", "/d", "/c", "set GVM_TCK_TCKDIR= && " + baseArgs.join(' ')]
162+
} else {
163+
["/usr/bin/env", "-u", "GVM_TCK_TCKDIR"] + baseArgs
164+
}
165+
}
166+
167+
def backupDirIfExists(File srcDir, File backupDir) {
168+
boolean had = srcDir?.isDirectory()
169+
if (had) {
170+
backupDir.parentFile?.mkdirs()
171+
project.copy {
172+
from(srcDir)
173+
into(backupDir)
174+
}
175+
}
176+
had
177+
}
178+
179+
def restoreDir(boolean had, File srcDir, File backupDir) {
180+
if (had) {
181+
project.delete(srcDir)
182+
srcDir.mkdirs()
183+
project.copy {
184+
from(backupDir)
185+
into(srcDir)
186+
}
187+
} else {
188+
project.delete(srcDir)
189+
}
190+
}
191+
def backupFileIfExists(File srcFile, File backupFile) {
192+
boolean had = srcFile?.isFile()
193+
if (had) {
194+
backupFile.parentFile?.mkdirs()
195+
backupFile.text = srcFile.getText('UTF-8')
196+
}
197+
had
198+
}
199+
def restoreFileIfBackedUp(boolean had, File srcFile, File backupFile) {
200+
if (had && backupFile?.isFile()) {
201+
srcFile.text = backupFile.getText('UTF-8')
202+
}
203+
}
204+
205+
// Test metadata generation tasks
206+
def testMetadataGeneration(String coordinate, String gradleCmd, File logsDir, String newVersion) {
207+
208+
def fileSuffix = coordinate.replaceAll(File.separator, "-")
209+
210+
// Compute paths and snapshot current state to allow revert after the test
211+
def parts = coordinate.split(":")
212+
if (parts.length != 3) {
213+
throw new GradleException("Invalid coordinates '${coordinate}'. Expected 'group:artifact:version'.")
214+
}
215+
def group = parts[0]
216+
def artifact = parts[1]
217+
def version = parts[2]
218+
def gaPath = "${group}/${artifact}"
219+
def versionPath = "${gaPath}/${version}"
220+
221+
def versionDir = new File(tck.metadataRoot.get().asFile, versionPath)
222+
def testsDir = new File(tck.testRoot.get().asFile, versionPath)
223+
224+
def backupRoot = layout.buildDirectory.dir("gm-backups/${fileSuffix}").get().asFile
225+
def backupMetadataDir = new File(backupRoot, "metadata-backup")
226+
def backupTestsDir = new File(backupRoot, "tests-backup")
227+
backupRoot.mkdirs()
228+
boolean hadVersionDir = backupDirIfExists(versionDir, backupMetadataDir)
229+
boolean hadTestsDir = backupDirIfExists(testsDir, backupTestsDir)
230+
231+
try {
232+
// Build base args once, then prepend an OS-specific unset of GVM_TCK_TCKDIR
233+
def baseGenArgs = [gradleCmd, "generateMetadata", "-Pcoordinates=${coordinate}", "--agentAllowedPackages=org.postgresql"]
234+
List<String> genArgs = withUnsetTckDir(baseGenArgs)
235+
def genLogFile = new File(logsDir, "generateMetadata-${fileSuffix}.log")
236+
int genExit = project.ext.runLoggedCommand(genArgs, "generateMetadata (${coordinate})", genLogFile, project.rootDir)
237+
if (genExit != 0) {
238+
throw new GradleException("generateMetadata failed with exit code ${genExit} (see ${genLogFile})")
239+
}
240+
241+
// Verify output directory and index.json for the specific version
242+
if (!versionDir.isDirectory()) {
243+
throw new GradleException("Version directory not found: ${versionDir}")
244+
}
245+
def indexFile = new File(versionDir, "index.json")
246+
if (!indexFile.isFile()) {
247+
throw new GradleException("Missing index.json in ${versionDir}")
248+
}
249+
250+
def actualFiles = versionDir.listFiles()?.findAll { it.isFile() && it.name != 'index.json' }?.collect { it.name }?.sort() ?: []
251+
if (actualFiles.isEmpty()) {
252+
throw new GradleException("No metadata files found in ${versionDir} (besides index.json)")
253+
}
254+
255+
def indexList = (List) new JsonSlurper().parse(indexFile)
256+
def sortedIndex = indexList.collect { it.toString() }.sort()
257+
if (!sortedIndex.equals(actualFiles)) {
258+
println("==== BEGIN index.json mismatch (${coordinate})")
259+
println("index.json: ${sortedIndex}")
260+
println("actual: ${actualFiles}")
261+
println("==== END index.json mismatch (${coordinate})")
262+
throw new GradleException("index.json does not match files in ${versionDir}")
263+
}
264+
println("Verified generated metadata for ${coordinate}: ${versionDir}")
265+
} finally {
266+
// Revert metadata directory changes
267+
restoreDir(hadVersionDir, versionDir, backupMetadataDir)
268+
// Revert tests directory changes (including build.gradle and user-code-filter.json)
269+
restoreDir(hadTestsDir, testsDir, backupTestsDir)
270+
// Cleanup backups
271+
project.delete(backupRoot)
272+
}
273+
274+
275+
def newVersionDir = new File(tck.metadataRoot.get().asFile, "${gaPath}/${newVersion}")
276+
277+
def moduleIndexFile = new File(tck.metadataRoot.get().asFile, "${gaPath}/index.json")
278+
279+
def fixBackupRoot = layout.buildDirectory.dir("fixnir-backups/${fileSuffix}").get().asFile
280+
def backupNewMetadataDir = new File(fixBackupRoot, "new-metadata-backup")
281+
def fixBackupTestsDir = new File(fixBackupRoot, "new-metadata-backup")
282+
def backupModuleIndexFile = new File(fixBackupRoot, "module-index.json.bak")
283+
fixBackupRoot.mkdirs()
284+
hadTestsDir = backupDirIfExists(testsDir, fixBackupTestsDir)
285+
def hadNewVersionDir = backupDirIfExists(newVersionDir, backupNewMetadataDir)
286+
def hadModuleIndexFile = backupFileIfExists(moduleIndexFile, backupModuleIndexFile)
287+
288+
try {
289+
def baseFixArgs = [gradleCmd, "fixTestNativeImageRun", "-PtestLibraryCoordinates=${coordinate}", "-PnewLibraryVersion=${newVersion}"]
290+
List<String> fixArgs = withUnsetTckDir(baseFixArgs)
291+
def fixLogFile = new File(logsDir, "fixTestNativeImageRun-${fileSuffix}.log")
292+
int fixExit = project.ext.runLoggedCommand(fixArgs, "fixTestNativeImageRun (${coordinate} -> ${newVersion})", fixLogFile, project.rootDir)
293+
if (fixExit != 0) {
294+
throw new GradleException("fixTestNativeImageRun failed with exit code ${fixExit} (see ${fixLogFile})")
295+
}
296+
} finally {
297+
// Revert changes
298+
restoreDir(hadNewVersionDir, newVersionDir, backupNewMetadataDir)
299+
restoreDir(hadTestsDir, testsDir, fixBackupTestsDir)
300+
restoreFileIfBackedUp(hadModuleIndexFile, moduleIndexFile, backupModuleIndexFile)
301+
// Cleanup backups
302+
project.delete(fixBackupRoot)
303+
}
304+
}
305+
103306
tasks.register('testAllParallel') { t ->
104307
t.group = "verification"
105308
t.setDescription("For each target, run clean and pullAllowedDockerImages first (sequentially), then run style checks and individual testing stages (${testAllCommands('', '').collect { it.name }.join(', ')}) concurrently with isolated logs. Options: -Pcoordinates to specify a single coordinate or 1/64 for the pull step; -Pparallelism to control the number of concurrent tasks.")
@@ -194,9 +397,11 @@ tasks.register('testAllParallel') { t ->
194397
println("All commands succeeded for coordinates=${coordinate}. Logs in: ${logsDir}")
195398
}
196399
}
400+
def newVersionForFix = "42.7.4"
197401

198402
// Run parallel phases sequentially: first the selectedArtifact, then the selectedBatch
199403
runPhaseForCoordinate(selectedArtifact)
404+
testMetadataGeneration(selectedArtifact, gradleCmd, logsDir, newVersionForFix)
200405
runPhaseForCoordinate(selectedBatch)
201406
}
202407
}

docs/CONTRIBUTING.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,18 @@ After it collects your answers, the task will:
3939
- generate metadata and store it in the proper location
4040
- ask you if you want to create a pull request, or you want to keep working on it locally
4141

42+
If you already have the test project structure in this repository and need to generate or regenerate metadata, use the `generateMetadata` task:
43+
44+
```shell
45+
./gradlew generateMetadata --coordinates=com.example:my-library:1.0.0
46+
```
47+
48+
To change the user-code-filter used during collection, pass `--allowedPackages` with a comma-separated list of packages:
49+
50+
```shell
51+
./gradlew generateMetadata --coordinates=com.example:my-library:1.0.0 --allowedPackages=com.example.pkg,org.acme.lib
52+
```
53+
4254
### Checklist
4355
In order to ensure that all contributions follow the same standards of quality we have devised a following list of requirements for each new added library.
4456
`org.example:library` project is also included as a template for new libraries.

docs/DEVELOPING.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ Tip: When debugging locally, add `--stacktrace` for better error output.
3838
```console
3939
./gradlew spotlessCheck
4040
```
41+
3. Auto-fix license headers and formatting locally:
42+
```console
43+
./gradlew spotlessApply
44+
```
45+
Spotless enforces the CC0 license header on Java, Groovy, Gradle build scripts, and shell scripts. The metadata/** directory is excluded from header checks.
4146

4247
### Testing one library locally
4348

@@ -88,6 +93,35 @@ Each stage of the testing can be run with `-Pcoordinates=[group:artifact:version
8893
./gradlew test -Pcoordinates=[group:artifact:version|k/n|all]
8994
```
9095

96+
### Generating Metadata
97+
98+
Generates metadata for a single library coordinate. If `agentAllowedPackages` is provided, a new user-code-filter.json will be created or updated to include those packages.
99+
100+
- `coordinates`: group:artifact:version (single coordinate only)
101+
- `agentAllowedPackages`: comma-separated package list; use `-` for none
102+
103+
Examples:
104+
```console
105+
./gradlew generateMetadata -Pcoordinates=org.postgresql:postgresql:42.7.3
106+
./gradlew generateMetadata -Pcoordinates=org.postgresql:postgresql:42.7.3 --agentAllowedPackages=org.example.app,com.acme.service
107+
```
108+
109+
### Fix failing tasks
110+
111+
Use this when a library's new version causes native-image run test failures. The task will:
112+
- Update the module's metadata index.json to mark the new version as latest
113+
- Ensure the tests project has an agent block and a user-code-filter.json if missing
114+
- Run the agent to collect metadata, then re-run tests (with a retry if needed)
115+
116+
Required properties:
117+
- -PtestLibraryCoordinates=group:artifact:version (coordinates of an existing tested version whose tests you run)
118+
- -PnewLibraryVersion=version (the new upstream version number only; do not include group or artifact)
119+
120+
Example:
121+
```console
122+
./gradlew fixTestNativeImageRun -PtestLibraryCoordinates=org.postgresql:postgresql:42.7.3 -PnewLibraryVersion=42.7.4
123+
```
124+
91125
### Docker image vulnerability scanning
92126

93127
1. Scan only images affected in a commit range:
@@ -128,8 +162,11 @@ These tasks support the scheduled workflow that checks newer upstream library ve
128162

129163
- Style: `./gradlew checkstyle`
130164
- Format check: `./gradlew spotlessCheck`
165+
- Format apply: `./gradlew spotlessApply`
131166
- Pull images (single lib): `./gradlew pullAllowedDockerImages -Pcoordinates=[group:artifact:version|k/n|all]`
132167
- Check metadata (single lib): `./gradlew checkMetadataFiles -Pcoordinates=[group:artifact:version|k/n|all]`
168+
- Generate metadata (single lib): `./gradlew generateMetadata -Pcoordinates=group:artifact:version`
169+
- Fix test that fails Native Image run for new library version: `./gradlew fixTestNativeImageRun -PtestLibraryCoordinates=group:artifact:version -PnewLibraryVersion=version`
133170
- Test (single lib): `./gradlew test -Pcoordinates=[group:artifact:version|k/n|all]`
134171
- Scan changed Docker images: `./gradlew checkAllowedDockerImages --baseCommit=<sha1> --newCommit=<sha2>`
135172
- Scan all Docker images: `./gradlew checkAllowedDockerImages`

gradle/header.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/*
2+
* Copyright and related rights waived via CC0
3+
*
4+
* You should have received a copy of the CC0 legalcode along with this
5+
* work. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
6+
*/

0 commit comments

Comments
 (0)