mirror of
https://github.com/actions/setup-java.git
synced 2026-07-16 13:52:59 +00:00
Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6e2e32e729 | |||
| 38fa86f9e4 | |||
| ecd5f809c2 | |||
| 4a24efdcc9 | |||
| cc8cdedf67 | |||
| 4b0728bd0d | |||
| 7d485884af | |||
| c3568cc9d9 | |||
| 81c13a41f9 | |||
| 3c85b14378 | |||
| 80c368b720 | |||
| cd57b95697 | |||
| 7a475d86d1 | |||
| 92f9362dd0 | |||
| 71cfe8e0ed | |||
| eb6157cd13 | |||
| 2adeb10550 | |||
| 23f8c419c6 | |||
| 6f7d7a6eb1 | |||
| 2301a55b6d | |||
| 2789aa9170 | |||
| 28fb8cb06b | |||
| 174d4b5609 | |||
| 86ce8e6cc8 | |||
| 90be2728bc | |||
| 3157986b3f |
@@ -1,102 +0,0 @@
|
||||
name: Validate cache with cache-dependency-path option
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- releases/*
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
gradle1-save:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Run setup-java with the cache for gradle
|
||||
uses: ./
|
||||
id: setup-java
|
||||
with:
|
||||
distribution: 'adopt'
|
||||
java-version: '17'
|
||||
cache: gradle
|
||||
cache-dependency-path: __tests__/cache/gradle1/*.gradle*
|
||||
- name: Create files to cache
|
||||
# Need to avoid using Gradle daemon to stabilize the save process on Windows
|
||||
# https://github.com/actions/cache/issues/454#issuecomment-840493935
|
||||
run: |
|
||||
gradle downloadDependencies --no-daemon -p __tests__/cache/gradle1
|
||||
if [ ! -d ~/.gradle/caches ]; then
|
||||
echo "::error::The ~/.gradle/caches directory does not exist unexpectedly"
|
||||
exit 1
|
||||
fi
|
||||
gradle1-restore:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||
needs: gradle1-save
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Run setup-java with the cache for gradle
|
||||
uses: ./
|
||||
id: setup-java
|
||||
with:
|
||||
distribution: 'adopt'
|
||||
java-version: '11'
|
||||
cache: gradle
|
||||
cache-dependency-path: __tests__/cache/gradle1/*.gradle*
|
||||
- name: Confirm that ~/.gradle/caches directory has been made
|
||||
run: |
|
||||
if [ ! -d ~/.gradle/caches ]; then
|
||||
echo "::error::The ~/.gradle/caches directory does not exist unexpectedly"
|
||||
exit 1
|
||||
fi
|
||||
ls ~/.gradle/caches/
|
||||
gradle2-restore:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||
needs: gradle1-save
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Run setup-java with the cache for gradle
|
||||
uses: ./
|
||||
id: setup-java
|
||||
with:
|
||||
distribution: 'adopt'
|
||||
java-version: '11'
|
||||
cache: gradle
|
||||
cache-dependency-path: __tests__/cache/gradle2/*.gradle*
|
||||
- name: Confirm that ~/.gradle/caches directory has not been made
|
||||
run: |
|
||||
if [ -d ~/.gradle/caches ]; then
|
||||
echo "::error::The ~/.gradle/caches directory exists unexpectedly"
|
||||
exit 1
|
||||
fi
|
||||
+255
-54
@@ -42,10 +42,7 @@ jobs:
|
||||
# https://github.com/actions/cache/issues/454#issuecomment-840493935
|
||||
run: |
|
||||
gradle downloadDependencies --no-daemon -p __tests__/cache/gradle1
|
||||
if [ ! -d ~/.gradle/caches ]; then
|
||||
echo "::error::The ~/.gradle/caches directory does not exist unexpectedly"
|
||||
exit 1
|
||||
fi
|
||||
bash __tests__/check-dir.sh "$HOME/.gradle/caches"
|
||||
gradle-restore:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
@@ -66,12 +63,7 @@ jobs:
|
||||
java-version: '11'
|
||||
cache: gradle
|
||||
- name: Confirm that ~/.gradle/caches directory has been made
|
||||
run: |
|
||||
if [ ! -d ~/.gradle/caches ]; then
|
||||
echo "::error::The ~/.gradle/caches directory does not exist unexpectedly"
|
||||
exit 1
|
||||
fi
|
||||
ls ~/.gradle/caches/
|
||||
run: bash __tests__/check-dir.sh "$HOME/.gradle/caches"
|
||||
maven-save:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
@@ -93,10 +85,7 @@ jobs:
|
||||
- name: Create files to cache
|
||||
run: |
|
||||
mvn verify -f __tests__/cache/maven/pom.xml
|
||||
if [ ! -d ~/.m2/repository ]; then
|
||||
echo "::error::The ~/.m2/repository directory does not exist unexpectedly"
|
||||
exit 1
|
||||
fi
|
||||
bash __tests__/check-dir.sh "$HOME/.m2/repository"
|
||||
maven-restore:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
@@ -117,12 +106,7 @@ jobs:
|
||||
java-version: '11'
|
||||
cache: maven
|
||||
- name: Confirm that ~/.m2/repository directory has been made
|
||||
run: |
|
||||
if [ ! -d ~/.m2/repository ]; then
|
||||
echo "::error::The ~/.m2/repository directory does not exist unexpectedly"
|
||||
exit 1
|
||||
fi
|
||||
ls ~/.m2/repository
|
||||
run: bash __tests__/check-dir.sh "$HOME/.m2/repository"
|
||||
sbt-save:
|
||||
runs-on: ${{ matrix.os }}
|
||||
defaults:
|
||||
@@ -155,25 +139,13 @@ jobs:
|
||||
|
||||
- name: Check files to cache on macos-latest
|
||||
if: matrix.os == 'macos-15-intel'
|
||||
run: |
|
||||
if [ ! -d ~/Library/Caches/Coursier ]; then
|
||||
echo "::error::The ~/Library/Caches/Coursier directory does not exist unexpectedly"
|
||||
exit 1
|
||||
fi
|
||||
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/Library/Caches/Coursier"
|
||||
- name: Check files to cache on windows-latest
|
||||
if: matrix.os == 'windows-latest'
|
||||
run: |
|
||||
if [ ! -d ~/AppData/Local/Coursier/Cache ]; then
|
||||
echo "::error::The ~/AppData/Local/Coursier/Cache directory does not exist unexpectedly"
|
||||
exit 1
|
||||
fi
|
||||
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/AppData/Local/Coursier/Cache"
|
||||
- name: Check files to cache on ubuntu-latest
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: |
|
||||
if [ ! -d ~/.cache/coursier ]; then
|
||||
echo "::error::The ~/.cache/coursier directory does not exist unexpectedly"
|
||||
exit 1
|
||||
fi
|
||||
if: matrix.os == 'ubuntu-22.04'
|
||||
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/.cache/coursier"
|
||||
sbt-restore:
|
||||
runs-on: ${{ matrix.os }}
|
||||
defaults:
|
||||
@@ -200,25 +172,254 @@ jobs:
|
||||
|
||||
- name: Confirm that ~/Library/Caches/Coursier directory has been made
|
||||
if: matrix.os == 'macos-15-intel'
|
||||
run: |
|
||||
if [ ! -d ~/Library/Caches/Coursier ]; then
|
||||
echo "::error::The ~/Library/Caches/Coursier directory does not exist unexpectedly"
|
||||
exit 1
|
||||
fi
|
||||
ls ~/Library/Caches/Coursier
|
||||
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/Library/Caches/Coursier"
|
||||
- name: Confirm that ~/AppData/Local/Coursier/Cache directory has been made
|
||||
if: matrix.os == 'windows-latest'
|
||||
run: |
|
||||
if [ ! -d ~/AppData/Local/Coursier/Cache ]; then
|
||||
echo "::error::The ~/AppData/Local/Coursier/Cache directory does not exist unexpectedly"
|
||||
exit 1
|
||||
fi
|
||||
ls ~/AppData/Local/Coursier/Cache
|
||||
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/AppData/Local/Coursier/Cache"
|
||||
- name: Confirm that ~/.cache/coursier directory has been made
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
if: matrix.os == 'ubuntu-22.04'
|
||||
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/.cache/coursier"
|
||||
gradle1-save:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Run setup-java with the cache for gradle
|
||||
uses: ./
|
||||
id: setup-java
|
||||
with:
|
||||
distribution: 'adopt'
|
||||
java-version: '17'
|
||||
cache: gradle
|
||||
cache-dependency-path: __tests__/cache/gradle1/*.gradle*
|
||||
- name: Create files to cache
|
||||
# Need to avoid using Gradle daemon to stabilize the save process on Windows
|
||||
# https://github.com/actions/cache/issues/454#issuecomment-840493935
|
||||
run: |
|
||||
if [ ! -d ~/.cache/coursier ]; then
|
||||
echo "::error::The ~/.cache/coursier directory does not exist unexpectedly"
|
||||
exit 1
|
||||
fi
|
||||
ls ~/.cache/coursier
|
||||
gradle downloadDependencies --no-daemon -p __tests__/cache/gradle1
|
||||
bash __tests__/check-dir.sh "$HOME/.gradle/caches"
|
||||
gradle1-restore:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||
needs: gradle1-save
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Run setup-java with the cache for gradle
|
||||
uses: ./
|
||||
id: setup-java
|
||||
with:
|
||||
distribution: 'adopt'
|
||||
java-version: '11'
|
||||
cache: gradle
|
||||
cache-dependency-path: __tests__/cache/gradle1/*.gradle*
|
||||
- name: Confirm that ~/.gradle/caches directory has been made
|
||||
run: bash __tests__/check-dir.sh "$HOME/.gradle/caches"
|
||||
gradle2-restore:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||
needs: gradle1-save
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Run setup-java with the cache for gradle
|
||||
uses: ./
|
||||
id: setup-java
|
||||
with:
|
||||
distribution: 'adopt'
|
||||
java-version: '11'
|
||||
cache: gradle
|
||||
cache-dependency-path: __tests__/cache/gradle2/*.gradle*
|
||||
- name: Confirm that ~/.gradle/caches directory has not been made
|
||||
run: bash __tests__/check-dir.sh "$HOME/.gradle/caches" absent
|
||||
maven1-save:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-15-intel, windows-latest, ubuntu-latest]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Run setup-java with the cache for maven
|
||||
uses: ./
|
||||
id: setup-java
|
||||
with:
|
||||
distribution: 'adopt'
|
||||
java-version: '11'
|
||||
cache: maven
|
||||
cache-dependency-path: __tests__/cache/maven/pom.xml
|
||||
- name: Create files to cache
|
||||
run: |
|
||||
mvn verify -f __tests__/cache/maven/pom.xml
|
||||
bash __tests__/check-dir.sh "$HOME/.m2/repository"
|
||||
maven1-restore:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-15-intel, windows-latest, ubuntu-latest]
|
||||
needs: maven1-save
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Run setup-java with the cache for maven
|
||||
uses: ./
|
||||
id: setup-java
|
||||
with:
|
||||
distribution: 'adopt'
|
||||
java-version: '11'
|
||||
cache: maven
|
||||
cache-dependency-path: __tests__/cache/maven/pom.xml
|
||||
- name: Confirm that ~/.m2/repository directory has been made
|
||||
run: bash __tests__/check-dir.sh "$HOME/.m2/repository"
|
||||
maven2-restore:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-15-intel, windows-latest, ubuntu-latest]
|
||||
needs: maven1-save
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Run setup-java with the cache for maven
|
||||
uses: ./
|
||||
id: setup-java
|
||||
with:
|
||||
distribution: 'adopt'
|
||||
java-version: '11'
|
||||
cache: maven
|
||||
cache-dependency-path: __tests__/cache/maven2/pom.xml
|
||||
- name: Confirm that ~/.m2/repository directory has not been made
|
||||
run: bash __tests__/check-dir.sh "$HOME/.m2/repository" absent
|
||||
sbt1-save:
|
||||
runs-on: ${{ matrix.os }}
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
working-directory: __tests__/cache/sbt
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-15-intel, windows-latest, ubuntu-22.04]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Run setup-java with the cache for sbt
|
||||
uses: ./
|
||||
id: setup-java
|
||||
with:
|
||||
distribution: 'adopt'
|
||||
java-version: '11'
|
||||
cache: sbt
|
||||
cache-dependency-path: __tests__/cache/sbt/*.sbt
|
||||
- name: Setup SBT
|
||||
if: matrix.os == 'macos-15-intel'
|
||||
run: |
|
||||
echo ""Installing SBT...""
|
||||
brew install sbt
|
||||
- name: Create files to cache
|
||||
run: sbt update
|
||||
|
||||
- name: Check files to cache on macos-latest
|
||||
if: matrix.os == 'macos-15-intel'
|
||||
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/Library/Caches/Coursier"
|
||||
- name: Check files to cache on windows-latest
|
||||
if: matrix.os == 'windows-latest'
|
||||
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/AppData/Local/Coursier/Cache"
|
||||
- name: Check files to cache on ubuntu-latest
|
||||
if: matrix.os == 'ubuntu-22.04'
|
||||
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/.cache/coursier"
|
||||
sbt1-restore:
|
||||
runs-on: ${{ matrix.os }}
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
working-directory: __tests__/cache/sbt
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-15-intel, windows-latest, ubuntu-22.04]
|
||||
needs: sbt1-save
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Run setup-java with the cache for sbt
|
||||
uses: ./
|
||||
id: setup-java
|
||||
with:
|
||||
distribution: 'adopt'
|
||||
java-version: '11'
|
||||
cache: sbt
|
||||
cache-dependency-path: __tests__/cache/sbt/*.sbt
|
||||
|
||||
- name: Confirm that ~/Library/Caches/Coursier directory has been made
|
||||
if: matrix.os == 'macos-15-intel'
|
||||
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/Library/Caches/Coursier"
|
||||
- name: Confirm that ~/AppData/Local/Coursier/Cache directory has been made
|
||||
if: matrix.os == 'windows-latest'
|
||||
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/AppData/Local/Coursier/Cache"
|
||||
- name: Confirm that ~/.cache/coursier directory has been made
|
||||
if: matrix.os == 'ubuntu-22.04'
|
||||
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/.cache/coursier"
|
||||
sbt2-restore:
|
||||
runs-on: ${{ matrix.os }}
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
working-directory: __tests__/cache/sbt2
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-15-intel, windows-latest, ubuntu-22.04]
|
||||
needs: sbt1-save
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Run setup-java with the cache for sbt
|
||||
uses: ./
|
||||
id: setup-java
|
||||
with:
|
||||
distribution: 'adopt'
|
||||
java-version: '11'
|
||||
cache: sbt
|
||||
cache-dependency-path: __tests__/cache/sbt2/*.sbt
|
||||
|
||||
- name: Confirm that ~/Library/Caches/Coursier directory has not been made
|
||||
if: matrix.os == 'macos-15-intel'
|
||||
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/Library/Caches/Coursier" absent
|
||||
- name: Confirm that ~/AppData/Local/Coursier/Cache directory has not been made
|
||||
if: matrix.os == 'windows-latest'
|
||||
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/AppData/Local/Coursier/Cache" absent
|
||||
- name: Confirm that ~/.cache/coursier directory has not been made
|
||||
if: matrix.os == 'ubuntu-22.04'
|
||||
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/.cache/coursier" absent
|
||||
|
||||
@@ -46,13 +46,25 @@ jobs:
|
||||
$xmlPath = Join-Path $HOME ".m2" "settings.xml"
|
||||
Get-Content $xmlPath | ForEach-Object { Write-Host $_ }
|
||||
|
||||
[xml]$xml = Get-Content $xmlPath
|
||||
$servers = $xml.settings.servers.server
|
||||
if (($servers[0].id -ne 'maven') -or ($servers[0].username -ne '${env.MAVEN_USERNAME}') -or ($servers[0].password -ne '${env.MAVEN_CENTRAL_TOKEN}')) {
|
||||
throw "Generated XML file is incorrect"
|
||||
}
|
||||
$content = [System.IO.File]::ReadAllText($xmlPath)
|
||||
$expected = @(
|
||||
'<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"'
|
||||
' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"'
|
||||
' xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">'
|
||||
' <interactiveMode>false</interactiveMode>'
|
||||
' <servers>'
|
||||
' <server>'
|
||||
' <id>maven</id>'
|
||||
' <username>${env.MAVEN_USERNAME}</username>'
|
||||
' <password>${env.MAVEN_CENTRAL_TOKEN}</password>'
|
||||
' </server>'
|
||||
' </servers>'
|
||||
'</settings>'
|
||||
) -join "`n"
|
||||
|
||||
if (($servers[1].id -ne 'gpg.passphrase') -or ($servers[1].passphrase -ne '${env.MAVEN_GPG_PASSPHRASE}')) {
|
||||
if ($content -ne $expected) {
|
||||
Write-Host "Expected settings.xml:"
|
||||
$expected -split "`n" | ForEach-Object { Write-Host $_ }
|
||||
throw "Generated XML file is incorrect"
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,8 @@ jobs:
|
||||
'dragonwell',
|
||||
'sapmachine',
|
||||
'jetbrains',
|
||||
'kona'
|
||||
'kona',
|
||||
'liberica-nik'
|
||||
] # internally 'adopt-hotspot' is the same as 'adopt'
|
||||
version: ['21', '11', '17']
|
||||
exclude:
|
||||
@@ -55,6 +56,24 @@ jobs:
|
||||
- distribution: microsoft
|
||||
os: macos-latest
|
||||
version: 25
|
||||
- distribution: kona
|
||||
os: windows-latest
|
||||
version: 25
|
||||
- distribution: kona
|
||||
os: ubuntu-latest
|
||||
version: 25
|
||||
- distribution: kona
|
||||
os: macos-latest
|
||||
version: 25
|
||||
- distribution: liberica-nik
|
||||
os: windows-latest
|
||||
version: 25
|
||||
- distribution: liberica-nik
|
||||
os: ubuntu-latest
|
||||
version: 25
|
||||
- distribution: liberica-nik
|
||||
os: macos-latest
|
||||
version: 25
|
||||
- distribution: oracle
|
||||
os: macos-15-intel
|
||||
version: 17
|
||||
@@ -77,7 +96,8 @@ jobs:
|
||||
os: ubuntu-latest
|
||||
version: '24-ea'
|
||||
steps:
|
||||
- name: Checkout
|
||||
- &checkout_step
|
||||
name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
@@ -108,10 +128,7 @@ jobs:
|
||||
distribution: ['temurin', 'sapmachine']
|
||||
version: ['21', '17']
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- *checkout_step
|
||||
- name: Install bash
|
||||
run: apk add --no-cache bash
|
||||
- name: setup-java
|
||||
@@ -134,7 +151,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||
os: &default_os [macos-latest, windows-latest, ubuntu-latest]
|
||||
distribution: ['temurin', 'zulu', 'liberica']
|
||||
version:
|
||||
- '11.0'
|
||||
@@ -163,10 +180,7 @@ jobs:
|
||||
os: ubuntu-latest
|
||||
version: '17.0.7'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- *checkout_step
|
||||
- name: setup-java
|
||||
uses: ./
|
||||
id: setup-java
|
||||
@@ -188,7 +202,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||
os: *default_os
|
||||
distribution:
|
||||
[
|
||||
'temurin',
|
||||
@@ -202,10 +216,7 @@ jobs:
|
||||
- distribution: dragonwell
|
||||
os: macos-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- *checkout_step
|
||||
- name: setup-java
|
||||
uses: ./
|
||||
id: setup-java
|
||||
@@ -228,7 +239,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||
os: *default_os
|
||||
distribution:
|
||||
[
|
||||
'temurin',
|
||||
@@ -242,10 +253,7 @@ jobs:
|
||||
- distribution: dragonwell
|
||||
os: macos-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- *checkout_step
|
||||
- name: setup-java
|
||||
uses: ./
|
||||
id: setup-java
|
||||
@@ -275,26 +283,37 @@ jobs:
|
||||
run: bash __tests__/verify-java.sh "17" "$JAVA_PATH"
|
||||
shell: bash
|
||||
|
||||
setup-java-ea-versions-zulu:
|
||||
name: zulu ${{ matrix.version }} (jdk-${{ contains(matrix.os, 'macos') && !contains(matrix.os, 'intel') && 'arm64' || 'x64' }}) - ${{ matrix.os }}
|
||||
setup-java-ea-versions:
|
||||
name: ${{ matrix.distribution }} ${{ matrix.version }} (jdk-${{ contains(matrix.os, 'macos') && !contains(matrix.os, 'intel') && 'arm64' || 'x64' }}) - ${{ matrix.os }}
|
||||
needs: setup-java-major-minor-versions
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-15-intel, windows-latest, ubuntu-latest]
|
||||
version: ['17-ea', '15.0.0-ea.14']
|
||||
include:
|
||||
- {os: macos-15-intel, version: '17-ea', distribution: zulu}
|
||||
- {os: windows-latest, version: '17-ea', distribution: zulu}
|
||||
- {os: ubuntu-latest, version: '17-ea', distribution: zulu}
|
||||
- {os: macos-15-intel, version: '15.0.0-ea.14', distribution: zulu}
|
||||
- {os: windows-latest, version: '15.0.0-ea.14', distribution: zulu}
|
||||
- {os: ubuntu-latest, version: '15.0.0-ea.14', distribution: zulu}
|
||||
- {os: macos-latest, version: '17-ea', distribution: temurin}
|
||||
- {os: windows-latest, version: '17-ea', distribution: temurin}
|
||||
- {os: ubuntu-latest, version: '17-ea', distribution: temurin}
|
||||
- {os: macos-latest, version: '17-ea', distribution: sapmachine}
|
||||
- {os: windows-latest, version: '17-ea', distribution: sapmachine}
|
||||
- {os: ubuntu-latest, version: '17-ea', distribution: sapmachine}
|
||||
- {os: macos-latest, version: '21-ea', distribution: sapmachine}
|
||||
- {os: windows-latest, version: '21-ea', distribution: sapmachine}
|
||||
- {os: ubuntu-latest, version: '21-ea', distribution: sapmachine}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- *checkout_step
|
||||
- name: setup-java
|
||||
uses: ./
|
||||
id: setup-java
|
||||
with:
|
||||
java-version: ${{ matrix.version }}
|
||||
distribution: zulu
|
||||
distribution: ${{ matrix.distribution }}
|
||||
- name: Verify Java
|
||||
env:
|
||||
JAVA_VERSION: ${{ matrix.version }}
|
||||
@@ -302,53 +321,24 @@ jobs:
|
||||
run: bash __tests__/verify-java.sh "$JAVA_VERSION" "$JAVA_PATH"
|
||||
shell: bash
|
||||
|
||||
setup-java-ea-versions-temurin:
|
||||
name: temurin ${{ matrix.version }} (jdk-${{ contains(matrix.os, 'macos') && !contains(matrix.os, 'intel') && 'arm64' || 'x64' }}) - ${{ matrix.os }}
|
||||
setup-java-signature-verification:
|
||||
name: ${{ matrix.distribution }} ${{ matrix.version }} signature verification - ${{ matrix.os }}
|
||||
needs: setup-java-major-minor-versions
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||
version: ['17-ea']
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: setup-java
|
||||
uses: ./
|
||||
id: setup-java
|
||||
with:
|
||||
java-version: ${{ matrix.version }}
|
||||
distribution: temurin
|
||||
- name: Verify Java
|
||||
env:
|
||||
JAVA_VERSION: ${{ matrix.version }}
|
||||
JAVA_PATH: ${{ steps.setup-java.outputs.path }}
|
||||
run: bash __tests__/verify-java.sh "$JAVA_VERSION" "$JAVA_PATH"
|
||||
shell: bash
|
||||
|
||||
setup-java-temurin-signature-verification:
|
||||
name: temurin ${{ matrix.version }} signature verification - ${{ matrix.os }}
|
||||
needs: setup-java-major-minor-versions
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||
os: *default_os
|
||||
version: ['21', '17']
|
||||
distribution: [temurin, microsoft]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- *checkout_step
|
||||
- name: setup-java with signature verification
|
||||
uses: ./
|
||||
id: setup-java
|
||||
with:
|
||||
java-version: ${{ matrix.version }}
|
||||
distribution: temurin
|
||||
distribution: ${{ matrix.distribution }}
|
||||
verify-signature: true
|
||||
- name: Verify Java
|
||||
env:
|
||||
@@ -357,61 +347,6 @@ jobs:
|
||||
run: bash __tests__/verify-java.sh "$JAVA_VERSION" "$JAVA_PATH"
|
||||
shell: bash
|
||||
|
||||
setup-java-microsoft-signature-verification:
|
||||
name: microsoft ${{ matrix.version }} signature verification - ${{ matrix.os }}
|
||||
needs: setup-java-major-minor-versions
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||
version: ['21', '17']
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: setup-java with signature verification
|
||||
uses: ./
|
||||
id: setup-java
|
||||
with:
|
||||
java-version: ${{ matrix.version }}
|
||||
distribution: microsoft
|
||||
verify-signature: true
|
||||
- name: Verify Java
|
||||
env:
|
||||
JAVA_VERSION: ${{ matrix.version }}
|
||||
JAVA_PATH: ${{ steps.setup-java.outputs.path }}
|
||||
run: bash __tests__/verify-java.sh "$JAVA_VERSION" "$JAVA_PATH"
|
||||
shell: bash
|
||||
|
||||
setup-java-ea-versions-sapmachine:
|
||||
name: sapmachine ${{ matrix.version }} (jdk-${{ contains(matrix.os, 'macos') && !contains(matrix.os, 'intel') && 'arm64' || 'x64' }}) - ${{ matrix.os }}
|
||||
needs: setup-java-major-minor-versions
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||
version: ['17-ea', '21-ea']
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: setup-java
|
||||
uses: ./
|
||||
id: setup-java
|
||||
with:
|
||||
java-version: ${{ matrix.version }}
|
||||
distribution: sapmachine
|
||||
- name: Verify Java
|
||||
env:
|
||||
JAVA_VERSION: ${{ matrix.version }}
|
||||
JAVA_PATH: ${{ steps.setup-java.outputs.path }}
|
||||
run: bash __tests__/verify-java.sh "$JAVA_VERSION" "$JAVA_PATH"
|
||||
shell: bash
|
||||
|
||||
setup-java-custom-package-type:
|
||||
name: ${{ matrix.distribution }} ${{ matrix.version }} (${{ matrix.java-package }}-x64) - ${{ matrix.os }}
|
||||
needs: setup-java-major-minor-versions
|
||||
@@ -441,6 +376,10 @@ jobs:
|
||||
java-package: jre+fx
|
||||
version: '11'
|
||||
os: ubuntu-latest
|
||||
- distribution: 'liberica-nik'
|
||||
java-package: jdk+fx
|
||||
version: '21'
|
||||
os: ubuntu-latest
|
||||
- distribution: 'corretto'
|
||||
java-package: jre
|
||||
version: '8'
|
||||
@@ -487,10 +426,7 @@ jobs:
|
||||
os: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- *checkout_step
|
||||
- name: setup-java
|
||||
uses: ./
|
||||
id: setup-java
|
||||
@@ -520,10 +456,7 @@ jobs:
|
||||
distribution: ['liberica', 'zulu', 'corretto']
|
||||
version: ['11']
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- *checkout_step
|
||||
- name: setup-java
|
||||
uses: ./
|
||||
id: setup-java
|
||||
@@ -544,14 +477,11 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||
os: *default_os
|
||||
distribution: ['temurin', 'microsoft', 'corretto']
|
||||
java-version-file: ['.java-version', '.tool-versions']
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- *checkout_step
|
||||
- name: Create .java-version file
|
||||
shell: bash
|
||||
run: echo "17" > .java-version
|
||||
@@ -577,14 +507,11 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||
os: *default_os
|
||||
distribution: ['temurin', 'zulu', 'liberica', 'microsoft', 'corretto']
|
||||
java-version-file: ['.java-version', '.tool-versions']
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- *checkout_step
|
||||
- name: Create .java-version file
|
||||
shell: bash
|
||||
run: echo "11" > .java-version
|
||||
@@ -609,14 +536,11 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||
os: *default_os
|
||||
distribution: ['adopt', 'adopt-openj9', 'zulu']
|
||||
java-version-file: ['.java-version', '.tool-versions']
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- *checkout_step
|
||||
- name: Create .java-version file
|
||||
shell: bash
|
||||
run: echo "17.0.10" > .java-version
|
||||
@@ -641,14 +565,11 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||
os: *default_os
|
||||
distribution: ['adopt', 'zulu', 'liberica']
|
||||
java-version-file: ['.java-version', '.tool-versions', '.sdkmanrc']
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- *checkout_step
|
||||
- name: Create .java-version file
|
||||
shell: bash
|
||||
run: echo "openjdk64-17.0.10" > .java-version
|
||||
@@ -677,10 +598,9 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||
os: *default_os
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
- *checkout_step
|
||||
- name: Setup Java 17 as default
|
||||
uses: ./
|
||||
id: setup-java-17
|
||||
@@ -699,10 +619,12 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Verify JAVA_HOME still points to Java 17
|
||||
env:
|
||||
JAVA_17_PATH: ${{ steps.setup-java-17.outputs.path }}
|
||||
run: |
|
||||
echo "JAVA_HOME=$JAVA_HOME"
|
||||
echo "Java 17 path=${{ steps.setup-java-17.outputs.path }}"
|
||||
if [ "$JAVA_HOME" != "${{ steps.setup-java-17.outputs.path }}" ]; then
|
||||
echo "Java 17 path=$JAVA_17_PATH"
|
||||
if [ "$JAVA_HOME" != "$JAVA_17_PATH" ]; then
|
||||
echo "JAVA_HOME should still point to Java 17"
|
||||
exit 1
|
||||
fi
|
||||
@@ -731,14 +653,17 @@ jobs:
|
||||
Write-Host "$envName=$JavaVersionPath"
|
||||
shell: pwsh
|
||||
- name: Verify Java 21 outputs are set
|
||||
env:
|
||||
JAVA_21_PATH: ${{ steps.setup-java-21.outputs.path }}
|
||||
JAVA_21_VERSION: ${{ steps.setup-java-21.outputs.version }}
|
||||
run: |
|
||||
echo "Java 21 path=${{ steps.setup-java-21.outputs.path }}"
|
||||
echo "Java 21 version=${{ steps.setup-java-21.outputs.version }}"
|
||||
if [ -z "${{ steps.setup-java-21.outputs.path }}" ]; then
|
||||
echo "Java 21 path=$JAVA_21_PATH"
|
||||
echo "Java 21 version=$JAVA_21_VERSION"
|
||||
if [ -z "$JAVA_21_PATH" ]; then
|
||||
echo "Java 21 path output should be set"
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "${{ steps.setup-java-21.outputs.version }}" ]; then
|
||||
if [ -z "$JAVA_21_VERSION" ]; then
|
||||
echo "Java 21 version output should be set"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: "@actions/cache"
|
||||
version: 6.1.0
|
||||
version: 6.2.0
|
||||
type: npm
|
||||
summary: Actions cache lib
|
||||
homepage: https://github.com/actions/toolkit/tree/main/packages/cache
|
||||
|
||||
@@ -22,6 +22,12 @@ This action allows you to work with Java and Scala projects.
|
||||
|
||||
- **Migrated to ESM** to enable support for the latest `@actions/*` package versions. This is an internal implementation change only. No changes are required to your workflow configuration, and the action's behavior is unchanged. Existing workflows continue to work as before.
|
||||
|
||||
## Breaking changes in V6
|
||||
|
||||
- **The GPG passphrase is now passed to the Maven GPG Plugin through an environment variable (`gpg.passphraseEnvName`) instead of the deprecated `gpg.passphrase` server in `settings.xml`.** The `gpg-passphrase` input and its default (`GPG_PASSPHRASE`) are unchanged, so if you already set that environment variable in your build step your workflow keeps working. However, this now requires `maven-gpg-plugin` **3.2.0 or newer**; older versions do not honor `gpg.passphraseEnvName` and, because the `gpg.passphrase` server is no longer written, will not pick up the passphrase. Upgrade the plugin to 3.2.0+.
|
||||
|
||||
See [GPG](docs/advanced-usage.md#gpg) for details.
|
||||
|
||||
## Breaking changes in V5
|
||||
|
||||
- Upgraded action from node20 to node24
|
||||
@@ -51,6 +57,8 @@ For more details, see the full release notes on the [releases page](https://git
|
||||
|
||||
- `verify-signature-public-key`: ASCII-armored GPG public key used to verify the downloaded package signature. Overrides the default bundled key for the selected distribution.
|
||||
|
||||
- `token`: The token used to authenticate when fetching version manifests hosted on GitHub.com. Defaults to `${{ github.token }}` when running on GitHub.com; defaults to an empty string on GitHub Enterprise Server. On GHES, provide a GitHub.com personal access token if manifest requests are rate-limited. See [Using Microsoft distribution on GHES](docs/advanced-usage.md#using-microsoft-distribution-on-ghes) for more details.
|
||||
|
||||
- `cache`: Quick [setup caching](#caching-packages-dependencies) for the dependencies managed through one of the predefined package managers. It can be one of "maven", "gradle" or "sbt".
|
||||
|
||||
- `cache-dependency-path`: The path to a dependency file: pom.xml, build.gradle, build.sbt, etc. This option can be used with the `cache` option. If this option is omitted, the action searches for the dependency file in the entire repository. This option supports wildcards and a list of file names for caching multiple dependencies.
|
||||
@@ -76,6 +84,8 @@ For more details, see the full release notes on the [releases page](https://git
|
||||
|
||||
- `mvn-toolchain-vendor`: Name of Maven Toolchain Vendor if the default name of `${distribution}` is not wanted.
|
||||
|
||||
- `show-download-progress`: Set to `true` to keep Maven artifact download and transfer progress in build logs. Default value: `false`. By default, the action adds `-ntp` (`--no-transfer-progress`) to `MAVEN_ARGS`. This input has no effect on non-Maven builds. See [Maven transfer progress](docs/advanced-usage.md#maven-transfer-progress-download-logs) for more details.
|
||||
|
||||
### Basic Configuration
|
||||
|
||||
#### Eclipse Temurin
|
||||
@@ -104,7 +114,16 @@ steps:
|
||||
The `java-version` input supports an exact version or a version range using [SemVer](https://semver.org/) notation. The values below are examples, not an exhaustive list:
|
||||
- major versions, such as: `8`, `11`, `16`, `17`, `21`, `25`
|
||||
- more specific versions: `8.0.282+8`, `8.0.232`, `11.0`, `11.0.4`, `17.0`
|
||||
- multi-field Java versions (JEP 322), such as: `11.0.9.1`, `18.0.1.1`
|
||||
- early access (EA) versions: `15-ea`, `15.0.0-ea`
|
||||
- the `latest` alias, which floats to the newest available stable (GA) release
|
||||
|
||||
> [!NOTE]
|
||||
> - `latest` always resolves the newest version from the distribution's remote metadata (it behaves like `check-latest: true`), so it ignores any older version already present in the runner tool cache. This has the same performance trade-off described in [Check latest](#check-latest).
|
||||
> - `latest` is only supported through the `java-version` input, not through `java-version-file`, and it resolves stable (GA) releases only — it cannot be combined with `-ea`.
|
||||
> - The `jdkfile` distribution does not support `latest`, as it installs from a local file.
|
||||
> - For `oracle` and `graalvm` (Oracle GraalVM), `latest` uses the Adoptium API only to determine the newest GA **major version number** — the JDK binary itself is still downloaded from the Oracle / GraalVM servers for that major. Because these distributions have no endpoint to list their own releases, if their servers haven't published the resolved major yet, the action fails and asks you to specify a concrete version. Note the Oracle JDK license caveat below still applies to a floating `latest`.
|
||||
> - For `graalvm-community`, `latest` floats to the newest GA release published on GitHub, so it never depends on the Adoptium API and always resolves to the newest major that GraalVM Community actually ships.
|
||||
|
||||
#### Supported distributions
|
||||
Currently, the following distributions are supported:
|
||||
@@ -115,6 +134,7 @@ Currently, the following distributions are supported:
|
||||
| `adopt` or `adopt-hotspot` | [AdoptOpenJDK Hotspot](https://adoptopenjdk.net/) | [`adopt-hotspot` license](https://adoptopenjdk.net/about.html) |
|
||||
| `adopt-openj9` | [AdoptOpenJDK OpenJ9](https://adoptopenjdk.net/) | [`adopt-openj9` license](https://adoptopenjdk.net/about.html) |
|
||||
| `liberica` | [Liberica JDK](https://bell-sw.com/) | [`liberica` license](https://bell-sw.com/liberica_eula/) |
|
||||
| `liberica-nik` | [Liberica Native Image Kit](https://bell-sw.com/pages/downloads/native-image-kit/) | [`liberica-nik` license](https://bell-sw.com/liberica_nik_eula/) |
|
||||
| `microsoft` | [Microsoft Build of OpenJDK](https://www.microsoft.com/openjdk) | [`microsoft` license](https://docs.microsoft.com/java/openjdk/faq)
|
||||
| `corretto` | [Amazon Corretto Build of OpenJDK](https://aws.amazon.com/corretto/) | [`corretto` license](https://aws.amazon.com/corretto/faqs/)
|
||||
| `semeru` | [IBM Semeru Runtime Open Edition](https://developer.ibm.com/languages/java/semeru-runtimes/downloads/) | [`semeru` license](https://openjdk.java.net/legal/gplv2+ce.html) |
|
||||
@@ -153,7 +173,7 @@ The workflow output `cache-primary-key` exposes the primary cache key computed b
|
||||
|
||||
The cache input is optional, and caching is turned off by default.
|
||||
|
||||
**Maven Wrapper:** when `cache: 'maven'` is enabled, the action also caches and restores the Maven Wrapper distribution downloaded to `~/.m2/wrapper/dists` (in addition to the local repository), so wrapper-based (`./mvnw`) builds don't re-download the wrapper on every run. This is keyed on `**/.mvn/wrapper/maven-wrapper.properties` as shown above.
|
||||
**Maven Wrapper:** when `cache: 'maven'` is enabled, the action also caches and restores the Maven Wrapper distribution downloaded to `~/.m2/wrapper/dists` (in addition to the local repository), so wrapper-based (`./mvnw`) builds don't re-download the Maven distribution. The wrapper distribution is stored in a **separate** cache entry keyed only on `**/.mvn/wrapper/maven-wrapper.properties`, so it stays cached across the frequent `pom.xml` changes that rotate the main dependency cache key.
|
||||
|
||||
#### Caching gradle dependencies
|
||||
```yaml
|
||||
@@ -171,6 +191,8 @@ steps:
|
||||
```
|
||||
Using the `cache: gradle` provides a simple and effective way to cache Gradle dependencies with minimal configuration.
|
||||
|
||||
**Gradle Wrapper:** when `cache: 'gradle'` is enabled, the action also caches and restores the Gradle Wrapper distribution downloaded to `~/.gradle/wrapper` (in addition to the Gradle caches), so wrapper-based (`./gradlew`) builds don't re-download the Gradle distribution. The wrapper distribution is stored in a **separate** cache entry keyed only on `**/gradle-wrapper.properties`, so it stays cached across the frequent `*.gradle*` changes that rotate the main dependency cache key.
|
||||
|
||||
For projects that require more advanced `Gradle` caching features, such as caching build outputs, support for Gradle configuration cache, encrypted cache storage, fine-grained cache control (including options to enable or disable the cache, set it to read-only or write-only, perform automated cleanup, and define custom cache rules), or optimized performance for complex CI workflows, consider using [`gradle/actions/setup-gradle`](https://github.com/gradle/actions/tree/main/setup-gradle).
|
||||
|
||||
For setup details and a comprehensive overview of all available features, visit the [setup-gradle documentation](https://github.com/gradle/actions/blob/main/docs/setup-gradle.md).
|
||||
@@ -189,6 +211,13 @@ steps:
|
||||
run: mvn -B package --file pom.xml
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> Maven resolves plugin dependencies lazily, so a cache created by a "thin" goal
|
||||
> (e.g. `mvn compile`) can be missing plugin dependencies that later
|
||||
> `test`/`verify`/`package` jobs then re-download on every run. See
|
||||
> [Ensuring the Maven cache is complete](docs/advanced-usage.md#ensuring-the-maven-cache-is-complete-plugin-dependencies)
|
||||
> for how to seed a complete cache.
|
||||
|
||||
#### Caching sbt dependencies
|
||||
```yaml
|
||||
steps:
|
||||
@@ -285,6 +314,7 @@ In the example above multiple JDKs are installed for the same job. The result af
|
||||
- [Adopt](docs/advanced-usage.md#Adopt)
|
||||
- [Zulu](docs/advanced-usage.md#Zulu)
|
||||
- [Liberica](docs/advanced-usage.md#Liberica)
|
||||
- [Liberica Native Image Kit](docs/advanced-usage.md#Liberica-Native-Image-Kit)
|
||||
- [Microsoft](docs/advanced-usage.md#Microsoft)
|
||||
- [Amazon Corretto](docs/advanced-usage.md#Amazon-Corretto)
|
||||
- [Oracle](docs/advanced-usage.md#Oracle)
|
||||
@@ -299,6 +329,7 @@ In the example above multiple JDKs are installed for the same job. The result af
|
||||
- [Testing against different Java distributions](docs/advanced-usage.md#Testing-against-different-Java-distributions)
|
||||
- [Testing against different platforms](docs/advanced-usage.md#Testing-against-different-platforms)
|
||||
- [Publishing using Apache Maven](docs/advanced-usage.md#Publishing-using-Apache-Maven)
|
||||
- [Maven transfer progress (download logs)](docs/advanced-usage.md#maven-transfer-progress-download-logs)
|
||||
- [Publishing using Gradle](docs/advanced-usage.md#Publishing-using-Gradle)
|
||||
- [Hosted Tool Cache](docs/advanced-usage.md#Hosted-Tool-Cache)
|
||||
- [Modifying Maven Toolchains](docs/advanced-usage.md#Modifying-Maven-Toolchains)
|
||||
|
||||
+33
-2
@@ -228,9 +228,40 @@ describe('auth tests', () => {
|
||||
<username>\${env.${username}}</username>
|
||||
<password>\${env.&<>"''"><&}</password>
|
||||
</server>
|
||||
</servers>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>setup-java-gpg</id>
|
||||
<properties>
|
||||
<gpg.passphraseEnvName>${gpgPassphrase}</gpg.passphraseEnvName>
|
||||
</properties>
|
||||
</profile>
|
||||
</profiles>
|
||||
<activeProfiles>
|
||||
<activeProfile>setup-java-gpg</activeProfile>
|
||||
</activeProfiles>
|
||||
</settings>`;
|
||||
|
||||
expect(auth.generate(id, username, password, gpgPassphrase)).toEqual(
|
||||
expectedSettings
|
||||
);
|
||||
});
|
||||
|
||||
it('does not add a gpg profile when the passphrase env var is the maven-gpg-plugin default', () => {
|
||||
const id = 'packages';
|
||||
const username = 'USER';
|
||||
const password = '&<>"\'\'"><&';
|
||||
const gpgPassphrase = 'MAVEN_GPG_PASSPHRASE';
|
||||
|
||||
const expectedSettings = `<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">
|
||||
<interactiveMode>false</interactiveMode>
|
||||
<servers>
|
||||
<server>
|
||||
<id>gpg.passphrase</id>
|
||||
<passphrase>\${env.${gpgPassphrase}}</passphrase>
|
||||
<id>${id}</id>
|
||||
<username>\${env.${username}}</username>
|
||||
<password>\${env.&<>"''"><&}</password>
|
||||
</server>
|
||||
</servers>
|
||||
</settings>`;
|
||||
|
||||
+196
-12
@@ -166,10 +166,7 @@ describe('dependency cache', () => {
|
||||
|
||||
await restore('maven', '');
|
||||
expect(spyCacheRestore).toHaveBeenCalledWith(
|
||||
[
|
||||
join(os.homedir(), '.m2', 'repository'),
|
||||
join(os.homedir(), '.m2', 'wrapper', 'dists')
|
||||
],
|
||||
[join(os.homedir(), '.m2', 'repository')],
|
||||
expect.any(String)
|
||||
);
|
||||
expect(spyGlobHashFiles).toHaveBeenCalledWith(
|
||||
@@ -196,10 +193,7 @@ describe('dependency cache', () => {
|
||||
|
||||
await restore('maven', '');
|
||||
expect(spyCacheRestore).toHaveBeenCalledWith(
|
||||
[
|
||||
join(os.homedir(), '.m2', 'repository'),
|
||||
join(os.homedir(), '.m2', 'wrapper', 'dists')
|
||||
],
|
||||
[join(os.homedir(), '.m2', 'repository')],
|
||||
expect.any(String)
|
||||
);
|
||||
expect(spyGlobHashFiles).toHaveBeenCalledWith(
|
||||
@@ -214,10 +208,7 @@ describe('dependency cache', () => {
|
||||
|
||||
await restore('maven', '');
|
||||
expect(spyCacheRestore).toHaveBeenCalledWith(
|
||||
[
|
||||
join(os.homedir(), '.m2', 'repository'),
|
||||
join(os.homedir(), '.m2', 'wrapper', 'dists')
|
||||
],
|
||||
[join(os.homedir(), '.m2', 'repository')],
|
||||
expect.any(String)
|
||||
);
|
||||
expect(spyGlobHashFiles).toHaveBeenCalledWith(
|
||||
@@ -226,6 +217,47 @@ describe('dependency cache', () => {
|
||||
expect(spyWarning).not.toHaveBeenCalled();
|
||||
expect(spyInfo).toHaveBeenCalledWith('maven cache is not found');
|
||||
});
|
||||
it('restores the maven wrapper distribution cache independently of the main cache', async () => {
|
||||
createDirectory(join(workspace, '.mvn'));
|
||||
createDirectory(join(workspace, '.mvn', 'wrapper'));
|
||||
createFile(
|
||||
join(workspace, '.mvn', 'wrapper', 'maven-wrapper.properties')
|
||||
);
|
||||
|
||||
await restore('maven', '');
|
||||
// Main dependency cache no longer carries the wrapper dists path.
|
||||
expect(spyCacheRestore).toHaveBeenCalledWith(
|
||||
[join(os.homedir(), '.m2', 'repository')],
|
||||
expect.any(String)
|
||||
);
|
||||
expect(spyCacheRestore).toHaveBeenCalledWith(
|
||||
[join(os.homedir(), '.m2', 'wrapper', 'dists')],
|
||||
expect.stringContaining('maven-wrapper')
|
||||
);
|
||||
expect(spyGlobHashFiles).toHaveBeenCalledWith(
|
||||
'**/.mvn/wrapper/maven-wrapper.properties'
|
||||
);
|
||||
});
|
||||
it('skips the maven wrapper cache when no wrapper properties exist', async () => {
|
||||
createFile(join(workspace, 'pom.xml'));
|
||||
spyGlobHashFiles.mockImplementation((pattern: string) =>
|
||||
Promise.resolve(
|
||||
pattern === '**/.mvn/wrapper/maven-wrapper.properties'
|
||||
? ''
|
||||
: 'hash-stub'
|
||||
)
|
||||
);
|
||||
|
||||
await restore('maven', '');
|
||||
// Only the main dependency cache is restored; the wrapper cache path is
|
||||
// never touched because the project does not use mvnw.
|
||||
expect(spyCacheRestore).toHaveBeenCalledTimes(1);
|
||||
expect(spyCacheRestore).toHaveBeenCalledWith(
|
||||
[join(os.homedir(), '.m2', 'repository')],
|
||||
expect.any(String)
|
||||
);
|
||||
expect(spyWarning).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
describe('for gradle', () => {
|
||||
it('throws error if no build.gradle found', async () => {
|
||||
@@ -282,6 +314,43 @@ describe('dependency cache', () => {
|
||||
expect(spyWarning).not.toHaveBeenCalled();
|
||||
expect(spyInfo).toHaveBeenCalledWith('gradle cache is not found');
|
||||
});
|
||||
it('restores the gradle wrapper distribution cache independently of the main cache', async () => {
|
||||
createFile(join(workspace, 'build.gradle'));
|
||||
|
||||
await restore('gradle', '');
|
||||
// Main dependency cache no longer carries the wrapper path.
|
||||
expect(spyCacheRestore).toHaveBeenCalledWith(
|
||||
[join(os.homedir(), '.gradle', 'caches')],
|
||||
expect.any(String)
|
||||
);
|
||||
// Wrapper distribution is restored on its own, keyed only on the
|
||||
// wrapper properties file.
|
||||
expect(spyCacheRestore).toHaveBeenCalledWith(
|
||||
[join(os.homedir(), '.gradle', 'wrapper')],
|
||||
expect.stringContaining('setup-java-')
|
||||
);
|
||||
expect(spyGlobHashFiles).toHaveBeenCalledWith(
|
||||
'**/gradle-wrapper.properties'
|
||||
);
|
||||
});
|
||||
it('skips the gradle wrapper cache when no wrapper properties exist', async () => {
|
||||
createFile(join(workspace, 'build.gradle'));
|
||||
spyGlobHashFiles.mockImplementation((pattern: string) =>
|
||||
Promise.resolve(
|
||||
pattern === '**/gradle-wrapper.properties' ? '' : 'hash-stub'
|
||||
)
|
||||
);
|
||||
|
||||
await restore('gradle', '');
|
||||
// Only the main dependency cache is restored; the wrapper cache path is
|
||||
// never touched because the project does not use the gradle wrapper.
|
||||
expect(spyCacheRestore).toHaveBeenCalledTimes(1);
|
||||
expect(spyCacheRestore).toHaveBeenCalledWith(
|
||||
[join(os.homedir(), '.gradle', 'caches')],
|
||||
expect.any(String)
|
||||
);
|
||||
expect(spyWarning).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
describe('for sbt', () => {
|
||||
it('throws error if no build.sbt found', async () => {
|
||||
@@ -457,6 +526,77 @@ describe('dependency cache', () => {
|
||||
expect.stringMatching(/^Cache saved with the key:.*/)
|
||||
);
|
||||
});
|
||||
it('saves the maven wrapper distribution cache under its own key', async () => {
|
||||
createFile(join(workspace, 'pom.xml'));
|
||||
(core.getState as jest.Mock<any>).mockImplementation((name: any) => {
|
||||
switch (name) {
|
||||
case 'cache-primary-key':
|
||||
return 'setup-java-cache-primary-key';
|
||||
case 'cache-matched-key':
|
||||
return 'setup-java-cache-matched-key';
|
||||
case 'cache-primary-key-maven-wrapper':
|
||||
return 'setup-java-maven-wrapper-key';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
});
|
||||
|
||||
await save('maven');
|
||||
expect(spyCacheSave).toHaveBeenCalledWith(
|
||||
[join(os.homedir(), '.m2', 'wrapper', 'dists')],
|
||||
'setup-java-maven-wrapper-key'
|
||||
);
|
||||
expect(spyWarning).not.toHaveBeenCalled();
|
||||
});
|
||||
it('does not save the maven wrapper cache on an exact wrapper hit', async () => {
|
||||
createFile(join(workspace, 'pom.xml'));
|
||||
(core.getState as jest.Mock<any>).mockImplementation((name: any) => {
|
||||
switch (name) {
|
||||
case 'cache-primary-key':
|
||||
return 'setup-java-cache-primary-key';
|
||||
case 'cache-matched-key':
|
||||
return 'setup-java-cache-matched-key';
|
||||
case 'cache-primary-key-maven-wrapper':
|
||||
case 'cache-matched-key-maven-wrapper':
|
||||
return 'setup-java-maven-wrapper-key';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
});
|
||||
|
||||
await save('maven');
|
||||
expect(spyCacheSave).not.toHaveBeenCalledWith(
|
||||
[join(os.homedir(), '.m2', 'wrapper', 'dists')],
|
||||
expect.any(String)
|
||||
);
|
||||
});
|
||||
it('does not fail the post step when the wrapper distribution path is missing', async () => {
|
||||
createFile(join(workspace, 'pom.xml'));
|
||||
(core.getState as jest.Mock<any>).mockImplementation((name: any) => {
|
||||
switch (name) {
|
||||
case 'cache-primary-key':
|
||||
return 'setup-java-cache-primary-key';
|
||||
case 'cache-matched-key':
|
||||
return 'setup-java-cache-matched-key';
|
||||
case 'cache-primary-key-maven-wrapper':
|
||||
return 'setup-java-maven-wrapper-key';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
});
|
||||
spyCacheSave.mockImplementation((paths: string[]) =>
|
||||
paths.includes(join(os.homedir(), '.m2', 'wrapper', 'dists'))
|
||||
? Promise.reject(
|
||||
new cache.ValidationError(
|
||||
'Path Validation Error: Path(s) specified in the action for caching do(es) not exist'
|
||||
)
|
||||
)
|
||||
: Promise.resolve(0)
|
||||
);
|
||||
|
||||
await expect(save('maven')).resolves.toBeUndefined();
|
||||
expect(spyWarning).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
describe('for gradle', () => {
|
||||
it('uploads cache even if no build.gradle found', async () => {
|
||||
@@ -509,6 +649,50 @@ describe('dependency cache', () => {
|
||||
expect.stringMatching(/^Cache saved with the key:.*/)
|
||||
);
|
||||
});
|
||||
it('saves the gradle wrapper distribution cache under its own key', async () => {
|
||||
createFile(join(workspace, 'build.gradle'));
|
||||
(core.getState as jest.Mock<any>).mockImplementation((name: any) => {
|
||||
switch (name) {
|
||||
case 'cache-primary-key':
|
||||
return 'setup-java-cache-primary-key';
|
||||
case 'cache-matched-key':
|
||||
return 'setup-java-cache-matched-key';
|
||||
case 'cache-primary-key-gradle-wrapper':
|
||||
return 'setup-java-gradle-wrapper-key';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
});
|
||||
|
||||
await save('gradle');
|
||||
expect(spyCacheSave).toHaveBeenCalledWith(
|
||||
[join(os.homedir(), '.gradle', 'wrapper')],
|
||||
'setup-java-gradle-wrapper-key'
|
||||
);
|
||||
expect(spyWarning).not.toHaveBeenCalled();
|
||||
});
|
||||
it('does not save the gradle wrapper cache on an exact wrapper hit', async () => {
|
||||
createFile(join(workspace, 'build.gradle'));
|
||||
(core.getState as jest.Mock<any>).mockImplementation((name: any) => {
|
||||
switch (name) {
|
||||
case 'cache-primary-key':
|
||||
return 'setup-java-cache-primary-key';
|
||||
case 'cache-matched-key':
|
||||
return 'setup-java-cache-matched-key';
|
||||
case 'cache-primary-key-gradle-wrapper':
|
||||
case 'cache-matched-key-gradle-wrapper':
|
||||
return 'setup-java-gradle-wrapper-key';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
});
|
||||
|
||||
await save('gradle');
|
||||
expect(spyCacheSave).not.toHaveBeenCalledWith(
|
||||
[join(os.homedir(), '.gradle', 'wrapper')],
|
||||
expect.any(String)
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('for sbt', () => {
|
||||
it('uploads cache even if no build.sbt found', async () => {
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
target/
|
||||
pom.xml.tag
|
||||
pom.xml.releaseBackup
|
||||
pom.xml.versionsBackup
|
||||
pom.xml.next
|
||||
release.properties
|
||||
dependency-reduced-pom.xml
|
||||
buildNumber.properties
|
||||
.mvn/timing.properties
|
||||
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
|
||||
.mvn/wrapper/maven-wrapper.jar
|
||||
Vendored
+15
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>io.github.actions</groupId>
|
||||
<artifactId>setup-java-maven2-example</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.12.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1 @@
|
||||
target/
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
ThisBuild / scalaVersion := "2.12.15"
|
||||
|
||||
libraryDependencies += "org.scala-lang.modules" %% "scala-parser-combinators" % "2.1.1"
|
||||
Executable
+39
@@ -0,0 +1,39 @@
|
||||
#!/bin/sh
|
||||
# Assert whether a directory exists, for use in the e2e cache workflows.
|
||||
#
|
||||
# Usage: check-dir.sh <dir> [present|absent]
|
||||
#
|
||||
# present (default): fail if <dir> does NOT exist, otherwise list its contents.
|
||||
# absent: fail if <dir> DOES exist.
|
||||
#
|
||||
# Call with already-expanded paths (e.g. "$HOME/.gradle/caches") to avoid
|
||||
# tilde-expansion pitfalls.
|
||||
set -eu
|
||||
|
||||
if [ "$#" -lt 1 ]; then
|
||||
echo "Usage: check-dir.sh <dir> [present|absent]" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
dir=$1
|
||||
mode=${2:-present}
|
||||
|
||||
case "$mode" in
|
||||
present)
|
||||
if [ ! -d "$dir" ]; then
|
||||
echo "::error::The $dir directory does not exist unexpectedly"
|
||||
exit 1
|
||||
fi
|
||||
ls "$dir"
|
||||
;;
|
||||
absent)
|
||||
if [ -d "$dir" ]; then
|
||||
echo "::error::The $dir directory exists unexpectedly"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "::error::Unknown mode '$mode' (expected 'present' or 'absent')"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@@ -158,5 +158,45 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"25": [
|
||||
{
|
||||
"version": "25.0.3",
|
||||
"jdkVersion": "25.0.3",
|
||||
"latest": true,
|
||||
"baseUrl": "https://github.com/Tencent/TencentKona-25/releases/download/TencentKona-25.0.3/",
|
||||
"files": [
|
||||
{
|
||||
"os": "linux",
|
||||
"arch": "aarch64",
|
||||
"filename": "TencentKona-25.0.3.b1-jdk_linux-aarch64.tar.gz",
|
||||
"checksum": "2fb77e3ba9c00045ca497ea22210f18dae4bf7df4c87029f5abadd42a5daf8c7"
|
||||
},
|
||||
{
|
||||
"os": "linux",
|
||||
"arch": "x86_64",
|
||||
"filename": "TencentKona-25.0.3.b1-jdk_linux-x86_64.tar.gz",
|
||||
"checksum": "47445e6fad020e834055a705bb48fa3cd0727a2c57ad6f1c5206a45f4efb2d67"
|
||||
},
|
||||
{
|
||||
"os": "macos",
|
||||
"arch": "aarch64",
|
||||
"filename": "TencentKona-25.0.3.b1_jdk_macosx-aarch64_notarized.tar.gz",
|
||||
"checksum": "e29405eff95da412ed7ecc890e6ef5ebbfcd9ab334005b3d32d1700bbe4204d2"
|
||||
},
|
||||
{
|
||||
"os": "macos",
|
||||
"arch": "x86_64",
|
||||
"filename": "TencentKona-25.0.3.b1_jdk_macosx-x86_64_notarized.tar.gz",
|
||||
"checksum": "d512db5c079db16bd3a9c86d9cb979808994e90e4de29e17d27e5219fe488659"
|
||||
},
|
||||
{
|
||||
"os": "windows",
|
||||
"arch": "x86_64",
|
||||
"filename": "TencentKona-25.0.3.b1_jdk_windows-x86_64_signed.zip",
|
||||
"checksum": "865bce92ccbbca75115076e618a98baa1d0f30fcccdce954c0a22bee33d6ae83"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,739 @@
|
||||
[
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/25.0.1+3-25.0.1+16/bellsoft-liberica-vm-openjdk25.0.1+16-25.0.1+3-linux-amd64.tar.gz",
|
||||
"version": "25.0.1+3",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "25.0.1+16",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/24.1.0+1-23+38/bellsoft-liberica-vm-openjdk23+38-24.1.0+1-linux-amd64.tar.gz",
|
||||
"version": "24.1.0+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "23+38",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://download.bell-sw.com/vm/21.3.2/bellsoft-liberica-vm-openjdk11.0.15.1+2-21.3.2+2-linux-amd64.tar.gz",
|
||||
"version": "21.3.2+2",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "11.0.15.1+2",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://download.bell-sw.com/vm/22.3.0/bellsoft-liberica-vm-openjdk17.0.5+8-22.3.0+2-linux-amd64.tar.gz",
|
||||
"version": "22.3.0+2",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "17.0.5+8",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.0.9+1-17.0.16+13/bellsoft-liberica-vm-openjdk17.0.16+13-23.0.9+1-linux-amd64.tar.gz",
|
||||
"version": "23.0.9+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "17.0.16+13",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://download.bell-sw.com/vm/23.0.0/bellsoft-liberica-vm-openjdk17.0.7+7-23.0.0+1-src.tar.gz",
|
||||
"version": "23.0.0+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "17.0.7+7",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/25.0.2+1-25.0.2+13/bellsoft-liberica-vm-openjdk25.0.2+13-25.0.2+1-linux-amd64.tar.gz",
|
||||
"version": "25.0.2+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "25.0.2+13",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/24.1.1+1-23.0.1+13/bellsoft-liberica-vm-openjdk23.0.1+13-24.1.1+1-linux-amd64.tar.gz",
|
||||
"version": "24.1.1+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "23.0.1+13",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.0.12+1-17.0.19+12/bellsoft-liberica-vm-openjdk17.0.19+12-23.0.12+1-linux-amd64.tar.gz",
|
||||
"version": "23.0.12+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "17.0.19+12",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.0.3+1-17.0.10+13/bellsoft-liberica-vm-openjdk17.0.10+13-23.0.3+1-linux-amd64.tar.gz",
|
||||
"version": "23.0.3+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "17.0.10+13",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://download.bell-sw.com/vm/21.3.2/bellsoft-liberica-vm-openjdk11-21.3.2-src.tar.gz",
|
||||
"version": "21.3.2+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "11.0.15+10",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://download.bell-sw.com/vm/22.3.3/bellsoft-liberica-vm-openjdk11.0.20+8-22.3.3+1-src.tar.gz",
|
||||
"version": "22.3.3+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "11.0.20+8",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.0.8+1-17.0.15+10/bellsoft-liberica-vm-openjdk17.0.15+10-23.0.8+1-linux-amd64.tar.gz",
|
||||
"version": "23.0.8+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "17.0.15+10",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://download.bell-sw.com/vm/21.3.3/bellsoft-liberica-vm-openjdk17.0.4-21.3.3-src.tar.gz",
|
||||
"version": "21.3.3+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "17.0.4+8",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.1.7+1-21.0.7+9/bellsoft-liberica-vm-openjdk21.0.7+9-23.1.7+1-linux-amd64.tar.gz",
|
||||
"version": "23.1.7+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "21.0.7+9",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.1.8+1-21.0.8+13/bellsoft-liberica-vm-openjdk21.0.8+13-23.1.8+1-linux-amd64.tar.gz",
|
||||
"version": "23.1.8+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "21.0.8+13",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://download.bell-sw.com/vm/21.0.0.2/bellsoft-liberica-vm-openjdk11-21.0.0.2-src.tar.gz",
|
||||
"version": "21.0.0.2",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "11.0.10+9",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://download.bell-sw.com/vm/23.0.1/bellsoft-liberica-vm-openjdk17.0.8+7-23.0.1+1-linux-amd64.tar.gz",
|
||||
"version": "23.0.1+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "17.0.8+7",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/24.0.0+1-22+37/bellsoft-liberica-vm-openjdk22+37-24.0.0+1-linux-amd64.tar.gz",
|
||||
"version": "24.0.0+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "22+37",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://download.bell-sw.com/vm/22.1.0/bellsoft-liberica-vm-openjdk17-22.1.0-src.tar.gz",
|
||||
"version": "22.1.0+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "17.0.3+7",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/24.0.2+1-22.0.2+11/bellsoft-liberica-vm-openjdk22.0.2+11-24.0.2+1-linux-amd64.tar.gz",
|
||||
"version": "24.0.2+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "22.0.2+11",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://download.bell-sw.com/vm/23.0.1/bellsoft-liberica-vm-openjdk20.0.2+10-23.0.1+1-src.tar.gz",
|
||||
"version": "23.0.1+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "20.0.2+10",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://download.bell-sw.com/vm/23.1.0/bellsoft-liberica-vm-openjdk21+37-23.1.0+1-linux-amd64.tar.gz",
|
||||
"version": "23.1.0+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "21+37",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.1.4+3-21.0.4+9/bellsoft-liberica-vm-openjdk21.0.4+9-23.1.4+3-linux-amd64.tar.gz",
|
||||
"version": "23.1.4+3",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "21.0.4+9",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://download.bell-sw.com/vm/22.3.3/bellsoft-liberica-vm-openjdk11.0.20.1+1-22.3.3+2-linux-amd64.tar.gz",
|
||||
"version": "22.3.3+2",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "11.0.20.1+1",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.0.4+1-17.0.11+10/bellsoft-liberica-vm-openjdk17.0.11+10-23.0.4+1-linux-amd64.tar.gz",
|
||||
"version": "23.0.4+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "17.0.11+10",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/24.1.2+1-23.0.2+9/bellsoft-liberica-vm-openjdk23.0.2+9-24.1.2+1-linux-amd64.tar.gz",
|
||||
"version": "24.1.2+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "23.0.2+9",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.0.10+1-17.0.17+12/bellsoft-liberica-vm-openjdk17.0.17+12-23.0.10+1-linux-amd64.tar.gz",
|
||||
"version": "23.0.10+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "17.0.17+12",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://download.bell-sw.com/vm/22.3.1/bellsoft-liberica-vm-openjdk11.0.18+10-22.3.1+1-src.tar.gz",
|
||||
"version": "22.3.1+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "11.0.18+10",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://download.bell-sw.com/vm/22.0.0.2/bellsoft-liberica-vm-openjdk17-22.0.0.2-src.tar.gz",
|
||||
"version": "22.0.0.2",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "17.0.2+9",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://download.bell-sw.com/vm/22.0.0.2/bellsoft-liberica-vm-openjdk11-22.0.0.2-linux-amd64.tar.gz",
|
||||
"version": "22.0.0.2",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "11.0.14.1+1",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/25.0.1+2-25.0.1+14/bellsoft-liberica-vm-openjdk25.0.1+14-25.0.1+2-linux-amd64.tar.gz",
|
||||
"version": "25.0.1+2",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "25.0.1+14",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://download.bell-sw.com/vm/21.3.3/bellsoft-liberica-vm-openjdk11.0.16-21.3.3-src.tar.gz",
|
||||
"version": "21.3.3+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "11.0.16+8",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.1.5+1-21.0.5+11/bellsoft-liberica-vm-openjdk21.0.5+11-23.1.5+1-linux-amd64.tar.gz",
|
||||
"version": "23.1.5+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "21.0.5+11",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://download.bell-sw.com/vm/22.3.4/bellsoft-liberica-vm-openjdk17.0.9+11-22.3.4+1-linux-amd64.tar.gz",
|
||||
"version": "22.3.4+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "17.0.9+11",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/25.0.0+1-25+37/bellsoft-liberica-vm-openjdk25+37-25.0.0+1-linux-amd64.tar.gz",
|
||||
"version": "25.0.0+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "25+37",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://download.bell-sw.com/vm/22.3.3/bellsoft-liberica-vm-openjdk17.0.8.1+1-22.3.3+2-linux-amd64.tar.gz",
|
||||
"version": "22.3.3+2",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "17.0.8.1+1",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.1.3+1-21.0.3+10/bellsoft-liberica-vm-openjdk21.0.3+10-23.1.3+1-linux-amd64.tar.gz",
|
||||
"version": "23.1.3+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "21.0.3+10",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/24.2.0+1-24+37/bellsoft-liberica-vm-openjdk24+37-24.2.0+1-linux-amd64.tar.gz",
|
||||
"version": "24.2.0+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "24+37",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://download.bell-sw.com/vm/23.1.1/bellsoft-liberica-vm-openjdk21.0.1+12-23.1.1+1-linux-amd64.tar.gz",
|
||||
"version": "23.1.1+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "21.0.1+12",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://download.bell-sw.com/vm/21.3.3/bellsoft-liberica-vm-openjdk17.0.4.1-21.3.3-src.tar.gz",
|
||||
"version": "21.3.3+2",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "17.0.4.1+1",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.1.11+2-21.0.11+12/bellsoft-liberica-vm-openjdk21.0.11+12-23.1.11+2-linux-amd64.tar.gz",
|
||||
"version": "23.1.11+2",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "21.0.11+12",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://download.bell-sw.com/vm/22.3.2/bellsoft-liberica-vm-openjdk11.0.19+7-22.3.2+1-src.tar.gz",
|
||||
"version": "22.3.2+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "11.0.19+7",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://download.bell-sw.com/vm/22.3.4/bellsoft-liberica-vm-openjdk11.0.21+10-22.3.4+1-src.tar.gz",
|
||||
"version": "22.3.4+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "11.0.21+10",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/25.0.3+2-25.0.3+12/bellsoft-liberica-vm-openjdk25.0.3+12-25.0.3+2-linux-amd64.tar.gz",
|
||||
"version": "25.0.3+2",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "25.0.3+12",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://download.bell-sw.com/vm/21.3.2/bellsoft-liberica-vm-openjdk17.0.3.1+2-21.3.2+2-linux-amd64.tar.gz",
|
||||
"version": "21.3.2+2",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "17.0.3.1+2",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/24.2.1+1-24.0.1+11/bellsoft-liberica-vm-openjdk24.0.1+11-24.2.1+1-linux-amd64.tar.gz",
|
||||
"version": "24.2.1+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "24.0.1+11",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://download.bell-sw.com/vm/22.2.0/bellsoft-liberica-vm-openjdk11.0.16.1+1-22.2.0+3-linux-amd64.tar.gz",
|
||||
"version": "22.2.0+3",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "11.0.16.1+1",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.0.6+1-17.0.13+12/bellsoft-liberica-vm-openjdk17.0.13+12-23.0.6+1-linux-amd64.tar.gz",
|
||||
"version": "23.0.6+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "17.0.13+12",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://download.bell-sw.com/vm/23.0.0/bellsoft-liberica-vm-openjdk20.0.1+10-23.0.0+1-linux-amd64.tar.gz",
|
||||
"version": "23.0.0+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "20.0.1+10",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.1.10+1-21.0.10+11/bellsoft-liberica-vm-openjdk21.0.10+11-23.1.10+1-linux-amd64.tar.gz",
|
||||
"version": "23.1.10+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "21.0.10+11",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://download.bell-sw.com/vm/22.3.1/bellsoft-liberica-vm-openjdk17.0.6+10-22.3.1+1-src.tar.gz",
|
||||
"version": "22.3.1+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "17.0.6+10",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://download.bell-sw.com/vm/21.3.0/bellsoft-liberica-vm-openjdk17-21.3.0-src.tar.gz",
|
||||
"version": "21.3.0",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "17.0.1+12",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://download.bell-sw.com/vm/21.3.0/bellsoft-liberica-vm-openjdk11-21.3.0-src.tar.gz",
|
||||
"version": "21.3.0",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "11.0.13+8",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/24.0.1+1-22.0.1+10/bellsoft-liberica-vm-openjdk22.0.1+10-24.0.1+1-linux-amd64.tar.gz",
|
||||
"version": "24.0.1+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "22.0.1+10",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.0.7+1-17.0.14+10/bellsoft-liberica-vm-openjdk17.0.14+10-23.0.7+1-linux-amd64.tar.gz",
|
||||
"version": "23.0.7+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "17.0.14+10",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://download.bell-sw.com/vm/21.1.0/bellsoft-liberica-vm-openjdk11-21.1.0-src.tar.gz",
|
||||
"version": "21.1.0",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "11.0.11+9",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.1.6+1-21.0.6+10/bellsoft-liberica-vm-openjdk21.0.6+10-23.1.6+1-linux-amd64.tar.gz",
|
||||
"version": "23.1.6+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "21.0.6+10",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/25.0.1+1-25.0.1+12/bellsoft-liberica-vm-openjdk25.0.1+12-25.0.1+1-linux-amd64.tar.gz",
|
||||
"version": "25.0.1+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "25.0.1+12",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.1.9+1-21.0.9+12/bellsoft-liberica-vm-openjdk21.0.9+12-23.1.9+1-linux-amd64.tar.gz",
|
||||
"version": "23.1.9+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "21.0.9+12",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/22.3.5+1-11.0.22+12/bellsoft-liberica-vm-openjdk11.0.22+12-22.3.5+1-linux-amd64.tar.gz",
|
||||
"version": "22.3.5+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "11.0.22+12",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.0.5+1-17.0.12+10/bellsoft-liberica-vm-openjdk17.0.12+10-23.0.5+1-linux-amd64.tar.gz",
|
||||
"version": "23.0.5+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "17.0.12+10",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://download.bell-sw.com/vm/21.3.3.1/bellsoft-liberica-vm-openjdk11.0.17+7-21.3.3.1+1-linux-amd64.tar.gz",
|
||||
"version": "21.3.3.1+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "11.0.17+7",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://download.bell-sw.com/vm/21.2.0/bellsoft-liberica-vm-openjdk11-21.2.0-linux-amd64.tar.gz",
|
||||
"version": "21.2.0",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "11.0.12+7",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.0.11+1-17.0.18+11/bellsoft-liberica-vm-openjdk17.0.18+11-23.0.11+1-linux-amd64.tar.gz",
|
||||
"version": "23.0.11+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "17.0.18+11",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/23.1.2+1-21.0.2+14/bellsoft-liberica-vm-openjdk21.0.2+14-23.1.2+1-linux-amd64.tar.gz",
|
||||
"version": "23.1.2+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "21.0.2+14",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"downloadUrl": "https://github.com/bell-sw/LibericaNIK/releases/download/24.2.2+1-24.0.2+13/bellsoft-liberica-vm-openjdk24.0.2+13-24.2.2+1-linux-amd64.tar.gz",
|
||||
"version": "24.2.2+1",
|
||||
"components": [
|
||||
{
|
||||
"component": "liberica",
|
||||
"version": "24.0.2+13",
|
||||
"embedded": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -420,6 +420,29 @@ describe('setupJava', () => {
|
||||
expect(spyCoreInfo).not.toHaveBeenCalledWith('Trying to download...');
|
||||
});
|
||||
|
||||
it('should resolve the latest version from remote when java-version is "latest", even if a version is cached', async () => {
|
||||
mockJavaBase = new EmptyJavaBase({
|
||||
version: 'latest',
|
||||
architecture: 'x86',
|
||||
packageType: 'jdk',
|
||||
checkLatest: false
|
||||
});
|
||||
|
||||
await expect(mockJavaBase.setupJava()).resolves.toEqual({
|
||||
version: actualJavaVersion,
|
||||
path: javaPathInstalled
|
||||
});
|
||||
|
||||
// `latest` must bypass the tool-cache short-circuit and always resolve remotely
|
||||
expect(spyCoreInfo).toHaveBeenCalledWith(
|
||||
'Trying to resolve the latest version from remote'
|
||||
);
|
||||
expect(spyCoreInfo).toHaveBeenCalledWith('Trying to download...');
|
||||
expect(spyCoreInfo).not.toHaveBeenCalledWith(
|
||||
`Resolved Java ${installedJavaVersion} from tool-cache`
|
||||
);
|
||||
});
|
||||
|
||||
it.each([
|
||||
[
|
||||
{
|
||||
@@ -744,11 +767,18 @@ describe('normalizeVersion', () => {
|
||||
const DummyJavaBase = JavaBase as any;
|
||||
|
||||
it.each([
|
||||
['11', {version: '11', stable: true}],
|
||||
['11.0', {version: '11.0', stable: true}],
|
||||
['11.0.10', {version: '11.0.10', stable: true}],
|
||||
['11-ea', {version: '11', stable: false}],
|
||||
['11.0.2-ea', {version: '11.0.2', stable: false}]
|
||||
['11', {version: '11', stable: true, latest: false}],
|
||||
['11.0', {version: '11.0', stable: true, latest: false}],
|
||||
['11.0.10', {version: '11.0.10', stable: true, latest: false}],
|
||||
['11-ea', {version: '11', stable: false, latest: false}],
|
||||
['11.0.2-ea', {version: '11.0.2', stable: false, latest: false}],
|
||||
['18.0.1.1', {version: '18.0.1+1', stable: true, latest: false}],
|
||||
['11.0.9.1', {version: '11.0.9+1', stable: true, latest: false}],
|
||||
['12.0.2.1.0', {version: '12.0.2+1.0', stable: true, latest: false}],
|
||||
['18.0.1.1-ea', {version: '18.0.1+1', stable: false, latest: false}],
|
||||
['latest', {version: 'x', stable: true, latest: true}],
|
||||
['LATEST', {version: 'x', stable: true, latest: true}],
|
||||
[' Latest ', {version: 'x', stable: true, latest: true}]
|
||||
])('normalizeVersion from %s to %s', (input, expected) => {
|
||||
expect(DummyJavaBase.prototype.normalizeVersion.call(null, input)).toEqual(
|
||||
expected
|
||||
@@ -763,6 +793,17 @@ describe('normalizeVersion', () => {
|
||||
`The string '${version}' is not valid SemVer notation for a Java version. Please check README file for code snippets and more detailed information`
|
||||
);
|
||||
});
|
||||
|
||||
it.each(['latest-ea', 'latest.1', 'LATEST-EA', ' latest-ea '])(
|
||||
'normalizeVersion should throw a targeted error for latest combined with a qualifier (%s)',
|
||||
version => {
|
||||
expect(
|
||||
DummyJavaBase.prototype.normalizeVersion.bind(null, version)
|
||||
).toThrow(
|
||||
`The 'latest' alias resolves stable (GA) releases only and cannot be combined with '-ea' or other qualifiers (received '${version}'). Use 'latest' on its own, or specify a concrete version.`
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe('createVersionNotFoundError', () => {
|
||||
|
||||
@@ -204,6 +204,24 @@ describe('getAvailableVersions', () => {
|
||||
expect(availableVersion.url).toBe(expectedLink);
|
||||
});
|
||||
|
||||
it('with latest resolves to the newest available major version', async () => {
|
||||
const distribution = new CorrettoDistribution({
|
||||
version: 'latest',
|
||||
architecture: 'x64',
|
||||
packageType: 'jdk',
|
||||
checkLatest: false
|
||||
});
|
||||
mockPlatform(distribution, 'linux');
|
||||
|
||||
const availableVersion =
|
||||
await distribution['findPackageForDownload']('x');
|
||||
expect(availableVersion).not.toBeNull();
|
||||
// 18 is the newest major present in the mocked Corretto index
|
||||
expect(availableVersion.url).toBe(
|
||||
'https://corretto.aws/downloads/resources/18.0.0.37.1/amazon-corretto-18.0.0.37.1-linux-x64.tar.gz'
|
||||
);
|
||||
});
|
||||
|
||||
it('with unstable version expect to throw not supported error', async () => {
|
||||
const version = '18.0.1-ea';
|
||||
const distribution = new CorrettoDistribution({
|
||||
|
||||
@@ -417,6 +417,61 @@ describe('GraalVMDistribution', () => {
|
||||
);
|
||||
});
|
||||
|
||||
describe('latest alias', () => {
|
||||
it('resolves the newest major version from the Adoptium API', async () => {
|
||||
const latestDistribution = new GraalVMDistribution({
|
||||
...defaultOptions,
|
||||
version: 'latest'
|
||||
});
|
||||
(latestDistribution as any).http = mockHttpClient;
|
||||
jest
|
||||
.spyOn(latestDistribution, 'getPlatform')
|
||||
.mockReturnValue('linux');
|
||||
mockHttpClient.getJson.mockResolvedValue({
|
||||
statusCode: 200,
|
||||
result: {most_recent_feature_release: 25},
|
||||
headers: {}
|
||||
});
|
||||
mockHttpClient.head.mockResolvedValue({
|
||||
message: {statusCode: 200}
|
||||
});
|
||||
|
||||
const result = await (
|
||||
latestDistribution as any
|
||||
).findPackageForDownload('x');
|
||||
|
||||
expect(result).toEqual({
|
||||
url: 'https://download.oracle.com/graalvm/25/latest/graalvm-jdk-25_linux-x64_bin.tar.gz',
|
||||
version: '25'
|
||||
});
|
||||
});
|
||||
|
||||
it('throws an actionable error when the latest major is not yet available', async () => {
|
||||
const latestDistribution = new GraalVMDistribution({
|
||||
...defaultOptions,
|
||||
version: 'latest'
|
||||
});
|
||||
(latestDistribution as any).http = mockHttpClient;
|
||||
jest
|
||||
.spyOn(latestDistribution, 'getPlatform')
|
||||
.mockReturnValue('linux');
|
||||
mockHttpClient.getJson.mockResolvedValue({
|
||||
statusCode: 200,
|
||||
result: {most_recent_feature_release: 25},
|
||||
headers: {}
|
||||
});
|
||||
mockHttpClient.head.mockResolvedValue({
|
||||
message: {statusCode: 404}
|
||||
});
|
||||
|
||||
await expect(
|
||||
(latestDistribution as any).findPackageForDownload('x')
|
||||
).rejects.toThrow(
|
||||
/is not yet available for the GraalVM distribution/
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw error for JDK versions less than 17', async () => {
|
||||
await expect(
|
||||
(distribution as any).findPackageForDownload('11')
|
||||
@@ -1115,6 +1170,60 @@ describe('GraalVMDistribution', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('resolves latest to the newest GA across all Community majors without calling Adoptium', async () => {
|
||||
const latestCommunity = new GraalVMCommunityDistribution({
|
||||
...defaultOptions,
|
||||
version: 'latest'
|
||||
});
|
||||
(latestCommunity as any).http = mockHttpClient;
|
||||
jest.spyOn(latestCommunity, 'getPlatform').mockReturnValue('linux');
|
||||
|
||||
mockHttpClient.getJson.mockResolvedValue({
|
||||
result: [
|
||||
{
|
||||
draft: false,
|
||||
prerelease: false,
|
||||
assets: [
|
||||
{
|
||||
name: 'graalvm-community-jdk-21.0.2_linux-x64_bin.tar.gz',
|
||||
browser_download_url:
|
||||
'https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-21.0.2/graalvm-community-jdk-21.0.2_linux-x64_bin.tar.gz'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
draft: false,
|
||||
prerelease: false,
|
||||
assets: [
|
||||
{
|
||||
name: 'graalvm-community-jdk-24.0.1_linux-x64_bin.tar.gz',
|
||||
browser_download_url:
|
||||
'https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-24.0.1/graalvm-community-jdk-24.0.1_linux-x64_bin.tar.gz'
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
statusCode: 200,
|
||||
headers: {}
|
||||
});
|
||||
|
||||
const result = await (latestCommunity as any).findPackageForDownload(
|
||||
'x'
|
||||
);
|
||||
|
||||
expect(result).toEqual({
|
||||
url: 'https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-24.0.1/graalvm-community-jdk-24.0.1_linux-x64_bin.tar.gz',
|
||||
version: '24.0.1'
|
||||
});
|
||||
// The Community release list is authoritative, so the Adoptium
|
||||
// most_recent_feature_release endpoint must not be consulted.
|
||||
expect(mockHttpClient.getJson).toHaveBeenCalledTimes(1);
|
||||
expect(mockHttpClient.getJson).toHaveBeenCalledWith(
|
||||
expect.stringContaining('graalvm-ce-builds/releases'),
|
||||
expect.anything()
|
||||
);
|
||||
});
|
||||
|
||||
it('should reject GraalVM Community early access requests', async () => {
|
||||
(communityDistribution as any).stable = false;
|
||||
|
||||
|
||||
@@ -28,7 +28,9 @@ describe('Check getAvailableReleases', () => {
|
||||
['11', 'linux', 'x86_64', 'linux-x86_64'],
|
||||
['11.0.25', 'macos', 'aarch64', 'macosx-aarch64'],
|
||||
['17.0.13', 'windows', 'x86_64', 'windows-x86_64'],
|
||||
['21.0.5', 'linux', 'x86_64', 'linux-x86_64']
|
||||
['21.0.5', 'linux', 'x86_64', 'linux-x86_64'],
|
||||
['25', 'linux', 'aarch64', 'linux-aarch64'],
|
||||
['25.0.3', 'macos', 'x86_64', 'macosx-x86_64']
|
||||
])(
|
||||
'should get releases with the specified version "%s", OS "%s" and arch "%s"',
|
||||
async (
|
||||
@@ -41,7 +43,7 @@ describe('Check getAvailableReleases', () => {
|
||||
|
||||
const releases = await distribution['getAvailableReleases']();
|
||||
expect(releases).not.toBeNull();
|
||||
expect(releases.length).toBe(4);
|
||||
expect(releases.length).toBe(5);
|
||||
releases.forEach(release =>
|
||||
expect(release.downloadUrl).toContain(expectedPattern)
|
||||
);
|
||||
@@ -173,6 +175,37 @@ describe('Check findPackageForDownload', () => {
|
||||
'windows',
|
||||
'x86_64',
|
||||
'https://github.com/Tencent/TencentKona-21/releases/download/TencentKona-21.0.5/TencentKona-21.0.5.b1_jdk_windows-x86_64_signed.zip'
|
||||
],
|
||||
|
||||
[
|
||||
'25',
|
||||
'linux',
|
||||
'aarch64',
|
||||
'https://github.com/Tencent/TencentKona-25/releases/download/TencentKona-25.0.3/TencentKona-25.0.3.b1-jdk_linux-aarch64.tar.gz'
|
||||
],
|
||||
[
|
||||
'25.0.3',
|
||||
'linux',
|
||||
'x86_64',
|
||||
'https://github.com/Tencent/TencentKona-25/releases/download/TencentKona-25.0.3/TencentKona-25.0.3.b1-jdk_linux-x86_64.tar.gz'
|
||||
],
|
||||
[
|
||||
'25.0.3',
|
||||
'macos',
|
||||
'aarch64',
|
||||
'https://github.com/Tencent/TencentKona-25/releases/download/TencentKona-25.0.3/TencentKona-25.0.3.b1_jdk_macosx-aarch64_notarized.tar.gz'
|
||||
],
|
||||
[
|
||||
'25.0.3',
|
||||
'macos',
|
||||
'x86_64',
|
||||
'https://github.com/Tencent/TencentKona-25/releases/download/TencentKona-25.0.3/TencentKona-25.0.3.b1_jdk_macosx-x86_64_notarized.tar.gz'
|
||||
],
|
||||
[
|
||||
'25.0.3',
|
||||
'windows',
|
||||
'x86_64',
|
||||
'https://github.com/Tencent/TencentKona-25/releases/download/TencentKona-25.0.3/TencentKona-25.0.3.b1_jdk_windows-x86_64_signed.zip'
|
||||
]
|
||||
])(
|
||||
'should return the download URL with the specified version "%s", OS "%s" and arch "%s"',
|
||||
|
||||
@@ -0,0 +1,219 @@
|
||||
import {jest, describe, it, expect, beforeEach, afterEach} from '@jest/globals';
|
||||
import type {
|
||||
ArchitectureOptions,
|
||||
NikVersion
|
||||
} from '../../src/distributions/liberica-nik/models.js';
|
||||
import {HttpClient} from '@actions/http-client';
|
||||
|
||||
import manifestData from '../data/liberica-nik.json' with {type: 'json'};
|
||||
|
||||
// Mock @actions/core before importing source modules that depend on it
|
||||
jest.unstable_mockModule('@actions/core', () => ({
|
||||
info: jest.fn(),
|
||||
warning: jest.fn(),
|
||||
debug: jest.fn(),
|
||||
error: jest.fn(),
|
||||
notice: jest.fn(),
|
||||
setFailed: jest.fn(),
|
||||
setOutput: jest.fn(),
|
||||
getInput: jest.fn(),
|
||||
getBooleanInput: jest.fn(),
|
||||
getMultilineInput: jest.fn(),
|
||||
addPath: jest.fn(),
|
||||
exportVariable: jest.fn(),
|
||||
saveState: jest.fn(),
|
||||
getState: jest.fn(),
|
||||
setSecret: jest.fn(),
|
||||
isDebug: jest.fn(() => false),
|
||||
startGroup: jest.fn(),
|
||||
endGroup: jest.fn(),
|
||||
group: jest.fn((_name: string, fn: () => Promise<unknown>) => fn()),
|
||||
toPlatformPath: jest.fn((p: string) => p),
|
||||
toWin32Path: jest.fn((p: string) => p),
|
||||
toPosixPath: jest.fn((p: string) => p)
|
||||
}));
|
||||
|
||||
// Dynamic imports after mocking
|
||||
const {LibericaNikDistributions} =
|
||||
await import('../../src/distributions/liberica-nik/installer.js');
|
||||
|
||||
const ADDITIONAL_PARAMS =
|
||||
'&installation-type=archive&fields=downloadUrl%2Cversion%2Ccomponents%2Ccomponent%2Cembedded';
|
||||
|
||||
describe('getAvailableVersions', () => {
|
||||
let spyHttpClient: any;
|
||||
|
||||
beforeEach(() => {
|
||||
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
|
||||
spyHttpClient.mockReturnValue({
|
||||
statusCode: 200,
|
||||
headers: {},
|
||||
result: manifestData as NikVersion[]
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
jest.clearAllMocks();
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
it.each([
|
||||
[
|
||||
{version: '21', architecture: 'x64', packageType: 'jdk'},
|
||||
'bundle-type=standard&bitness=64&arch=x86&build-type=all'
|
||||
],
|
||||
[
|
||||
{version: '21-ea', architecture: 'x64', packageType: 'jdk'},
|
||||
'bundle-type=standard&bitness=64&arch=x86&build-type=ea'
|
||||
],
|
||||
[
|
||||
{version: '21', architecture: 'aarch64', packageType: 'jdk'},
|
||||
'bundle-type=standard&bitness=64&arch=arm&build-type=all'
|
||||
],
|
||||
[
|
||||
{version: '21', architecture: 'x64', packageType: 'jdk+fx'},
|
||||
'bundle-type=full&bitness=64&arch=x86&build-type=all'
|
||||
]
|
||||
])('build correct url for %s -> %s', async (input, urlParams) => {
|
||||
const distribution = new LibericaNikDistributions({
|
||||
...input,
|
||||
checkLatest: false
|
||||
});
|
||||
distribution['getPlatformOption'] = () => 'linux';
|
||||
const buildUrl = `https://api.bell-sw.com/v1/nik/releases?os=linux&${urlParams}${ADDITIONAL_PARAMS}`;
|
||||
|
||||
await distribution['getAvailableVersions']();
|
||||
|
||||
expect(spyHttpClient.mock.calls).toHaveLength(1);
|
||||
expect(spyHttpClient.mock.calls[0][0]).toBe(buildUrl);
|
||||
});
|
||||
|
||||
it('load available versions', async () => {
|
||||
const distribution = new LibericaNikDistributions({
|
||||
version: '21',
|
||||
architecture: 'x64',
|
||||
packageType: 'jdk',
|
||||
checkLatest: false
|
||||
});
|
||||
const availableVersions = await distribution['getAvailableVersions']();
|
||||
expect(availableVersions).toEqual(manifestData);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getArchitectureOptions', () => {
|
||||
it.each([
|
||||
['x64', {bitness: '64', arch: 'x86'}],
|
||||
['aarch64', {bitness: '64', arch: 'arm'}]
|
||||
] as [string, ArchitectureOptions][])(
|
||||
'parse architecture %s -> %s',
|
||||
(input, expected) => {
|
||||
const distributions = new LibericaNikDistributions({
|
||||
architecture: input,
|
||||
checkLatest: false,
|
||||
packageType: 'jdk',
|
||||
version: '21'
|
||||
});
|
||||
|
||||
expect(distributions['getArchitectureOptions']()).toEqual(expected);
|
||||
}
|
||||
);
|
||||
|
||||
it.each(['x86', 'armv7', 's390x'])('not support architecture %s', input => {
|
||||
const distributions = new LibericaNikDistributions({
|
||||
architecture: input,
|
||||
checkLatest: false,
|
||||
packageType: 'jdk',
|
||||
version: '21'
|
||||
});
|
||||
|
||||
expect(() => distributions['getArchitectureOptions']()).toThrow(
|
||||
/Architecture '\w+' is not supported\. Supported architectures: .*/
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('findPackageForDownload', () => {
|
||||
let distribution: InstanceType<typeof LibericaNikDistributions>;
|
||||
|
||||
beforeEach(() => {
|
||||
distribution = new LibericaNikDistributions({
|
||||
version: '',
|
||||
architecture: 'x64',
|
||||
packageType: 'jdk',
|
||||
checkLatest: false
|
||||
});
|
||||
distribution['getAvailableVersions'] = async () => manifestData;
|
||||
});
|
||||
|
||||
// The user's java-version resolves against the embedded JDK version, not
|
||||
// NIK's own GraalVM version.
|
||||
it.each([
|
||||
['21', '21.0.11+12'],
|
||||
['17', '17.0.19+12'],
|
||||
['25', '25.0.3+12'],
|
||||
['11', '11.0.22+12'],
|
||||
['21.0.2', '21.0.2+14'],
|
||||
['23', '23.0.2+9'],
|
||||
['20.x', '20.0.2+10'],
|
||||
['25.0.1', '25.0.1+16']
|
||||
])('version is %s -> %s', async (input, expected) => {
|
||||
const result = await distribution['findPackageForDownload'](input);
|
||||
expect(result.version).toBe(expected);
|
||||
});
|
||||
|
||||
it('should throw an error', async () => {
|
||||
await expect(distribution['findPackageForDownload']('7')).rejects.toThrow(
|
||||
/No matching version found for SemVer/
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getPlatformOption', () => {
|
||||
const distributions = new LibericaNikDistributions({
|
||||
architecture: 'x64',
|
||||
version: '21',
|
||||
packageType: 'jdk',
|
||||
checkLatest: false
|
||||
});
|
||||
|
||||
it.each([
|
||||
['linux', 'linux'],
|
||||
['darwin', 'macos'],
|
||||
['win32', 'windows'],
|
||||
['cygwin', 'windows']
|
||||
])('os version %s -> %s', (input, expected) => {
|
||||
const actual = distributions['getPlatformOption'](input as NodeJS.Platform);
|
||||
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
|
||||
it.each(['sunos', 'aix', 'android', 'freebsd'])(
|
||||
'not support os version %s',
|
||||
input => {
|
||||
expect(() =>
|
||||
distributions['getPlatformOption'](input as NodeJS.Platform)
|
||||
).toThrow(/Platform '\w+' is not supported\. Supported platforms: .+/);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe('convertVersionToSemver', () => {
|
||||
const distributions = new LibericaNikDistributions({
|
||||
architecture: 'x64',
|
||||
version: '21',
|
||||
packageType: 'jdk',
|
||||
checkLatest: false
|
||||
});
|
||||
|
||||
it.each([
|
||||
['25.0.1+16', '25.0.1+16'],
|
||||
['21+37', '21.0.0+37'],
|
||||
['23+38', '23.0.0+38'],
|
||||
['11.0.15.1+2', '11.0.15+1.2'],
|
||||
['17.0.5', '17.0.5']
|
||||
])('%s -> %s', (input, expected) => {
|
||||
const actual = distributions['convertVersionToSemver'](input);
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
});
|
||||
@@ -170,6 +170,20 @@ describe('setupJava', () => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('throws for the latest alias since jdkfile has no version list', async () => {
|
||||
const inputs = {
|
||||
version: 'latest',
|
||||
architecture: 'x86',
|
||||
packageType: 'jdk',
|
||||
checkLatest: false
|
||||
};
|
||||
|
||||
mockJavaBase = new LocalDistribution(inputs, expectedJdkFile);
|
||||
await expect(mockJavaBase.setupJava()).rejects.toThrow(
|
||||
"The 'latest' version alias is not supported for the 'jdkfile' distribution. Please specify a concrete version."
|
||||
);
|
||||
});
|
||||
|
||||
it('java is resolved from toolcache, jdkfile is untouched', async () => {
|
||||
const inputs = {
|
||||
version: actualJavaVersion,
|
||||
|
||||
@@ -174,3 +174,59 @@ describe('findPackageForDownload', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('findPackageForDownload with latest', () => {
|
||||
let spyHttpClientHead: any;
|
||||
let spyHttpClientGetJson: any;
|
||||
|
||||
beforeEach(() => {
|
||||
(core.debug as jest.Mock).mockImplementation(() => {});
|
||||
(core.error as jest.Mock).mockImplementation(() => {});
|
||||
spyHttpClientGetJson = jest.spyOn(HttpClient.prototype, 'getJson');
|
||||
spyHttpClientGetJson.mockResolvedValue({
|
||||
statusCode: 200,
|
||||
result: {most_recent_feature_release: 25},
|
||||
headers: {}
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('resolves the newest major version from the Adoptium API', async () => {
|
||||
spyHttpClientHead = jest.spyOn(HttpClient.prototype, 'head');
|
||||
spyHttpClientHead.mockResolvedValue({message: {statusCode: 200}});
|
||||
|
||||
const distribution = new OracleDistribution({
|
||||
version: 'latest',
|
||||
architecture: 'x64',
|
||||
packageType: 'jdk',
|
||||
checkLatest: false
|
||||
});
|
||||
|
||||
const result = await distribution['findPackageForDownload']('x');
|
||||
const osType = distribution.getPlatform();
|
||||
const archiveType = getDownloadArchiveExtension();
|
||||
|
||||
expect(result.version).toBe('25');
|
||||
expect(result.url).toBe(
|
||||
`https://download.oracle.com/java/25/latest/jdk-25_${osType}-x64_bin.${archiveType}`
|
||||
);
|
||||
});
|
||||
|
||||
it('throws an actionable error when the latest major is not yet available', async () => {
|
||||
spyHttpClientHead = jest.spyOn(HttpClient.prototype, 'head');
|
||||
spyHttpClientHead.mockResolvedValue({message: {statusCode: 404}});
|
||||
|
||||
const distribution = new OracleDistribution({
|
||||
version: 'latest',
|
||||
architecture: 'x64',
|
||||
packageType: 'jdk',
|
||||
checkLatest: false
|
||||
});
|
||||
|
||||
await expect(distribution['findPackageForDownload']('x')).rejects.toThrow(
|
||||
/is not yet available for the Oracle JDK distribution/
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -312,6 +312,24 @@ describe('findPackageForDownload', () => {
|
||||
expect(resolvedVersion.signatureUrl).toBeDefined();
|
||||
});
|
||||
|
||||
it('version "latest" is normalized to the newest available version', async () => {
|
||||
const distribution = new TemurinDistribution(
|
||||
{
|
||||
version: 'latest',
|
||||
architecture: 'x64',
|
||||
packageType: 'jdk',
|
||||
checkLatest: false
|
||||
},
|
||||
TemurinImplementation.Hotspot
|
||||
);
|
||||
distribution['getAvailableVersions'] = async () => manifestData as any;
|
||||
// normalizeVersion turns `latest` into the wildcard carried on `this.version`
|
||||
const resolvedVersion = await distribution['findPackageForDownload'](
|
||||
distribution['version']
|
||||
);
|
||||
expect(resolvedVersion.version).toBe('16.0.2+7');
|
||||
});
|
||||
|
||||
it('version is found but binaries list is empty', async () => {
|
||||
const distribution = new TemurinDistribution(
|
||||
{
|
||||
|
||||
@@ -86,8 +86,7 @@ describe('toolchains tests', () => {
|
||||
|
||||
await toolchains.createToolchainsSettings({
|
||||
jdkInfo,
|
||||
settingsDirectory: altHome,
|
||||
overwriteSettings: true
|
||||
settingsDirectory: altHome
|
||||
});
|
||||
|
||||
expect(fs.existsSync(m2Dir)).toBe(false);
|
||||
@@ -135,8 +134,7 @@ describe('toolchains tests', () => {
|
||||
|
||||
await toolchains.createToolchainsSettings({
|
||||
jdkInfo,
|
||||
settingsDirectory: m2Dir,
|
||||
overwriteSettings: true
|
||||
settingsDirectory: m2Dir
|
||||
});
|
||||
|
||||
expect(fs.existsSync(m2Dir)).toBe(true);
|
||||
@@ -217,8 +215,7 @@ describe('toolchains tests', () => {
|
||||
|
||||
await toolchains.createToolchainsSettings({
|
||||
jdkInfo,
|
||||
settingsDirectory: m2Dir,
|
||||
overwriteSettings: true
|
||||
settingsDirectory: m2Dir
|
||||
});
|
||||
|
||||
expect(fs.existsSync(m2Dir)).toBe(true);
|
||||
@@ -303,8 +300,7 @@ describe('toolchains tests', () => {
|
||||
|
||||
await toolchains.createToolchainsSettings({
|
||||
jdkInfo,
|
||||
settingsDirectory: m2Dir,
|
||||
overwriteSettings: true
|
||||
settingsDirectory: m2Dir
|
||||
});
|
||||
|
||||
expect(fs.existsSync(m2Dir)).toBe(true);
|
||||
@@ -381,8 +377,7 @@ describe('toolchains tests', () => {
|
||||
|
||||
await toolchains.createToolchainsSettings({
|
||||
jdkInfo,
|
||||
settingsDirectory: m2Dir,
|
||||
overwriteSettings: true
|
||||
settingsDirectory: m2Dir
|
||||
});
|
||||
|
||||
expect(fs.existsSync(m2Dir)).toBe(true);
|
||||
@@ -452,8 +447,7 @@ describe('toolchains tests', () => {
|
||||
|
||||
await toolchains.createToolchainsSettings({
|
||||
jdkInfo,
|
||||
settingsDirectory: m2Dir,
|
||||
overwriteSettings: true
|
||||
settingsDirectory: m2Dir
|
||||
});
|
||||
|
||||
expect(fs.existsSync(m2Dir)).toBe(true);
|
||||
@@ -545,8 +539,7 @@ describe('toolchains tests', () => {
|
||||
|
||||
await toolchains.createToolchainsSettings({
|
||||
jdkInfo,
|
||||
settingsDirectory: m2Dir,
|
||||
overwriteSettings: true
|
||||
settingsDirectory: m2Dir
|
||||
});
|
||||
|
||||
expect(fs.existsSync(m2Dir)).toBe(true);
|
||||
@@ -605,8 +598,7 @@ describe('toolchains tests', () => {
|
||||
|
||||
await toolchains.createToolchainsSettings({
|
||||
jdkInfo,
|
||||
settingsDirectory: m2Dir,
|
||||
overwriteSettings: true
|
||||
settingsDirectory: m2Dir
|
||||
});
|
||||
|
||||
expect(fs.existsSync(m2Dir)).toBe(true);
|
||||
@@ -664,8 +656,7 @@ describe('toolchains tests', () => {
|
||||
|
||||
await toolchains.createToolchainsSettings({
|
||||
jdkInfo,
|
||||
settingsDirectory: m2Dir,
|
||||
overwriteSettings: true
|
||||
settingsDirectory: m2Dir
|
||||
});
|
||||
|
||||
expect(fs.existsSync(m2Dir)).toBe(true);
|
||||
@@ -748,8 +739,7 @@ describe('toolchains tests', () => {
|
||||
|
||||
await toolchains.createToolchainsSettings({
|
||||
jdkInfo,
|
||||
settingsDirectory: m2Dir,
|
||||
overwriteSettings: true
|
||||
settingsDirectory: m2Dir
|
||||
});
|
||||
|
||||
expect(fs.existsSync(m2Dir)).toBe(true);
|
||||
@@ -828,8 +818,7 @@ describe('toolchains tests', () => {
|
||||
|
||||
await toolchains.createToolchainsSettings({
|
||||
jdkInfo,
|
||||
settingsDirectory: m2Dir,
|
||||
overwriteSettings: true
|
||||
settingsDirectory: m2Dir
|
||||
});
|
||||
|
||||
expect(fs.existsSync(m2Dir)).toBe(true);
|
||||
@@ -854,7 +843,7 @@ describe('toolchains tests', () => {
|
||||
).toEqual(result);
|
||||
}, 100000);
|
||||
|
||||
it('does not overwrite existing toolchains.xml files', async () => {
|
||||
it('extends existing toolchains.xml files instead of overwriting them', async () => {
|
||||
const jdkInfo = {
|
||||
version: '17',
|
||||
vendor: 'Eclipse Temurin',
|
||||
@@ -883,13 +872,20 @@ describe('toolchains tests', () => {
|
||||
|
||||
await toolchains.createToolchainsSettings({
|
||||
jdkInfo,
|
||||
settingsDirectory: m2Dir,
|
||||
overwriteSettings: false
|
||||
settingsDirectory: m2Dir
|
||||
});
|
||||
|
||||
expect(fs.existsSync(m2Dir)).toBe(true);
|
||||
expect(fs.existsSync(toolchainsFile)).toBe(true);
|
||||
expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(originalFile);
|
||||
|
||||
const updated = fs.readFileSync(toolchainsFile, 'utf-8');
|
||||
// The pre-existing (Sun 1.6) toolchain must be preserved ...
|
||||
expect(updated).toContain('<id>sun_1.6</id>');
|
||||
expect(updated).toContain('<jdkHome>/opt/jdk/sun/1.6</jdkHome>');
|
||||
// ... and the newly installed JDK must be appended.
|
||||
expect(updated).toContain('<id>temurin_17</id>');
|
||||
expect(updated).toContain('<vendor>Eclipse Temurin</vendor>');
|
||||
expect(updated).toContain(`<jdkHome>${jdkInfo.jdkHome}</jdkHome>`);
|
||||
}, 100000);
|
||||
|
||||
it('generates valid toolchains.xml with minimal configuration', () => {
|
||||
@@ -959,4 +955,55 @@ describe('toolchains tests', () => {
|
||||
)
|
||||
);
|
||||
}, 100000);
|
||||
|
||||
it('preserves toolchains from previous executions across multiple setup-java runs', async () => {
|
||||
// Regression test for https://github.com/actions/setup-java/issues/1099
|
||||
// Running setup-java several times in the same job (e.g. multiple steps / multiple
|
||||
// java-version entries) must accumulate every JDK in toolchains.xml rather
|
||||
// than replacing previously registered entries.
|
||||
(core.getInput as jest.Mock<any>).mockImplementation((name: string) => {
|
||||
if (name === 'settings-path') return m2Dir;
|
||||
return '';
|
||||
});
|
||||
|
||||
const runs = [
|
||||
{
|
||||
version: '8',
|
||||
distributionName: 'temurin',
|
||||
id: 'temurin_8',
|
||||
jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/8.0.1-12/x64'
|
||||
},
|
||||
{
|
||||
version: '11',
|
||||
distributionName: 'temurin',
|
||||
id: 'temurin_11',
|
||||
jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/11.0.1-12/x64'
|
||||
},
|
||||
{
|
||||
version: '17',
|
||||
distributionName: 'temurin',
|
||||
id: 'temurin_17',
|
||||
jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64'
|
||||
}
|
||||
];
|
||||
|
||||
for (const run of runs) {
|
||||
await toolchains.configureToolchains(
|
||||
run.version,
|
||||
run.distributionName,
|
||||
run.jdkHome,
|
||||
undefined
|
||||
);
|
||||
}
|
||||
|
||||
expect(fs.existsSync(toolchainsFile)).toBe(true);
|
||||
const contents = fs.readFileSync(toolchainsFile, 'utf-8');
|
||||
|
||||
for (const run of runs) {
|
||||
expect(contents).toContain(`<id>${run.id}</id>`);
|
||||
expect(contents).toContain(`<jdkHome>${run.jdkHome}</jdkHome>`);
|
||||
}
|
||||
// Exactly one <toolchain> entry per run – no duplicates, none dropped.
|
||||
expect((contents.match(/<toolchain>/g) || []).length).toBe(runs.length);
|
||||
}, 100000);
|
||||
});
|
||||
|
||||
+32
-1
@@ -56,7 +56,8 @@ const {
|
||||
isVersionSatisfies,
|
||||
isCacheFeatureAvailable,
|
||||
isGhes,
|
||||
validatePaginationUrl
|
||||
validatePaginationUrl,
|
||||
getLatestMajorVersion
|
||||
} = await import('../src/util.js');
|
||||
|
||||
describe('isVersionSatisfies', () => {
|
||||
@@ -400,3 +401,33 @@ describe('isGhes', () => {
|
||||
expect(isGhes()).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getLatestMajorVersion', () => {
|
||||
const makeHttp = (getJson: jest.Mock) =>
|
||||
({getJson}) as unknown as import('@actions/http-client').HttpClient;
|
||||
|
||||
it('returns most_recent_feature_release from the Adoptium API', async () => {
|
||||
const getJson = jest.fn(async () => ({
|
||||
statusCode: 200,
|
||||
result: {most_recent_feature_release: 25},
|
||||
headers: {}
|
||||
}));
|
||||
|
||||
await expect(getLatestMajorVersion(makeHttp(getJson))).resolves.toBe(25);
|
||||
expect(getJson).toHaveBeenCalledWith(
|
||||
'https://api.adoptium.net/v3/info/available_releases'
|
||||
);
|
||||
});
|
||||
|
||||
it('throws when the response does not contain a usable value', async () => {
|
||||
const getJson = jest.fn(async () => ({
|
||||
statusCode: 200,
|
||||
result: {},
|
||||
headers: {}
|
||||
}));
|
||||
|
||||
await expect(getLatestMajorVersion(makeHttp(getJson))).rejects.toThrow(
|
||||
'Could not determine the latest available Java major version'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ description: 'Set up a specific version of the Java JDK and add the
|
||||
author: 'GitHub'
|
||||
inputs:
|
||||
java-version:
|
||||
description: 'The Java version to set up. Takes a whole or semver Java version. See examples of supported syntax in README file'
|
||||
description: 'The Java version to set up. Takes a whole or semver Java version, or the "latest" alias to use the newest available stable release. See examples of supported syntax in README file'
|
||||
required: false
|
||||
java-version-file:
|
||||
description: 'The path to a file containing the Java version to set up (.java-version, .tool-versions, .sdkmanrc). Used when java-version is not set. See examples of supported syntax in README file'
|
||||
|
||||
Vendored
+257
-38
@@ -39023,7 +39023,7 @@ module.exports = { version: packageJson.version }
|
||||
/***/ 4012:
|
||||
/***/ ((module) => {
|
||||
|
||||
module.exports = /*#__PURE__*/JSON.parse('{"name":"@actions/cache","version":"6.1.0","description":"Actions cache lib","keywords":["github","actions","cache"],"homepage":"https://github.com/actions/toolkit/tree/main/packages/cache","license":"MIT","type":"module","main":"lib/cache.js","types":"lib/cache.d.ts","exports":{".":{"types":"./lib/cache.d.ts","import":"./lib/cache.js"}},"directories":{"lib":"lib","test":"__tests__"},"files":["lib","!.DS_Store"],"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/actions/toolkit.git","directory":"packages/cache"},"scripts":{"audit-moderate":"npm install && npm audit --json --audit-level=moderate > audit.json","test":"echo \\"Error: run tests from root\\" && exit 1","tsc":"tsc && cp src/internal/shared/package-version.cjs lib/internal/shared/"},"bugs":{"url":"https://github.com/actions/toolkit/issues"},"dependencies":{"@actions/core":"^3.0.1","@actions/exec":"^3.0.0","@actions/glob":"^0.6.1","@actions/http-client":"^4.0.1","@actions/io":"^3.0.2","@azure/core-rest-pipeline":"^1.23.0","@azure/storage-blob":"^12.31.0","@protobuf-ts/runtime-rpc":"^2.11.1","semver":"^7.7.4"},"devDependencies":{"@protobuf-ts/plugin":"^2.11.1","@types/node":"^25.6.0","@types/semver":"^7.7.1","typescript":"^5.9.3"},"overrides":{"uri-js":"npm:uri-js-replace@^1.0.1","node-fetch":"^3.3.2"}}');
|
||||
module.exports = /*#__PURE__*/JSON.parse('{"name":"@actions/cache","version":"6.2.0","description":"Actions cache lib","keywords":["github","actions","cache"],"homepage":"https://github.com/actions/toolkit/tree/main/packages/cache","license":"MIT","type":"module","main":"lib/cache.js","types":"lib/cache.d.ts","exports":{".":{"types":"./lib/cache.d.ts","import":"./lib/cache.js"}},"directories":{"lib":"lib","test":"__tests__"},"files":["lib","!.DS_Store"],"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/actions/toolkit.git","directory":"packages/cache"},"scripts":{"audit-moderate":"npm install && npm audit --json --audit-level=moderate > audit.json","test":"echo \\"Error: run tests from root\\" && exit 1","tsc":"tsc && cp src/internal/shared/package-version.cjs lib/internal/shared/"},"bugs":{"url":"https://github.com/actions/toolkit/issues"},"dependencies":{"@actions/core":"^3.0.1","@actions/exec":"^3.0.0","@actions/glob":"^0.6.1","@actions/http-client":"^4.0.1","@actions/io":"^3.0.2","@azure/core-rest-pipeline":"^1.23.0","@azure/storage-blob":"^12.31.0","@protobuf-ts/runtime-rpc":"^2.11.1","semver":"^7.7.4"},"devDependencies":{"@protobuf-ts/plugin":"^2.11.1","@types/node":"^25.6.0","@types/semver":"^7.7.1","typescript":"^5.9.3"},"overrides":{"uri-js":"npm:uri-js-replace@^1.0.1","node-fetch":"^3.3.2"}}');
|
||||
|
||||
/***/ })
|
||||
|
||||
@@ -44068,6 +44068,10 @@ const SystemTarPathOnWindows = `${process.env['SYSTEMDRIVE']}\\Windows\\System32
|
||||
const TarFilename = 'cache.tar';
|
||||
const ManifestFilename = 'manifest.txt';
|
||||
const CacheFileSizeLimit = 10 * Math.pow(1024, 3); // 10GiB per repository
|
||||
// Prefix the cache backend embeds in a read-denial message (v2 twirp
|
||||
// GetCacheEntryDownloadURL error or the GHES v1 `_apis/artifactcache` 403 body).
|
||||
// Shared so cache.ts and cacheHttpClient.ts match the same contract value.
|
||||
const constants_CacheReadDeniedMessagePrefix = 'cache read denied:';
|
||||
//# sourceMappingURL=constants.js.map
|
||||
;// CONCATENATED MODULE: ./node_modules/@actions/cache/lib/internal/cacheUtils.js
|
||||
var cacheUtils_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
@@ -93948,6 +93952,24 @@ function config_getCacheServiceVersion() {
|
||||
return 'v1';
|
||||
return process.env['ACTIONS_CACHE_SERVICE_V2'] ? 'v2' : 'v1';
|
||||
}
|
||||
// The cache-mode lattice: readable = {read, write}, writable = {write,
|
||||
// write-only}, none = neither.
|
||||
const KNOWN_CACHE_MODES = ['none', 'read', 'write', 'write-only'];
|
||||
// The effective cache-mode exported by the runner, or '' when not set.
|
||||
function config_getCacheMode() {
|
||||
return (process.env['ACTIONS_CACHE_MODE'] || '').trim().toLowerCase();
|
||||
}
|
||||
// Unset or unrecognized modes are permissive so behavior matches today.
|
||||
function config_isCacheReadable(mode) {
|
||||
if (!KNOWN_CACHE_MODES.includes(mode))
|
||||
return true;
|
||||
return mode === 'read' || mode === 'write';
|
||||
}
|
||||
function isCacheWritable(mode) {
|
||||
if (!KNOWN_CACHE_MODES.includes(mode))
|
||||
return true;
|
||||
return mode === 'write' || mode === 'write-only';
|
||||
}
|
||||
function getCacheServiceURL() {
|
||||
const version = config_getCacheServiceVersion();
|
||||
// Based on the version of the cache service, we will determine which
|
||||
@@ -93997,6 +94019,7 @@ var cacheHttpClient_awaiter = (undefined && undefined.__awaiter) || function (th
|
||||
|
||||
|
||||
|
||||
|
||||
function getCacheApiUrl(resource) {
|
||||
const baseUrl = getCacheServiceURL();
|
||||
if (!baseUrl) {
|
||||
@@ -94024,6 +94047,7 @@ function createHttpClient() {
|
||||
}
|
||||
function getCacheEntry(keys, paths, options) {
|
||||
return cacheHttpClient_awaiter(this, void 0, void 0, function* () {
|
||||
var _a;
|
||||
const httpClient = createHttpClient();
|
||||
const version = utils.getCacheVersion(paths, options === null || options === void 0 ? void 0 : options.compressionMethod, options === null || options === void 0 ? void 0 : options.enableCrossOsArchive);
|
||||
const resource = `cache?keys=${encodeURIComponent(keys.join(','))}&version=${version}`;
|
||||
@@ -94037,6 +94061,12 @@ function getCacheEntry(keys, paths, options) {
|
||||
return null;
|
||||
}
|
||||
if (!isSuccessStatusCode(response.statusCode)) {
|
||||
// Only surface the receiver's body for a `cache read denied:` policy denial
|
||||
// so callers can dispatch on it; keep the generic message otherwise.
|
||||
const errorMessage = (_a = response.error) === null || _a === void 0 ? void 0 : _a.message;
|
||||
if (errorMessage === null || errorMessage === void 0 ? void 0 : errorMessage.includes(CacheReadDeniedMessagePrefix)) {
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
throw new Error(`Cache service responded with ${response.statusCode}`);
|
||||
}
|
||||
const cacheResult = response.result;
|
||||
@@ -95297,6 +95327,7 @@ var cache_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _ar
|
||||
|
||||
|
||||
|
||||
|
||||
class ValidationError extends Error {
|
||||
constructor(message) {
|
||||
super(message);
|
||||
@@ -95312,19 +95343,20 @@ class ReserveCacheError extends Error {
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Stable prefix the receiver writes into the cache reservation response when
|
||||
* the issuer downgraded the cache token to read-only (for example, because
|
||||
* Stable prefix the cache service writes into the cache reservation response
|
||||
* when the issuer downgraded the cache token to read-only (for example, because
|
||||
* the run was triggered by an untrusted event). saveCacheV1 / saveCacheV2
|
||||
* dispatch on this prefix to re-classify the failure as a
|
||||
* CacheWriteDeniedError so consumers (and the outer catch arm) can
|
||||
* distinguish a policy denial from other reservation failures.
|
||||
* dispatch on this prefix to re-classify the failure as a CacheWriteDeniedError
|
||||
* so consumers and tests can distinguish a policy denial from other reservation
|
||||
* failures. Internally it is logged as a non-fatal warning like other
|
||||
* best-effort save failures.
|
||||
*/
|
||||
const CACHE_WRITE_DENIED_PREFIX = 'cache write denied:';
|
||||
/**
|
||||
* Raised when the cache backend refuses to reserve a writable cache entry
|
||||
* because the JWT issued for this run was scoped read-only (for example, the
|
||||
* run was triggered by an event the repository administrator classified as
|
||||
* untrusted). The receiver-supplied detail message always begins with
|
||||
* untrusted). The service-supplied detail message always begins with
|
||||
* `cache write denied:` (the full error message includes additional context
|
||||
* like the cache key).
|
||||
*
|
||||
@@ -95340,6 +95372,19 @@ class CacheWriteDeniedError extends ReserveCacheError {
|
||||
Object.setPrototypeOf(this, CacheWriteDeniedError.prototype);
|
||||
}
|
||||
}
|
||||
// Re-exported from constants so consumers keep referencing it here; the shared
|
||||
// value also drives detection in cacheHttpClient without duplicating the string.
|
||||
const CACHE_READ_DENIED_PREFIX = (/* unused pure expression or super */ null && (CacheReadDeniedMessagePrefix));
|
||||
// Raised when the cache backend denies a download URL because the run's token
|
||||
// has no readable cache scopes. Caching is best-effort, so restoreCache logs a
|
||||
// warning and reports a cache miss rather than rethrowing this.
|
||||
class CacheReadDeniedError extends Error {
|
||||
constructor(message) {
|
||||
super(message);
|
||||
this.name = 'CacheReadDeniedError';
|
||||
Object.setPrototypeOf(this, CacheReadDeniedError.prototype);
|
||||
}
|
||||
}
|
||||
class FinalizeCacheError extends Error {
|
||||
constructor(message) {
|
||||
super(message);
|
||||
@@ -95394,6 +95439,12 @@ function restoreCache(paths_1, primaryKey_1, restoreKeys_1, options_1) {
|
||||
const cacheServiceVersion = getCacheServiceVersion();
|
||||
core.debug(`Cache service version: ${cacheServiceVersion}`);
|
||||
checkPaths(paths);
|
||||
const cacheMode = getCacheMode();
|
||||
if (!isCacheReadable(cacheMode)) {
|
||||
core.info(`Cache restore skipped: the effective cache-mode '${cacheMode}' does not permit reads.`);
|
||||
core.debug(`Skipped restore for paths [${paths.join(', ')}] with primary key '${primaryKey}'.`);
|
||||
return undefined;
|
||||
}
|
||||
switch (cacheServiceVersion) {
|
||||
case 'v2':
|
||||
return yield restoreCacheV2(paths, primaryKey, restoreKeys, options, enableCrossOsArchive);
|
||||
@@ -95415,6 +95466,7 @@ function restoreCache(paths_1, primaryKey_1, restoreKeys_1, options_1) {
|
||||
*/
|
||||
function restoreCacheV1(paths_1, primaryKey_1, restoreKeys_1, options_1) {
|
||||
return cache_awaiter(this, arguments, void 0, function* (paths, primaryKey, restoreKeys, options, enableCrossOsArchive = false) {
|
||||
var _a;
|
||||
restoreKeys = restoreKeys || [];
|
||||
const keys = [primaryKey, ...restoreKeys];
|
||||
core.debug('Resolved Keys:');
|
||||
@@ -95429,10 +95481,26 @@ function restoreCacheV1(paths_1, primaryKey_1, restoreKeys_1, options_1) {
|
||||
let archivePath = '';
|
||||
try {
|
||||
// path are needed to compute version
|
||||
const cacheEntry = yield cacheHttpClient.getCacheEntry(keys, paths, {
|
||||
compressionMethod,
|
||||
enableCrossOsArchive
|
||||
});
|
||||
let cacheEntry;
|
||||
try {
|
||||
cacheEntry = yield cacheHttpClient.getCacheEntry(keys, paths, {
|
||||
compressionMethod,
|
||||
enableCrossOsArchive
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
// The v1 artifact cache service returns HTTP 403 with a
|
||||
// `cache read denied:` body when the run's token has no readable cache
|
||||
// scopes. getCacheEntry lives in a dependency-free internal module and
|
||||
// cannot import CacheReadDeniedError without a circular dependency, so it
|
||||
// only surfaces the raw denial message; we classify it into the typed
|
||||
// error here so the outer catch and consumers can dispatch on it.
|
||||
const errorMessage = (_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : '';
|
||||
if (errorMessage.includes(CACHE_READ_DENIED_PREFIX)) {
|
||||
throw new CacheReadDeniedError(errorMessage);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
if (!(cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.archiveLocation)) {
|
||||
// Cache not found
|
||||
return undefined;
|
||||
@@ -95461,7 +95529,9 @@ function restoreCacheV1(paths_1, primaryKey_1, restoreKeys_1, options_1) {
|
||||
}
|
||||
else {
|
||||
// warn on cache restore failure and continue build
|
||||
// Log server errors (5xx) as errors, all other errors as warnings
|
||||
// Log server errors (5xx) as errors, all other errors as warnings.
|
||||
// A read denied by policy (CacheReadDeniedError) is not an HttpClientError
|
||||
// so it falls here and is warned, treated as a cache miss.
|
||||
if (typedError instanceof HttpClientError &&
|
||||
typeof typedError.statusCode === 'number' &&
|
||||
typedError.statusCode >= 500) {
|
||||
@@ -95496,6 +95566,7 @@ function restoreCacheV1(paths_1, primaryKey_1, restoreKeys_1, options_1) {
|
||||
*/
|
||||
function restoreCacheV2(paths_1, primaryKey_1, restoreKeys_1, options_1) {
|
||||
return cache_awaiter(this, arguments, void 0, function* (paths, primaryKey, restoreKeys, options, enableCrossOsArchive = false) {
|
||||
var _a;
|
||||
// Override UploadOptions to force the use of Azure
|
||||
options = Object.assign(Object.assign({}, options), { useAzureSdk: true });
|
||||
restoreKeys = restoreKeys || [];
|
||||
@@ -95517,7 +95588,20 @@ function restoreCacheV2(paths_1, primaryKey_1, restoreKeys_1, options_1) {
|
||||
restoreKeys,
|
||||
version: utils.getCacheVersion(paths, compressionMethod, enableCrossOsArchive)
|
||||
};
|
||||
const response = yield twirpClient.GetCacheEntryDownloadURL(request);
|
||||
let response;
|
||||
try {
|
||||
response = yield twirpClient.GetCacheEntryDownloadURL(request);
|
||||
}
|
||||
catch (error) {
|
||||
// The receiver returns twirp PermissionDenied (403) when the run's token
|
||||
// has no readable cache scopes. The client wraps that 403, so the stable
|
||||
// prefix is embedded in the message rather than leading it.
|
||||
const errorMessage = (_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : '';
|
||||
if (errorMessage.includes(CACHE_READ_DENIED_PREFIX)) {
|
||||
throw new CacheReadDeniedError(errorMessage);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
if (!response.ok) {
|
||||
core.debug(`Cache not found for version ${request.version} of keys: ${keys.join(', ')}`);
|
||||
return undefined;
|
||||
@@ -95552,8 +95636,10 @@ function restoreCacheV2(paths_1, primaryKey_1, restoreKeys_1, options_1) {
|
||||
throw error;
|
||||
}
|
||||
else {
|
||||
// Supress all non-validation cache related errors because caching should be optional
|
||||
// Log server errors (5xx) as errors, all other errors as warnings
|
||||
// Suppress all non-validation cache related errors because caching should be optional
|
||||
// Log server errors (5xx) as errors, all other errors as warnings.
|
||||
// A read denied by policy (CacheReadDeniedError) is not an HttpClientError
|
||||
// so it falls here and is warned, treated as a cache miss.
|
||||
if (typedError instanceof HttpClientError &&
|
||||
typeof typedError.statusCode === 'number' &&
|
||||
typedError.statusCode >= 500) {
|
||||
@@ -95592,6 +95678,12 @@ function cache_saveCache(paths_1, key_1, options_1) {
|
||||
core_debug(`Cache service version: ${cacheServiceVersion}`);
|
||||
checkPaths(paths);
|
||||
checkKey(key);
|
||||
const cacheMode = config_getCacheMode();
|
||||
if (!isCacheWritable(cacheMode)) {
|
||||
info(`Cache save skipped: the effective cache-mode '${cacheMode}' does not permit writes.`);
|
||||
core_debug(`Skipped save for paths [${paths.join(', ')}] with key '${key}'.`);
|
||||
return -1;
|
||||
}
|
||||
switch (cacheServiceVersion) {
|
||||
case 'v2':
|
||||
return yield saveCacheV2(paths, key, options, enableCrossOsArchive);
|
||||
@@ -95669,17 +95761,14 @@ function saveCacheV1(paths_1, key_1, options_1) {
|
||||
if (typedError.name === ValidationError.name) {
|
||||
throw error;
|
||||
}
|
||||
else if (typedError.name === CacheWriteDeniedError.name) {
|
||||
// Cache write was denied by policy (read-only token). Surface to the
|
||||
// customer at warning level so it is visible in the workflow log
|
||||
// without failing the run.
|
||||
warning(`Failed to save: ${typedError.message}`);
|
||||
}
|
||||
else if (typedError.name === ReserveCacheError.name) {
|
||||
info(`Failed to save: ${typedError.message}`);
|
||||
}
|
||||
else {
|
||||
// Log server errors (5xx) as errors, all other errors as warnings
|
||||
// Log server errors (5xx) as errors, all other errors as warnings.
|
||||
// A write denied by policy (CacheWriteDeniedError) is not an
|
||||
// HttpClientError and its name does not match the ReserveCacheError arm,
|
||||
// so it falls here and is warned without failing the run.
|
||||
if (typedError instanceof lib_HttpClientError &&
|
||||
typeof typedError.statusCode === 'number' &&
|
||||
typedError.statusCode >= 500) {
|
||||
@@ -95790,12 +95879,6 @@ function saveCacheV2(paths_1, key_1, options_1) {
|
||||
if (typedError.name === ValidationError.name) {
|
||||
throw error;
|
||||
}
|
||||
else if (typedError.name === CacheWriteDeniedError.name) {
|
||||
// Cache write was denied by policy (read-only token). Surface to the
|
||||
// customer at warning level so it is visible in the workflow log
|
||||
// without failing the run.
|
||||
warning(`Failed to save: ${typedError.message}`);
|
||||
}
|
||||
else if (typedError.name === ReserveCacheError.name) {
|
||||
info(`Failed to save: ${typedError.message}`);
|
||||
}
|
||||
@@ -95803,7 +95886,10 @@ function saveCacheV2(paths_1, key_1, options_1) {
|
||||
warning(typedError.message);
|
||||
}
|
||||
else {
|
||||
// Log server errors (5xx) as errors, all other errors as warnings
|
||||
// Log server errors (5xx) as errors, all other errors as warnings.
|
||||
// A write denied by policy (CacheWriteDeniedError) is not an
|
||||
// HttpClientError and its name does not match the ReserveCacheError arm,
|
||||
// so it falls here and is warned without failing the run.
|
||||
if (typedError instanceof lib_HttpClientError &&
|
||||
typeof typedError.statusCode === 'number' &&
|
||||
typedError.statusCode >= 500) {
|
||||
@@ -95849,6 +95935,12 @@ const INPUT_GPG_PRIVATE_KEY = 'gpg-private-key';
|
||||
const INPUT_GPG_PASSPHRASE = 'gpg-passphrase';
|
||||
const INPUT_DEFAULT_GPG_PRIVATE_KEY = (/* unused pure expression or super */ null && (undefined));
|
||||
const INPUT_DEFAULT_GPG_PASSPHRASE = 'GPG_PASSPHRASE';
|
||||
// The default name of the environment variable the maven-gpg-plugin reads the
|
||||
// passphrase from (property `gpg.passphraseEnvName`). When the configured
|
||||
// passphrase env var name matches this, no extra configuration is required.
|
||||
const MAVEN_GPG_PASSPHRASE_DEFAULT_ENV = 'MAVEN_GPG_PASSPHRASE';
|
||||
// Id of the settings.xml profile used to set `gpg.passphraseEnvName`.
|
||||
const GPG_PASSPHRASE_PROFILE_ID = 'setup-java-gpg';
|
||||
const INPUT_CACHE = 'cache';
|
||||
const INPUT_CACHE_DEPENDENCY_PATH = 'cache-dependency-path';
|
||||
const INPUT_JOB_STATUS = 'job-status';
|
||||
@@ -96154,6 +96246,22 @@ function renameWinArchive(javaArchivePath) {
|
||||
fs.renameSync(javaArchivePath, javaArchivePathRenamed);
|
||||
return javaArchivePathRenamed;
|
||||
}
|
||||
// Resolve the newest available stable/GA feature (major) release.
|
||||
//
|
||||
// Some distributions (e.g. Oracle, GraalVM) construct their download URLs from a
|
||||
// concrete major version and don't expose an endpoint to list every available
|
||||
// release, so a bare `latest` alias can't be resolved from their own metadata.
|
||||
// The Adoptium (Temurin) API is used as a proxy for "what is the newest GA major
|
||||
// version out there", which those distributions typically publish at the same time.
|
||||
async function getLatestMajorVersion(http) {
|
||||
const availableReleasesUrl = 'https://api.adoptium.net/v3/info/available_releases';
|
||||
const response = await http.getJson(availableReleasesUrl);
|
||||
const mostRecent = response.result?.most_recent_feature_release;
|
||||
if (!mostRecent || Number.isNaN(Number(mostRecent))) {
|
||||
throw new Error(`Could not determine the latest available Java major version from ${availableReleasesUrl}`);
|
||||
}
|
||||
return Number(mostRecent);
|
||||
}
|
||||
|
||||
;// CONCATENATED MODULE: ./src/gpg.ts
|
||||
|
||||
@@ -99650,23 +99758,28 @@ const CACHE_KEY_PREFIX = 'setup-java';
|
||||
const supportedPackageManager = [
|
||||
{
|
||||
id: 'maven',
|
||||
path: [
|
||||
(0,external_path_.join)(external_os_default().homedir(), '.m2', 'repository'),
|
||||
(0,external_path_.join)(external_os_default().homedir(), '.m2', 'wrapper', 'dists')
|
||||
],
|
||||
path: [(0,external_path_.join)(external_os_default().homedir(), '.m2', 'repository')],
|
||||
// https://github.com/actions/cache/blob/0638051e9af2c23d10bb70fa9beffcad6cff9ce3/examples.md#java---maven
|
||||
pattern: [
|
||||
'**/pom.xml',
|
||||
'**/.mvn/wrapper/maven-wrapper.properties',
|
||||
'**/.mvn/extensions.xml'
|
||||
],
|
||||
// The Maven wrapper distribution only depends on the wrapper properties,
|
||||
// which change very rarely, so it is cached separately from the local
|
||||
// repository. This keeps it available across the frequent pom.xml changes
|
||||
// that rotate the main cache key. See issue #1095.
|
||||
additionalCaches: [
|
||||
{
|
||||
name: 'maven-wrapper',
|
||||
path: [(0,external_path_.join)(external_os_default().homedir(), '.m2', 'wrapper', 'dists')],
|
||||
pattern: ['**/.mvn/wrapper/maven-wrapper.properties']
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'gradle',
|
||||
path: [
|
||||
(0,external_path_.join)(external_os_default().homedir(), '.gradle', 'caches'),
|
||||
(0,external_path_.join)(external_os_default().homedir(), '.gradle', 'wrapper')
|
||||
],
|
||||
path: [(0,external_path_.join)(external_os_default().homedir(), '.gradle', 'caches')],
|
||||
// https://github.com/actions/cache/blob/0638051e9af2c23d10bb70fa9beffcad6cff9ce3/examples.md#java---gradle
|
||||
pattern: [
|
||||
'**/*.gradle*',
|
||||
@@ -99675,6 +99788,17 @@ const supportedPackageManager = [
|
||||
'buildSrc/**/Dependencies.kt',
|
||||
'gradle/*.versions.toml',
|
||||
'**/versions.properties'
|
||||
],
|
||||
// The Gradle wrapper distribution only depends on the wrapper properties,
|
||||
// which change very rarely, so it is cached separately from the Gradle
|
||||
// caches. This keeps it available across the frequent *.gradle* changes
|
||||
// that rotate the main cache key. See issue #269.
|
||||
additionalCaches: [
|
||||
{
|
||||
name: 'gradle-wrapper',
|
||||
path: [(0,external_path_.join)(external_os_default().homedir(), '.gradle', 'wrapper')],
|
||||
pattern: ['**/gradle-wrapper.properties']
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -99710,6 +99834,19 @@ function findPackageManager(id) {
|
||||
}
|
||||
return packageManager;
|
||||
}
|
||||
/**
|
||||
* State keys used to carry an additional cache's restore-time information over
|
||||
* to the post (save) action, scoped by the additional cache name.
|
||||
*/
|
||||
function additionalCachePrimaryKeyState(name) {
|
||||
return `${STATE_CACHE_PRIMARY_KEY}-${name}`;
|
||||
}
|
||||
function additionalCacheMatchedKeyState(name) {
|
||||
return `${CACHE_MATCHED_KEY}-${name}`;
|
||||
}
|
||||
function buildCacheKey(id, fileHash) {
|
||||
return `${CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${process.arch}-${id}-${fileHash}`;
|
||||
}
|
||||
/**
|
||||
* A function that generates a cache key to use.
|
||||
* Format of the generated key will be "${{ platform }}-${{ id }}-${{ fileHash }}"".
|
||||
@@ -99723,7 +99860,19 @@ async function computeCacheKey(packageManager, cacheDependencyPath) {
|
||||
if (!fileHash) {
|
||||
throw new Error(`No file in ${process.cwd()} matched to [${pattern}], make sure you have checked out the target repository`);
|
||||
}
|
||||
return `${CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${process.arch}-${packageManager.id}-${fileHash}`;
|
||||
return buildCacheKey(packageManager.id, fileHash);
|
||||
}
|
||||
/**
|
||||
* Computes the cache key for an additional cache. Unlike {@link computeCacheKey}
|
||||
* this returns undefined (instead of throwing) when no file matches the pattern,
|
||||
* because additional caches are optional features that many projects do not use.
|
||||
*/
|
||||
async function computeAdditionalCacheKey(additionalCache) {
|
||||
const fileHash = await glob.hashFiles(additionalCache.pattern.join('\n'));
|
||||
if (!fileHash) {
|
||||
return undefined;
|
||||
}
|
||||
return buildCacheKey(additionalCache.name, fileHash);
|
||||
}
|
||||
/**
|
||||
* Restore the dependency cache
|
||||
@@ -99747,6 +99896,29 @@ async function restore(id, cacheDependencyPath) {
|
||||
core.setOutput('cache-hit', false);
|
||||
core.info(`${packageManager.id} cache is not found`);
|
||||
}
|
||||
for (const additionalCache of packageManager.additionalCaches ?? []) {
|
||||
await restoreAdditionalCache(additionalCache);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Restore an additional cache (e.g. a build-tool wrapper distribution) that is
|
||||
* keyed independently of the main dependency cache so that it survives changes
|
||||
* to volatile dependency files. Skips silently when the project does not use
|
||||
* the corresponding feature.
|
||||
*/
|
||||
async function restoreAdditionalCache(additionalCache) {
|
||||
const primaryKey = await computeAdditionalCacheKey(additionalCache);
|
||||
if (!primaryKey) {
|
||||
core.debug(`No file matched [${additionalCache.pattern}] for the ${additionalCache.name} cache, skipping.`);
|
||||
return;
|
||||
}
|
||||
core.debug(`${additionalCache.name} primary key is ${primaryKey}`);
|
||||
core.saveState(additionalCachePrimaryKeyState(additionalCache.name), primaryKey);
|
||||
const matchedKey = await cache.restoreCache(additionalCache.path, primaryKey);
|
||||
if (matchedKey) {
|
||||
core.saveState(additionalCacheMatchedKeyState(additionalCache.name), matchedKey);
|
||||
core.info(`${additionalCache.name} cache restored from key: ${matchedKey}`);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Save the dependency cache
|
||||
@@ -99757,6 +99929,9 @@ async function save(id) {
|
||||
const matchedKey = getState(CACHE_MATCHED_KEY);
|
||||
// Inputs are re-evaluated before the post action, so we want the original key used for restore
|
||||
const primaryKey = getState(STATE_CACHE_PRIMARY_KEY);
|
||||
for (const additionalCache of packageManager.additionalCaches ?? []) {
|
||||
await saveAdditionalCache(packageManager, additionalCache);
|
||||
}
|
||||
if (!primaryKey) {
|
||||
warning('Error retrieving key from state.');
|
||||
return;
|
||||
@@ -99791,6 +99966,50 @@ async function save(id) {
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Save an additional cache under its own key. Skips when no key was recorded at
|
||||
* restore time (feature unused) or when the exact key was already restored.
|
||||
*/
|
||||
async function saveAdditionalCache(packageManager, additionalCache) {
|
||||
const primaryKey = getState(additionalCachePrimaryKeyState(additionalCache.name));
|
||||
const matchedKey = getState(additionalCacheMatchedKeyState(additionalCache.name));
|
||||
if (!primaryKey) {
|
||||
// The feature is not used by this project, nothing to save.
|
||||
core_debug(`No primary key for the ${additionalCache.name} cache, not saving cache.`);
|
||||
return;
|
||||
}
|
||||
else if (matchedKey === primaryKey) {
|
||||
info(`Cache hit occurred on the ${additionalCache.name} primary key ${primaryKey}, not saving cache.`);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const cacheId = await cache_saveCache(additionalCache.path, primaryKey);
|
||||
if (cacheId === -1) {
|
||||
core_debug(`${additionalCache.name} cache was not saved for the key: ${primaryKey}`);
|
||||
return;
|
||||
}
|
||||
info(`${additionalCache.name} cache saved with the key: ${primaryKey}`);
|
||||
}
|
||||
catch (error) {
|
||||
const err = error;
|
||||
if (err.name === ValidationError.name) {
|
||||
// The cache paths did not resolve, e.g. the wrapper distribution was
|
||||
// never downloaded because a system build tool was used or the download
|
||||
// failed. Optional wrapper caches must not fail the post step, so skip.
|
||||
core_debug(`${additionalCache.name} cache paths do not exist, not saving cache: ${err.message}`);
|
||||
return;
|
||||
}
|
||||
if (err.name === ReserveCacheError.name) {
|
||||
info(err.message);
|
||||
}
|
||||
else {
|
||||
if (isProbablyGradleDaemonProblem(packageManager, err)) {
|
||||
warning('Failed to save Gradle cache on Windows. If tar.exe reported "Permission denied", try to run Gradle with `--no-daemon` option. Refer to https://github.com/actions/cache/issues/454 for details.');
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param packageManager the specified package manager by user
|
||||
* @param error the error thrown by the saveCache
|
||||
|
||||
Vendored
+517
-68
@@ -38608,7 +38608,7 @@ let h2ExperimentalWarned = false
|
||||
/** @type {import('http2')} */
|
||||
let http2
|
||||
try {
|
||||
http2 = __nccwpck_require__(4848)
|
||||
http2 = __nccwpck_require__(2467)
|
||||
} catch {
|
||||
// @ts-ignore
|
||||
http2 = { constants: {} }
|
||||
@@ -64403,7 +64403,7 @@ module.exports = __WEBPACK_EXTERNAL_createRequire(import.meta.url)("node:http");
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 4848:
|
||||
/***/ 2467:
|
||||
/***/ ((module) => {
|
||||
|
||||
module.exports = __WEBPACK_EXTERNAL_createRequire(import.meta.url)("node:http2");
|
||||
@@ -70021,7 +70021,7 @@ module.exports = { version: packageJson.version }
|
||||
/***/ 4012:
|
||||
/***/ ((module) => {
|
||||
|
||||
module.exports = /*#__PURE__*/JSON.parse('{"name":"@actions/cache","version":"6.1.0","description":"Actions cache lib","keywords":["github","actions","cache"],"homepage":"https://github.com/actions/toolkit/tree/main/packages/cache","license":"MIT","type":"module","main":"lib/cache.js","types":"lib/cache.d.ts","exports":{".":{"types":"./lib/cache.d.ts","import":"./lib/cache.js"}},"directories":{"lib":"lib","test":"__tests__"},"files":["lib","!.DS_Store"],"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/actions/toolkit.git","directory":"packages/cache"},"scripts":{"audit-moderate":"npm install && npm audit --json --audit-level=moderate > audit.json","test":"echo \\"Error: run tests from root\\" && exit 1","tsc":"tsc && cp src/internal/shared/package-version.cjs lib/internal/shared/"},"bugs":{"url":"https://github.com/actions/toolkit/issues"},"dependencies":{"@actions/core":"^3.0.1","@actions/exec":"^3.0.0","@actions/glob":"^0.6.1","@actions/http-client":"^4.0.1","@actions/io":"^3.0.2","@azure/core-rest-pipeline":"^1.23.0","@azure/storage-blob":"^12.31.0","@protobuf-ts/runtime-rpc":"^2.11.1","semver":"^7.7.4"},"devDependencies":{"@protobuf-ts/plugin":"^2.11.1","@types/node":"^25.6.0","@types/semver":"^7.7.1","typescript":"^5.9.3"},"overrides":{"uri-js":"npm:uri-js-replace@^1.0.1","node-fetch":"^3.3.2"}}');
|
||||
module.exports = /*#__PURE__*/JSON.parse('{"name":"@actions/cache","version":"6.2.0","description":"Actions cache lib","keywords":["github","actions","cache"],"homepage":"https://github.com/actions/toolkit/tree/main/packages/cache","license":"MIT","type":"module","main":"lib/cache.js","types":"lib/cache.d.ts","exports":{".":{"types":"./lib/cache.d.ts","import":"./lib/cache.js"}},"directories":{"lib":"lib","test":"__tests__"},"files":["lib","!.DS_Store"],"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/actions/toolkit.git","directory":"packages/cache"},"scripts":{"audit-moderate":"npm install && npm audit --json --audit-level=moderate > audit.json","test":"echo \\"Error: run tests from root\\" && exit 1","tsc":"tsc && cp src/internal/shared/package-version.cjs lib/internal/shared/"},"bugs":{"url":"https://github.com/actions/toolkit/issues"},"dependencies":{"@actions/core":"^3.0.1","@actions/exec":"^3.0.0","@actions/glob":"^0.6.1","@actions/http-client":"^4.0.1","@actions/io":"^3.0.2","@azure/core-rest-pipeline":"^1.23.0","@azure/storage-blob":"^12.31.0","@protobuf-ts/runtime-rpc":"^2.11.1","semver":"^7.7.4"},"devDependencies":{"@protobuf-ts/plugin":"^2.11.1","@types/node":"^25.6.0","@types/semver":"^7.7.1","typescript":"^5.9.3"},"overrides":{"uri-js":"npm:uri-js-replace@^1.0.1","node-fetch":"^3.3.2"}}');
|
||||
|
||||
/***/ })
|
||||
|
||||
@@ -73294,6 +73294,12 @@ const INPUT_GPG_PRIVATE_KEY = 'gpg-private-key';
|
||||
const INPUT_GPG_PASSPHRASE = 'gpg-passphrase';
|
||||
const INPUT_DEFAULT_GPG_PRIVATE_KEY = undefined;
|
||||
const INPUT_DEFAULT_GPG_PASSPHRASE = 'GPG_PASSPHRASE';
|
||||
// The default name of the environment variable the maven-gpg-plugin reads the
|
||||
// passphrase from (property `gpg.passphraseEnvName`). When the configured
|
||||
// passphrase env var name matches this, no extra configuration is required.
|
||||
const MAVEN_GPG_PASSPHRASE_DEFAULT_ENV = 'MAVEN_GPG_PASSPHRASE';
|
||||
// Id of the settings.xml profile used to set `gpg.passphraseEnvName`.
|
||||
const GPG_PASSPHRASE_PROFILE_ID = 'setup-java-gpg';
|
||||
const INPUT_CACHE = 'cache';
|
||||
const INPUT_CACHE_DEPENDENCY_PATH = 'cache-dependency-path';
|
||||
const constants_INPUT_JOB_STATUS = 'job-status';
|
||||
@@ -75095,6 +75101,10 @@ const SystemTarPathOnWindows = `${process.env['SYSTEMDRIVE']}\\Windows\\System32
|
||||
const TarFilename = 'cache.tar';
|
||||
const constants_ManifestFilename = 'manifest.txt';
|
||||
const CacheFileSizeLimit = 10 * Math.pow(1024, 3); // 10GiB per repository
|
||||
// Prefix the cache backend embeds in a read-denial message (v2 twirp
|
||||
// GetCacheEntryDownloadURL error or the GHES v1 `_apis/artifactcache` 403 body).
|
||||
// Shared so cache.ts and cacheHttpClient.ts match the same contract value.
|
||||
const CacheReadDeniedMessagePrefix = 'cache read denied:';
|
||||
//# sourceMappingURL=constants.js.map
|
||||
;// CONCATENATED MODULE: ./node_modules/@actions/cache/lib/internal/cacheUtils.js
|
||||
var cacheUtils_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
@@ -124976,6 +124986,24 @@ function config_getCacheServiceVersion() {
|
||||
return 'v1';
|
||||
return process.env['ACTIONS_CACHE_SERVICE_V2'] ? 'v2' : 'v1';
|
||||
}
|
||||
// The cache-mode lattice: readable = {read, write}, writable = {write,
|
||||
// write-only}, none = neither.
|
||||
const KNOWN_CACHE_MODES = ['none', 'read', 'write', 'write-only'];
|
||||
// The effective cache-mode exported by the runner, or '' when not set.
|
||||
function config_getCacheMode() {
|
||||
return (process.env['ACTIONS_CACHE_MODE'] || '').trim().toLowerCase();
|
||||
}
|
||||
// Unset or unrecognized modes are permissive so behavior matches today.
|
||||
function isCacheReadable(mode) {
|
||||
if (!KNOWN_CACHE_MODES.includes(mode))
|
||||
return true;
|
||||
return mode === 'read' || mode === 'write';
|
||||
}
|
||||
function config_isCacheWritable(mode) {
|
||||
if (!KNOWN_CACHE_MODES.includes(mode))
|
||||
return true;
|
||||
return mode === 'write' || mode === 'write-only';
|
||||
}
|
||||
function getCacheServiceURL() {
|
||||
const version = config_getCacheServiceVersion();
|
||||
// Based on the version of the cache service, we will determine which
|
||||
@@ -125025,6 +125053,7 @@ var cacheHttpClient_awaiter = (undefined && undefined.__awaiter) || function (th
|
||||
|
||||
|
||||
|
||||
|
||||
function getCacheApiUrl(resource) {
|
||||
const baseUrl = getCacheServiceURL();
|
||||
if (!baseUrl) {
|
||||
@@ -125052,6 +125081,7 @@ function createHttpClient() {
|
||||
}
|
||||
function getCacheEntry(keys, paths, options) {
|
||||
return cacheHttpClient_awaiter(this, void 0, void 0, function* () {
|
||||
var _a;
|
||||
const httpClient = createHttpClient();
|
||||
const version = getCacheVersion(paths, options === null || options === void 0 ? void 0 : options.compressionMethod, options === null || options === void 0 ? void 0 : options.enableCrossOsArchive);
|
||||
const resource = `cache?keys=${encodeURIComponent(keys.join(','))}&version=${version}`;
|
||||
@@ -125065,6 +125095,12 @@ function getCacheEntry(keys, paths, options) {
|
||||
return null;
|
||||
}
|
||||
if (!requestUtils_isSuccessStatusCode(response.statusCode)) {
|
||||
// Only surface the receiver's body for a `cache read denied:` policy denial
|
||||
// so callers can dispatch on it; keep the generic message otherwise.
|
||||
const errorMessage = (_a = response.error) === null || _a === void 0 ? void 0 : _a.message;
|
||||
if (errorMessage === null || errorMessage === void 0 ? void 0 : errorMessage.includes(CacheReadDeniedMessagePrefix)) {
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
throw new Error(`Cache service responded with ${response.statusCode}`);
|
||||
}
|
||||
const cacheResult = response.result;
|
||||
@@ -126326,6 +126362,7 @@ var cache_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _ar
|
||||
|
||||
|
||||
|
||||
|
||||
class ValidationError extends Error {
|
||||
constructor(message) {
|
||||
super(message);
|
||||
@@ -126341,19 +126378,20 @@ class ReserveCacheError extends Error {
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Stable prefix the receiver writes into the cache reservation response when
|
||||
* the issuer downgraded the cache token to read-only (for example, because
|
||||
* Stable prefix the cache service writes into the cache reservation response
|
||||
* when the issuer downgraded the cache token to read-only (for example, because
|
||||
* the run was triggered by an untrusted event). saveCacheV1 / saveCacheV2
|
||||
* dispatch on this prefix to re-classify the failure as a
|
||||
* CacheWriteDeniedError so consumers (and the outer catch arm) can
|
||||
* distinguish a policy denial from other reservation failures.
|
||||
* dispatch on this prefix to re-classify the failure as a CacheWriteDeniedError
|
||||
* so consumers and tests can distinguish a policy denial from other reservation
|
||||
* failures. Internally it is logged as a non-fatal warning like other
|
||||
* best-effort save failures.
|
||||
*/
|
||||
const CACHE_WRITE_DENIED_PREFIX = 'cache write denied:';
|
||||
/**
|
||||
* Raised when the cache backend refuses to reserve a writable cache entry
|
||||
* because the JWT issued for this run was scoped read-only (for example, the
|
||||
* run was triggered by an event the repository administrator classified as
|
||||
* untrusted). The receiver-supplied detail message always begins with
|
||||
* untrusted). The service-supplied detail message always begins with
|
||||
* `cache write denied:` (the full error message includes additional context
|
||||
* like the cache key).
|
||||
*
|
||||
@@ -126369,6 +126407,19 @@ class CacheWriteDeniedError extends ReserveCacheError {
|
||||
Object.setPrototypeOf(this, CacheWriteDeniedError.prototype);
|
||||
}
|
||||
}
|
||||
// Re-exported from constants so consumers keep referencing it here; the shared
|
||||
// value also drives detection in cacheHttpClient without duplicating the string.
|
||||
const CACHE_READ_DENIED_PREFIX = CacheReadDeniedMessagePrefix;
|
||||
// Raised when the cache backend denies a download URL because the run's token
|
||||
// has no readable cache scopes. Caching is best-effort, so restoreCache logs a
|
||||
// warning and reports a cache miss rather than rethrowing this.
|
||||
class CacheReadDeniedError extends Error {
|
||||
constructor(message) {
|
||||
super(message);
|
||||
this.name = 'CacheReadDeniedError';
|
||||
Object.setPrototypeOf(this, CacheReadDeniedError.prototype);
|
||||
}
|
||||
}
|
||||
class FinalizeCacheError extends Error {
|
||||
constructor(message) {
|
||||
super(message);
|
||||
@@ -126423,6 +126474,12 @@ function restoreCache(paths_1, primaryKey_1, restoreKeys_1, options_1) {
|
||||
const cacheServiceVersion = config_getCacheServiceVersion();
|
||||
core_debug(`Cache service version: ${cacheServiceVersion}`);
|
||||
checkPaths(paths);
|
||||
const cacheMode = config_getCacheMode();
|
||||
if (!isCacheReadable(cacheMode)) {
|
||||
info(`Cache restore skipped: the effective cache-mode '${cacheMode}' does not permit reads.`);
|
||||
core_debug(`Skipped restore for paths [${paths.join(', ')}] with primary key '${primaryKey}'.`);
|
||||
return undefined;
|
||||
}
|
||||
switch (cacheServiceVersion) {
|
||||
case 'v2':
|
||||
return yield restoreCacheV2(paths, primaryKey, restoreKeys, options, enableCrossOsArchive);
|
||||
@@ -126444,6 +126501,7 @@ function restoreCache(paths_1, primaryKey_1, restoreKeys_1, options_1) {
|
||||
*/
|
||||
function restoreCacheV1(paths_1, primaryKey_1, restoreKeys_1, options_1) {
|
||||
return cache_awaiter(this, arguments, void 0, function* (paths, primaryKey, restoreKeys, options, enableCrossOsArchive = false) {
|
||||
var _a;
|
||||
restoreKeys = restoreKeys || [];
|
||||
const keys = [primaryKey, ...restoreKeys];
|
||||
core_debug('Resolved Keys:');
|
||||
@@ -126458,10 +126516,26 @@ function restoreCacheV1(paths_1, primaryKey_1, restoreKeys_1, options_1) {
|
||||
let archivePath = '';
|
||||
try {
|
||||
// path are needed to compute version
|
||||
const cacheEntry = yield getCacheEntry(keys, paths, {
|
||||
compressionMethod,
|
||||
enableCrossOsArchive
|
||||
});
|
||||
let cacheEntry;
|
||||
try {
|
||||
cacheEntry = yield getCacheEntry(keys, paths, {
|
||||
compressionMethod,
|
||||
enableCrossOsArchive
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
// The v1 artifact cache service returns HTTP 403 with a
|
||||
// `cache read denied:` body when the run's token has no readable cache
|
||||
// scopes. getCacheEntry lives in a dependency-free internal module and
|
||||
// cannot import CacheReadDeniedError without a circular dependency, so it
|
||||
// only surfaces the raw denial message; we classify it into the typed
|
||||
// error here so the outer catch and consumers can dispatch on it.
|
||||
const errorMessage = (_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : '';
|
||||
if (errorMessage.includes(CACHE_READ_DENIED_PREFIX)) {
|
||||
throw new CacheReadDeniedError(errorMessage);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
if (!(cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.archiveLocation)) {
|
||||
// Cache not found
|
||||
return undefined;
|
||||
@@ -126490,7 +126564,9 @@ function restoreCacheV1(paths_1, primaryKey_1, restoreKeys_1, options_1) {
|
||||
}
|
||||
else {
|
||||
// warn on cache restore failure and continue build
|
||||
// Log server errors (5xx) as errors, all other errors as warnings
|
||||
// Log server errors (5xx) as errors, all other errors as warnings.
|
||||
// A read denied by policy (CacheReadDeniedError) is not an HttpClientError
|
||||
// so it falls here and is warned, treated as a cache miss.
|
||||
if (typedError instanceof lib_HttpClientError &&
|
||||
typeof typedError.statusCode === 'number' &&
|
||||
typedError.statusCode >= 500) {
|
||||
@@ -126525,6 +126601,7 @@ function restoreCacheV1(paths_1, primaryKey_1, restoreKeys_1, options_1) {
|
||||
*/
|
||||
function restoreCacheV2(paths_1, primaryKey_1, restoreKeys_1, options_1) {
|
||||
return cache_awaiter(this, arguments, void 0, function* (paths, primaryKey, restoreKeys, options, enableCrossOsArchive = false) {
|
||||
var _a;
|
||||
// Override UploadOptions to force the use of Azure
|
||||
options = Object.assign(Object.assign({}, options), { useAzureSdk: true });
|
||||
restoreKeys = restoreKeys || [];
|
||||
@@ -126546,7 +126623,20 @@ function restoreCacheV2(paths_1, primaryKey_1, restoreKeys_1, options_1) {
|
||||
restoreKeys,
|
||||
version: getCacheVersion(paths, compressionMethod, enableCrossOsArchive)
|
||||
};
|
||||
const response = yield twirpClient.GetCacheEntryDownloadURL(request);
|
||||
let response;
|
||||
try {
|
||||
response = yield twirpClient.GetCacheEntryDownloadURL(request);
|
||||
}
|
||||
catch (error) {
|
||||
// The receiver returns twirp PermissionDenied (403) when the run's token
|
||||
// has no readable cache scopes. The client wraps that 403, so the stable
|
||||
// prefix is embedded in the message rather than leading it.
|
||||
const errorMessage = (_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : '';
|
||||
if (errorMessage.includes(CACHE_READ_DENIED_PREFIX)) {
|
||||
throw new CacheReadDeniedError(errorMessage);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
if (!response.ok) {
|
||||
core_debug(`Cache not found for version ${request.version} of keys: ${keys.join(', ')}`);
|
||||
return undefined;
|
||||
@@ -126581,8 +126671,10 @@ function restoreCacheV2(paths_1, primaryKey_1, restoreKeys_1, options_1) {
|
||||
throw error;
|
||||
}
|
||||
else {
|
||||
// Supress all non-validation cache related errors because caching should be optional
|
||||
// Log server errors (5xx) as errors, all other errors as warnings
|
||||
// Suppress all non-validation cache related errors because caching should be optional
|
||||
// Log server errors (5xx) as errors, all other errors as warnings.
|
||||
// A read denied by policy (CacheReadDeniedError) is not an HttpClientError
|
||||
// so it falls here and is warned, treated as a cache miss.
|
||||
if (typedError instanceof lib_HttpClientError &&
|
||||
typeof typedError.statusCode === 'number' &&
|
||||
typedError.statusCode >= 500) {
|
||||
@@ -126621,6 +126713,12 @@ function cache_saveCache(paths_1, key_1, options_1) {
|
||||
core.debug(`Cache service version: ${cacheServiceVersion}`);
|
||||
checkPaths(paths);
|
||||
checkKey(key);
|
||||
const cacheMode = getCacheMode();
|
||||
if (!isCacheWritable(cacheMode)) {
|
||||
core.info(`Cache save skipped: the effective cache-mode '${cacheMode}' does not permit writes.`);
|
||||
core.debug(`Skipped save for paths [${paths.join(', ')}] with key '${key}'.`);
|
||||
return -1;
|
||||
}
|
||||
switch (cacheServiceVersion) {
|
||||
case 'v2':
|
||||
return yield saveCacheV2(paths, key, options, enableCrossOsArchive);
|
||||
@@ -126698,17 +126796,14 @@ function saveCacheV1(paths_1, key_1, options_1) {
|
||||
if (typedError.name === ValidationError.name) {
|
||||
throw error;
|
||||
}
|
||||
else if (typedError.name === CacheWriteDeniedError.name) {
|
||||
// Cache write was denied by policy (read-only token). Surface to the
|
||||
// customer at warning level so it is visible in the workflow log
|
||||
// without failing the run.
|
||||
core.warning(`Failed to save: ${typedError.message}`);
|
||||
}
|
||||
else if (typedError.name === ReserveCacheError.name) {
|
||||
core.info(`Failed to save: ${typedError.message}`);
|
||||
}
|
||||
else {
|
||||
// Log server errors (5xx) as errors, all other errors as warnings
|
||||
// Log server errors (5xx) as errors, all other errors as warnings.
|
||||
// A write denied by policy (CacheWriteDeniedError) is not an
|
||||
// HttpClientError and its name does not match the ReserveCacheError arm,
|
||||
// so it falls here and is warned without failing the run.
|
||||
if (typedError instanceof HttpClientError &&
|
||||
typeof typedError.statusCode === 'number' &&
|
||||
typedError.statusCode >= 500) {
|
||||
@@ -126819,12 +126914,6 @@ function saveCacheV2(paths_1, key_1, options_1) {
|
||||
if (typedError.name === ValidationError.name) {
|
||||
throw error;
|
||||
}
|
||||
else if (typedError.name === CacheWriteDeniedError.name) {
|
||||
// Cache write was denied by policy (read-only token). Surface to the
|
||||
// customer at warning level so it is visible in the workflow log
|
||||
// without failing the run.
|
||||
core.warning(`Failed to save: ${typedError.message}`);
|
||||
}
|
||||
else if (typedError.name === ReserveCacheError.name) {
|
||||
core.info(`Failed to save: ${typedError.message}`);
|
||||
}
|
||||
@@ -126832,7 +126921,10 @@ function saveCacheV2(paths_1, key_1, options_1) {
|
||||
core.warning(typedError.message);
|
||||
}
|
||||
else {
|
||||
// Log server errors (5xx) as errors, all other errors as warnings
|
||||
// Log server errors (5xx) as errors, all other errors as warnings.
|
||||
// A write denied by policy (CacheWriteDeniedError) is not an
|
||||
// HttpClientError and its name does not match the ReserveCacheError arm,
|
||||
// so it falls here and is warned without failing the run.
|
||||
if (typedError instanceof HttpClientError &&
|
||||
typeof typedError.statusCode === 'number' &&
|
||||
typedError.statusCode >= 500) {
|
||||
@@ -127146,6 +127238,22 @@ function renameWinArchive(javaArchivePath) {
|
||||
external_fs_namespaceObject.renameSync(javaArchivePath, javaArchivePathRenamed);
|
||||
return javaArchivePathRenamed;
|
||||
}
|
||||
// Resolve the newest available stable/GA feature (major) release.
|
||||
//
|
||||
// Some distributions (e.g. Oracle, GraalVM) construct their download URLs from a
|
||||
// concrete major version and don't expose an endpoint to list every available
|
||||
// release, so a bare `latest` alias can't be resolved from their own metadata.
|
||||
// The Adoptium (Temurin) API is used as a proxy for "what is the newest GA major
|
||||
// version out there", which those distributions typically publish at the same time.
|
||||
async function getLatestMajorVersion(http) {
|
||||
const availableReleasesUrl = 'https://api.adoptium.net/v3/info/available_releases';
|
||||
const response = await http.getJson(availableReleasesUrl);
|
||||
const mostRecent = response.result?.most_recent_feature_release;
|
||||
if (!mostRecent || Number.isNaN(Number(mostRecent))) {
|
||||
throw new Error(`Could not determine the latest available Java major version from ${availableReleasesUrl}`);
|
||||
}
|
||||
return Number(mostRecent);
|
||||
}
|
||||
|
||||
;// CONCATENATED MODULE: ./src/gpg.ts
|
||||
|
||||
@@ -127295,12 +127403,25 @@ function generate(id, username, password, gpgPassphrase) {
|
||||
}
|
||||
}
|
||||
};
|
||||
if (gpgPassphrase) {
|
||||
const gpgServer = {
|
||||
id: 'gpg.passphrase',
|
||||
passphrase: `\${env.${gpgPassphrase}}`
|
||||
// The maven-gpg-plugin reads the passphrase from the environment variable
|
||||
// named by the `gpg.passphraseEnvName` property (default MAVEN_GPG_PASSPHRASE).
|
||||
// Only configure it when the requested env var name differs from that default;
|
||||
// otherwise the plugin already reads the right variable and no extra settings
|
||||
// are needed. Writing `gpg.passphrase` to settings.xml is deprecated and fails
|
||||
// when the plugin's `bestPractices` mode is enabled.
|
||||
if (gpgPassphrase &&
|
||||
gpgPassphrase !== MAVEN_GPG_PASSPHRASE_DEFAULT_ENV) {
|
||||
xmlObj.settings.profiles = {
|
||||
profile: {
|
||||
id: GPG_PASSPHRASE_PROFILE_ID,
|
||||
properties: {
|
||||
'gpg.passphraseEnvName': gpgPassphrase
|
||||
}
|
||||
}
|
||||
};
|
||||
xmlObj.settings.activeProfiles = {
|
||||
activeProfile: GPG_PASSPHRASE_PROFILE_ID
|
||||
};
|
||||
xmlObj.settings.servers.server.push(gpgServer);
|
||||
}
|
||||
return (0,lib/* create */.vt)(xmlObj).end({
|
||||
headless: true,
|
||||
@@ -127335,13 +127456,11 @@ async function write(directory, settings, overwriteSettings) {
|
||||
|
||||
|
||||
|
||||
|
||||
async function configureToolchains(version, distributionName, jdkHome, toolchainId) {
|
||||
const vendor = getInput(INPUT_MVN_TOOLCHAIN_VENDOR) || distributionName;
|
||||
const id = toolchainId || `${vendor}_${version}`;
|
||||
const settingsDirectory = getInput(INPUT_SETTINGS_PATH) ||
|
||||
external_path_.join(external_os_.homedir(), M2_DIR);
|
||||
const overwriteSettings = util_getBooleanInput(INPUT_OVERWRITE_SETTINGS, true);
|
||||
await createToolchainsSettings({
|
||||
jdkInfo: {
|
||||
version,
|
||||
@@ -127349,18 +127468,17 @@ async function configureToolchains(version, distributionName, jdkHome, toolchain
|
||||
id,
|
||||
jdkHome
|
||||
},
|
||||
settingsDirectory,
|
||||
overwriteSettings
|
||||
settingsDirectory
|
||||
});
|
||||
}
|
||||
async function createToolchainsSettings({ jdkInfo, settingsDirectory, overwriteSettings }) {
|
||||
async function createToolchainsSettings({ jdkInfo, settingsDirectory }) {
|
||||
info(`Creating ${MVN_TOOLCHAINS_FILE} for JDK version ${jdkInfo.version} from ${jdkInfo.vendor}`);
|
||||
// when an alternate m2 location is specified use only that location (no .m2 directory)
|
||||
// otherwise use the home/.m2/ path
|
||||
await mkdirP(settingsDirectory);
|
||||
const originalToolchains = await readExistingToolchainsFile(settingsDirectory);
|
||||
const updatedToolchains = generateToolchainDefinition(originalToolchains, jdkInfo.version, jdkInfo.vendor, jdkInfo.id, jdkInfo.jdkHome);
|
||||
await writeToolchainsFileToDisk(settingsDirectory, updatedToolchains, overwriteSettings);
|
||||
await writeToolchainsFileToDisk(settingsDirectory, updatedToolchains);
|
||||
}
|
||||
// only exported for testing purposes
|
||||
function generateToolchainDefinition(original, version, vendor, id, jdkHome) {
|
||||
@@ -127442,18 +127560,20 @@ async function readExistingToolchainsFile(directory) {
|
||||
}
|
||||
return '';
|
||||
}
|
||||
async function writeToolchainsFileToDisk(directory, settings, overwriteSettings) {
|
||||
async function writeToolchainsFileToDisk(directory, settings) {
|
||||
const location = external_path_.join(directory, MVN_TOOLCHAINS_FILE);
|
||||
const settingsExists = external_fs_namespaceObject.existsSync(location);
|
||||
if (settingsExists && overwriteSettings) {
|
||||
info(`Overwriting existing file ${location}`);
|
||||
}
|
||||
else if (!settingsExists) {
|
||||
info(`Writing to ${location}`);
|
||||
// The toolchains file is produced by a non-destructive merge (existing JDK,
|
||||
// custom, and non-jdk toolchains are preserved – see generateToolchainDefinition),
|
||||
// so it is always safe to write it. Unlike settings.xml, it is therefore not
|
||||
// gated behind the `overwrite-settings` input; that would prevent subsequent
|
||||
// setup-java runs from registering additional JDKs and silently drop the
|
||||
// toolchain entries created by earlier runs.
|
||||
if (settingsExists) {
|
||||
info(`Updating existing file ${location}`);
|
||||
}
|
||||
else {
|
||||
info(`Skipping generation of ${location} because file already exists and overwriting is not enabled`);
|
||||
return;
|
||||
info(`Writing to ${location}`);
|
||||
}
|
||||
return external_fs_namespaceObject.writeFileSync(location, settings, {
|
||||
encoding: 'utf-8',
|
||||
@@ -130872,23 +130992,28 @@ const CACHE_KEY_PREFIX = 'setup-java';
|
||||
const supportedPackageManager = [
|
||||
{
|
||||
id: 'maven',
|
||||
path: [
|
||||
(0,external_path_.join)(external_os_default().homedir(), '.m2', 'repository'),
|
||||
(0,external_path_.join)(external_os_default().homedir(), '.m2', 'wrapper', 'dists')
|
||||
],
|
||||
path: [(0,external_path_.join)(external_os_default().homedir(), '.m2', 'repository')],
|
||||
// https://github.com/actions/cache/blob/0638051e9af2c23d10bb70fa9beffcad6cff9ce3/examples.md#java---maven
|
||||
pattern: [
|
||||
'**/pom.xml',
|
||||
'**/.mvn/wrapper/maven-wrapper.properties',
|
||||
'**/.mvn/extensions.xml'
|
||||
],
|
||||
// The Maven wrapper distribution only depends on the wrapper properties,
|
||||
// which change very rarely, so it is cached separately from the local
|
||||
// repository. This keeps it available across the frequent pom.xml changes
|
||||
// that rotate the main cache key. See issue #1095.
|
||||
additionalCaches: [
|
||||
{
|
||||
name: 'maven-wrapper',
|
||||
path: [(0,external_path_.join)(external_os_default().homedir(), '.m2', 'wrapper', 'dists')],
|
||||
pattern: ['**/.mvn/wrapper/maven-wrapper.properties']
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'gradle',
|
||||
path: [
|
||||
(0,external_path_.join)(external_os_default().homedir(), '.gradle', 'caches'),
|
||||
(0,external_path_.join)(external_os_default().homedir(), '.gradle', 'wrapper')
|
||||
],
|
||||
path: [(0,external_path_.join)(external_os_default().homedir(), '.gradle', 'caches')],
|
||||
// https://github.com/actions/cache/blob/0638051e9af2c23d10bb70fa9beffcad6cff9ce3/examples.md#java---gradle
|
||||
pattern: [
|
||||
'**/*.gradle*',
|
||||
@@ -130897,6 +131022,17 @@ const supportedPackageManager = [
|
||||
'buildSrc/**/Dependencies.kt',
|
||||
'gradle/*.versions.toml',
|
||||
'**/versions.properties'
|
||||
],
|
||||
// The Gradle wrapper distribution only depends on the wrapper properties,
|
||||
// which change very rarely, so it is cached separately from the Gradle
|
||||
// caches. This keeps it available across the frequent *.gradle* changes
|
||||
// that rotate the main cache key. See issue #269.
|
||||
additionalCaches: [
|
||||
{
|
||||
name: 'gradle-wrapper',
|
||||
path: [(0,external_path_.join)(external_os_default().homedir(), '.gradle', 'wrapper')],
|
||||
pattern: ['**/gradle-wrapper.properties']
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -130932,6 +131068,19 @@ function findPackageManager(id) {
|
||||
}
|
||||
return packageManager;
|
||||
}
|
||||
/**
|
||||
* State keys used to carry an additional cache's restore-time information over
|
||||
* to the post (save) action, scoped by the additional cache name.
|
||||
*/
|
||||
function additionalCachePrimaryKeyState(name) {
|
||||
return `${STATE_CACHE_PRIMARY_KEY}-${name}`;
|
||||
}
|
||||
function additionalCacheMatchedKeyState(name) {
|
||||
return `${CACHE_MATCHED_KEY}-${name}`;
|
||||
}
|
||||
function buildCacheKey(id, fileHash) {
|
||||
return `${CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${process.arch}-${id}-${fileHash}`;
|
||||
}
|
||||
/**
|
||||
* A function that generates a cache key to use.
|
||||
* Format of the generated key will be "${{ platform }}-${{ id }}-${{ fileHash }}"".
|
||||
@@ -130945,7 +131094,19 @@ async function computeCacheKey(packageManager, cacheDependencyPath) {
|
||||
if (!fileHash) {
|
||||
throw new Error(`No file in ${process.cwd()} matched to [${pattern}], make sure you have checked out the target repository`);
|
||||
}
|
||||
return `${CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${process.arch}-${packageManager.id}-${fileHash}`;
|
||||
return buildCacheKey(packageManager.id, fileHash);
|
||||
}
|
||||
/**
|
||||
* Computes the cache key for an additional cache. Unlike {@link computeCacheKey}
|
||||
* this returns undefined (instead of throwing) when no file matches the pattern,
|
||||
* because additional caches are optional features that many projects do not use.
|
||||
*/
|
||||
async function computeAdditionalCacheKey(additionalCache) {
|
||||
const fileHash = await lib_glob_hashFiles(additionalCache.pattern.join('\n'));
|
||||
if (!fileHash) {
|
||||
return undefined;
|
||||
}
|
||||
return buildCacheKey(additionalCache.name, fileHash);
|
||||
}
|
||||
/**
|
||||
* Restore the dependency cache
|
||||
@@ -130969,6 +131130,29 @@ async function restore(id, cacheDependencyPath) {
|
||||
setOutput('cache-hit', false);
|
||||
info(`${packageManager.id} cache is not found`);
|
||||
}
|
||||
for (const additionalCache of packageManager.additionalCaches ?? []) {
|
||||
await restoreAdditionalCache(additionalCache);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Restore an additional cache (e.g. a build-tool wrapper distribution) that is
|
||||
* keyed independently of the main dependency cache so that it survives changes
|
||||
* to volatile dependency files. Skips silently when the project does not use
|
||||
* the corresponding feature.
|
||||
*/
|
||||
async function restoreAdditionalCache(additionalCache) {
|
||||
const primaryKey = await computeAdditionalCacheKey(additionalCache);
|
||||
if (!primaryKey) {
|
||||
core_debug(`No file matched [${additionalCache.pattern}] for the ${additionalCache.name} cache, skipping.`);
|
||||
return;
|
||||
}
|
||||
core_debug(`${additionalCache.name} primary key is ${primaryKey}`);
|
||||
saveState(additionalCachePrimaryKeyState(additionalCache.name), primaryKey);
|
||||
const matchedKey = await restoreCache(additionalCache.path, primaryKey);
|
||||
if (matchedKey) {
|
||||
saveState(additionalCacheMatchedKeyState(additionalCache.name), matchedKey);
|
||||
info(`${additionalCache.name} cache restored from key: ${matchedKey}`);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Save the dependency cache
|
||||
@@ -130979,6 +131163,9 @@ async function save(id) {
|
||||
const matchedKey = core.getState(CACHE_MATCHED_KEY);
|
||||
// Inputs are re-evaluated before the post action, so we want the original key used for restore
|
||||
const primaryKey = core.getState(STATE_CACHE_PRIMARY_KEY);
|
||||
for (const additionalCache of packageManager.additionalCaches ?? []) {
|
||||
await saveAdditionalCache(packageManager, additionalCache);
|
||||
}
|
||||
if (!primaryKey) {
|
||||
core.warning('Error retrieving key from state.');
|
||||
return;
|
||||
@@ -131013,6 +131200,50 @@ async function save(id) {
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Save an additional cache under its own key. Skips when no key was recorded at
|
||||
* restore time (feature unused) or when the exact key was already restored.
|
||||
*/
|
||||
async function saveAdditionalCache(packageManager, additionalCache) {
|
||||
const primaryKey = core.getState(additionalCachePrimaryKeyState(additionalCache.name));
|
||||
const matchedKey = core.getState(additionalCacheMatchedKeyState(additionalCache.name));
|
||||
if (!primaryKey) {
|
||||
// The feature is not used by this project, nothing to save.
|
||||
core.debug(`No primary key for the ${additionalCache.name} cache, not saving cache.`);
|
||||
return;
|
||||
}
|
||||
else if (matchedKey === primaryKey) {
|
||||
core.info(`Cache hit occurred on the ${additionalCache.name} primary key ${primaryKey}, not saving cache.`);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const cacheId = await cache.saveCache(additionalCache.path, primaryKey);
|
||||
if (cacheId === -1) {
|
||||
core.debug(`${additionalCache.name} cache was not saved for the key: ${primaryKey}`);
|
||||
return;
|
||||
}
|
||||
core.info(`${additionalCache.name} cache saved with the key: ${primaryKey}`);
|
||||
}
|
||||
catch (error) {
|
||||
const err = error;
|
||||
if (err.name === cache.ValidationError.name) {
|
||||
// The cache paths did not resolve, e.g. the wrapper distribution was
|
||||
// never downloaded because a system build tool was used or the download
|
||||
// failed. Optional wrapper caches must not fail the post step, so skip.
|
||||
core.debug(`${additionalCache.name} cache paths do not exist, not saving cache: ${err.message}`);
|
||||
return;
|
||||
}
|
||||
if (err.name === cache.ReserveCacheError.name) {
|
||||
core.info(err.message);
|
||||
}
|
||||
else {
|
||||
if (isProbablyGradleDaemonProblem(packageManager, err)) {
|
||||
core.warning('Failed to save Gradle cache on Windows. If tar.exe reported "Permission denied", try to run Gradle with `--no-daemon` option. Refer to https://github.com/actions/cache/issues/454 for details.');
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param packageManager the specified package manager by user
|
||||
* @param error the error thrown by the saveCache
|
||||
@@ -131045,6 +131276,7 @@ class JavaBase {
|
||||
architecture;
|
||||
packageType;
|
||||
stable;
|
||||
latest;
|
||||
checkLatest;
|
||||
setDefault;
|
||||
verifySignature;
|
||||
@@ -131055,7 +131287,11 @@ class JavaBase {
|
||||
allowRetries: true,
|
||||
maxRetries: 3
|
||||
});
|
||||
({ version: this.version, stable: this.stable } = this.normalizeVersion(installerOptions.version));
|
||||
({
|
||||
version: this.version,
|
||||
stable: this.stable,
|
||||
latest: this.latest
|
||||
} = this.normalizeVersion(installerOptions.version));
|
||||
this.architecture = installerOptions.architecture || external_os_default().arch();
|
||||
this.packageType = installerOptions.packageType;
|
||||
this.checkLatest = installerOptions.checkLatest;
|
||||
@@ -131071,7 +131307,7 @@ class JavaBase {
|
||||
throw new Error(`Input 'verify-signature' is not supported for distribution '${this.distribution}'.`);
|
||||
}
|
||||
let foundJava = this.findInToolcache();
|
||||
if (foundJava && !this.checkLatest) {
|
||||
if (foundJava && !this.checkLatest && !this.latest) {
|
||||
info(`Resolved Java ${foundJava.version} from tool-cache`);
|
||||
}
|
||||
else {
|
||||
@@ -131249,6 +131485,26 @@ class JavaBase {
|
||||
}
|
||||
normalizeVersion(version) {
|
||||
let stable = true;
|
||||
const latest = false;
|
||||
// Support the `latest` alias (case-insensitive), which floats to the newest
|
||||
// available stable/GA release. It is translated to the SemVer wildcard `x`
|
||||
// so the existing "newest satisfying version wins" resolution applies.
|
||||
const normalized = version.trim().toLowerCase();
|
||||
if (normalized === 'latest') {
|
||||
return {
|
||||
version: 'x',
|
||||
stable: true,
|
||||
latest: true
|
||||
};
|
||||
}
|
||||
// Reject `latest` combined with any qualifier (e.g. `latest-ea`). Such inputs
|
||||
// would otherwise have their `-ea` suffix stripped and fall through to the
|
||||
// generic SemVer check, which fails with a confusing "'latest' is not valid
|
||||
// SemVer" message even though `latest` is a supported value. Fail early with a
|
||||
// targeted explanation instead.
|
||||
if (normalized.startsWith('latest')) {
|
||||
throw new Error(`The 'latest' alias resolves stable (GA) releases only and cannot be combined with '-ea' or other qualifiers (received '${version}'). Use 'latest' on its own, or specify a concrete version.`);
|
||||
}
|
||||
if (version.endsWith('-ea')) {
|
||||
version = version.replace(/-ea$/, '');
|
||||
stable = false;
|
||||
@@ -131258,12 +131514,21 @@ class JavaBase {
|
||||
version = version.replace('-ea.', '+');
|
||||
stable = false;
|
||||
}
|
||||
// Java uses a versioning scheme (JEP 322) that can contain more numeric
|
||||
// fields than SemVer allows, e.g. '18.0.1.1' or '11.0.9.1'. Convert such
|
||||
// exact versions to SemVer build notation ('18.0.1+1') so they are
|
||||
// accepted. Ranges and versions that already carry build metadata are
|
||||
// left untouched.
|
||||
if (/^\d+(\.\d+){3,}$/.test(version)) {
|
||||
version = convertVersionToSemver(version);
|
||||
}
|
||||
if (!semver_default().validRange(version)) {
|
||||
throw new Error(`The string '${version}' is not valid SemVer notation for a Java version. Please check README file for code snippets and more detailed information`);
|
||||
}
|
||||
return {
|
||||
version,
|
||||
stable
|
||||
stable,
|
||||
latest
|
||||
};
|
||||
}
|
||||
createVersionNotFoundError(versionOrRange, availableVersions, additionalContext) {
|
||||
@@ -131337,6 +131602,9 @@ class LocalDistribution extends JavaBase {
|
||||
this.jdkFile = jdkFile;
|
||||
}
|
||||
async setupJava() {
|
||||
if (this.latest) {
|
||||
throw new Error("The 'latest' version alias is not supported for the 'jdkfile' distribution. Please specify a concrete version.");
|
||||
}
|
||||
let foundJava = this.findInToolcache();
|
||||
if (foundJava) {
|
||||
info(`Resolved Java ${foundJava.version} from tool-cache`);
|
||||
@@ -132041,6 +132309,129 @@ class LibericaDistributions extends JavaBase {
|
||||
}
|
||||
}
|
||||
|
||||
;// CONCATENATED MODULE: ./src/distributions/liberica-nik/installer.ts
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const installer_supportedPlatform = `'linux', 'macos', 'windows'`;
|
||||
const installer_supportedArchitectures = `'x64', 'aarch64'`;
|
||||
class LibericaNikDistributions extends JavaBase {
|
||||
constructor(installerOptions) {
|
||||
super('Liberica_NIK', installerOptions);
|
||||
}
|
||||
async downloadTool(javaRelease) {
|
||||
info(`Downloading Java ${javaRelease.version} (${this.distribution}) from ${javaRelease.url} ...`);
|
||||
let javaArchivePath = await downloadTool(javaRelease.url);
|
||||
info(`Extracting Java archive...`);
|
||||
const extension = getDownloadArchiveExtension();
|
||||
if (process.platform === 'win32') {
|
||||
javaArchivePath = renameWinArchive(javaArchivePath);
|
||||
}
|
||||
const extractedJavaPath = await extractJdkFile(javaArchivePath, extension);
|
||||
const archiveName = external_fs_default().readdirSync(extractedJavaPath)[0];
|
||||
const archivePath = external_path_default().join(extractedJavaPath, archiveName);
|
||||
const javaPath = await cacheDir(archivePath, this.toolcacheFolderName, this.getToolcacheVersionName(javaRelease.version), this.architecture);
|
||||
return { version: javaRelease.version, path: javaPath };
|
||||
}
|
||||
async findPackageForDownload(range) {
|
||||
const availableVersionsRaw = await this.getAvailableVersions();
|
||||
const availableVersions = availableVersionsRaw
|
||||
.map(item => {
|
||||
const jdkVersion = this.getJdkVersion(item);
|
||||
return jdkVersion ? { url: item.downloadUrl, version: jdkVersion } : null;
|
||||
})
|
||||
.filter((item) => item !== null);
|
||||
const satisfiedVersion = availableVersions
|
||||
.filter(item => isVersionSatisfies(range, item.version))
|
||||
.sort((a, b) => -semver_default().compareBuild(a.version, b.version))[0];
|
||||
if (!satisfiedVersion) {
|
||||
const availableVersionStrings = availableVersions.map(item => item.version);
|
||||
throw this.createVersionNotFoundError(range, availableVersionStrings);
|
||||
}
|
||||
return satisfiedVersion;
|
||||
}
|
||||
async getAvailableVersions() {
|
||||
if (isDebug()) {
|
||||
console.time('Retrieving available versions for Liberica NIK took'); // eslint-disable-line no-console
|
||||
}
|
||||
const url = this.prepareAvailableVersionsUrl();
|
||||
core_debug(`Gathering available versions from '${url}'`);
|
||||
const availableVersions = (await this.http.getJson(url)).result ?? [];
|
||||
if (isDebug()) {
|
||||
startGroup('Print information about available versions');
|
||||
console.timeEnd('Retrieving available versions for Liberica NIK took'); // eslint-disable-line no-console
|
||||
core_debug(`Available versions: [${availableVersions.length}]`);
|
||||
core_debug(availableVersions.map(item => item.version).join(', '));
|
||||
endGroup();
|
||||
}
|
||||
return availableVersions;
|
||||
}
|
||||
prepareAvailableVersionsUrl() {
|
||||
const urlOptions = {
|
||||
os: this.getPlatformOption(),
|
||||
'bundle-type': this.getBundleType(),
|
||||
...this.getArchitectureOptions(),
|
||||
'build-type': this.stable ? 'all' : 'ea',
|
||||
'installation-type': 'archive',
|
||||
fields: 'downloadUrl,version,components,component,embedded'
|
||||
};
|
||||
const searchParams = new URLSearchParams(urlOptions).toString();
|
||||
return `https://api.bell-sw.com/v1/nik/releases?${searchParams}`;
|
||||
}
|
||||
// NIK's top-level `version` is the GraalVM/NIK version; the JDK version that
|
||||
// users select on lives in the embedded `liberica` component.
|
||||
getJdkVersion(release) {
|
||||
const liberica = release.components?.find(component => component.component === 'liberica');
|
||||
return liberica ? this.convertVersionToSemver(liberica.version) : null;
|
||||
}
|
||||
// The `full` bundle adds JavaFX/Swing GUI support; otherwise use `standard`.
|
||||
getBundleType() {
|
||||
const [, feature] = this.packageType.split('+');
|
||||
return feature?.includes('fx') ? 'full' : 'standard';
|
||||
}
|
||||
getArchitectureOptions() {
|
||||
const arch = this.distributionArchitecture();
|
||||
switch (arch) {
|
||||
case 'x64':
|
||||
return { bitness: '64', arch: 'x86' };
|
||||
case 'aarch64':
|
||||
return { bitness: '64', arch: 'arm' };
|
||||
default:
|
||||
throw new Error(`Architecture '${this.architecture}' is not supported. Supported architectures: ${installer_supportedArchitectures}`);
|
||||
}
|
||||
}
|
||||
getPlatformOption(platform = process.platform) {
|
||||
switch (platform) {
|
||||
case 'darwin':
|
||||
return 'macos';
|
||||
case 'win32':
|
||||
case 'cygwin':
|
||||
return 'windows';
|
||||
case 'linux':
|
||||
return 'linux';
|
||||
default:
|
||||
throw new Error(`Platform '${platform}' is not supported. Supported platforms: ${installer_supportedPlatform}`);
|
||||
}
|
||||
}
|
||||
// JDK versions come as strings like '25.0.1+16', '23+38' or '11.0.15.1+2'.
|
||||
// Normalize them to valid SemVer while preserving build metadata so newer
|
||||
// NIK builds of the same JDK sort ahead of older ones.
|
||||
convertVersionToSemver(jdkVersion) {
|
||||
const [main, build] = jdkVersion.split('+');
|
||||
const parts = main.split('.');
|
||||
while (parts.length < 3) {
|
||||
parts.push('0');
|
||||
}
|
||||
const base = parts.slice(0, 3).join('.');
|
||||
const buildMeta = [...parts.slice(3), ...(build ? [build] : [])];
|
||||
return buildMeta.length ? `${base}+${buildMeta.join('.')}` : base;
|
||||
}
|
||||
}
|
||||
|
||||
;// CONCATENATED MODULE: ./src/distributions/microsoft/microsoft-key.ts
|
||||
// Microsoft Build of OpenJDK GPG signing key
|
||||
// Retrieved from: https://download.visualstudio.microsoft.com/download/pr/b90071e2-e0cf-4411-98be-dbeb09d67bf0/8622862bcd54206e158c5abca0582c9b/464279_464280_aoc_20210208.asc
|
||||
@@ -132181,7 +132572,7 @@ class MicrosoftDistributions extends JavaBase {
|
||||
|
||||
|
||||
|
||||
const installer_supportedArchitectures = [
|
||||
const semeru_installer_supportedArchitectures = [
|
||||
'x64',
|
||||
'x86',
|
||||
'ppc64le',
|
||||
@@ -132195,8 +132586,8 @@ class SemeruDistribution extends JavaBase {
|
||||
}
|
||||
async findPackageForDownload(version) {
|
||||
const arch = this.distributionArchitecture();
|
||||
if (!installer_supportedArchitectures.includes(arch)) {
|
||||
throw new Error(`Unsupported architecture for IBM Semeru: ${this.architecture} for your current OS version, the following are supported: ${installer_supportedArchitectures.join(', ')}`);
|
||||
if (!semeru_installer_supportedArchitectures.includes(arch)) {
|
||||
throw new Error(`Unsupported architecture for IBM Semeru: ${this.architecture} for your current OS version, the following are supported: ${semeru_installer_supportedArchitectures.join(', ')}`);
|
||||
}
|
||||
if (!this.stable) {
|
||||
throw new Error('IBM Semeru does not provide builds for early access versions');
|
||||
@@ -132352,10 +132743,22 @@ class CorrettoDistribution extends JavaBase {
|
||||
if (!this.stable) {
|
||||
throw new Error('Early access versions are not supported');
|
||||
}
|
||||
const availableVersions = await this.getAvailableVersions();
|
||||
// The `latest` alias is normalized to the SemVer wildcard, but Corretto
|
||||
// matches on an exact major version, so resolve it to the newest available
|
||||
// major from Corretto's own list.
|
||||
if (this.latest) {
|
||||
const majors = availableVersions
|
||||
.map(item => parseInt(item.version, 10))
|
||||
.filter(major => Number.isFinite(major) && major > 0);
|
||||
if (majors.length === 0) {
|
||||
throw new Error('Could not determine the latest available Corretto major version from remote metadata');
|
||||
}
|
||||
version = Math.max(...majors).toString();
|
||||
}
|
||||
if (version.includes('.')) {
|
||||
throw new Error('Only major versions are supported');
|
||||
}
|
||||
const availableVersions = await this.getAvailableVersions();
|
||||
const matchingVersions = availableVersions
|
||||
.filter(item => item.version == version)
|
||||
.map(item => {
|
||||
@@ -132483,6 +132886,13 @@ class OracleDistribution extends JavaBase {
|
||||
}
|
||||
const platform = this.getPlatform();
|
||||
const extension = getDownloadArchiveExtension();
|
||||
// The `latest` alias is normalized to the SemVer wildcard. Oracle builds its
|
||||
// download URLs from a concrete major and has no endpoint to list releases,
|
||||
// so resolve the newest available GA major from the Adoptium API and use it.
|
||||
if (this.latest) {
|
||||
const latestMajor = await getLatestMajorVersion(this.http);
|
||||
range = latestMajor.toString();
|
||||
}
|
||||
const isOnlyMajorProvided = !range.includes('.');
|
||||
const major = isOnlyMajorProvided ? range : range.split('.')[0];
|
||||
const possibleUrls = [];
|
||||
@@ -132509,6 +132919,11 @@ class OracleDistribution extends JavaBase {
|
||||
throw new Error(`Http request for Oracle JDK failed with status code: ${response.message.statusCode}`);
|
||||
}
|
||||
}
|
||||
if (this.latest) {
|
||||
const error = this.createVersionNotFoundError(range);
|
||||
error.message += `\nThe latest Java major version (${range}) is not yet available for the Oracle JDK distribution. Please specify a concrete version instead of 'latest'.`;
|
||||
throw error;
|
||||
}
|
||||
throw this.createVersionNotFoundError(range);
|
||||
}
|
||||
getPlatform(platform = process.platform) {
|
||||
@@ -132907,6 +133322,12 @@ class GraalVMDistribution extends JavaBase {
|
||||
if (!this.stable) {
|
||||
return this.findEABuildDownloadUrl(`${range}-ea`);
|
||||
}
|
||||
// The `latest` alias is normalized to the SemVer wildcard. Oracle GraalVM
|
||||
// builds its download URLs from a concrete major and has no endpoint to list
|
||||
// releases, so resolve the newest available GA major from the Adoptium API.
|
||||
if (this.latest) {
|
||||
range = (await getLatestMajorVersion(this.http)).toString();
|
||||
}
|
||||
const { platform, extension, major } = this.validateStableBuildRequest(range);
|
||||
const fileUrl = this.constructFileUrl(range, major, platform, arch, extension);
|
||||
const response = await this.http.head(fileUrl);
|
||||
@@ -132955,6 +133376,9 @@ class GraalVMDistribution extends JavaBase {
|
||||
if (statusCode === HttpCodes.NotFound) {
|
||||
// Create the standard error with additional hint about checking the download URL
|
||||
const error = this.createVersionNotFoundError(range);
|
||||
if (this.latest) {
|
||||
error.message += `\nThe latest Java major version (${range}) is not yet available for the ${this.distribution} distribution. Please specify a concrete version instead of 'latest'.`;
|
||||
}
|
||||
error.message += `\nPlease check if this version is available at ${GRAALVM_DOWNLOAD_URL} . Pick a version from the list.`;
|
||||
throw error;
|
||||
}
|
||||
@@ -133042,7 +133466,24 @@ class GraalVMCommunityDistribution extends GraalVMDistribution {
|
||||
throw new Error('GraalVM Community does not provide early access builds');
|
||||
}
|
||||
const arch = this.getSupportedArchitecture();
|
||||
const { platform, extension } = this.validateStableBuildRequest(range);
|
||||
// GraalVM Community publishes its releases on GitHub, so the `latest` alias
|
||||
// (normalized to the SemVer wildcard `x`) can float to the newest GA it
|
||||
// actually ships. Unlike Oracle GraalVM (which has no listing endpoint and
|
||||
// must derive the newest major from the Adoptium API), we match against the
|
||||
// real release list here, so `latest` never fails when GraalVM lags behind a
|
||||
// brand-new Java major.
|
||||
let platform;
|
||||
let extension;
|
||||
if (this.latest) {
|
||||
if (this.packageType !== 'jdk') {
|
||||
throw new Error(`${this.distribution} provides only the \`jdk\` package type`);
|
||||
}
|
||||
platform = this.getPlatform();
|
||||
extension = getDownloadArchiveExtension();
|
||||
}
|
||||
else {
|
||||
({ platform, extension } = this.validateStableBuildRequest(range));
|
||||
}
|
||||
// GraalVM Community asset names embed the platform, architecture and
|
||||
// archive type, e.g. `graalvm-community-jdk-21.0.2_linux-x64_bin.tar.gz`.
|
||||
const assetSuffix = `_${platform}-${arch}_bin.${extension}`;
|
||||
@@ -133436,6 +133877,7 @@ class KonaDistribution extends JavaBase {
|
||||
|
||||
|
||||
|
||||
|
||||
var JavaDistribution;
|
||||
(function (JavaDistribution) {
|
||||
JavaDistribution["Adopt"] = "adopt";
|
||||
@@ -133444,6 +133886,7 @@ var JavaDistribution;
|
||||
JavaDistribution["Temurin"] = "temurin";
|
||||
JavaDistribution["Zulu"] = "zulu";
|
||||
JavaDistribution["Liberica"] = "liberica";
|
||||
JavaDistribution["LibericaNik"] = "liberica-nik";
|
||||
JavaDistribution["JdkFile"] = "jdkfile";
|
||||
JavaDistribution["Microsoft"] = "microsoft";
|
||||
JavaDistribution["Semeru"] = "semeru";
|
||||
@@ -133471,6 +133914,8 @@ function getJavaDistribution(distributionName, installerOptions, jdkFile) {
|
||||
return new ZuluDistribution(installerOptions);
|
||||
case JavaDistribution.Liberica:
|
||||
return new LibericaDistributions(installerOptions);
|
||||
case JavaDistribution.LibericaNik:
|
||||
return new LibericaNikDistributions(installerOptions);
|
||||
case JavaDistribution.Microsoft:
|
||||
return new MicrosoftDistributions(installerOptions);
|
||||
case JavaDistribution.Semeru:
|
||||
@@ -133664,7 +134109,11 @@ async function installVersion(version, options, toolchainId = 0) {
|
||||
throw new Error(`No supported distribution was found for input ${distributionName}`);
|
||||
}
|
||||
const result = await distribution.setupJava();
|
||||
await configureToolchains(version, distributionName, result.path, toolchainIds[toolchainId]);
|
||||
// When the `latest` alias is used, the literal input isn't a real version, so
|
||||
// pass the resolved version to the toolchains configuration instead.
|
||||
const isLatest = version.trim().toLowerCase() === 'latest';
|
||||
const toolchainVersion = isLatest ? result.version : version;
|
||||
await configureToolchains(toolchainVersion, distributionName, result.path, toolchainIds[toolchainId]);
|
||||
info('');
|
||||
info('Java configuration:');
|
||||
info(` Distribution: ${distributionName}`);
|
||||
|
||||
+203
-23
@@ -4,6 +4,7 @@
|
||||
- [Adopt](#Adopt)
|
||||
- [Zulu](#Zulu)
|
||||
- [Liberica](#Liberica)
|
||||
- [Liberica Native Image Kit](#Liberica-Native-Image-Kit)
|
||||
- [Microsoft](#Microsoft)
|
||||
- [Amazon Corretto](#Amazon-Corretto)
|
||||
- [Oracle](#Oracle)
|
||||
@@ -15,6 +16,7 @@
|
||||
- [Tencent Kona](#Tencent-Kona)
|
||||
- [Installing custom Java package type](#Installing-custom-Java-package-type)
|
||||
- [JavaFX Maven project](#JavaFX-Maven-project)
|
||||
- [Ensuring the Maven cache is complete (plugin dependencies)](#ensuring-the-maven-cache-is-complete-plugin-dependencies)
|
||||
- [Installing custom Java architecture](#Installing-custom-Java-architecture)
|
||||
- [Installing JDK without setting as default](#Installing-JDK-without-setting-as-default)
|
||||
- [Installing custom Java distribution from local file](#Installing-Java-from-local-file)
|
||||
@@ -84,6 +86,20 @@ steps:
|
||||
- run: java --version
|
||||
```
|
||||
|
||||
### Liberica Native Image Kit
|
||||
Liberica Native Image Kit (NIK) is a GraalVM-based distribution. `java-version` selects the underlying JDK version (e.g. `17`, `21`, `25`). Use `java-package: jdk+fx` to get the `full` bundle with JavaFX/Swing support; otherwise the `standard` bundle (with extra languages) is installed. Available on Linux, macOS and Windows for `x64` and `aarch64`.
|
||||
|
||||
```yaml
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: 'liberica-nik'
|
||||
java-version: '25'
|
||||
java-package: jdk # optional (jdk or jdk+fx) - defaults to jdk
|
||||
- run: native-image --version
|
||||
```
|
||||
|
||||
### Microsoft
|
||||
|
||||
```yaml
|
||||
@@ -237,7 +253,7 @@ The available package types are:
|
||||
- `jre+ft` - JBR (FreeType)
|
||||
|
||||
### Tencent Kona
|
||||
**NOTE:** Tencent Kona supports major versions 8, 11, 17 and 21, and provides jdk only.
|
||||
**NOTE:** Tencent Kona supports major versions 8, 11, 17, 21 and 25, and provides jdk only.
|
||||
|
||||
```yaml
|
||||
steps:
|
||||
@@ -285,6 +301,129 @@ To run the JavaFX application in CI:
|
||||
run: mvn --no-transfer-progress javafx:run
|
||||
```
|
||||
|
||||
## Ensuring the Maven cache is complete (plugin dependencies)
|
||||
|
||||
When you enable `cache: maven`, the action caches your local Maven repository
|
||||
(`~/.m2/repository`). The cache key is a hash of your Maven inputs — every
|
||||
`**/pom.xml`, plus `**/.mvn/wrapper/maven-wrapper.properties` and
|
||||
`**/.mvn/extensions.xml` — so changing any of those files (for example bumping
|
||||
the wrapper version or editing core extensions) produces a new key and
|
||||
invalidates the cache. At the end of the job the action saves whatever was
|
||||
downloaded during that run. It does **not** re-save the cache when the key
|
||||
already matches (a cache *hit*).
|
||||
|
||||
Downloaded Maven Wrapper distributions (`~/.m2/wrapper/dists`) are cached in a
|
||||
**separate** cache entry keyed only on `**/.mvn/wrapper/maven-wrapper.properties`.
|
||||
Because the wrapper distribution changes far less often than your `pom.xml`
|
||||
files, this keeps it available across the frequent dependency changes that
|
||||
rotate the main cache key, so wrapper-based (`./mvnw`) builds don't re-download
|
||||
the Maven distribution on every dependency change. See
|
||||
[issue #1095](https://github.com/actions/setup-java/issues/1095).
|
||||
|
||||
Maven resolves **plugin** dependencies lazily: it only downloads the plugins and
|
||||
plugin dependencies required by the goals that actually execute. As a result, the
|
||||
run that first creates the cache determines what is stored. If that run executed a
|
||||
"thin" goal such as `mvn compile`, plugins bound to later phases are never
|
||||
resolved. For example, `maven-shade-plugin` (bound to `package`) pulls in
|
||||
`plexus-archiver`, `commons-compress`, `io.airlift:aircompressor` and
|
||||
`org.tukaani:xz` — none of which a `compile` run downloads. Those artifacts are
|
||||
therefore absent from the cache, and because the action does not re-save on a
|
||||
hit, every later `test`/`verify`/`package` job re-downloads them on every run.
|
||||
|
||||
### Seed the cache with a resolution step
|
||||
|
||||
To populate `~/.m2` as comprehensively as possible on the run that creates the
|
||||
cache, run a dependency-resolution "seed" command before your build. Choose a
|
||||
command based on how thorough you need it to be:
|
||||
|
||||
| Seed command | Resolves plugin dependencies? | Notes |
|
||||
|--------------|:-----------------------------:|-------|
|
||||
| `mvn dependency:resolve` | No | Resolves project dependencies only — misses plugin dependencies (e.g. `aircompressor`). |
|
||||
| `mvn dependency:resolve-plugins` | Yes | Resolves plugins **and their dependencies**. |
|
||||
| `mvn dependency:go-offline` | Yes | Resolves project and plugin dependencies (a superset). |
|
||||
| `mvn dependency:go-offline dependency:resolve-plugins` | Yes (most thorough) | Recommended default. Use `dependency:resolve dependency:resolve-plugins` if `go-offline` is flaky or insufficient for your project. |
|
||||
|
||||
Single job — seed, then build (the cache saved at the end of this run contains
|
||||
the full set):
|
||||
|
||||
```yaml
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '25'
|
||||
cache: 'maven'
|
||||
- name: Seed the Maven cache
|
||||
run: mvn -B dependency:go-offline dependency:resolve-plugins
|
||||
- name: Build with Maven
|
||||
run: mvn -B verify --file pom.xml
|
||||
```
|
||||
|
||||
Separate seed job — useful for a matrix where different legs run different goals
|
||||
(`test`, `check`, `verify`, `-Pprofile1`, ...) but all share the same `~/.m2`
|
||||
cache. Without a seed, whichever job finishes first creates the cache from its
|
||||
own partial `.m2`, and parallel jobs race to save an equally partial cache; the
|
||||
seed job instead creates one comprehensive cache that every other job reuses:
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
seed-cache:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '25'
|
||||
cache: 'maven'
|
||||
- name: Seed the Maven cache
|
||||
run: mvn -B dependency:go-offline dependency:resolve-plugins
|
||||
|
||||
build:
|
||||
needs: seed-cache
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
goal: ['test', 'verify', 'test -Pprofile1']
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '25'
|
||||
cache: 'maven'
|
||||
- name: Build
|
||||
run: mvn -B ${{ matrix.goal }} --file pom.xml
|
||||
```
|
||||
|
||||
### Caveats
|
||||
|
||||
- **The seed only helps on the run that creates the cache.** Once a cache exists
|
||||
for the current `pom.xml` hash, later runs get a hit and any additional
|
||||
downloads are not saved. On an existing repository whose cache is already
|
||||
incomplete, invalidate it once (for example by changing `cache-dependency-path`
|
||||
or deleting the repository's caches) so a complete cache is created from the
|
||||
seed.
|
||||
- **Static resolution is not exhaustive.** `go-offline`/`resolve-plugins` resolve
|
||||
the statically declared plugin set for the *active* profiles and modules.
|
||||
Profile-gated plugins, conditionally-active modules, and artifacts a plugin
|
||||
fetches at execution time may still be missed. For the most complete cache,
|
||||
seed with the fullest goal set your CI actually uses (for example
|
||||
`mvn -B verify` with every profile enabled).
|
||||
- **Multi-module projects:** run the seed at the reactor root so every module's
|
||||
plugins are resolved.
|
||||
|
||||
> [!NOTE]
|
||||
> The same "the cache stores only what the creating run downloaded, and is not
|
||||
> re-saved on a hit" behavior applies to `cache: gradle`, since Gradle also
|
||||
> resolves dependencies and plugin/buildscript classpaths lazily. Gradle has no
|
||||
> direct equivalent of `dependency:go-offline`, so for complete and fine-grained
|
||||
> dependency caching on Gradle projects we recommend
|
||||
> [`gradle/actions/setup-gradle`](https://github.com/gradle/actions/tree/main/setup-gradle),
|
||||
> which provides purpose-built caching (see the
|
||||
> [setup-gradle documentation](https://github.com/gradle/actions/blob/main/docs/setup-gradle.md)).
|
||||
|
||||
## Installing custom Java architecture
|
||||
|
||||
```yaml
|
||||
@@ -461,14 +600,13 @@ jobs:
|
||||
server-id: maven # Value of the distributionManagement/repository/id field of the pom.xml
|
||||
server-username: MAVEN_USERNAME # env variable for username in deploy
|
||||
server-password: MAVEN_CENTRAL_TOKEN # env variable for token in deploy
|
||||
gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} # Value of the GPG private key to import
|
||||
gpg-passphrase: MAVEN_GPG_PASSPHRASE # env variable for GPG private key passphrase
|
||||
|
||||
- name: Publish to Apache Maven Central
|
||||
run: mvn deploy
|
||||
run: mvn deploy -Dgpg.signer=bc # requires maven-gpg-plugin >= 3.2.0 (bc signer support)
|
||||
env:
|
||||
MAVEN_USERNAME: maven_username123
|
||||
MAVEN_CENTRAL_TOKEN: ${{ secrets.MAVEN_CENTRAL_TOKEN }}
|
||||
MAVEN_GPG_KEY: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} # ASCII-armored secret key (TSK), e.g. from `gpg --armor --export-secret-keys YOUR_ID`
|
||||
MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }}
|
||||
```
|
||||
|
||||
@@ -486,10 +624,6 @@ The two `settings.xml` files created from the above example look like the follow
|
||||
<username>${env.GITHUB_ACTOR}</username>
|
||||
<password>${env.GITHUB_TOKEN}</password>
|
||||
</server>
|
||||
<server>
|
||||
<id>gpg.passphrase</id>
|
||||
<passphrase>${env.GPG_PASSPHRASE}</passphrase>
|
||||
</server>
|
||||
</servers>
|
||||
</settings>
|
||||
```
|
||||
@@ -506,10 +640,6 @@ The two `settings.xml` files created from the above example look like the follow
|
||||
<username>${env.MAVEN_USERNAME}</username>
|
||||
<password>${env.MAVEN_CENTRAL_TOKEN}</password>
|
||||
</server>
|
||||
<server>
|
||||
<id>gpg.passphrase</id>
|
||||
<passphrase>${env.MAVEN_GPG_PASSPHRASE}</passphrase>
|
||||
</server>
|
||||
</servers>
|
||||
</settings>
|
||||
```
|
||||
@@ -520,9 +650,64 @@ The two `settings.xml` files created from the above example look like the follow
|
||||
|
||||
If you don't want to overwrite the `settings.xml` file, you can set `overwrite-settings: false`
|
||||
|
||||
### Extra setup for pom.xml:
|
||||
### GPG
|
||||
|
||||
The Maven GPG Plugin configuration in the pom.xml file should contain the following structure to avoid possible issues like `Inappropriate ioctl for device` or `gpg: signing failed: No such file or directory`:
|
||||
The example above uses the [Maven GPG Plugin](https://maven.apache.org/plugins/maven-gpg-plugin/)'s Bouncy Castle signer (`-Dgpg.signer=bc`, available since `maven-gpg-plugin` 3.2.0). It is a pure-Java signer that reads the key directly from the `MAVEN_GPG_KEY` environment variable, so it does **not** require the `gpg` executable, importing the key into a GPG keychain, or the `--pinentry-mode loopback` workaround in your `pom.xml`. The key must be an ASCII-armored secret key (transferable secret key format).
|
||||
|
||||
**GPG key should be exported by: `gpg --armor --export-secret-keys YOUR_ID`**
|
||||
|
||||
See the help docs on [Publishing a Package](https://help.github.com/en/github/managing-packages-with-github-packages/configuring-apache-maven-for-use-with-github-packages#publishing-a-package) for more information on the `pom.xml` file.
|
||||
|
||||
#### Legacy / alternative: let setup-java import the key
|
||||
|
||||
If you prefer signing with the `gpg` executable (for example because you are using `maven-gpg-plugin` older than 3.2.0), you can let setup-java import the key instead by providing the `gpg-private-key` and `gpg-passphrase` inputs. The private key is written to a file in the runner's temp directory, imported into the GPG keychain, and the file is promptly removed before proceeding with the rest of the setup process. A cleanup step removes the imported private key from the GPG keychain after the job completes regardless of the job status. This ensures that the private key is no longer accessible on self-hosted runners and cannot "leak" between jobs (hosted runners are always clean instances).
|
||||
|
||||
setup-java imports the key independently of the plugin version, but the generated passphrase profile described below uses `gpg.passphraseEnvName`, which requires `maven-gpg-plugin` 3.2.0 or newer. Since `gpg-passphrase` defaults to `GPG_PASSPHRASE`, setup-java writes that profile unless you override the input to `MAVEN_GPG_PASSPHRASE`.
|
||||
|
||||
```yaml
|
||||
- name: Set up Apache Maven Central
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '11'
|
||||
server-id: maven # Value of the distributionManagement/repository/id field of the pom.xml
|
||||
server-username: MAVEN_USERNAME # env variable for username in deploy
|
||||
server-password: MAVEN_CENTRAL_TOKEN # env variable for token in deploy
|
||||
gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} # Value of the GPG private key to import
|
||||
gpg-passphrase: MAVEN_GPG_PASSPHRASE # env variable for GPG private key passphrase
|
||||
|
||||
- name: Publish to Apache Maven Central
|
||||
run: mvn deploy
|
||||
env:
|
||||
MAVEN_USERNAME: maven_username123
|
||||
MAVEN_CENTRAL_TOKEN: ${{ secrets.MAVEN_CENTRAL_TOKEN }}
|
||||
MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }}
|
||||
```
|
||||
|
||||
The `gpg-passphrase` input is the **name of the environment variable** that holds the passphrase (not the passphrase itself). It defaults to `GPG_PASSPHRASE`. The [Maven GPG Plugin](https://maven.apache.org/plugins/maven-gpg-plugin/) reads the passphrase from the environment variable named by its `gpg.passphraseEnvName` property, whose own default is `MAVEN_GPG_PASSPHRASE`.
|
||||
|
||||
- If `gpg-passphrase` is `MAVEN_GPG_PASSPHRASE`, the plugin already reads that variable by default, so setup-java writes nothing extra to `settings.xml`.
|
||||
- Otherwise (including the default `GPG_PASSPHRASE`), setup-java configures `gpg.passphraseEnvName` through an active profile in the generated `settings.xml` so the plugin reads the passphrase from that variable. For the default `gpg-passphrase: GPG_PASSPHRASE`:
|
||||
|
||||
```xml
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>setup-java-gpg</id>
|
||||
<properties>
|
||||
<gpg.passphraseEnvName>GPG_PASSPHRASE</gpg.passphraseEnvName>
|
||||
</properties>
|
||||
</profile>
|
||||
</profiles>
|
||||
<activeProfiles>
|
||||
<activeProfile>setup-java-gpg</activeProfile>
|
||||
</activeProfiles>
|
||||
```
|
||||
|
||||
> **Note:** Earlier versions of setup-java wrote a `gpg.passphrase` server to `settings.xml`. That mechanism is deprecated by the Maven GPG Plugin and fails when its `bestPractices` mode is enabled, so setup-java now relies on `gpg.passphraseEnvName` instead. The `gpg-passphrase` input and its `GPG_PASSPHRASE` default are unchanged, so existing workflows that set the `GPG_PASSPHRASE` environment variable keep working.
|
||||
|
||||
> **Compatibility note:** Reading the passphrase from an environment variable (`gpg.passphraseEnvName`) requires `maven-gpg-plugin` 3.2.0 or newer. Older versions do not honor this property and will not pick up the passphrase, because setup-java no longer writes the deprecated `gpg.passphrase` server to `settings.xml`. If you are pinned to `maven-gpg-plugin` older than 3.2.0, upgrade to 3.2.0+.
|
||||
|
||||
When signing with the `gpg` executable, the Maven GPG Plugin configuration in your `pom.xml` should contain the following structure to avoid possible issues like `Inappropriate ioctl for device` or `gpg: signing failed: No such file or directory`:
|
||||
|
||||
```xml
|
||||
<configuration>
|
||||
@@ -533,17 +718,10 @@ The Maven GPG Plugin configuration in the pom.xml file should contain the follow
|
||||
</gpgArguments>
|
||||
</configuration>
|
||||
```
|
||||
GPG 2.1 requires `--pinentry-mode` to be set to `loopback` in order to pick up the `gpg.passphrase` value defined in Maven `settings.xml`.
|
||||
|
||||
### GPG
|
||||
GPG 2.1 requires `--pinentry-mode` to be set to `loopback` in order to read the passphrase non-interactively.
|
||||
|
||||
If `gpg-private-key` input is provided, the private key will be written to a file in the runner's temp directory, the private key file will be imported into the GPG keychain, and then the file will be promptly removed before proceeding with the rest of the setup process. A cleanup step will remove the imported private key from the GPG keychain after the job completes regardless of the job status. This ensures that the private key is no longer accessible on self-hosted runners and cannot "leak" between jobs (hosted runners are always clean instances).
|
||||
|
||||
**GPG key should be exported by: `gpg --armor --export-secret-keys YOUR_ID`**
|
||||
|
||||
See the help docs on [Publishing a Package](https://help.github.com/en/github/managing-packages-with-github-packages/configuring-apache-maven-for-use-with-github-packages#publishing-a-package) for more information on the `pom.xml` file.
|
||||
|
||||
***NOTE***: If the error that states, `gpg: Sorry, no terminal at all requested - can't get input` [is encountered](https://github.com/actions/setup-java/issues/554), please update the version of `maven-gpg-plugin` to 1.6 or higher.
|
||||
***NOTE***: If, when using the default `gpg` signer, the error `gpg: Sorry, no terminal at all requested - can't get input` [is encountered](https://github.com/actions/setup-java/issues/554), please update the version of `maven-gpg-plugin` to 1.6 or higher.
|
||||
|
||||
## Apache Maven with a settings path
|
||||
|
||||
@@ -684,6 +862,8 @@ The `setup-java` action generates a basic [Maven Toolchains declaration](https:/
|
||||
### Installing Multiple JDKs With Toolchains
|
||||
Subsequent calls to `setup-java` with distinct distribution and version parameters will continue to extend the toolchains declaration and make all specified Java versions available.
|
||||
|
||||
Toolchain entries are always merged non-destructively: existing JDK, custom, and user-managed toolchains are preserved, and only an entry with the exact same `type` and `provides.id` is replaced. This behavior is independent of the `overwrite-settings` input, which only controls regeneration of `settings.xml`. As a result, running `setup-java` several times in the same job (for example in multiple steps or with multiple `java-version` values) accumulates every JDK in `toolchains.xml` instead of dropping previously registered entries.
|
||||
|
||||
```yaml
|
||||
steps:
|
||||
- uses: actions/setup-java@v5
|
||||
|
||||
Generated
+403
-145
@@ -9,7 +9,7 @@
|
||||
"version": "6.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/cache": "^6.1.0",
|
||||
"@actions/cache": "^6.2.0",
|
||||
"@actions/core": "^3.0.1",
|
||||
"@actions/exec": "^3.0.0",
|
||||
"@actions/glob": "^0.7.0",
|
||||
@@ -22,20 +22,20 @@
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@jest/globals": "^30.4.1",
|
||||
"@types/node": "^26.0.0",
|
||||
"@types/node": "^26.1.1",
|
||||
"@types/semver": "^7.7.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.62.0",
|
||||
"@typescript-eslint/parser": "^8.62.0",
|
||||
"@vercel/ncc": "^0.44.0",
|
||||
"eslint": "^10.5.0",
|
||||
"eslint": "^10.7.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-jest": "^29.15.4",
|
||||
"eslint-plugin-n": "^18.1.0",
|
||||
"eslint-plugin-n": "^18.2.2",
|
||||
"globals": "^17.7.0",
|
||||
"husky": "^9.1.7",
|
||||
"jest": "^30.4.2",
|
||||
"lint-staged": "^17.0.8",
|
||||
"prettier": "^3.9.1",
|
||||
"prettier": "^3.9.5",
|
||||
"ts-jest": "^29.4.11",
|
||||
"typescript": "^6.0.3"
|
||||
},
|
||||
@@ -44,9 +44,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/cache": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@actions/cache/-/cache-6.1.0.tgz",
|
||||
"integrity": "sha512-LVqybSbzhBp2uAETOQ3HnVjXA4AcjavgMH+LCr+cjgO+PZfciv/1QAgoW+esXBaAhvDid+vXeV70GGJpAh4V5Q==",
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@actions/cache/-/cache-6.2.0.tgz",
|
||||
"integrity": "sha512-Nv0xWRmbxfDbAn/70flO/F6tj2Nv4XTYMAsQHiDFSojCDfso/Zni+fRKa14ToI9hnmOW/rQcY1WYb6wsM7Pgwg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/core": "^3.0.1",
|
||||
@@ -1831,9 +1831,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "26.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-26.1.0.tgz",
|
||||
"integrity": "sha512-O0A1G3xPGy4w7AgQdAQYUlQ+BKk2Oovw8eRpofyp5KdBZULnbe+WqaOVNrm705SHphCiG4XHsACrSmPu1f+Kgw==",
|
||||
"version": "26.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-26.1.1.tgz",
|
||||
"integrity": "sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -1900,6 +1900,189 @@
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "8.63.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.63.0.tgz",
|
||||
"integrity": "sha512-Nzzh/OGxVCOjObjaj1CQF2RUasyYy2Jfuh+zZ3PjLzG2fYRriAiZLib9UKtO+CpQAS3YHiAS+ckZDclwqI1TPA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.63.0",
|
||||
"@typescript-eslint/typescript-estree": "8.63.0",
|
||||
"@typescript-eslint/utils": "8.63.0",
|
||||
"debug": "^4.4.3",
|
||||
"ts-api-utils": "^2.5.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "8.63.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.63.0.tgz",
|
||||
"integrity": "sha512-ygBkU+B7ex5UI/gKhaqexWev79uISfIv7XQCRNYO/jmD8rGLPyWLAb3KMRT6nd8Gt9bmUBi9+iX6tBdYfOY81Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/project-service": "8.63.0",
|
||||
"@typescript-eslint/tsconfig-utils": "8.63.0",
|
||||
"@typescript-eslint/types": "8.63.0",
|
||||
"@typescript-eslint/visitor-keys": "8.63.0",
|
||||
"debug": "^4.4.3",
|
||||
"minimatch": "^10.2.2",
|
||||
"semver": "^7.7.3",
|
||||
"tinyglobby": "^0.2.15",
|
||||
"ts-api-utils": "^2.5.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/project-service": {
|
||||
"version": "8.63.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.63.0.tgz",
|
||||
"integrity": "sha512-e5dh0/UI0ok53AlZ5wRkXCB32z/f2jUZqPR/ygAw5WYaSw8j9EoJWlS7wQjr/dmOaqWjnPIn2m+HhVPCMWGZVQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/tsconfig-utils": "^8.63.0",
|
||||
"@typescript-eslint/types": "^8.63.0",
|
||||
"debug": "^4.4.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/tsconfig-utils": {
|
||||
"version": "8.63.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.63.0.tgz",
|
||||
"integrity": "sha512-sUAbkulqBAsncKnbRP3+7CtQFRKicexnj7ZwNC6ddCR7EmrXvjvdCYMJbUIqMd6lwoEriZjwLo08aS5tSjVMHg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": {
|
||||
"version": "8.63.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.63.0.tgz",
|
||||
"integrity": "sha512-fUKaeAvrTuQg/Tgt3nliAUSZHJM6DlCcfyEmxCvlX8kieWSStBX+5O5Fnidtc3i2JrH+9c/GL4RY2iasd/GPTA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.9.1",
|
||||
"@typescript-eslint/scope-manager": "8.63.0",
|
||||
"@typescript-eslint/types": "8.63.0",
|
||||
"@typescript-eslint/typescript-estree": "8.63.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "8.63.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.63.0.tgz",
|
||||
"integrity": "sha512-ygBkU+B7ex5UI/gKhaqexWev79uISfIv7XQCRNYO/jmD8rGLPyWLAb3KMRT6nd8Gt9bmUBi9+iX6tBdYfOY81Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/project-service": "8.63.0",
|
||||
"@typescript-eslint/tsconfig-utils": "8.63.0",
|
||||
"@typescript-eslint/types": "8.63.0",
|
||||
"@typescript-eslint/visitor-keys": "8.63.0",
|
||||
"debug": "^4.4.3",
|
||||
"minimatch": "^10.2.2",
|
||||
"semver": "^7.7.3",
|
||||
"tinyglobby": "^0.2.15",
|
||||
"ts-api-utils": "^2.5.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/project-service": {
|
||||
"version": "8.63.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.63.0.tgz",
|
||||
"integrity": "sha512-e5dh0/UI0ok53AlZ5wRkXCB32z/f2jUZqPR/ygAw5WYaSw8j9EoJWlS7wQjr/dmOaqWjnPIn2m+HhVPCMWGZVQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/tsconfig-utils": "^8.63.0",
|
||||
"@typescript-eslint/types": "^8.63.0",
|
||||
"debug": "^4.4.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/tsconfig-utils": {
|
||||
"version": "8.63.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.63.0.tgz",
|
||||
"integrity": "sha512-sUAbkulqBAsncKnbRP3+7CtQFRKicexnj7ZwNC6ddCR7EmrXvjvdCYMJbUIqMd6lwoEriZjwLo08aS5tSjVMHg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "8.63.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.63.0.tgz",
|
||||
@@ -1925,7 +2108,35 @@
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/project-service": {
|
||||
"node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "8.63.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.63.0.tgz",
|
||||
"integrity": "sha512-ygBkU+B7ex5UI/gKhaqexWev79uISfIv7XQCRNYO/jmD8rGLPyWLAb3KMRT6nd8Gt9bmUBi9+iX6tBdYfOY81Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/project-service": "8.63.0",
|
||||
"@typescript-eslint/tsconfig-utils": "8.63.0",
|
||||
"@typescript-eslint/types": "8.63.0",
|
||||
"@typescript-eslint/visitor-keys": "8.63.0",
|
||||
"debug": "^4.4.3",
|
||||
"minimatch": "^10.2.2",
|
||||
"semver": "^7.7.3",
|
||||
"tinyglobby": "^0.2.15",
|
||||
"ts-api-utils": "^2.5.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/project-service": {
|
||||
"version": "8.63.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.63.0.tgz",
|
||||
"integrity": "sha512-e5dh0/UI0ok53AlZ5wRkXCB32z/f2jUZqPR/ygAw5WYaSw8j9EoJWlS7wQjr/dmOaqWjnPIn2m+HhVPCMWGZVQ==",
|
||||
@@ -1947,6 +2158,23 @@
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/tsconfig-utils": {
|
||||
"version": "8.63.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.63.0.tgz",
|
||||
"integrity": "sha512-sUAbkulqBAsncKnbRP3+7CtQFRKicexnj7ZwNC6ddCR7EmrXvjvdCYMJbUIqMd6lwoEriZjwLo08aS5tSjVMHg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "8.63.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.63.0.tgz",
|
||||
@@ -1965,48 +2193,6 @@
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/tsconfig-utils": {
|
||||
"version": "8.63.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.63.0.tgz",
|
||||
"integrity": "sha512-sUAbkulqBAsncKnbRP3+7CtQFRKicexnj7ZwNC6ddCR7EmrXvjvdCYMJbUIqMd6lwoEriZjwLo08aS5tSjVMHg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "8.63.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.63.0.tgz",
|
||||
"integrity": "sha512-Nzzh/OGxVCOjObjaj1CQF2RUasyYy2Jfuh+zZ3PjLzG2fYRriAiZLib9UKtO+CpQAS3YHiAS+ckZDclwqI1TPA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.63.0",
|
||||
"@typescript-eslint/typescript-estree": "8.63.0",
|
||||
"@typescript-eslint/utils": "8.63.0",
|
||||
"debug": "^4.4.3",
|
||||
"ts-api-utils": "^2.5.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "8.63.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.63.0.tgz",
|
||||
@@ -2021,58 +2207,6 @@
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "8.63.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.63.0.tgz",
|
||||
"integrity": "sha512-ygBkU+B7ex5UI/gKhaqexWev79uISfIv7XQCRNYO/jmD8rGLPyWLAb3KMRT6nd8Gt9bmUBi9+iX6tBdYfOY81Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/project-service": "8.63.0",
|
||||
"@typescript-eslint/tsconfig-utils": "8.63.0",
|
||||
"@typescript-eslint/types": "8.63.0",
|
||||
"@typescript-eslint/visitor-keys": "8.63.0",
|
||||
"debug": "^4.4.3",
|
||||
"minimatch": "^10.2.2",
|
||||
"semver": "^7.7.3",
|
||||
"tinyglobby": "^0.2.15",
|
||||
"ts-api-utils": "^2.5.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "8.63.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.63.0.tgz",
|
||||
"integrity": "sha512-fUKaeAvrTuQg/Tgt3nliAUSZHJM6DlCcfyEmxCvlX8kieWSStBX+5O5Fnidtc3i2JrH+9c/GL4RY2iasd/GPTA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.9.1",
|
||||
"@typescript-eslint/scope-manager": "8.63.0",
|
||||
"@typescript-eslint/types": "8.63.0",
|
||||
"@typescript-eslint/typescript-estree": "8.63.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "8.63.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.63.0.tgz",
|
||||
@@ -2231,9 +2365,6 @@
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2248,9 +2379,6 @@
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2265,9 +2393,6 @@
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2282,9 +2407,6 @@
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2299,9 +2421,6 @@
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2316,9 +2435,6 @@
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2333,9 +2449,6 @@
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2350,9 +2463,6 @@
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2367,9 +2477,6 @@
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -2384,9 +2491,6 @@
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -3267,9 +3371,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint": {
|
||||
"version": "10.6.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-10.6.0.tgz",
|
||||
"integrity": "sha512-6lVbcqSodALYo+4ELD0heG6lFiFxnLMuLkiMi2qV8LMp54N8tE8FT1GMH+ev4Ti00nFjNze2+Su6DsV5OQW3Dg==",
|
||||
"version": "10.7.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-10.7.0.tgz",
|
||||
"integrity": "sha512-GVTD7s1vdIl6UYvAfriOPeY1Df8LIZjfofLvHwde+erDHGGuHyuM6xoxRxmHiebhYuD2p1vN4wWh0XzPARSGDQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"workspaces": [
|
||||
@@ -3409,10 +3513,164 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "8.64.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.64.0.tgz",
|
||||
"integrity": "sha512-CXEaFdYXjSTgKhisNkwCcJwTP8Pl+fmRrEQrri4nm3vU743bALrxzLmq7fHG/7e6a5xO0lDYeURpZmBuhHk54w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.64.0",
|
||||
"@typescript-eslint/visitor-keys": "8.64.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/types": {
|
||||
"version": "8.64.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.64.0.tgz",
|
||||
"integrity": "sha512-qjhfuTfLXjA4IOzXvz0rTjT01BqEiIgPoUeMwiEjnaHKJMTNo8rH5pYW1a2L/0Dnux2fPC85AeyJoWaGa8WxTA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/utils": {
|
||||
"version": "8.64.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.64.0.tgz",
|
||||
"integrity": "sha512-aJUGVB3+U0htrrCjoA8qukw8cm8fNCGAxK/tVoS70k8aeb7DETKeFozRiVFIwEeN9WJLsjaP3ph8I60tY2XZoQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.9.1",
|
||||
"@typescript-eslint/scope-manager": "8.64.0",
|
||||
"@typescript-eslint/types": "8.64.0",
|
||||
"@typescript-eslint/typescript-estree": "8.64.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "8.64.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.64.0.tgz",
|
||||
"integrity": "sha512-Pztpsn1aCE1oWDvDEfUk31nngvvF7vUB5SwHFEaZIFpvw7WJtqUHHL4plBZDA9HfWJJjL13BdG0YrJInTUvoVA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/project-service": "8.64.0",
|
||||
"@typescript-eslint/tsconfig-utils": "8.64.0",
|
||||
"@typescript-eslint/types": "8.64.0",
|
||||
"@typescript-eslint/visitor-keys": "8.64.0",
|
||||
"debug": "^4.4.3",
|
||||
"minimatch": "^10.2.2",
|
||||
"semver": "^7.7.3",
|
||||
"tinyglobby": "^0.2.15",
|
||||
"ts-api-utils": "^2.5.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/project-service": {
|
||||
"version": "8.64.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.64.0.tgz",
|
||||
"integrity": "sha512-tk4WpOJ6IEbGrVHaNmM0YRrwAD3exZlIK3iadQNAxh4YKk6jvUQ4ecq18n+v7+meh+cJ3j+D8nbk8sRKhlwLQg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/tsconfig-utils": "^8.64.0",
|
||||
"@typescript-eslint/types": "^8.64.0",
|
||||
"debug": "^4.4.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/tsconfig-utils": {
|
||||
"version": "8.64.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.64.0.tgz",
|
||||
"integrity": "sha512-2yo8rRNKuzbVWQp5kslhANqZ2uDAeROQHBRZNPu8JDsHmeFNj/XJJhX/FhNUWmkHHvoNsKa6+tHJiig87EzsQw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "8.64.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.64.0.tgz",
|
||||
"integrity": "sha512-mrtuL8Nsn6gi2H4mo5KMTp823M+3Q19Ew/i+Zlikq20tIMm99C3Ez0dCmkWWnxut20esQvTg8aUSEhMcAOXhEw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.64.0",
|
||||
"eslint-visitor-keys": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-jest/node_modules/eslint-visitor-keys": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz",
|
||||
"integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": "^20.19.0 || ^22.13.0 || >=24"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-n": {
|
||||
"version": "18.2.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-18.2.1.tgz",
|
||||
"integrity": "sha512-aO3C9//yq8JIvYOi/T+jPvcZ9hZzpwzbR8esrYpFtgE9vpbyM8kn42AQOtIqYspVmpaSWr8X+nrlQuAJYxXAaw==",
|
||||
"version": "18.2.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-18.2.2.tgz",
|
||||
"integrity": "sha512-gOO0lIqwEjZ750kv9/SptCWArUoAZXJoBr0vYWTO2dCBxctHUXlBIigiC8xuxxr/NKqgIT6Ehz1xRcilj8a5cA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -5749,9 +6007,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/prettier": {
|
||||
"version": "3.9.4",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.4.tgz",
|
||||
"integrity": "sha512-yWG/o/4oJfo036EKAfK6ACAoDOfHeRHx4tuxkfBZiauURiaSmYwlpOr5LQqKtIkRD2z1PLteme2WoxEnj4tHTg==",
|
||||
"version": "3.9.5",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.5.tgz",
|
||||
"integrity": "sha512-/FVl766LpUfB5vXgCYOYa0MeV/441Ia99AeICQIQFTY/Nw0roZwULcXpku5i1/m5kt/baz+s4Zogspd839HSMg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
|
||||
+5
-5
@@ -42,7 +42,7 @@
|
||||
"author": "GitHub",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/cache": "^6.1.0",
|
||||
"@actions/cache": "^6.2.0",
|
||||
"@actions/core": "^3.0.1",
|
||||
"@actions/exec": "^3.0.0",
|
||||
"@actions/glob": "^0.7.0",
|
||||
@@ -55,20 +55,20 @@
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@jest/globals": "^30.4.1",
|
||||
"@types/node": "^26.0.0",
|
||||
"@types/node": "^26.1.1",
|
||||
"@types/semver": "^7.7.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.62.0",
|
||||
"@typescript-eslint/parser": "^8.62.0",
|
||||
"@vercel/ncc": "^0.44.0",
|
||||
"eslint": "^10.5.0",
|
||||
"eslint": "^10.7.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-jest": "^29.15.4",
|
||||
"eslint-plugin-n": "^18.1.0",
|
||||
"eslint-plugin-n": "^18.2.2",
|
||||
"globals": "^17.7.0",
|
||||
"husky": "^9.1.7",
|
||||
"jest": "^30.4.2",
|
||||
"lint-staged": "^17.0.8",
|
||||
"prettier": "^3.9.1",
|
||||
"prettier": "^3.9.5",
|
||||
"ts-jest": "^29.4.11",
|
||||
"typescript": "^6.0.3"
|
||||
},
|
||||
|
||||
+20
-5
@@ -93,12 +93,27 @@ export function generate(
|
||||
}
|
||||
};
|
||||
|
||||
if (gpgPassphrase) {
|
||||
const gpgServer = {
|
||||
id: 'gpg.passphrase',
|
||||
passphrase: `\${env.${gpgPassphrase}}`
|
||||
// The maven-gpg-plugin reads the passphrase from the environment variable
|
||||
// named by the `gpg.passphraseEnvName` property (default MAVEN_GPG_PASSPHRASE).
|
||||
// Only configure it when the requested env var name differs from that default;
|
||||
// otherwise the plugin already reads the right variable and no extra settings
|
||||
// are needed. Writing `gpg.passphrase` to settings.xml is deprecated and fails
|
||||
// when the plugin's `bestPractices` mode is enabled.
|
||||
if (
|
||||
gpgPassphrase &&
|
||||
gpgPassphrase !== constants.MAVEN_GPG_PASSPHRASE_DEFAULT_ENV
|
||||
) {
|
||||
xmlObj.settings.profiles = {
|
||||
profile: {
|
||||
id: constants.GPG_PASSPHRASE_PROFILE_ID,
|
||||
properties: {
|
||||
'gpg.passphraseEnvName': gpgPassphrase
|
||||
}
|
||||
}
|
||||
};
|
||||
xmlObj.settings.activeProfiles = {
|
||||
activeProfile: constants.GPG_PASSPHRASE_PROFILE_ID
|
||||
};
|
||||
xmlObj.settings.servers.server.push(gpgServer);
|
||||
}
|
||||
|
||||
return xmlCreate(xmlObj).end({
|
||||
|
||||
+185
-9
@@ -12,6 +12,30 @@ const STATE_CACHE_PRIMARY_KEY = 'cache-primary-key';
|
||||
const CACHE_MATCHED_KEY = 'cache-matched-key';
|
||||
const CACHE_KEY_PREFIX = 'setup-java';
|
||||
|
||||
/**
|
||||
* An additional cache entry that is restored and saved independently of the
|
||||
* main dependency cache. Used for build-tool wrapper distributions that rarely
|
||||
* change (e.g. the Maven wrapper distribution) so that they are not evicted
|
||||
* every time a volatile dependency file such as pom.xml changes. See
|
||||
* https://github.com/actions/setup-java/issues/1095.
|
||||
*/
|
||||
interface AdditionalCache {
|
||||
/**
|
||||
* Short identifier for the cache, used to build its cache key and to scope
|
||||
* the state keys that carry information from restore to save.
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* Paths that make up this cache entry.
|
||||
*/
|
||||
path: string[];
|
||||
/**
|
||||
* Glob patterns whose hash forms the cache key. If no file matches, the
|
||||
* cache is skipped silently (the project simply does not use this feature).
|
||||
*/
|
||||
pattern: string[];
|
||||
}
|
||||
|
||||
interface PackageManager {
|
||||
id: 'maven' | 'gradle' | 'sbt';
|
||||
/**
|
||||
@@ -19,27 +43,36 @@ interface PackageManager {
|
||||
*/
|
||||
path: string[];
|
||||
pattern: string[];
|
||||
/**
|
||||
* Additional caches keyed independently of the main dependency cache.
|
||||
*/
|
||||
additionalCaches?: AdditionalCache[];
|
||||
}
|
||||
const supportedPackageManager: PackageManager[] = [
|
||||
{
|
||||
id: 'maven',
|
||||
path: [
|
||||
join(os.homedir(), '.m2', 'repository'),
|
||||
join(os.homedir(), '.m2', 'wrapper', 'dists')
|
||||
],
|
||||
path: [join(os.homedir(), '.m2', 'repository')],
|
||||
// https://github.com/actions/cache/blob/0638051e9af2c23d10bb70fa9beffcad6cff9ce3/examples.md#java---maven
|
||||
pattern: [
|
||||
'**/pom.xml',
|
||||
'**/.mvn/wrapper/maven-wrapper.properties',
|
||||
'**/.mvn/extensions.xml'
|
||||
],
|
||||
// The Maven wrapper distribution only depends on the wrapper properties,
|
||||
// which change very rarely, so it is cached separately from the local
|
||||
// repository. This keeps it available across the frequent pom.xml changes
|
||||
// that rotate the main cache key. See issue #1095.
|
||||
additionalCaches: [
|
||||
{
|
||||
name: 'maven-wrapper',
|
||||
path: [join(os.homedir(), '.m2', 'wrapper', 'dists')],
|
||||
pattern: ['**/.mvn/wrapper/maven-wrapper.properties']
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'gradle',
|
||||
path: [
|
||||
join(os.homedir(), '.gradle', 'caches'),
|
||||
join(os.homedir(), '.gradle', 'wrapper')
|
||||
],
|
||||
path: [join(os.homedir(), '.gradle', 'caches')],
|
||||
// https://github.com/actions/cache/blob/0638051e9af2c23d10bb70fa9beffcad6cff9ce3/examples.md#java---gradle
|
||||
pattern: [
|
||||
'**/*.gradle*',
|
||||
@@ -48,6 +81,17 @@ const supportedPackageManager: PackageManager[] = [
|
||||
'buildSrc/**/Dependencies.kt',
|
||||
'gradle/*.versions.toml',
|
||||
'**/versions.properties'
|
||||
],
|
||||
// The Gradle wrapper distribution only depends on the wrapper properties,
|
||||
// which change very rarely, so it is cached separately from the Gradle
|
||||
// caches. This keeps it available across the frequent *.gradle* changes
|
||||
// that rotate the main cache key. See issue #269.
|
||||
additionalCaches: [
|
||||
{
|
||||
name: 'gradle-wrapper',
|
||||
path: [join(os.homedir(), '.gradle', 'wrapper')],
|
||||
pattern: ['**/gradle-wrapper.properties']
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -87,6 +131,21 @@ function findPackageManager(id: string): PackageManager {
|
||||
return packageManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* State keys used to carry an additional cache's restore-time information over
|
||||
* to the post (save) action, scoped by the additional cache name.
|
||||
*/
|
||||
function additionalCachePrimaryKeyState(name: string): string {
|
||||
return `${STATE_CACHE_PRIMARY_KEY}-${name}`;
|
||||
}
|
||||
function additionalCacheMatchedKeyState(name: string): string {
|
||||
return `${CACHE_MATCHED_KEY}-${name}`;
|
||||
}
|
||||
|
||||
function buildCacheKey(id: string, fileHash: string): string {
|
||||
return `${CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${process.arch}-${id}-${fileHash}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* A function that generates a cache key to use.
|
||||
* Format of the generated key will be "${{ platform }}-${{ id }}-${{ fileHash }}"".
|
||||
@@ -105,7 +164,22 @@ async function computeCacheKey(
|
||||
`No file in ${process.cwd()} matched to [${pattern}], make sure you have checked out the target repository`
|
||||
);
|
||||
}
|
||||
return `${CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${process.arch}-${packageManager.id}-${fileHash}`;
|
||||
return buildCacheKey(packageManager.id, fileHash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the cache key for an additional cache. Unlike {@link computeCacheKey}
|
||||
* this returns undefined (instead of throwing) when no file matches the pattern,
|
||||
* because additional caches are optional features that many projects do not use.
|
||||
*/
|
||||
async function computeAdditionalCacheKey(
|
||||
additionalCache: AdditionalCache
|
||||
): Promise<string | undefined> {
|
||||
const fileHash = await glob.hashFiles(additionalCache.pattern.join('\n'));
|
||||
if (!fileHash) {
|
||||
return undefined;
|
||||
}
|
||||
return buildCacheKey(additionalCache.name, fileHash);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,6 +204,40 @@ export async function restore(id: string, cacheDependencyPath: string) {
|
||||
core.setOutput('cache-hit', false);
|
||||
core.info(`${packageManager.id} cache is not found`);
|
||||
}
|
||||
|
||||
for (const additionalCache of packageManager.additionalCaches ?? []) {
|
||||
await restoreAdditionalCache(additionalCache);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore an additional cache (e.g. a build-tool wrapper distribution) that is
|
||||
* keyed independently of the main dependency cache so that it survives changes
|
||||
* to volatile dependency files. Skips silently when the project does not use
|
||||
* the corresponding feature.
|
||||
*/
|
||||
async function restoreAdditionalCache(additionalCache: AdditionalCache) {
|
||||
const primaryKey = await computeAdditionalCacheKey(additionalCache);
|
||||
if (!primaryKey) {
|
||||
core.debug(
|
||||
`No file matched [${additionalCache.pattern}] for the ${additionalCache.name} cache, skipping.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
core.debug(`${additionalCache.name} primary key is ${primaryKey}`);
|
||||
core.saveState(
|
||||
additionalCachePrimaryKeyState(additionalCache.name),
|
||||
primaryKey
|
||||
);
|
||||
|
||||
const matchedKey = await cache.restoreCache(additionalCache.path, primaryKey);
|
||||
if (matchedKey) {
|
||||
core.saveState(
|
||||
additionalCacheMatchedKeyState(additionalCache.name),
|
||||
matchedKey
|
||||
);
|
||||
core.info(`${additionalCache.name} cache restored from key: ${matchedKey}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,6 +251,10 @@ export async function save(id: string) {
|
||||
// Inputs are re-evaluated before the post action, so we want the original key used for restore
|
||||
const primaryKey = core.getState(STATE_CACHE_PRIMARY_KEY);
|
||||
|
||||
for (const additionalCache of packageManager.additionalCaches ?? []) {
|
||||
await saveAdditionalCache(packageManager, additionalCache);
|
||||
}
|
||||
|
||||
if (!primaryKey) {
|
||||
core.warning('Error retrieving key from state.');
|
||||
return;
|
||||
@@ -180,6 +292,70 @@ export async function save(id: string) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save an additional cache under its own key. Skips when no key was recorded at
|
||||
* restore time (feature unused) or when the exact key was already restored.
|
||||
*/
|
||||
async function saveAdditionalCache(
|
||||
packageManager: PackageManager,
|
||||
additionalCache: AdditionalCache
|
||||
) {
|
||||
const primaryKey = core.getState(
|
||||
additionalCachePrimaryKeyState(additionalCache.name)
|
||||
);
|
||||
const matchedKey = core.getState(
|
||||
additionalCacheMatchedKeyState(additionalCache.name)
|
||||
);
|
||||
|
||||
if (!primaryKey) {
|
||||
// The feature is not used by this project, nothing to save.
|
||||
core.debug(
|
||||
`No primary key for the ${additionalCache.name} cache, not saving cache.`
|
||||
);
|
||||
return;
|
||||
} else if (matchedKey === primaryKey) {
|
||||
core.info(
|
||||
`Cache hit occurred on the ${additionalCache.name} primary key ${primaryKey}, not saving cache.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const cacheId = await cache.saveCache(additionalCache.path, primaryKey);
|
||||
if (cacheId === -1) {
|
||||
core.debug(
|
||||
`${additionalCache.name} cache was not saved for the key: ${primaryKey}`
|
||||
);
|
||||
return;
|
||||
}
|
||||
core.info(
|
||||
`${additionalCache.name} cache saved with the key: ${primaryKey}`
|
||||
);
|
||||
} catch (error) {
|
||||
const err = error as Error;
|
||||
|
||||
if (err.name === cache.ValidationError.name) {
|
||||
// The cache paths did not resolve, e.g. the wrapper distribution was
|
||||
// never downloaded because a system build tool was used or the download
|
||||
// failed. Optional wrapper caches must not fail the post step, so skip.
|
||||
core.debug(
|
||||
`${additionalCache.name} cache paths do not exist, not saving cache: ${err.message}`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (err.name === cache.ReserveCacheError.name) {
|
||||
core.info(err.message);
|
||||
} else {
|
||||
if (isProbablyGradleDaemonProblem(packageManager, err)) {
|
||||
core.warning(
|
||||
'Failed to save Gradle cache on Windows. If tar.exe reported "Permission denied", try to run Gradle with `--no-daemon` option. Refer to https://github.com/actions/cache/issues/454 for details.'
|
||||
);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param packageManager the specified package manager by user
|
||||
* @param error the error thrown by the saveCache
|
||||
|
||||
@@ -21,6 +21,14 @@ export const INPUT_GPG_PASSPHRASE = 'gpg-passphrase';
|
||||
export const INPUT_DEFAULT_GPG_PRIVATE_KEY = undefined;
|
||||
export const INPUT_DEFAULT_GPG_PASSPHRASE = 'GPG_PASSPHRASE';
|
||||
|
||||
// The default name of the environment variable the maven-gpg-plugin reads the
|
||||
// passphrase from (property `gpg.passphraseEnvName`). When the configured
|
||||
// passphrase env var name matches this, no extra configuration is required.
|
||||
export const MAVEN_GPG_PASSPHRASE_DEFAULT_ENV = 'MAVEN_GPG_PASSPHRASE';
|
||||
|
||||
// Id of the settings.xml profile used to set `gpg.passphraseEnvName`.
|
||||
export const GPG_PASSPHRASE_PROFILE_ID = 'setup-java-gpg';
|
||||
|
||||
export const INPUT_CACHE = 'cache';
|
||||
export const INPUT_CACHE_DEPENDENCY_PATH = 'cache-dependency-path';
|
||||
export const INPUT_JOB_STATUS = 'job-status';
|
||||
|
||||
@@ -4,7 +4,11 @@ import * as fs from 'fs';
|
||||
import semver from 'semver';
|
||||
import path from 'path';
|
||||
import * as httpm from '@actions/http-client';
|
||||
import {getToolcachePath, isVersionSatisfies} from '../util.js';
|
||||
import {
|
||||
convertVersionToSemver,
|
||||
getToolcachePath,
|
||||
isVersionSatisfies
|
||||
} from '../util.js';
|
||||
import {
|
||||
JavaDownloadRelease,
|
||||
JavaInstallerOptions,
|
||||
@@ -19,6 +23,7 @@ export abstract class JavaBase {
|
||||
protected architecture: string;
|
||||
protected packageType: string;
|
||||
protected stable: boolean;
|
||||
protected latest: boolean;
|
||||
protected checkLatest: boolean;
|
||||
protected setDefault: boolean;
|
||||
protected verifySignature: boolean;
|
||||
@@ -33,9 +38,11 @@ export abstract class JavaBase {
|
||||
maxRetries: 3
|
||||
});
|
||||
|
||||
({version: this.version, stable: this.stable} = this.normalizeVersion(
|
||||
installerOptions.version
|
||||
));
|
||||
({
|
||||
version: this.version,
|
||||
stable: this.stable,
|
||||
latest: this.latest
|
||||
} = this.normalizeVersion(installerOptions.version));
|
||||
this.architecture = installerOptions.architecture || os.arch();
|
||||
this.packageType = installerOptions.packageType;
|
||||
this.checkLatest = installerOptions.checkLatest;
|
||||
@@ -62,7 +69,7 @@ export abstract class JavaBase {
|
||||
}
|
||||
|
||||
let foundJava = this.findInToolcache();
|
||||
if (foundJava && !this.checkLatest) {
|
||||
if (foundJava && !this.checkLatest && !this.latest) {
|
||||
core.info(`Resolved Java ${foundJava.version} from tool-cache`);
|
||||
} else {
|
||||
core.info('Trying to resolve the latest version from remote');
|
||||
@@ -263,6 +270,30 @@ export abstract class JavaBase {
|
||||
|
||||
protected normalizeVersion(version: string) {
|
||||
let stable = true;
|
||||
const latest = false;
|
||||
|
||||
// Support the `latest` alias (case-insensitive), which floats to the newest
|
||||
// available stable/GA release. It is translated to the SemVer wildcard `x`
|
||||
// so the existing "newest satisfying version wins" resolution applies.
|
||||
const normalized = version.trim().toLowerCase();
|
||||
if (normalized === 'latest') {
|
||||
return {
|
||||
version: 'x',
|
||||
stable: true,
|
||||
latest: true
|
||||
};
|
||||
}
|
||||
|
||||
// Reject `latest` combined with any qualifier (e.g. `latest-ea`). Such inputs
|
||||
// would otherwise have their `-ea` suffix stripped and fall through to the
|
||||
// generic SemVer check, which fails with a confusing "'latest' is not valid
|
||||
// SemVer" message even though `latest` is a supported value. Fail early with a
|
||||
// targeted explanation instead.
|
||||
if (normalized.startsWith('latest')) {
|
||||
throw new Error(
|
||||
`The 'latest' alias resolves stable (GA) releases only and cannot be combined with '-ea' or other qualifiers (received '${version}'). Use 'latest' on its own, or specify a concrete version.`
|
||||
);
|
||||
}
|
||||
|
||||
if (version.endsWith('-ea')) {
|
||||
version = version.replace(/-ea$/, '');
|
||||
@@ -273,6 +304,15 @@ export abstract class JavaBase {
|
||||
stable = false;
|
||||
}
|
||||
|
||||
// Java uses a versioning scheme (JEP 322) that can contain more numeric
|
||||
// fields than SemVer allows, e.g. '18.0.1.1' or '11.0.9.1'. Convert such
|
||||
// exact versions to SemVer build notation ('18.0.1+1') so they are
|
||||
// accepted. Ranges and versions that already carry build metadata are
|
||||
// left untouched.
|
||||
if (/^\d+(\.\d+){3,}$/.test(version)) {
|
||||
version = convertVersionToSemver(version);
|
||||
}
|
||||
|
||||
if (!semver.validRange(version)) {
|
||||
throw new Error(
|
||||
`The string '${version}' is not valid SemVer notation for a Java version. Please check README file for code snippets and more detailed information`
|
||||
@@ -281,7 +321,8 @@ export abstract class JavaBase {
|
||||
|
||||
return {
|
||||
version,
|
||||
stable
|
||||
stable,
|
||||
latest
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -59,10 +59,28 @@ export class CorrettoDistribution extends JavaBase {
|
||||
if (!this.stable) {
|
||||
throw new Error('Early access versions are not supported');
|
||||
}
|
||||
const availableVersions = await this.getAvailableVersions();
|
||||
|
||||
// The `latest` alias is normalized to the SemVer wildcard, but Corretto
|
||||
// matches on an exact major version, so resolve it to the newest available
|
||||
// major from Corretto's own list.
|
||||
if (this.latest) {
|
||||
const majors = availableVersions
|
||||
.map(item => parseInt(item.version, 10))
|
||||
.filter(major => Number.isFinite(major) && major > 0);
|
||||
|
||||
if (majors.length === 0) {
|
||||
throw new Error(
|
||||
'Could not determine the latest available Corretto major version from remote metadata'
|
||||
);
|
||||
}
|
||||
|
||||
version = Math.max(...majors).toString();
|
||||
}
|
||||
|
||||
if (version.includes('.')) {
|
||||
throw new Error('Only major versions are supported');
|
||||
}
|
||||
const availableVersions = await this.getAvailableVersions();
|
||||
const matchingVersions = availableVersions
|
||||
.filter(item => item.version == version)
|
||||
.map(item => {
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
TemurinImplementation
|
||||
} from './temurin/installer.js';
|
||||
import {LibericaDistributions} from './liberica/installer.js';
|
||||
import {LibericaNikDistributions} from './liberica-nik/installer.js';
|
||||
import {MicrosoftDistributions} from './microsoft/installer.js';
|
||||
import {SemeruDistribution} from './semeru/installer.js';
|
||||
import {CorrettoDistribution} from './corretto/installer.js';
|
||||
@@ -28,6 +29,7 @@ enum JavaDistribution {
|
||||
Temurin = 'temurin',
|
||||
Zulu = 'zulu',
|
||||
Liberica = 'liberica',
|
||||
LibericaNik = 'liberica-nik',
|
||||
JdkFile = 'jdkfile',
|
||||
Microsoft = 'microsoft',
|
||||
Semeru = 'semeru',
|
||||
@@ -69,6 +71,8 @@ export function getJavaDistribution(
|
||||
return new ZuluDistribution(installerOptions);
|
||||
case JavaDistribution.Liberica:
|
||||
return new LibericaDistributions(installerOptions);
|
||||
case JavaDistribution.LibericaNik:
|
||||
return new LibericaNikDistributions(installerOptions);
|
||||
case JavaDistribution.Microsoft:
|
||||
return new MicrosoftDistributions(installerOptions);
|
||||
case JavaDistribution.Semeru:
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
extractJdkFile,
|
||||
getDownloadArchiveExtension,
|
||||
getGitHubHttpHeaders,
|
||||
getLatestMajorVersion,
|
||||
getNextPageUrlFromLinkHeader,
|
||||
isVersionSatisfies,
|
||||
MAX_PAGINATION_PAGES,
|
||||
@@ -119,6 +120,13 @@ export class GraalVMDistribution extends JavaBase {
|
||||
return this.findEABuildDownloadUrl(`${range}-ea`);
|
||||
}
|
||||
|
||||
// The `latest` alias is normalized to the SemVer wildcard. Oracle GraalVM
|
||||
// builds its download URLs from a concrete major and has no endpoint to list
|
||||
// releases, so resolve the newest available GA major from the Adoptium API.
|
||||
if (this.latest) {
|
||||
range = (await getLatestMajorVersion(this.http)).toString();
|
||||
}
|
||||
|
||||
const {platform, extension, major} = this.validateStableBuildRequest(range);
|
||||
|
||||
const fileUrl = this.constructFileUrl(
|
||||
@@ -203,6 +211,9 @@ export class GraalVMDistribution extends JavaBase {
|
||||
if (statusCode === HttpCodes.NotFound) {
|
||||
// Create the standard error with additional hint about checking the download URL
|
||||
const error = this.createVersionNotFoundError(range);
|
||||
if (this.latest) {
|
||||
error.message += `\nThe latest Java major version (${range}) is not yet available for the ${this.distribution} distribution. Please specify a concrete version instead of 'latest'.`;
|
||||
}
|
||||
error.message += `\nPlease check if this version is available at ${GRAALVM_DOWNLOAD_URL} . Pick a version from the list.`;
|
||||
throw error;
|
||||
}
|
||||
@@ -354,7 +365,27 @@ export class GraalVMCommunityDistribution extends GraalVMDistribution {
|
||||
}
|
||||
|
||||
const arch = this.getSupportedArchitecture();
|
||||
const {platform, extension} = this.validateStableBuildRequest(range);
|
||||
|
||||
// GraalVM Community publishes its releases on GitHub, so the `latest` alias
|
||||
// (normalized to the SemVer wildcard `x`) can float to the newest GA it
|
||||
// actually ships. Unlike Oracle GraalVM (which has no listing endpoint and
|
||||
// must derive the newest major from the Adoptium API), we match against the
|
||||
// real release list here, so `latest` never fails when GraalVM lags behind a
|
||||
// brand-new Java major.
|
||||
let platform: OsVersions;
|
||||
let extension: string;
|
||||
if (this.latest) {
|
||||
if (this.packageType !== 'jdk') {
|
||||
throw new Error(
|
||||
`${this.distribution} provides only the \`jdk\` package type`
|
||||
);
|
||||
}
|
||||
platform = this.getPlatform();
|
||||
extension = getDownloadArchiveExtension();
|
||||
} else {
|
||||
({platform, extension} = this.validateStableBuildRequest(range));
|
||||
}
|
||||
|
||||
// GraalVM Community asset names embed the platform, architecture and
|
||||
// archive type, e.g. `graalvm-community-jdk-21.0.2_linux-x64_bin.tar.gz`.
|
||||
const assetSuffix = `_${platform}-${arch}_bin.${extension}`;
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
import {JavaBase} from '../base-installer.js';
|
||||
import {
|
||||
JavaDownloadRelease,
|
||||
JavaInstallerOptions,
|
||||
JavaInstallerResults
|
||||
} from '../base-models.js';
|
||||
import semver from 'semver';
|
||||
import {
|
||||
extractJdkFile,
|
||||
getDownloadArchiveExtension,
|
||||
isVersionSatisfies,
|
||||
renameWinArchive
|
||||
} from '../../util.js';
|
||||
import * as core from '@actions/core';
|
||||
import {ArchitectureOptions, NikVersion, OsVersions} from './models.js';
|
||||
import * as tc from '@actions/tool-cache';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
const supportedPlatform = `'linux', 'macos', 'windows'`;
|
||||
|
||||
const supportedArchitectures = `'x64', 'aarch64'`;
|
||||
|
||||
export class LibericaNikDistributions extends JavaBase {
|
||||
constructor(installerOptions: JavaInstallerOptions) {
|
||||
super('Liberica_NIK', installerOptions);
|
||||
}
|
||||
|
||||
protected async downloadTool(
|
||||
javaRelease: JavaDownloadRelease
|
||||
): Promise<JavaInstallerResults> {
|
||||
core.info(
|
||||
`Downloading Java ${javaRelease.version} (${this.distribution}) from ${javaRelease.url} ...`
|
||||
);
|
||||
let javaArchivePath = await tc.downloadTool(javaRelease.url);
|
||||
|
||||
core.info(`Extracting Java archive...`);
|
||||
const extension = getDownloadArchiveExtension();
|
||||
if (process.platform === 'win32') {
|
||||
javaArchivePath = renameWinArchive(javaArchivePath);
|
||||
}
|
||||
const extractedJavaPath = await extractJdkFile(javaArchivePath, extension);
|
||||
|
||||
const archiveName = fs.readdirSync(extractedJavaPath)[0];
|
||||
const archivePath = path.join(extractedJavaPath, archiveName);
|
||||
|
||||
const javaPath = await tc.cacheDir(
|
||||
archivePath,
|
||||
this.toolcacheFolderName,
|
||||
this.getToolcacheVersionName(javaRelease.version),
|
||||
this.architecture
|
||||
);
|
||||
|
||||
return {version: javaRelease.version, path: javaPath};
|
||||
}
|
||||
|
||||
protected async findPackageForDownload(
|
||||
range: string
|
||||
): Promise<JavaDownloadRelease> {
|
||||
const availableVersionsRaw = await this.getAvailableVersions();
|
||||
|
||||
const availableVersions = availableVersionsRaw
|
||||
.map(item => {
|
||||
const jdkVersion = this.getJdkVersion(item);
|
||||
return jdkVersion ? {url: item.downloadUrl, version: jdkVersion} : null;
|
||||
})
|
||||
.filter((item): item is {url: string; version: string} => item !== null);
|
||||
|
||||
const satisfiedVersion = availableVersions
|
||||
.filter(item => isVersionSatisfies(range, item.version))
|
||||
.sort((a, b) => -semver.compareBuild(a.version, b.version))[0];
|
||||
|
||||
if (!satisfiedVersion) {
|
||||
const availableVersionStrings = availableVersions.map(
|
||||
item => item.version
|
||||
);
|
||||
throw this.createVersionNotFoundError(range, availableVersionStrings);
|
||||
}
|
||||
|
||||
return satisfiedVersion;
|
||||
}
|
||||
|
||||
private async getAvailableVersions(): Promise<NikVersion[]> {
|
||||
if (core.isDebug()) {
|
||||
console.time('Retrieving available versions for Liberica NIK took'); // eslint-disable-line no-console
|
||||
}
|
||||
const url = this.prepareAvailableVersionsUrl();
|
||||
|
||||
core.debug(`Gathering available versions from '${url}'`);
|
||||
|
||||
const availableVersions =
|
||||
(await this.http.getJson<NikVersion[]>(url)).result ?? [];
|
||||
|
||||
if (core.isDebug()) {
|
||||
core.startGroup('Print information about available versions');
|
||||
console.timeEnd('Retrieving available versions for Liberica NIK took'); // eslint-disable-line no-console
|
||||
core.debug(`Available versions: [${availableVersions.length}]`);
|
||||
core.debug(availableVersions.map(item => item.version).join(', '));
|
||||
core.endGroup();
|
||||
}
|
||||
|
||||
return availableVersions;
|
||||
}
|
||||
|
||||
private prepareAvailableVersionsUrl() {
|
||||
const urlOptions = {
|
||||
os: this.getPlatformOption(),
|
||||
'bundle-type': this.getBundleType(),
|
||||
...this.getArchitectureOptions(),
|
||||
'build-type': this.stable ? 'all' : 'ea',
|
||||
'installation-type': 'archive',
|
||||
fields: 'downloadUrl,version,components,component,embedded'
|
||||
};
|
||||
|
||||
const searchParams = new URLSearchParams(urlOptions).toString();
|
||||
|
||||
return `https://api.bell-sw.com/v1/nik/releases?${searchParams}`;
|
||||
}
|
||||
|
||||
// NIK's top-level `version` is the GraalVM/NIK version; the JDK version that
|
||||
// users select on lives in the embedded `liberica` component.
|
||||
private getJdkVersion(release: NikVersion): string | null {
|
||||
const liberica = release.components?.find(
|
||||
component => component.component === 'liberica'
|
||||
);
|
||||
return liberica ? this.convertVersionToSemver(liberica.version) : null;
|
||||
}
|
||||
|
||||
// The `full` bundle adds JavaFX/Swing GUI support; otherwise use `standard`.
|
||||
private getBundleType(): string {
|
||||
const [, feature] = this.packageType.split('+');
|
||||
return feature?.includes('fx') ? 'full' : 'standard';
|
||||
}
|
||||
|
||||
private getArchitectureOptions(): ArchitectureOptions {
|
||||
const arch = this.distributionArchitecture();
|
||||
switch (arch) {
|
||||
case 'x64':
|
||||
return {bitness: '64', arch: 'x86'};
|
||||
case 'aarch64':
|
||||
return {bitness: '64', arch: 'arm'};
|
||||
default:
|
||||
throw new Error(
|
||||
`Architecture '${this.architecture}' is not supported. Supported architectures: ${supportedArchitectures}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private getPlatformOption(
|
||||
platform: NodeJS.Platform = process.platform
|
||||
): OsVersions {
|
||||
switch (platform) {
|
||||
case 'darwin':
|
||||
return 'macos';
|
||||
case 'win32':
|
||||
case 'cygwin':
|
||||
return 'windows';
|
||||
case 'linux':
|
||||
return 'linux';
|
||||
default:
|
||||
throw new Error(
|
||||
`Platform '${platform}' is not supported. Supported platforms: ${supportedPlatform}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// JDK versions come as strings like '25.0.1+16', '23+38' or '11.0.15.1+2'.
|
||||
// Normalize them to valid SemVer while preserving build metadata so newer
|
||||
// NIK builds of the same JDK sort ahead of older ones.
|
||||
private convertVersionToSemver(jdkVersion: string): string {
|
||||
const [main, build] = jdkVersion.split('+');
|
||||
const parts = main.split('.');
|
||||
while (parts.length < 3) {
|
||||
parts.push('0');
|
||||
}
|
||||
const base = parts.slice(0, 3).join('.');
|
||||
const buildMeta = [...parts.slice(3), ...(build ? [build] : [])];
|
||||
return buildMeta.length ? `${base}+${buildMeta.join('.')}` : base;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// Models from https://api.bell-sw.com/api.html (NIK product)
|
||||
|
||||
export type Bitness = '32' | '64';
|
||||
export type ArchType = 'arm' | 'ppc' | 'sparc' | 'x86';
|
||||
|
||||
export type OsVersions = 'linux' | 'linux-musl' | 'macos' | 'windows';
|
||||
|
||||
export interface ArchitectureOptions {
|
||||
bitness: Bitness;
|
||||
arch: ArchType;
|
||||
}
|
||||
|
||||
export interface NikComponent {
|
||||
component: string;
|
||||
version: string;
|
||||
embedded?: boolean;
|
||||
}
|
||||
|
||||
export interface NikVersion {
|
||||
// The main Liberica NIK VM bundle download URL.
|
||||
downloadUrl: string;
|
||||
// NIK/GraalVM version (e.g. '24.1.0+1'), kept for logging only.
|
||||
version: string;
|
||||
// The embedded `liberica` component carries the actual JDK version.
|
||||
components: NikComponent[];
|
||||
}
|
||||
@@ -22,6 +22,12 @@ export class LocalDistribution extends JavaBase {
|
||||
}
|
||||
|
||||
public async setupJava(): Promise<JavaInstallerResults> {
|
||||
if (this.latest) {
|
||||
throw new Error(
|
||||
"The 'latest' version alias is not supported for the 'jdkfile' distribution. Please specify a concrete version."
|
||||
);
|
||||
}
|
||||
|
||||
let foundJava = this.findInToolcache();
|
||||
|
||||
if (foundJava) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -13,6 +13,7 @@ import {
|
||||
import {
|
||||
extractJdkFile,
|
||||
getDownloadArchiveExtension,
|
||||
getLatestMajorVersion,
|
||||
renameWinArchive
|
||||
} from '../../util.js';
|
||||
import {HttpCodes} from '@actions/http-client';
|
||||
@@ -73,6 +74,14 @@ export class OracleDistribution extends JavaBase {
|
||||
const platform = this.getPlatform();
|
||||
const extension = getDownloadArchiveExtension();
|
||||
|
||||
// The `latest` alias is normalized to the SemVer wildcard. Oracle builds its
|
||||
// download URLs from a concrete major and has no endpoint to list releases,
|
||||
// so resolve the newest available GA major from the Adoptium API and use it.
|
||||
if (this.latest) {
|
||||
const latestMajor = await getLatestMajorVersion(this.http);
|
||||
range = latestMajor.toString();
|
||||
}
|
||||
|
||||
const isOnlyMajorProvided = !range.includes('.');
|
||||
const major = isOnlyMajorProvided ? range : range.split('.')[0];
|
||||
|
||||
@@ -113,6 +122,12 @@ export class OracleDistribution extends JavaBase {
|
||||
}
|
||||
}
|
||||
|
||||
if (this.latest) {
|
||||
const error = this.createVersionNotFoundError(range);
|
||||
error.message += `\nThe latest Java major version (${range}) is not yet available for the Oracle JDK distribution. Please specify a concrete version instead of 'latest'.`;
|
||||
throw error;
|
||||
}
|
||||
|
||||
throw this.createVersionNotFoundError(range);
|
||||
}
|
||||
|
||||
|
||||
+7
-1
@@ -186,8 +186,14 @@ async function installVersion(
|
||||
}
|
||||
|
||||
const result = await distribution.setupJava();
|
||||
|
||||
// When the `latest` alias is used, the literal input isn't a real version, so
|
||||
// pass the resolved version to the toolchains configuration instead.
|
||||
const isLatest = version.trim().toLowerCase() === 'latest';
|
||||
const toolchainVersion = isLatest ? result.version : version;
|
||||
|
||||
await toolchains.configureToolchains(
|
||||
version,
|
||||
toolchainVersion,
|
||||
distributionName,
|
||||
result.path,
|
||||
toolchainIds[toolchainId]
|
||||
|
||||
+13
-28
@@ -5,7 +5,6 @@ import * as core from '@actions/core';
|
||||
import * as io from '@actions/io';
|
||||
import * as constants from './constants.js';
|
||||
|
||||
import {getBooleanInput} from './util.js';
|
||||
import {create as xmlCreate} from 'xmlbuilder2';
|
||||
|
||||
interface JdkInfo {
|
||||
@@ -27,10 +26,6 @@ export async function configureToolchains(
|
||||
const settingsDirectory =
|
||||
core.getInput(constants.INPUT_SETTINGS_PATH) ||
|
||||
path.join(os.homedir(), constants.M2_DIR);
|
||||
const overwriteSettings = getBooleanInput(
|
||||
constants.INPUT_OVERWRITE_SETTINGS,
|
||||
true
|
||||
);
|
||||
|
||||
await createToolchainsSettings({
|
||||
jdkInfo: {
|
||||
@@ -39,19 +34,16 @@ export async function configureToolchains(
|
||||
id,
|
||||
jdkHome
|
||||
},
|
||||
settingsDirectory,
|
||||
overwriteSettings
|
||||
settingsDirectory
|
||||
});
|
||||
}
|
||||
|
||||
export async function createToolchainsSettings({
|
||||
jdkInfo,
|
||||
settingsDirectory,
|
||||
overwriteSettings
|
||||
settingsDirectory
|
||||
}: {
|
||||
jdkInfo: JdkInfo;
|
||||
settingsDirectory: string;
|
||||
overwriteSettings: boolean;
|
||||
}) {
|
||||
core.info(
|
||||
`Creating ${constants.MVN_TOOLCHAINS_FILE} for JDK version ${jdkInfo.version} from ${jdkInfo.vendor}`
|
||||
@@ -68,11 +60,7 @@ export async function createToolchainsSettings({
|
||||
jdkInfo.id,
|
||||
jdkInfo.jdkHome
|
||||
);
|
||||
await writeToolchainsFileToDisk(
|
||||
settingsDirectory,
|
||||
updatedToolchains,
|
||||
overwriteSettings
|
||||
);
|
||||
await writeToolchainsFileToDisk(settingsDirectory, updatedToolchains);
|
||||
}
|
||||
|
||||
// only exported for testing purposes
|
||||
@@ -172,22 +160,19 @@ async function readExistingToolchainsFile(directory: string) {
|
||||
return '';
|
||||
}
|
||||
|
||||
async function writeToolchainsFileToDisk(
|
||||
directory: string,
|
||||
settings: string,
|
||||
overwriteSettings: boolean
|
||||
) {
|
||||
async function writeToolchainsFileToDisk(directory: string, settings: string) {
|
||||
const location = path.join(directory, constants.MVN_TOOLCHAINS_FILE);
|
||||
const settingsExists = fs.existsSync(location);
|
||||
if (settingsExists && overwriteSettings) {
|
||||
core.info(`Overwriting existing file ${location}`);
|
||||
} else if (!settingsExists) {
|
||||
core.info(`Writing to ${location}`);
|
||||
// The toolchains file is produced by a non-destructive merge (existing JDK,
|
||||
// custom, and non-jdk toolchains are preserved – see generateToolchainDefinition),
|
||||
// so it is always safe to write it. Unlike settings.xml, it is therefore not
|
||||
// gated behind the `overwrite-settings` input; that would prevent subsequent
|
||||
// setup-java runs from registering additional JDKs and silently drop the
|
||||
// toolchain entries created by earlier runs.
|
||||
if (settingsExists) {
|
||||
core.info(`Updating existing file ${location}`);
|
||||
} else {
|
||||
core.info(
|
||||
`Skipping generation of ${location} because file already exists and overwriting is not enabled`
|
||||
);
|
||||
return;
|
||||
core.info(`Writing to ${location}`);
|
||||
}
|
||||
|
||||
return fs.writeFileSync(location, settings, {
|
||||
|
||||
+31
@@ -6,6 +6,7 @@ import * as cache from '@actions/cache';
|
||||
import * as core from '@actions/core';
|
||||
|
||||
import * as tc from '@actions/tool-cache';
|
||||
import * as httpm from '@actions/http-client';
|
||||
import {
|
||||
INPUT_JOB_STATUS,
|
||||
DISTRIBUTIONS_ONLY_MAJOR_VERSION
|
||||
@@ -382,3 +383,33 @@ export function renameWinArchive(javaArchivePath: string): string {
|
||||
fs.renameSync(javaArchivePath, javaArchivePathRenamed);
|
||||
return javaArchivePathRenamed;
|
||||
}
|
||||
|
||||
interface IAdoptiumAvailableReleases {
|
||||
most_recent_feature_release: number;
|
||||
}
|
||||
|
||||
// Resolve the newest available stable/GA feature (major) release.
|
||||
//
|
||||
// Some distributions (e.g. Oracle, GraalVM) construct their download URLs from a
|
||||
// concrete major version and don't expose an endpoint to list every available
|
||||
// release, so a bare `latest` alias can't be resolved from their own metadata.
|
||||
// The Adoptium (Temurin) API is used as a proxy for "what is the newest GA major
|
||||
// version out there", which those distributions typically publish at the same time.
|
||||
export async function getLatestMajorVersion(
|
||||
http: httpm.HttpClient
|
||||
): Promise<number> {
|
||||
const availableReleasesUrl =
|
||||
'https://api.adoptium.net/v3/info/available_releases';
|
||||
|
||||
const response =
|
||||
await http.getJson<IAdoptiumAvailableReleases>(availableReleasesUrl);
|
||||
|
||||
const mostRecent = response.result?.most_recent_feature_release;
|
||||
if (!mostRecent || Number.isNaN(Number(mostRecent))) {
|
||||
throw new Error(
|
||||
`Could not determine the latest available Java major version from ${availableReleasesUrl}`
|
||||
);
|
||||
}
|
||||
|
||||
return Number(mostRecent);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user