mirror of
https://github.com/actions/setup-java.git
synced 2026-08-05 12:59:28 +08:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| da5776e2a6 | |||
| f2629cfa70 | |||
| b73b3683e5 |
@@ -1,209 +0,0 @@
|
|||||||
name: Benchmark cache restore
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
baseline-ref:
|
|
||||||
description: Git ref containing the sequential restore implementation
|
|
||||||
required: true
|
|
||||||
default: main
|
|
||||||
type: string
|
|
||||||
candidate-ref:
|
|
||||||
description: Git ref containing the concurrent restore implementation (defaults to the dispatched ref)
|
|
||||||
required: false
|
|
||||||
type: string
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
warm-caches:
|
|
||||||
name: Warm ${{ matrix.tool }} ${{ matrix.profile }} caches (${{ matrix.os }})
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
os: [macos-15-intel, windows-latest, ubuntu-latest]
|
|
||||||
tool: [maven, gradle]
|
|
||||||
profile: [small, large]
|
|
||||||
steps:
|
|
||||||
- name: Checkout benchmark workflow
|
|
||||||
uses: actions/checkout@v7
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
- name: Checkout baseline
|
|
||||||
uses: actions/checkout@v7
|
|
||||||
with:
|
|
||||||
path: baseline
|
|
||||||
persist-credentials: false
|
|
||||||
ref: ${{ inputs.baseline-ref }}
|
|
||||||
- name: Checkout candidate
|
|
||||||
uses: actions/checkout@v7
|
|
||||||
with:
|
|
||||||
path: candidate
|
|
||||||
persist-credentials: false
|
|
||||||
ref: ${{ inputs.candidate-ref || github.ref }}
|
|
||||||
- name: Prepare benchmark inputs
|
|
||||||
run: bash __tests__/benchmark-cache-restore.sh prepare "${{ matrix.tool }}" "${{ matrix.profile }}"
|
|
||||||
- name: Prepare cache save
|
|
||||||
uses: ./candidate
|
|
||||||
with:
|
|
||||||
distribution: temurin
|
|
||||||
java-version: '17'
|
|
||||||
cache: ${{ matrix.tool }}
|
|
||||||
cache-dependency-path: benchmark/${{ matrix.tool == 'maven' && 'pom.xml' || 'build.gradle' }}
|
|
||||||
- name: Populate benchmark caches
|
|
||||||
run: |
|
|
||||||
bash __tests__/benchmark-cache-restore.sh reset "${{ matrix.tool }}"
|
|
||||||
bash __tests__/benchmark-cache-restore.sh populate "${{ matrix.tool }}" "${{ matrix.profile }}"
|
|
||||||
|
|
||||||
benchmark:
|
|
||||||
name: Benchmark ${{ matrix.tool }} ${{ matrix.profile }} (${{ matrix.os }})
|
|
||||||
needs: warm-caches
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
os: [macos-15-intel, windows-latest, ubuntu-latest]
|
|
||||||
tool: [maven, gradle]
|
|
||||||
profile: [small, large]
|
|
||||||
steps:
|
|
||||||
- name: Checkout benchmark workflow
|
|
||||||
uses: actions/checkout@v7
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
- name: Checkout baseline
|
|
||||||
uses: actions/checkout@v7
|
|
||||||
with:
|
|
||||||
path: baseline
|
|
||||||
persist-credentials: false
|
|
||||||
ref: ${{ inputs.baseline-ref }}
|
|
||||||
- name: Checkout candidate
|
|
||||||
uses: actions/checkout@v7
|
|
||||||
with:
|
|
||||||
path: candidate
|
|
||||||
persist-credentials: false
|
|
||||||
ref: ${{ inputs.candidate-ref || github.ref }}
|
|
||||||
- name: Prepare benchmark inputs
|
|
||||||
run: bash __tests__/benchmark-cache-restore.sh prepare "${{ matrix.tool }}" "${{ matrix.profile }}"
|
|
||||||
|
|
||||||
- name: Reset caches for baseline iteration 1
|
|
||||||
run: bash __tests__/benchmark-cache-restore.sh reset "${{ matrix.tool }}"
|
|
||||||
- name: Start baseline iteration 1 timer
|
|
||||||
run: bash __tests__/benchmark-cache-restore.sh start "${{ matrix.tool }}"
|
|
||||||
- name: Restore with baseline iteration 1
|
|
||||||
id: baseline-1
|
|
||||||
uses: ./baseline
|
|
||||||
with:
|
|
||||||
distribution: temurin
|
|
||||||
java-version: '17'
|
|
||||||
cache: ${{ matrix.tool }}
|
|
||||||
cache-dependency-path: benchmark/${{ matrix.tool == 'maven' && 'pom.xml' || 'build.gradle' }}
|
|
||||||
cache-read-only: true
|
|
||||||
- name: Record baseline iteration 1
|
|
||||||
env:
|
|
||||||
CACHE_HIT: ${{ steps.baseline-1.outputs.cache-hit }}
|
|
||||||
run: bash __tests__/benchmark-cache-restore.sh record "${{ matrix.tool }}" "${{ matrix.os }}" "${{ matrix.profile }}" baseline 1 "$CACHE_HIT"
|
|
||||||
|
|
||||||
- name: Reset caches for candidate iteration 1
|
|
||||||
run: bash __tests__/benchmark-cache-restore.sh reset "${{ matrix.tool }}"
|
|
||||||
- name: Start candidate iteration 1 timer
|
|
||||||
run: bash __tests__/benchmark-cache-restore.sh start "${{ matrix.tool }}"
|
|
||||||
- name: Restore with candidate iteration 1
|
|
||||||
id: candidate-1
|
|
||||||
uses: ./candidate
|
|
||||||
with:
|
|
||||||
distribution: temurin
|
|
||||||
java-version: '17'
|
|
||||||
cache: ${{ matrix.tool }}
|
|
||||||
cache-dependency-path: benchmark/${{ matrix.tool == 'maven' && 'pom.xml' || 'build.gradle' }}
|
|
||||||
cache-read-only: true
|
|
||||||
- name: Record candidate iteration 1
|
|
||||||
env:
|
|
||||||
CACHE_HIT: ${{ steps.candidate-1.outputs.cache-hit }}
|
|
||||||
run: bash __tests__/benchmark-cache-restore.sh record "${{ matrix.tool }}" "${{ matrix.os }}" "${{ matrix.profile }}" candidate 1 "$CACHE_HIT"
|
|
||||||
|
|
||||||
- name: Reset caches for candidate iteration 2
|
|
||||||
run: bash __tests__/benchmark-cache-restore.sh reset "${{ matrix.tool }}"
|
|
||||||
- name: Start candidate iteration 2 timer
|
|
||||||
run: bash __tests__/benchmark-cache-restore.sh start "${{ matrix.tool }}"
|
|
||||||
- name: Restore with candidate iteration 2
|
|
||||||
id: candidate-2
|
|
||||||
uses: ./candidate
|
|
||||||
with:
|
|
||||||
distribution: temurin
|
|
||||||
java-version: '17'
|
|
||||||
cache: ${{ matrix.tool }}
|
|
||||||
cache-dependency-path: benchmark/${{ matrix.tool == 'maven' && 'pom.xml' || 'build.gradle' }}
|
|
||||||
cache-read-only: true
|
|
||||||
- name: Record candidate iteration 2
|
|
||||||
env:
|
|
||||||
CACHE_HIT: ${{ steps.candidate-2.outputs.cache-hit }}
|
|
||||||
run: bash __tests__/benchmark-cache-restore.sh record "${{ matrix.tool }}" "${{ matrix.os }}" "${{ matrix.profile }}" candidate 2 "$CACHE_HIT"
|
|
||||||
|
|
||||||
- name: Reset caches for baseline iteration 2
|
|
||||||
run: bash __tests__/benchmark-cache-restore.sh reset "${{ matrix.tool }}"
|
|
||||||
- name: Start baseline iteration 2 timer
|
|
||||||
run: bash __tests__/benchmark-cache-restore.sh start "${{ matrix.tool }}"
|
|
||||||
- name: Restore with baseline iteration 2
|
|
||||||
id: baseline-2
|
|
||||||
uses: ./baseline
|
|
||||||
with:
|
|
||||||
distribution: temurin
|
|
||||||
java-version: '17'
|
|
||||||
cache: ${{ matrix.tool }}
|
|
||||||
cache-dependency-path: benchmark/${{ matrix.tool == 'maven' && 'pom.xml' || 'build.gradle' }}
|
|
||||||
cache-read-only: true
|
|
||||||
- name: Record baseline iteration 2
|
|
||||||
env:
|
|
||||||
CACHE_HIT: ${{ steps.baseline-2.outputs.cache-hit }}
|
|
||||||
run: bash __tests__/benchmark-cache-restore.sh record "${{ matrix.tool }}" "${{ matrix.os }}" "${{ matrix.profile }}" baseline 2 "$CACHE_HIT"
|
|
||||||
|
|
||||||
- name: Reset caches for baseline iteration 3
|
|
||||||
run: bash __tests__/benchmark-cache-restore.sh reset "${{ matrix.tool }}"
|
|
||||||
- name: Start baseline iteration 3 timer
|
|
||||||
run: bash __tests__/benchmark-cache-restore.sh start "${{ matrix.tool }}"
|
|
||||||
- name: Restore with baseline iteration 3
|
|
||||||
id: baseline-3
|
|
||||||
uses: ./baseline
|
|
||||||
with:
|
|
||||||
distribution: temurin
|
|
||||||
java-version: '17'
|
|
||||||
cache: ${{ matrix.tool }}
|
|
||||||
cache-dependency-path: benchmark/${{ matrix.tool == 'maven' && 'pom.xml' || 'build.gradle' }}
|
|
||||||
cache-read-only: true
|
|
||||||
- name: Record baseline iteration 3
|
|
||||||
env:
|
|
||||||
CACHE_HIT: ${{ steps.baseline-3.outputs.cache-hit }}
|
|
||||||
run: bash __tests__/benchmark-cache-restore.sh record "${{ matrix.tool }}" "${{ matrix.os }}" "${{ matrix.profile }}" baseline 3 "$CACHE_HIT"
|
|
||||||
|
|
||||||
- name: Reset caches for candidate iteration 3
|
|
||||||
run: bash __tests__/benchmark-cache-restore.sh reset "${{ matrix.tool }}"
|
|
||||||
- name: Start candidate iteration 3 timer
|
|
||||||
run: bash __tests__/benchmark-cache-restore.sh start "${{ matrix.tool }}"
|
|
||||||
- name: Restore with candidate iteration 3
|
|
||||||
id: candidate-3
|
|
||||||
uses: ./candidate
|
|
||||||
with:
|
|
||||||
distribution: temurin
|
|
||||||
java-version: '17'
|
|
||||||
cache: ${{ matrix.tool }}
|
|
||||||
cache-dependency-path: benchmark/${{ matrix.tool == 'maven' && 'pom.xml' || 'build.gradle' }}
|
|
||||||
cache-read-only: true
|
|
||||||
- name: Record candidate iteration 3
|
|
||||||
env:
|
|
||||||
CACHE_HIT: ${{ steps.candidate-3.outputs.cache-hit }}
|
|
||||||
run: bash __tests__/benchmark-cache-restore.sh record "${{ matrix.tool }}" "${{ matrix.os }}" "${{ matrix.profile }}" candidate 3 "$CACHE_HIT"
|
|
||||||
|
|
||||||
- name: Summarize benchmark
|
|
||||||
run: bash __tests__/benchmark-cache-restore.sh summarize "${{ matrix.tool }}" "$GITHUB_STEP_SUMMARY"
|
|
||||||
- name: Upload raw timings
|
|
||||||
uses: actions/upload-artifact@v7
|
|
||||||
with:
|
|
||||||
name: cache-restore-${{ matrix.os }}-${{ matrix.tool }}-${{ matrix.profile }}
|
|
||||||
path: .benchmark-results/timings.csv
|
|
||||||
if-no-files-found: error
|
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
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
|
||||||
+60
-333
@@ -34,7 +34,7 @@ jobs:
|
|||||||
uses: ./
|
uses: ./
|
||||||
id: setup-java
|
id: setup-java
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin'
|
distribution: 'adopt'
|
||||||
java-version: '17'
|
java-version: '17'
|
||||||
cache: gradle
|
cache: gradle
|
||||||
- name: Create files to cache
|
- name: Create files to cache
|
||||||
@@ -42,10 +42,10 @@ jobs:
|
|||||||
# https://github.com/actions/cache/issues/454#issuecomment-840493935
|
# https://github.com/actions/cache/issues/454#issuecomment-840493935
|
||||||
run: |
|
run: |
|
||||||
gradle downloadDependencies --no-daemon -p __tests__/cache/gradle1
|
gradle downloadDependencies --no-daemon -p __tests__/cache/gradle1
|
||||||
mkdir -p "$HOME/.gradle/wrapper/dists/setup-java-e2e"
|
if [ ! -d ~/.gradle/caches ]; then
|
||||||
echo "gradle wrapper cache" > "$HOME/.gradle/wrapper/dists/setup-java-e2e/payload"
|
echo "::error::The ~/.gradle/caches directory does not exist unexpectedly"
|
||||||
bash __tests__/check-dir.sh "$HOME/.gradle/caches"
|
exit 1
|
||||||
bash __tests__/check-dir.sh "$HOME/.gradle/wrapper/dists"
|
fi
|
||||||
gradle-restore:
|
gradle-restore:
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
@@ -62,14 +62,16 @@ jobs:
|
|||||||
uses: ./
|
uses: ./
|
||||||
id: setup-java
|
id: setup-java
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin'
|
distribution: 'adopt'
|
||||||
java-version: '11'
|
java-version: '11'
|
||||||
cache: gradle
|
cache: gradle
|
||||||
cache-read-only: true
|
|
||||||
- name: Confirm that ~/.gradle/caches directory has been made
|
- name: Confirm that ~/.gradle/caches directory has been made
|
||||||
run: bash __tests__/check-dir.sh "$HOME/.gradle/caches"
|
run: |
|
||||||
- name: Confirm that the Gradle Wrapper cache has been restored
|
if [ ! -d ~/.gradle/caches ]; then
|
||||||
run: bash __tests__/check-dir.sh "$HOME/.gradle/wrapper/dists"
|
echo "::error::The ~/.gradle/caches directory does not exist unexpectedly"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
ls ~/.gradle/caches/
|
||||||
maven-save:
|
maven-save:
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
@@ -85,16 +87,16 @@ jobs:
|
|||||||
uses: ./
|
uses: ./
|
||||||
id: setup-java
|
id: setup-java
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin'
|
distribution: 'adopt'
|
||||||
java-version: '11'
|
java-version: '11'
|
||||||
cache: maven
|
cache: maven
|
||||||
- name: Create files to cache
|
- name: Create files to cache
|
||||||
run: |
|
run: |
|
||||||
mvn verify -f __tests__/cache/maven/pom.xml
|
mvn verify -f __tests__/cache/maven/pom.xml
|
||||||
mkdir -p "$HOME/.m2/wrapper/dists/setup-java-e2e"
|
if [ ! -d ~/.m2/repository ]; then
|
||||||
echo "maven wrapper cache" > "$HOME/.m2/wrapper/dists/setup-java-e2e/payload"
|
echo "::error::The ~/.m2/repository directory does not exist unexpectedly"
|
||||||
bash __tests__/check-dir.sh "$HOME/.m2/repository"
|
exit 1
|
||||||
bash __tests__/check-dir.sh "$HOME/.m2/wrapper/dists"
|
fi
|
||||||
maven-restore:
|
maven-restore:
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
@@ -111,14 +113,16 @@ jobs:
|
|||||||
uses: ./
|
uses: ./
|
||||||
id: setup-java
|
id: setup-java
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin'
|
distribution: 'adopt'
|
||||||
java-version: '11'
|
java-version: '11'
|
||||||
cache: maven
|
cache: maven
|
||||||
cache-read-only: true
|
|
||||||
- name: Confirm that ~/.m2/repository directory has been made
|
- name: Confirm that ~/.m2/repository directory has been made
|
||||||
run: bash __tests__/check-dir.sh "$HOME/.m2/repository"
|
run: |
|
||||||
- name: Confirm that the Maven Wrapper cache has been restored
|
if [ ! -d ~/.m2/repository ]; then
|
||||||
run: bash __tests__/check-dir.sh "$HOME/.m2/wrapper/dists"
|
echo "::error::The ~/.m2/repository directory does not exist unexpectedly"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
ls ~/.m2/repository
|
||||||
sbt-save:
|
sbt-save:
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
defaults:
|
defaults:
|
||||||
@@ -138,7 +142,7 @@ jobs:
|
|||||||
uses: ./
|
uses: ./
|
||||||
id: setup-java
|
id: setup-java
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin'
|
distribution: 'adopt'
|
||||||
java-version: '11'
|
java-version: '11'
|
||||||
cache: sbt
|
cache: sbt
|
||||||
- name: Setup SBT
|
- name: Setup SBT
|
||||||
@@ -151,13 +155,25 @@ jobs:
|
|||||||
|
|
||||||
- name: Check files to cache on macos-latest
|
- name: Check files to cache on macos-latest
|
||||||
if: matrix.os == 'macos-15-intel'
|
if: matrix.os == 'macos-15-intel'
|
||||||
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/Library/Caches/Coursier"
|
run: |
|
||||||
|
if [ ! -d ~/Library/Caches/Coursier ]; then
|
||||||
|
echo "::error::The ~/Library/Caches/Coursier directory does not exist unexpectedly"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
- name: Check files to cache on windows-latest
|
- name: Check files to cache on windows-latest
|
||||||
if: matrix.os == 'windows-latest'
|
if: matrix.os == 'windows-latest'
|
||||||
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/AppData/Local/Coursier/Cache"
|
run: |
|
||||||
|
if [ ! -d ~/AppData/Local/Coursier/Cache ]; then
|
||||||
|
echo "::error::The ~/AppData/Local/Coursier/Cache directory does not exist unexpectedly"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
- name: Check files to cache on ubuntu-latest
|
- name: Check files to cache on ubuntu-latest
|
||||||
if: matrix.os == 'ubuntu-22.04'
|
if: matrix.os == 'ubuntu-latest'
|
||||||
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/.cache/coursier"
|
run: |
|
||||||
|
if [ ! -d ~/.cache/coursier ]; then
|
||||||
|
echo "::error::The ~/.cache/coursier directory does not exist unexpectedly"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
sbt-restore:
|
sbt-restore:
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
defaults:
|
defaults:
|
||||||
@@ -178,320 +194,31 @@ jobs:
|
|||||||
uses: ./
|
uses: ./
|
||||||
id: setup-java
|
id: setup-java
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin'
|
distribution: 'adopt'
|
||||||
java-version: '11'
|
java-version: '11'
|
||||||
cache: sbt
|
cache: sbt
|
||||||
cache-read-only: true
|
|
||||||
|
|
||||||
- name: Confirm that ~/Library/Caches/Coursier directory has been made
|
- name: Confirm that ~/Library/Caches/Coursier directory has been made
|
||||||
if: matrix.os == 'macos-15-intel'
|
if: matrix.os == 'macos-15-intel'
|
||||||
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/Library/Caches/Coursier"
|
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
|
||||||
- name: Confirm that ~/AppData/Local/Coursier/Cache directory has been made
|
- name: Confirm that ~/AppData/Local/Coursier/Cache directory has been made
|
||||||
if: matrix.os == 'windows-latest'
|
if: matrix.os == 'windows-latest'
|
||||||
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/AppData/Local/Coursier/Cache"
|
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
|
||||||
- name: Confirm that ~/.cache/coursier directory has been made
|
- name: Confirm that ~/.cache/coursier directory has been made
|
||||||
if: matrix.os == 'ubuntu-22.04'
|
if: matrix.os == 'ubuntu-latest'
|
||||||
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: 'temurin'
|
|
||||||
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: |
|
run: |
|
||||||
gradle downloadDependencies --no-daemon -p __tests__/cache/gradle1
|
if [ ! -d ~/.cache/coursier ]; then
|
||||||
mkdir -p "$HOME/.gradle/wrapper/dists/setup-java-e2e-gradle1"
|
echo "::error::The ~/.cache/coursier directory does not exist unexpectedly"
|
||||||
echo "gradle wrapper cache gradle1" > "$HOME/.gradle/wrapper/dists/setup-java-e2e-gradle1/payload"
|
exit 1
|
||||||
bash __tests__/check-dir.sh "$HOME/.gradle/caches"
|
fi
|
||||||
bash __tests__/check-dir.sh "$HOME/.gradle/wrapper/dists"
|
ls ~/.cache/coursier
|
||||||
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: 'temurin'
|
|
||||||
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"
|
|
||||||
- name: Confirm that the Gradle Wrapper cache has been restored
|
|
||||||
run: bash __tests__/check-dir.sh "$HOME/.gradle/wrapper/dists"
|
|
||||||
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: 'temurin'
|
|
||||||
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: 'temurin'
|
|
||||||
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
|
|
||||||
mkdir -p "$HOME/.m2/wrapper/dists/setup-java-e2e-maven1"
|
|
||||||
echo "maven wrapper cache maven1" > "$HOME/.m2/wrapper/dists/setup-java-e2e-maven1/payload"
|
|
||||||
bash __tests__/check-dir.sh "$HOME/.m2/repository"
|
|
||||||
bash __tests__/check-dir.sh "$HOME/.m2/wrapper/dists"
|
|
||||||
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: 'temurin'
|
|
||||||
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"
|
|
||||||
- name: Confirm that the Maven Wrapper cache has been restored
|
|
||||||
run: bash __tests__/check-dir.sh "$HOME/.m2/wrapper/dists"
|
|
||||||
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: 'temurin'
|
|
||||||
java-version: '11'
|
|
||||||
cache: maven
|
|
||||||
cache-dependency-path: |
|
|
||||||
__tests__/cache/maven2/pom.xml
|
|
||||||
README.md
|
|
||||||
- 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: 'temurin'
|
|
||||||
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: 'temurin'
|
|
||||||
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: 'temurin'
|
|
||||||
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
|
|
||||||
custom-maven-path-save:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v7
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
- name: Run setup-java with a custom Maven cache path
|
|
||||||
uses: ./
|
|
||||||
with:
|
|
||||||
distribution: 'temurin'
|
|
||||||
java-version: '11'
|
|
||||||
cache: maven
|
|
||||||
cache-dependency-path: |
|
|
||||||
__tests__/cache/maven2/pom.xml
|
|
||||||
.github/workflows/e2e-cache.yml
|
|
||||||
cache-path: |
|
|
||||||
${{ runner.temp }}/setup-java-custom-maven-repository
|
|
||||||
!${{ runner.temp }}/setup-java-custom-maven-repository/**/*.lastUpdated
|
|
||||||
- name: Populate the custom Maven repository
|
|
||||||
run: |
|
|
||||||
mvn -Dmaven.repo.local="$RUNNER_TEMP/setup-java-custom-maven-repository" verify -f __tests__/cache/maven2/pom.xml
|
|
||||||
touch "$RUNNER_TEMP/setup-java-custom-maven-repository/setup-java-cache-path-marker"
|
|
||||||
bash __tests__/check-dir.sh "$RUNNER_TEMP/setup-java-custom-maven-repository"
|
|
||||||
custom-maven-path-restore:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: custom-maven-path-save
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v7
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
- name: Run setup-java with a custom Maven cache path
|
|
||||||
uses: ./
|
|
||||||
with:
|
|
||||||
distribution: 'temurin'
|
|
||||||
java-version: '11'
|
|
||||||
cache: maven
|
|
||||||
cache-dependency-path: |
|
|
||||||
__tests__/cache/maven2/pom.xml
|
|
||||||
.github/workflows/e2e-cache.yml
|
|
||||||
cache-path: |
|
|
||||||
${{ runner.temp }}/setup-java-custom-maven-repository
|
|
||||||
!${{ runner.temp }}/setup-java-custom-maven-repository/**/*.lastUpdated
|
|
||||||
cache-read-only: true
|
|
||||||
- name: Confirm that the custom Maven repository has been restored
|
|
||||||
run: test -f "$RUNNER_TEMP/setup-java-custom-maven-repository/setup-java-cache-path-marker"
|
|
||||||
|
|||||||
@@ -15,6 +15,47 @@ permissions:
|
|||||||
contents: read
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
setup-java-local-file-adopt:
|
||||||
|
name: Validate installation from local file Adopt
|
||||||
|
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: Download Adopt OpenJDK file
|
||||||
|
run: |
|
||||||
|
if ($IsLinux) {
|
||||||
|
$downloadUrl = "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.10%2B9/OpenJDK11U-jdk_x64_linux_hotspot_11.0.10_9.tar.gz"
|
||||||
|
$localFilename = "java_package.tar.gz"
|
||||||
|
} elseif ($IsMacOS) {
|
||||||
|
$downloadUrl = "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.10%2B9/OpenJDK11U-jdk_x64_mac_hotspot_11.0.10_9.tar.gz"
|
||||||
|
$localFilename = "java_package.tar.gz"
|
||||||
|
} elseif ($IsWindows) {
|
||||||
|
$downloadUrl = "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.10%2B9/OpenJDK11U-jdk_x64_windows_hotspot_11.0.10_9.zip"
|
||||||
|
$localFilename = "java_package.zip"
|
||||||
|
}
|
||||||
|
echo "LocalFilename=$localFilename" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
||||||
|
(New-Object System.Net.WebClient).DownloadFile($downloadUrl, "$env:RUNNER_TEMP/$localFilename")
|
||||||
|
shell: pwsh
|
||||||
|
- name: setup-java
|
||||||
|
uses: ./
|
||||||
|
id: setup-java
|
||||||
|
with:
|
||||||
|
distribution: 'jdkfile'
|
||||||
|
jdk-file: ${{ runner.temp }}/${{ env.LocalFilename }}
|
||||||
|
java-version: '11.0.0-ea'
|
||||||
|
architecture: x64
|
||||||
|
- name: Verify Java version
|
||||||
|
env:
|
||||||
|
JAVA_PATH: ${{ steps.setup-java.outputs.path }}
|
||||||
|
run: bash __tests__/verify-java.sh "11.0.10" "$JAVA_PATH"
|
||||||
|
shell: bash
|
||||||
|
|
||||||
setup-java-local-file-zulu:
|
setup-java-local-file-zulu:
|
||||||
name: Validate installation from local file Zulu
|
name: Validate installation from local file Zulu
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
|||||||
@@ -35,36 +35,24 @@ jobs:
|
|||||||
uses: ./
|
uses: ./
|
||||||
id: setup-java
|
id: setup-java
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin'
|
distribution: 'adopt'
|
||||||
java-version: '11'
|
java-version: '11'
|
||||||
server-id: maven
|
server-id: maven
|
||||||
server-username-env-var: MAVEN_USERNAME
|
server-username: MAVEN_USERNAME
|
||||||
server-password-env-var: MAVEN_CENTRAL_TOKEN
|
server-password: MAVEN_CENTRAL_TOKEN
|
||||||
gpg-passphrase-env-var: MAVEN_GPG_PASSPHRASE
|
gpg-passphrase: MAVEN_GPG_PASSPHRASE
|
||||||
- name: Validate settings.xml
|
- name: Validate settings.xml
|
||||||
run: |
|
run: |
|
||||||
$xmlPath = Join-Path $HOME ".m2" "settings.xml"
|
$xmlPath = Join-Path $HOME ".m2" "settings.xml"
|
||||||
Get-Content $xmlPath | ForEach-Object { Write-Host $_ }
|
Get-Content $xmlPath | ForEach-Object { Write-Host $_ }
|
||||||
|
|
||||||
$content = [System.IO.File]::ReadAllText($xmlPath)
|
[xml]$xml = Get-Content $xmlPath
|
||||||
$expected = @(
|
$servers = $xml.settings.servers.server
|
||||||
'<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"'
|
if (($servers[0].id -ne 'maven') -or ($servers[0].username -ne '${env.MAVEN_USERNAME}') -or ($servers[0].password -ne '${env.MAVEN_CENTRAL_TOKEN}')) {
|
||||||
' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"'
|
throw "Generated XML file is incorrect"
|
||||||
' 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 ($content -ne $expected) {
|
if (($servers[1].id -ne 'gpg.passphrase') -or ($servers[1].passphrase -ne '${env.MAVEN_GPG_PASSPHRASE}')) {
|
||||||
Write-Host "Expected settings.xml:"
|
|
||||||
$expected -split "`n" | ForEach-Object { Write-Host $_ }
|
|
||||||
throw "Generated XML file is incorrect"
|
throw "Generated XML file is incorrect"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,12 +78,12 @@ jobs:
|
|||||||
uses: ./
|
uses: ./
|
||||||
id: setup-java
|
id: setup-java
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin'
|
distribution: 'adopt'
|
||||||
java-version: '11'
|
java-version: '11'
|
||||||
server-id: maven
|
server-id: maven
|
||||||
server-username-env-var: MAVEN_USERNAME
|
server-username: MAVEN_USERNAME
|
||||||
server-password-env-var: MAVEN_CENTRAL_TOKEN
|
server-password: MAVEN_CENTRAL_TOKEN
|
||||||
gpg-passphrase-env-var: MAVEN_GPG_PASSPHRASE
|
gpg-passphrase: MAVEN_GPG_PASSPHRASE
|
||||||
- name: Validate settings.xml is overwritten
|
- name: Validate settings.xml is overwritten
|
||||||
run: |
|
run: |
|
||||||
$xmlPath = Join-Path $HOME ".m2" "settings.xml"
|
$xmlPath = Join-Path $HOME ".m2" "settings.xml"
|
||||||
@@ -128,13 +116,13 @@ jobs:
|
|||||||
uses: ./
|
uses: ./
|
||||||
id: setup-java
|
id: setup-java
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin'
|
distribution: 'adopt'
|
||||||
java-version: '11'
|
java-version: '11'
|
||||||
server-id: maven
|
server-id: maven
|
||||||
server-username-env-var: MAVEN_USERNAME
|
server-username: MAVEN_USERNAME
|
||||||
server-password-env-var: MAVEN_CENTRAL_TOKEN
|
server-password: MAVEN_CENTRAL_TOKEN
|
||||||
overwrite-settings: false
|
overwrite-settings: false
|
||||||
gpg-passphrase-env-var: MAVEN_GPG_PASSPHRASE
|
gpg-passphrase: MAVEN_GPG_PASSPHRASE
|
||||||
- name: Validate that settings.xml is not overwritten
|
- name: Validate that settings.xml is not overwritten
|
||||||
run: |
|
run: |
|
||||||
$xmlPath = Join-Path $HOME ".m2" "settings.xml"
|
$xmlPath = Join-Path $HOME ".m2" "settings.xml"
|
||||||
@@ -161,12 +149,12 @@ jobs:
|
|||||||
uses: ./
|
uses: ./
|
||||||
id: setup-java
|
id: setup-java
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin'
|
distribution: 'adopt'
|
||||||
java-version: '11'
|
java-version: '11'
|
||||||
server-id: maven
|
server-id: maven
|
||||||
server-username-env-var: MAVEN_USERNAME
|
server-username: MAVEN_USERNAME
|
||||||
server-password-env-var: MAVEN_CENTRAL_TOKEN
|
server-password: MAVEN_CENTRAL_TOKEN
|
||||||
gpg-passphrase-env-var: MAVEN_GPG_PASSPHRASE
|
gpg-passphrase: MAVEN_GPG_PASSPHRASE
|
||||||
settings-path: ${{ runner.temp }}
|
settings-path: ${{ runner.temp }}
|
||||||
- name: Validate settings.xml location
|
- name: Validate settings.xml location
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -1,87 +0,0 @@
|
|||||||
name: Validate Java e2e smoke
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
paths-ignore:
|
|
||||||
- '**.md'
|
|
||||||
pull_request:
|
|
||||||
paths-ignore:
|
|
||||||
- '**.md'
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
setup-java:
|
|
||||||
name: ${{ matrix.distribution }} ${{ matrix.version }} (${{ matrix.java-package }}) - ${{ matrix.os }}
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- os: macos-latest
|
|
||||||
distribution: temurin
|
|
||||||
version: '11'
|
|
||||||
java-package: jdk
|
|
||||||
- os: windows-latest
|
|
||||||
distribution: temurin
|
|
||||||
version: '17'
|
|
||||||
java-package: jdk
|
|
||||||
- os: ubuntu-latest
|
|
||||||
distribution: temurin
|
|
||||||
version: '21'
|
|
||||||
java-package: jdk
|
|
||||||
- os: macos-latest
|
|
||||||
distribution: temurin
|
|
||||||
version: '25'
|
|
||||||
java-package: jdk
|
|
||||||
- os: windows-latest
|
|
||||||
distribution: temurin
|
|
||||||
version: '25'
|
|
||||||
java-package: jdk
|
|
||||||
- os: ubuntu-latest
|
|
||||||
distribution: temurin
|
|
||||||
version: '25'
|
|
||||||
java-package: jdk
|
|
||||||
- os: macos-latest
|
|
||||||
distribution: microsoft
|
|
||||||
version: '25'
|
|
||||||
java-package: jdk
|
|
||||||
- os: windows-latest
|
|
||||||
distribution: microsoft
|
|
||||||
version: '25'
|
|
||||||
java-package: jdk
|
|
||||||
- os: ubuntu-latest
|
|
||||||
distribution: microsoft
|
|
||||||
version: '25'
|
|
||||||
java-package: jdk
|
|
||||||
- os: ubuntu-latest
|
|
||||||
distribution: zulu
|
|
||||||
version: '17'
|
|
||||||
java-package: jre
|
|
||||||
- os: ubuntu-latest
|
|
||||||
distribution: liberica
|
|
||||||
version: '21'
|
|
||||||
java-package: jdk+fx
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v7
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
- name: setup-java
|
|
||||||
uses: ./
|
|
||||||
id: setup-java
|
|
||||||
with:
|
|
||||||
java-version: ${{ matrix.version }}
|
|
||||||
java-package: ${{ matrix.java-package }}
|
|
||||||
distribution: ${{ matrix.distribution }}
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- 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
|
|
||||||
+169
-110
@@ -3,9 +3,13 @@ name: Validate Java e2e
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
|
- main
|
||||||
- releases/*
|
- releases/*
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- '**.md'
|
- '**.md'
|
||||||
|
pull_request:
|
||||||
|
paths-ignore:
|
||||||
|
- '**.md'
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 */12 * * *'
|
- cron: '0 */12 * * *'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
@@ -21,9 +25,10 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: [macos-15-intel, windows-latest, ubuntu-latest]
|
os: [macos-15-intel, windows-latest, ubuntu-latest]
|
||||||
distribution:
|
distribution: [
|
||||||
[
|
|
||||||
'temurin',
|
'temurin',
|
||||||
|
'adopt',
|
||||||
|
'adopt-openj9',
|
||||||
'zulu',
|
'zulu',
|
||||||
'liberica',
|
'liberica',
|
||||||
'microsoft',
|
'microsoft',
|
||||||
@@ -34,7 +39,7 @@ jobs:
|
|||||||
'jetbrains',
|
'jetbrains',
|
||||||
'kona',
|
'kona',
|
||||||
'liberica-nik'
|
'liberica-nik'
|
||||||
]
|
] # internally 'adopt-hotspot' is the same as 'adopt'
|
||||||
version: ['21', '11', '17']
|
version: ['21', '11', '17']
|
||||||
exclude:
|
exclude:
|
||||||
- distribution: microsoft
|
- distribution: microsoft
|
||||||
@@ -78,15 +83,6 @@ jobs:
|
|||||||
- distribution: oracle
|
- distribution: oracle
|
||||||
os: ubuntu-latest
|
os: ubuntu-latest
|
||||||
version: 21
|
version: 21
|
||||||
- distribution: oracle-openjdk
|
|
||||||
os: macos-15-intel
|
|
||||||
version: 21
|
|
||||||
- distribution: oracle-openjdk
|
|
||||||
os: windows-latest
|
|
||||||
version: 21
|
|
||||||
- distribution: oracle-openjdk
|
|
||||||
os: ubuntu-latest
|
|
||||||
version: 21
|
|
||||||
- distribution: graalvm
|
- distribution: graalvm
|
||||||
os: macos-latest
|
os: macos-latest
|
||||||
version: 17.0.12
|
version: 17.0.12
|
||||||
@@ -100,8 +96,7 @@ jobs:
|
|||||||
os: ubuntu-latest
|
os: ubuntu-latest
|
||||||
version: '24-ea'
|
version: '24-ea'
|
||||||
steps:
|
steps:
|
||||||
- &checkout_step
|
- name: Checkout
|
||||||
name: Checkout
|
|
||||||
uses: actions/checkout@v7
|
uses: actions/checkout@v7
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
@@ -120,25 +115,6 @@ jobs:
|
|||||||
run: bash __tests__/verify-java.sh "$JAVA_VERSION" "$JAVA_PATH"
|
run: bash __tests__/verify-java.sh "$JAVA_VERSION" "$JAVA_PATH"
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
setup-java-checksum-verification:
|
|
||||||
name: Corretto checksum verification - ubuntu-latest
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- *checkout_step
|
|
||||||
- name: setup-java with forced download
|
|
||||||
uses: ./
|
|
||||||
id: setup-java
|
|
||||||
with:
|
|
||||||
java-version: '21'
|
|
||||||
distribution: corretto
|
|
||||||
force-download: true
|
|
||||||
- name: Verify Java
|
|
||||||
env:
|
|
||||||
JAVA_VERSION: '21'
|
|
||||||
JAVA_PATH: ${{ steps.setup-java.outputs.path }}
|
|
||||||
run: bash __tests__/verify-java.sh "$JAVA_VERSION" "$JAVA_PATH"
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
setup-java-alpine-linux:
|
setup-java-alpine-linux:
|
||||||
name: ${{ matrix.distribution }} ${{ matrix.version }} (jdk-${{ contains(matrix.os, 'macos') && !contains(matrix.os, 'intel') && 'arm64' || 'x64' }}) - alpine-linux - ${{ matrix.os }}
|
name: ${{ matrix.distribution }} ${{ matrix.version }} (jdk-${{ contains(matrix.os, 'macos') && !contains(matrix.os, 'intel') && 'arm64' || 'x64' }}) - alpine-linux - ${{ matrix.os }}
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
@@ -151,7 +127,10 @@ jobs:
|
|||||||
distribution: ['temurin', 'sapmachine']
|
distribution: ['temurin', 'sapmachine']
|
||||||
version: ['21', '17']
|
version: ['21', '17']
|
||||||
steps:
|
steps:
|
||||||
- *checkout_step
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v7
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
- name: Install bash
|
- name: Install bash
|
||||||
run: apk add --no-cache bash
|
run: apk add --no-cache bash
|
||||||
- name: setup-java
|
- name: setup-java
|
||||||
@@ -174,7 +153,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: &default_os [macos-latest, windows-latest, ubuntu-latest]
|
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||||
distribution: ['temurin', 'zulu', 'liberica']
|
distribution: ['temurin', 'zulu', 'liberica']
|
||||||
version:
|
version:
|
||||||
- '11.0'
|
- '11.0'
|
||||||
@@ -203,7 +182,10 @@ jobs:
|
|||||||
os: ubuntu-latest
|
os: ubuntu-latest
|
||||||
version: '17.0.7'
|
version: '17.0.7'
|
||||||
steps:
|
steps:
|
||||||
- *checkout_step
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v7
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
- name: setup-java
|
- name: setup-java
|
||||||
uses: ./
|
uses: ./
|
||||||
id: setup-java
|
id: setup-java
|
||||||
@@ -225,7 +207,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: *default_os
|
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||||
distribution:
|
distribution:
|
||||||
[
|
[
|
||||||
'temurin',
|
'temurin',
|
||||||
@@ -239,7 +221,10 @@ jobs:
|
|||||||
- distribution: dragonwell
|
- distribution: dragonwell
|
||||||
os: macos-latest
|
os: macos-latest
|
||||||
steps:
|
steps:
|
||||||
- *checkout_step
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v7
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
- name: setup-java
|
- name: setup-java
|
||||||
uses: ./
|
uses: ./
|
||||||
id: setup-java
|
id: setup-java
|
||||||
@@ -262,7 +247,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: *default_os
|
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||||
distribution:
|
distribution:
|
||||||
[
|
[
|
||||||
'temurin',
|
'temurin',
|
||||||
@@ -276,7 +261,10 @@ jobs:
|
|||||||
- distribution: dragonwell
|
- distribution: dragonwell
|
||||||
os: macos-latest
|
os: macos-latest
|
||||||
steps:
|
steps:
|
||||||
- *checkout_step
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v7
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
- name: setup-java
|
- name: setup-java
|
||||||
uses: ./
|
uses: ./
|
||||||
id: setup-java
|
id: setup-java
|
||||||
@@ -289,11 +277,10 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: Verify Java env variables
|
- name: Verify Java env variables
|
||||||
run: |
|
run: |
|
||||||
$javaArch = if ($env:RUNNER_ARCH -eq "ARM64") { "AARCH64" } else { $env:RUNNER_ARCH }
|
|
||||||
$versionsArr = "11","17"
|
$versionsArr = "11","17"
|
||||||
foreach ($version in $versionsArr)
|
foreach ($version in $versionsArr)
|
||||||
{
|
{
|
||||||
$envName = "JAVA_HOME_${version}_${javaArch}"
|
$envName = "JAVA_HOME_${version}_${env:RUNNER_ARCH}"
|
||||||
$JavaVersionPath = [Environment]::GetEnvironmentVariable($envName)
|
$JavaVersionPath = [Environment]::GetEnvironmentVariable($envName)
|
||||||
if (-not (Test-Path "$JavaVersionPath")) {
|
if (-not (Test-Path "$JavaVersionPath")) {
|
||||||
Write-Host "$envName is not found"
|
Write-Host "$envName is not found"
|
||||||
@@ -307,37 +294,26 @@ jobs:
|
|||||||
run: bash __tests__/verify-java.sh "17" "$JAVA_PATH"
|
run: bash __tests__/verify-java.sh "17" "$JAVA_PATH"
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
setup-java-ea-versions:
|
setup-java-ea-versions-zulu:
|
||||||
name: ${{ matrix.distribution }} ${{ matrix.version }} (jdk-${{ contains(matrix.os, 'macos') && !contains(matrix.os, 'intel') && 'arm64' || 'x64' }}) - ${{ matrix.os }}
|
name: zulu ${{ matrix.version }} (jdk-${{ contains(matrix.os, 'macos') && !contains(matrix.os, 'intel') && 'arm64' || 'x64' }}) - ${{ matrix.os }}
|
||||||
needs: setup-java-major-minor-versions
|
needs: setup-java-major-minor-versions
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
os: [macos-15-intel, windows-latest, ubuntu-latest]
|
||||||
- {os: macos-15-intel, version: '17-ea', distribution: zulu}
|
version: ['17-ea', '15.0.0-ea.14']
|
||||||
- {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:
|
steps:
|
||||||
- *checkout_step
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v7
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
- name: setup-java
|
- name: setup-java
|
||||||
uses: ./
|
uses: ./
|
||||||
id: setup-java
|
id: setup-java
|
||||||
with:
|
with:
|
||||||
java-version: ${{ matrix.version }}
|
java-version: ${{ matrix.version }}
|
||||||
distribution: ${{ matrix.distribution }}
|
distribution: zulu
|
||||||
- name: Verify Java
|
- name: Verify Java
|
||||||
env:
|
env:
|
||||||
JAVA_VERSION: ${{ matrix.version }}
|
JAVA_VERSION: ${{ matrix.version }}
|
||||||
@@ -345,24 +321,53 @@ jobs:
|
|||||||
run: bash __tests__/verify-java.sh "$JAVA_VERSION" "$JAVA_PATH"
|
run: bash __tests__/verify-java.sh "$JAVA_VERSION" "$JAVA_PATH"
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
setup-java-signature-verification:
|
setup-java-ea-versions-temurin:
|
||||||
name: ${{ matrix.distribution }} ${{ matrix.version }} signature verification - ${{ matrix.os }}
|
name: temurin ${{ matrix.version }} (jdk-${{ contains(matrix.os, 'macos') && !contains(matrix.os, 'intel') && 'arm64' || 'x64' }}) - ${{ matrix.os }}
|
||||||
needs: setup-java-major-minor-versions
|
needs: setup-java-major-minor-versions
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: *default_os
|
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||||
version: ['21', '17']
|
version: ['17-ea']
|
||||||
distribution: [temurin, microsoft]
|
|
||||||
steps:
|
steps:
|
||||||
- *checkout_step
|
- 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]
|
||||||
|
version: ['21', '17']
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v7
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
- name: setup-java with signature verification
|
- name: setup-java with signature verification
|
||||||
uses: ./
|
uses: ./
|
||||||
id: setup-java
|
id: setup-java
|
||||||
with:
|
with:
|
||||||
java-version: ${{ matrix.version }}
|
java-version: ${{ matrix.version }}
|
||||||
distribution: ${{ matrix.distribution }}
|
distribution: temurin
|
||||||
verify-signature: true
|
verify-signature: true
|
||||||
- name: Verify Java
|
- name: Verify Java
|
||||||
env:
|
env:
|
||||||
@@ -371,6 +376,61 @@ jobs:
|
|||||||
run: bash __tests__/verify-java.sh "$JAVA_VERSION" "$JAVA_PATH"
|
run: bash __tests__/verify-java.sh "$JAVA_VERSION" "$JAVA_PATH"
|
||||||
shell: bash
|
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:
|
setup-java-custom-package-type:
|
||||||
name: ${{ matrix.distribution }} ${{ matrix.version }} (${{ matrix.java-package }}-x64) - ${{ matrix.os }}
|
name: ${{ matrix.distribution }} ${{ matrix.version }} (${{ matrix.java-package }}-x64) - ${{ matrix.os }}
|
||||||
needs: setup-java-major-minor-versions
|
needs: setup-java-major-minor-versions
|
||||||
@@ -450,7 +510,10 @@ jobs:
|
|||||||
os: ubuntu-latest
|
os: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- *checkout_step
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v7
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
- name: setup-java
|
- name: setup-java
|
||||||
uses: ./
|
uses: ./
|
||||||
id: setup-java
|
id: setup-java
|
||||||
@@ -480,7 +543,10 @@ jobs:
|
|||||||
distribution: ['liberica', 'zulu', 'corretto']
|
distribution: ['liberica', 'zulu', 'corretto']
|
||||||
version: ['11']
|
version: ['11']
|
||||||
steps:
|
steps:
|
||||||
- *checkout_step
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v7
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
- name: setup-java
|
- name: setup-java
|
||||||
uses: ./
|
uses: ./
|
||||||
id: setup-java
|
id: setup-java
|
||||||
@@ -495,36 +561,20 @@ jobs:
|
|||||||
run: bash __tests__/verify-java.sh "$JAVA_VERSION" "$JAVA_PATH"
|
run: bash __tests__/verify-java.sh "$JAVA_VERSION" "$JAVA_PATH"
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
setup-java-unsupported-platform:
|
|
||||||
name: Reject unsupported Oracle x86 on Linux
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- *checkout_step
|
|
||||||
- name: Attempt unsupported setup
|
|
||||||
id: unsupported-setup
|
|
||||||
continue-on-error: true
|
|
||||||
uses: ./
|
|
||||||
with:
|
|
||||||
distribution: oracle
|
|
||||||
java-version: '21'
|
|
||||||
architecture: x86
|
|
||||||
- name: Verify setup was rejected
|
|
||||||
if: always()
|
|
||||||
env:
|
|
||||||
SETUP_OUTCOME: ${{ steps.unsupported-setup.outcome }}
|
|
||||||
run: test "$SETUP_OUTCOME" = failure
|
|
||||||
|
|
||||||
setup-java-version-both-version-inputs-presents:
|
setup-java-version-both-version-inputs-presents:
|
||||||
name: ${{ matrix.distribution }} version (should be from input) - ${{ matrix.os }}
|
name: ${{ matrix.distribution }} version (should be from input) - ${{ matrix.os }}
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: *default_os
|
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||||
distribution: ['temurin', 'microsoft', 'corretto']
|
distribution: ['temurin', 'microsoft', 'corretto']
|
||||||
java-version-file: ['.java-version', '.tool-versions']
|
java-version-file: ['.java-version', '.tool-versions']
|
||||||
steps:
|
steps:
|
||||||
- *checkout_step
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v7
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
- name: Create .java-version file
|
- name: Create .java-version file
|
||||||
shell: bash
|
shell: bash
|
||||||
run: echo "17" > .java-version
|
run: echo "17" > .java-version
|
||||||
@@ -550,11 +600,14 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: *default_os
|
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||||
distribution: ['temurin', 'zulu', 'liberica', 'microsoft', 'corretto']
|
distribution: ['temurin', 'zulu', 'liberica', 'microsoft', 'corretto']
|
||||||
java-version-file: ['.java-version', '.tool-versions']
|
java-version-file: ['.java-version', '.tool-versions']
|
||||||
steps:
|
steps:
|
||||||
- *checkout_step
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v7
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
- name: Create .java-version file
|
- name: Create .java-version file
|
||||||
shell: bash
|
shell: bash
|
||||||
run: echo "11" > .java-version
|
run: echo "11" > .java-version
|
||||||
@@ -579,11 +632,14 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: *default_os
|
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||||
distribution: ['temurin', 'zulu']
|
distribution: ['adopt', 'adopt-openj9', 'zulu']
|
||||||
java-version-file: ['.java-version', '.tool-versions']
|
java-version-file: ['.java-version', '.tool-versions']
|
||||||
steps:
|
steps:
|
||||||
- *checkout_step
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v7
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
- name: Create .java-version file
|
- name: Create .java-version file
|
||||||
shell: bash
|
shell: bash
|
||||||
run: echo "17.0.10" > .java-version
|
run: echo "17.0.10" > .java-version
|
||||||
@@ -608,11 +664,14 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: *default_os
|
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||||
distribution: ['temurin', 'zulu', 'liberica']
|
distribution: ['adopt', 'zulu', 'liberica']
|
||||||
java-version-file: ['.java-version', '.tool-versions', '.sdkmanrc']
|
java-version-file: ['.java-version', '.tool-versions', '.sdkmanrc']
|
||||||
steps:
|
steps:
|
||||||
- *checkout_step
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v7
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
- name: Create .java-version file
|
- name: Create .java-version file
|
||||||
shell: bash
|
shell: bash
|
||||||
run: echo "openjdk64-17.0.10" > .java-version
|
run: echo "openjdk64-17.0.10" > .java-version
|
||||||
@@ -641,9 +700,10 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: *default_os
|
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||||
steps:
|
steps:
|
||||||
- *checkout_step
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v7
|
||||||
- name: Setup Java 17 as default
|
- name: Setup Java 17 as default
|
||||||
uses: ./
|
uses: ./
|
||||||
id: setup-java-17
|
id: setup-java-17
|
||||||
@@ -683,8 +743,7 @@ jobs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
- name: Verify JAVA_HOME_21 env var is set
|
- name: Verify JAVA_HOME_21 env var is set
|
||||||
run: |
|
run: |
|
||||||
$javaArch = if ($env:RUNNER_ARCH -eq "ARM64") { "AARCH64" } else { $env:RUNNER_ARCH }
|
$envName = "JAVA_HOME_21_${env:RUNNER_ARCH}"
|
||||||
$envName = "JAVA_HOME_21_${javaArch}"
|
|
||||||
$JavaVersionPath = [Environment]::GetEnvironmentVariable($envName)
|
$JavaVersionPath = [Environment]::GetEnvironmentVariable($envName)
|
||||||
if (-not $JavaVersionPath) {
|
if (-not $JavaVersionPath) {
|
||||||
Write-Host "$envName is not set"
|
Write-Host "$envName is not set"
|
||||||
@@ -698,16 +757,16 @@ jobs:
|
|||||||
shell: pwsh
|
shell: pwsh
|
||||||
- name: Verify Java 21 outputs are set
|
- name: Verify Java 21 outputs are set
|
||||||
env:
|
env:
|
||||||
JAVA_21_PATH: ${{ steps.setup-java-21.outputs.path }}
|
JAVA21_PATH: ${{ steps.setup-java-21.outputs.path }}
|
||||||
JAVA_21_VERSION: ${{ steps.setup-java-21.outputs.version }}
|
JAVA21_VERSION: ${{ steps.setup-java-21.outputs.version }}
|
||||||
run: |
|
run: |
|
||||||
echo "Java 21 path=$JAVA_21_PATH"
|
echo "Java 21 path=$JAVA21_PATH"
|
||||||
echo "Java 21 version=$JAVA_21_VERSION"
|
echo "Java 21 version=$JAVA21_VERSION"
|
||||||
if [ -z "$JAVA_21_PATH" ]; then
|
if [ -z "$JAVA21_PATH" ]; then
|
||||||
echo "Java 21 path output should be set"
|
echo "Java 21 path output should be set"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
if [ -z "$JAVA_21_VERSION" ]; then
|
if [ -z "$JAVA21_VERSION" ]; then
|
||||||
echo "Java 21 version output should be set"
|
echo "Java 21 version output should be set"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v7
|
uses: actions/setup-python@v6
|
||||||
with:
|
with:
|
||||||
python-version: '3.x'
|
python-version: '3.x'
|
||||||
|
|
||||||
|
|||||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: "@actions/cache"
|
name: "@actions/cache"
|
||||||
version: 6.2.0
|
version: 6.1.0
|
||||||
type: npm
|
type: npm
|
||||||
summary: Actions cache lib
|
summary: Actions cache lib
|
||||||
homepage: https://github.com/actions/toolkit/tree/main/packages/cache
|
homepage: https://github.com/actions/toolkit/tree/main/packages/cache
|
||||||
|
|||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
name: "@actions/glob"
|
||||||
|
version: 0.6.1
|
||||||
|
type: npm
|
||||||
|
summary: Actions glob lib
|
||||||
|
homepage: https://github.com/actions/toolkit/tree/main/packages/glob
|
||||||
|
license: mit
|
||||||
|
licenses:
|
||||||
|
- sources: LICENSE.md
|
||||||
|
text: |-
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright 2019 GitHub
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
notices: []
|
||||||
+4
-4
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: "@azure/abort-controller"
|
name: "@azure/abort-controller"
|
||||||
version: 2.2.0
|
version: 2.1.2
|
||||||
type: npm
|
type: npm
|
||||||
summary: Microsoft Azure SDK for JavaScript - Aborter
|
summary: Microsoft Azure SDK for JavaScript - Aborter
|
||||||
homepage: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/abort-controller/README.md
|
homepage: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/abort-controller/README.md
|
||||||
@@ -8,9 +8,9 @@ license: mit
|
|||||||
licenses:
|
licenses:
|
||||||
- sources: LICENSE
|
- sources: LICENSE
|
||||||
text: |
|
text: |
|
||||||
Copyright (c) Microsoft Corporation.
|
The MIT License (MIT)
|
||||||
|
|
||||||
MIT License
|
Copyright (c) 2020 Microsoft
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -22,7 +22,7 @@ licenses:
|
|||||||
The above copyright notice and this permission notice shall be included in all
|
The above copyright notice and this permission notice shall be included in all
|
||||||
copies or substantial portions of the Software.
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,10 +1,10 @@
|
|||||||
---
|
---
|
||||||
name: "@azure/core-auth"
|
name: "@azure/core-auth"
|
||||||
version: 1.11.0
|
version: 1.10.1
|
||||||
type: npm
|
type: npm
|
||||||
summary: Provides low-level interfaces and helper methods for authentication in Azure
|
summary: Provides low-level interfaces and helper methods for authentication in Azure
|
||||||
SDK
|
SDK
|
||||||
homepage: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/core-auth/README.md
|
homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-auth/README.md
|
||||||
license: mit
|
license: mit
|
||||||
licenses:
|
licenses:
|
||||||
- sources: LICENSE
|
- sources: LICENSE
|
||||||
|
|||||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: "@azure/core-client"
|
name: "@azure/core-client"
|
||||||
version: 1.11.0
|
version: 1.10.2
|
||||||
type: npm
|
type: npm
|
||||||
summary: Core library for interfacing with AutoRest generated code
|
summary: Core library for interfacing with AutoRest generated code
|
||||||
homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-client/
|
homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-client/
|
||||||
|
|||||||
+2
-2
@@ -1,9 +1,9 @@
|
|||||||
---
|
---
|
||||||
name: "@azure/core-http-compat"
|
name: "@azure/core-http-compat"
|
||||||
version: 2.5.0
|
version: 2.4.0
|
||||||
type: npm
|
type: npm
|
||||||
summary: Core HTTP Compatibility Library to bridge the gap between Core V1 & V2 packages.
|
summary: Core HTTP Compatibility Library to bridge the gap between Core V1 & V2 packages.
|
||||||
homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-http-compat/
|
homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-compat/
|
||||||
license: mit
|
license: mit
|
||||||
licenses:
|
licenses:
|
||||||
- sources: LICENSE
|
- sources: LICENSE
|
||||||
|
|||||||
Generated
+4
-4
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: "@azure/core-paging"
|
name: "@azure/core-paging"
|
||||||
version: 1.7.0
|
version: 1.6.2
|
||||||
type: npm
|
type: npm
|
||||||
summary: Core types for paging async iterable iterators
|
summary: Core types for paging async iterable iterators
|
||||||
homepage: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/core-paging/README.md
|
homepage: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/core-paging/README.md
|
||||||
@@ -8,9 +8,9 @@ license: mit
|
|||||||
licenses:
|
licenses:
|
||||||
- sources: LICENSE
|
- sources: LICENSE
|
||||||
text: |
|
text: |
|
||||||
Copyright (c) Microsoft Corporation.
|
The MIT License (MIT)
|
||||||
|
|
||||||
MIT License
|
Copyright (c) 2020 Microsoft
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -22,7 +22,7 @@ licenses:
|
|||||||
The above copyright notice and this permission notice shall be included in all
|
The above copyright notice and this permission notice shall be included in all
|
||||||
copies or substantial portions of the Software.
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: "@azure/core-rest-pipeline"
|
name: "@azure/core-rest-pipeline"
|
||||||
version: 1.25.0
|
version: 1.24.0
|
||||||
type: npm
|
type: npm
|
||||||
summary: Isomorphic client library for making HTTP requests in node.js and browser.
|
summary: Isomorphic client library for making HTTP requests in node.js and browser.
|
||||||
homepage: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/core-rest-pipeline/README.md
|
homepage: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/core-rest-pipeline/README.md
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: "@azure/core-tracing"
|
name: "@azure/core-tracing"
|
||||||
version: 1.4.0
|
version: 1.3.1
|
||||||
type: npm
|
type: npm
|
||||||
summary: Provides low-level interfaces and helper methods for tracing in Azure SDK
|
summary: Provides low-level interfaces and helper methods for tracing in Azure SDK
|
||||||
homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-tracing/README.md
|
homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-tracing/README.md
|
||||||
|
|||||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: "@azure/core-util"
|
name: "@azure/core-util"
|
||||||
version: 1.14.0
|
version: 1.13.1
|
||||||
type: npm
|
type: npm
|
||||||
summary: Core library for shared utility methods
|
summary: Core library for shared utility methods
|
||||||
homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-util/
|
homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-util/
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,9 +1,9 @@
|
|||||||
---
|
---
|
||||||
name: "@azure/core-xml"
|
name: "@azure/core-xml"
|
||||||
version: 1.6.0
|
version: 1.5.1
|
||||||
type: npm
|
type: npm
|
||||||
summary: Core library for interacting with XML payloads
|
summary: Core library for interacting with XML payloads
|
||||||
homepage: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/core-xml/README.md
|
homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-xml/
|
||||||
license: mit
|
license: mit
|
||||||
licenses:
|
licenses:
|
||||||
- sources: LICENSE
|
- sources: LICENSE
|
||||||
|
|||||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: "@azure/logger"
|
name: "@azure/logger"
|
||||||
version: 1.4.0
|
version: 1.3.0
|
||||||
type: npm
|
type: npm
|
||||||
summary: Microsoft Azure SDK for JavaScript - Logger
|
summary: Microsoft Azure SDK for JavaScript - Logger
|
||||||
homepage: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/logger/README.md
|
homepage: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/logger/README.md
|
||||||
|
|||||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: "@nodable/entities"
|
name: "@nodable/entities"
|
||||||
version: 3.0.0
|
version: 2.2.0
|
||||||
type: npm
|
type: npm
|
||||||
summary: Entity parser for XML, HTML, External entites with security and NCR control
|
summary: Entity parser for XML, HTML, External entites with security and NCR control
|
||||||
homepage:
|
homepage:
|
||||||
|
|||||||
Generated
+32
@@ -0,0 +1,32 @@
|
|||||||
|
---
|
||||||
|
name: "@oozcitak/dom"
|
||||||
|
version: 2.0.2
|
||||||
|
type: npm
|
||||||
|
summary: A modern DOM implementation
|
||||||
|
homepage: http://github.com/oozcitak/dom
|
||||||
|
license: mit
|
||||||
|
licenses:
|
||||||
|
- sources: LICENSE
|
||||||
|
text: |
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2019 Ozgur Ozcitak
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
notices: []
|
||||||
Generated
+32
@@ -0,0 +1,32 @@
|
|||||||
|
---
|
||||||
|
name: "@oozcitak/infra"
|
||||||
|
version: 2.0.2
|
||||||
|
type: npm
|
||||||
|
summary: An implementation of the Infra Living Standard
|
||||||
|
homepage: http://github.com/oozcitak/infra
|
||||||
|
license: mit
|
||||||
|
licenses:
|
||||||
|
- sources: LICENSE
|
||||||
|
text: |
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2019 Ozgur Ozcitak
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
notices: []
|
||||||
Generated
+32
@@ -0,0 +1,32 @@
|
|||||||
|
---
|
||||||
|
name: "@oozcitak/url"
|
||||||
|
version: 3.0.0
|
||||||
|
type: npm
|
||||||
|
summary: An implementation of the URL Living Standard
|
||||||
|
homepage: http://github.com/oozcitak/url
|
||||||
|
license: mit
|
||||||
|
licenses:
|
||||||
|
- sources: LICENSE
|
||||||
|
text: |
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2019 Ozgur Ozcitak
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
notices: []
|
||||||
Generated
+32
@@ -0,0 +1,32 @@
|
|||||||
|
---
|
||||||
|
name: "@oozcitak/util"
|
||||||
|
version: 10.0.0
|
||||||
|
type: npm
|
||||||
|
summary: Utility functions
|
||||||
|
homepage: http://github.com/oozcitak/util
|
||||||
|
license: mit
|
||||||
|
licenses:
|
||||||
|
- sources: LICENSE
|
||||||
|
text: |
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2019 Ozgur Ozcitak
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
notices: []
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: "@typespec/ts-http-runtime"
|
name: "@typespec/ts-http-runtime"
|
||||||
version: 0.3.7
|
version: 0.3.6
|
||||||
type: npm
|
type: npm
|
||||||
summary: Isomorphic client library for making HTTP requests in node.js and browser.
|
summary: Isomorphic client library for making HTTP requests in node.js and browser.
|
||||||
homepage: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/ts-http-runtime/README.md
|
homepage: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/ts-http-runtime/README.md
|
||||||
|
|||||||
Generated
+265
@@ -0,0 +1,265 @@
|
|||||||
|
---
|
||||||
|
name: argparse
|
||||||
|
version: 2.0.1
|
||||||
|
type: npm
|
||||||
|
summary: CLI arguments parser. Native port of python's argparse.
|
||||||
|
homepage:
|
||||||
|
license: other
|
||||||
|
licenses:
|
||||||
|
- sources: LICENSE
|
||||||
|
text: |
|
||||||
|
A. HISTORY OF THE SOFTWARE
|
||||||
|
==========================
|
||||||
|
|
||||||
|
Python was created in the early 1990s by Guido van Rossum at Stichting
|
||||||
|
Mathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands
|
||||||
|
as a successor of a language called ABC. Guido remains Python's
|
||||||
|
principal author, although it includes many contributions from others.
|
||||||
|
|
||||||
|
In 1995, Guido continued his work on Python at the Corporation for
|
||||||
|
National Research Initiatives (CNRI, see http://www.cnri.reston.va.us)
|
||||||
|
in Reston, Virginia where he released several versions of the
|
||||||
|
software.
|
||||||
|
|
||||||
|
In May 2000, Guido and the Python core development team moved to
|
||||||
|
BeOpen.com to form the BeOpen PythonLabs team. In October of the same
|
||||||
|
year, the PythonLabs team moved to Digital Creations, which became
|
||||||
|
Zope Corporation. In 2001, the Python Software Foundation (PSF, see
|
||||||
|
https://www.python.org/psf/) was formed, a non-profit organization
|
||||||
|
created specifically to own Python-related Intellectual Property.
|
||||||
|
Zope Corporation was a sponsoring member of the PSF.
|
||||||
|
|
||||||
|
All Python releases are Open Source (see http://www.opensource.org for
|
||||||
|
the Open Source Definition). Historically, most, but not all, Python
|
||||||
|
releases have also been GPL-compatible; the table below summarizes
|
||||||
|
the various releases.
|
||||||
|
|
||||||
|
Release Derived Year Owner GPL-
|
||||||
|
from compatible? (1)
|
||||||
|
|
||||||
|
0.9.0 thru 1.2 1991-1995 CWI yes
|
||||||
|
1.3 thru 1.5.2 1.2 1995-1999 CNRI yes
|
||||||
|
1.6 1.5.2 2000 CNRI no
|
||||||
|
2.0 1.6 2000 BeOpen.com no
|
||||||
|
1.6.1 1.6 2001 CNRI yes (2)
|
||||||
|
2.1 2.0+1.6.1 2001 PSF no
|
||||||
|
2.0.1 2.0+1.6.1 2001 PSF yes
|
||||||
|
2.1.1 2.1+2.0.1 2001 PSF yes
|
||||||
|
2.1.2 2.1.1 2002 PSF yes
|
||||||
|
2.1.3 2.1.2 2002 PSF yes
|
||||||
|
2.2 and above 2.1.1 2001-now PSF yes
|
||||||
|
|
||||||
|
Footnotes:
|
||||||
|
|
||||||
|
(1) GPL-compatible doesn't mean that we're distributing Python under
|
||||||
|
the GPL. All Python licenses, unlike the GPL, let you distribute
|
||||||
|
a modified version without making your changes open source. The
|
||||||
|
GPL-compatible licenses make it possible to combine Python with
|
||||||
|
other software that is released under the GPL; the others don't.
|
||||||
|
|
||||||
|
(2) According to Richard Stallman, 1.6.1 is not GPL-compatible,
|
||||||
|
because its license has a choice of law clause. According to
|
||||||
|
CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1
|
||||||
|
is "not incompatible" with the GPL.
|
||||||
|
|
||||||
|
Thanks to the many outside volunteers who have worked under Guido's
|
||||||
|
direction to make these releases possible.
|
||||||
|
|
||||||
|
|
||||||
|
B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON
|
||||||
|
===============================================================
|
||||||
|
|
||||||
|
PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
|
||||||
|
--------------------------------------------
|
||||||
|
|
||||||
|
1. This LICENSE AGREEMENT is between the Python Software Foundation
|
||||||
|
("PSF"), and the Individual or Organization ("Licensee") accessing and
|
||||||
|
otherwise using this software ("Python") in source or binary form and
|
||||||
|
its associated documentation.
|
||||||
|
|
||||||
|
2. Subject to the terms and conditions of this License Agreement, PSF hereby
|
||||||
|
grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
|
||||||
|
analyze, test, perform and/or display publicly, prepare derivative works,
|
||||||
|
distribute, and otherwise use Python alone or in any derivative version,
|
||||||
|
provided, however, that PSF's License Agreement and PSF's notice of copyright,
|
||||||
|
i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
||||||
|
2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Python Software Foundation;
|
||||||
|
All Rights Reserved" are retained in Python alone or in any derivative version
|
||||||
|
prepared by Licensee.
|
||||||
|
|
||||||
|
3. In the event Licensee prepares a derivative work that is based on
|
||||||
|
or incorporates Python or any part thereof, and wants to make
|
||||||
|
the derivative work available to others as provided herein, then
|
||||||
|
Licensee hereby agrees to include in any such work a brief summary of
|
||||||
|
the changes made to Python.
|
||||||
|
|
||||||
|
4. PSF is making Python available to Licensee on an "AS IS"
|
||||||
|
basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
|
||||||
|
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
|
||||||
|
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
|
||||||
|
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
|
||||||
|
INFRINGE ANY THIRD PARTY RIGHTS.
|
||||||
|
|
||||||
|
5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
|
||||||
|
FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
|
||||||
|
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
|
||||||
|
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
|
||||||
|
|
||||||
|
6. This License Agreement will automatically terminate upon a material
|
||||||
|
breach of its terms and conditions.
|
||||||
|
|
||||||
|
7. Nothing in this License Agreement shall be deemed to create any
|
||||||
|
relationship of agency, partnership, or joint venture between PSF and
|
||||||
|
Licensee. This License Agreement does not grant permission to use PSF
|
||||||
|
trademarks or trade name in a trademark sense to endorse or promote
|
||||||
|
products or services of Licensee, or any third party.
|
||||||
|
|
||||||
|
8. By copying, installing or otherwise using Python, Licensee
|
||||||
|
agrees to be bound by the terms and conditions of this License
|
||||||
|
Agreement.
|
||||||
|
|
||||||
|
|
||||||
|
BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1
|
||||||
|
|
||||||
|
1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an
|
||||||
|
office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the
|
||||||
|
Individual or Organization ("Licensee") accessing and otherwise using
|
||||||
|
this software in source or binary form and its associated
|
||||||
|
documentation ("the Software").
|
||||||
|
|
||||||
|
2. Subject to the terms and conditions of this BeOpen Python License
|
||||||
|
Agreement, BeOpen hereby grants Licensee a non-exclusive,
|
||||||
|
royalty-free, world-wide license to reproduce, analyze, test, perform
|
||||||
|
and/or display publicly, prepare derivative works, distribute, and
|
||||||
|
otherwise use the Software alone or in any derivative version,
|
||||||
|
provided, however, that the BeOpen Python License is retained in the
|
||||||
|
Software, alone or in any derivative version prepared by Licensee.
|
||||||
|
|
||||||
|
3. BeOpen is making the Software available to Licensee on an "AS IS"
|
||||||
|
basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
|
||||||
|
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND
|
||||||
|
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
|
||||||
|
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT
|
||||||
|
INFRINGE ANY THIRD PARTY RIGHTS.
|
||||||
|
|
||||||
|
4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
|
||||||
|
SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS
|
||||||
|
AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY
|
||||||
|
DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
|
||||||
|
|
||||||
|
5. This License Agreement will automatically terminate upon a material
|
||||||
|
breach of its terms and conditions.
|
||||||
|
|
||||||
|
6. This License Agreement shall be governed by and interpreted in all
|
||||||
|
respects by the law of the State of California, excluding conflict of
|
||||||
|
law provisions. Nothing in this License Agreement shall be deemed to
|
||||||
|
create any relationship of agency, partnership, or joint venture
|
||||||
|
between BeOpen and Licensee. This License Agreement does not grant
|
||||||
|
permission to use BeOpen trademarks or trade names in a trademark
|
||||||
|
sense to endorse or promote products or services of Licensee, or any
|
||||||
|
third party. As an exception, the "BeOpen Python" logos available at
|
||||||
|
http://www.pythonlabs.com/logos.html may be used according to the
|
||||||
|
permissions granted on that web page.
|
||||||
|
|
||||||
|
7. By copying, installing or otherwise using the software, Licensee
|
||||||
|
agrees to be bound by the terms and conditions of this License
|
||||||
|
Agreement.
|
||||||
|
|
||||||
|
|
||||||
|
CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
1. This LICENSE AGREEMENT is between the Corporation for National
|
||||||
|
Research Initiatives, having an office at 1895 Preston White Drive,
|
||||||
|
Reston, VA 20191 ("CNRI"), and the Individual or Organization
|
||||||
|
("Licensee") accessing and otherwise using Python 1.6.1 software in
|
||||||
|
source or binary form and its associated documentation.
|
||||||
|
|
||||||
|
2. Subject to the terms and conditions of this License Agreement, CNRI
|
||||||
|
hereby grants Licensee a nonexclusive, royalty-free, world-wide
|
||||||
|
license to reproduce, analyze, test, perform and/or display publicly,
|
||||||
|
prepare derivative works, distribute, and otherwise use Python 1.6.1
|
||||||
|
alone or in any derivative version, provided, however, that CNRI's
|
||||||
|
License Agreement and CNRI's notice of copyright, i.e., "Copyright (c)
|
||||||
|
1995-2001 Corporation for National Research Initiatives; All Rights
|
||||||
|
Reserved" are retained in Python 1.6.1 alone or in any derivative
|
||||||
|
version prepared by Licensee. Alternately, in lieu of CNRI's License
|
||||||
|
Agreement, Licensee may substitute the following text (omitting the
|
||||||
|
quotes): "Python 1.6.1 is made available subject to the terms and
|
||||||
|
conditions in CNRI's License Agreement. This Agreement together with
|
||||||
|
Python 1.6.1 may be located on the Internet using the following
|
||||||
|
unique, persistent identifier (known as a handle): 1895.22/1013. This
|
||||||
|
Agreement may also be obtained from a proxy server on the Internet
|
||||||
|
using the following URL: http://hdl.handle.net/1895.22/1013".
|
||||||
|
|
||||||
|
3. In the event Licensee prepares a derivative work that is based on
|
||||||
|
or incorporates Python 1.6.1 or any part thereof, and wants to make
|
||||||
|
the derivative work available to others as provided herein, then
|
||||||
|
Licensee hereby agrees to include in any such work a brief summary of
|
||||||
|
the changes made to Python 1.6.1.
|
||||||
|
|
||||||
|
4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS"
|
||||||
|
basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
|
||||||
|
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND
|
||||||
|
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
|
||||||
|
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT
|
||||||
|
INFRINGE ANY THIRD PARTY RIGHTS.
|
||||||
|
|
||||||
|
5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
|
||||||
|
1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
|
||||||
|
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1,
|
||||||
|
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
|
||||||
|
|
||||||
|
6. This License Agreement will automatically terminate upon a material
|
||||||
|
breach of its terms and conditions.
|
||||||
|
|
||||||
|
7. This License Agreement shall be governed by the federal
|
||||||
|
intellectual property law of the United States, including without
|
||||||
|
limitation the federal copyright law, and, to the extent such
|
||||||
|
U.S. federal law does not apply, by the law of the Commonwealth of
|
||||||
|
Virginia, excluding Virginia's conflict of law provisions.
|
||||||
|
Notwithstanding the foregoing, with regard to derivative works based
|
||||||
|
on Python 1.6.1 that incorporate non-separable material that was
|
||||||
|
previously distributed under the GNU General Public License (GPL), the
|
||||||
|
law of the Commonwealth of Virginia shall govern this License
|
||||||
|
Agreement only as to issues arising under or with respect to
|
||||||
|
Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this
|
||||||
|
License Agreement shall be deemed to create any relationship of
|
||||||
|
agency, partnership, or joint venture between CNRI and Licensee. This
|
||||||
|
License Agreement does not grant permission to use CNRI trademarks or
|
||||||
|
trade name in a trademark sense to endorse or promote products or
|
||||||
|
services of Licensee, or any third party.
|
||||||
|
|
||||||
|
8. By clicking on the "ACCEPT" button where indicated, or by copying,
|
||||||
|
installing or otherwise using Python 1.6.1, Licensee agrees to be
|
||||||
|
bound by the terms and conditions of this License Agreement.
|
||||||
|
|
||||||
|
ACCEPT
|
||||||
|
|
||||||
|
|
||||||
|
CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2
|
||||||
|
--------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam,
|
||||||
|
The Netherlands. All rights reserved.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and distribute this software and its
|
||||||
|
documentation for any purpose and without fee is hereby granted,
|
||||||
|
provided that the above copyright notice appear in all copies and that
|
||||||
|
both that copyright notice and this permission notice appear in
|
||||||
|
supporting documentation, and that the name of Stichting Mathematisch
|
||||||
|
Centrum or CWI not be used in advertising or publicity pertaining to
|
||||||
|
distribution of the software without specific, written prior
|
||||||
|
permission.
|
||||||
|
|
||||||
|
STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
|
||||||
|
THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
|
||||||
|
FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||||
|
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
notices: []
|
||||||
+55
@@ -0,0 +1,55 @@
|
|||||||
|
---
|
||||||
|
name: balanced-match
|
||||||
|
version: 1.0.2
|
||||||
|
type: npm
|
||||||
|
summary: Match balanced character pairs, like "{" and "}"
|
||||||
|
homepage: https://github.com/juliangruber/balanced-match
|
||||||
|
license: mit
|
||||||
|
licenses:
|
||||||
|
- sources: LICENSE.md
|
||||||
|
text: |
|
||||||
|
(MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2013 Julian Gruber <julian@juliangruber.com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
- sources: README.md
|
||||||
|
text: |-
|
||||||
|
(MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2013 Julian Gruber <julian@juliangruber.com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
notices: []
|
||||||
+1
-1
@@ -4,7 +4,7 @@ version: 4.0.4
|
|||||||
type: npm
|
type: npm
|
||||||
summary: Match balanced character pairs, like "{" and "}"
|
summary: Match balanced character pairs, like "{" and "}"
|
||||||
homepage:
|
homepage:
|
||||||
license: mit
|
license: other
|
||||||
licenses:
|
licenses:
|
||||||
- sources: LICENSE.md
|
- sources: LICENSE.md
|
||||||
text: |
|
text: |
|
||||||
+55
@@ -0,0 +1,55 @@
|
|||||||
|
---
|
||||||
|
name: brace-expansion
|
||||||
|
version: 1.1.15
|
||||||
|
type: npm
|
||||||
|
summary: Brace expansion as known from sh/bash
|
||||||
|
homepage: https://github.com/juliangruber/brace-expansion
|
||||||
|
license: mit
|
||||||
|
licenses:
|
||||||
|
- sources: LICENSE
|
||||||
|
text: |
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2013 Julian Gruber <julian@juliangruber.com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
- sources: README.md
|
||||||
|
text: |-
|
||||||
|
(MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2013 Julian Gruber <julian@juliangruber.com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
notices: []
|
||||||
+2
-2
@@ -1,10 +1,10 @@
|
|||||||
---
|
---
|
||||||
name: brace-expansion
|
name: brace-expansion
|
||||||
version: 5.0.9
|
version: 5.0.7
|
||||||
type: npm
|
type: npm
|
||||||
summary: Brace expansion as known from sh/bash
|
summary: Brace expansion as known from sh/bash
|
||||||
homepage:
|
homepage:
|
||||||
license: mit
|
license: other
|
||||||
licenses:
|
licenses:
|
||||||
- sources: LICENSE
|
- sources: LICENSE
|
||||||
text: |
|
text: |
|
||||||
Generated
+31
@@ -0,0 +1,31 @@
|
|||||||
|
---
|
||||||
|
name: concat-map
|
||||||
|
version: 0.0.1
|
||||||
|
type: npm
|
||||||
|
summary: concatenative mapdashery
|
||||||
|
homepage: https://github.com/substack/node-concat-map#readme
|
||||||
|
license: other
|
||||||
|
licenses:
|
||||||
|
- sources: LICENSE
|
||||||
|
text: |
|
||||||
|
This software is released under the MIT license:
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
- sources: README.markdown
|
||||||
|
text: MIT
|
||||||
|
notices: []
|
||||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: fast-xml-builder
|
name: fast-xml-builder
|
||||||
version: 1.3.0
|
version: 1.2.1
|
||||||
type: npm
|
type: npm
|
||||||
summary: Build XML from JSON without C/C++ based libraries
|
summary: Build XML from JSON without C/C++ based libraries
|
||||||
homepage:
|
homepage:
|
||||||
|
|||||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: fast-xml-parser
|
name: fast-xml-parser
|
||||||
version: 5.10.1
|
version: 5.9.3
|
||||||
type: npm
|
type: npm
|
||||||
summary: Validate XML, Parse XML, Build XML without C/C++ based libraries
|
summary: Validate XML, Parse XML, Build XML without C/C++ based libraries
|
||||||
homepage:
|
homepage:
|
||||||
|
|||||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: is-unsafe
|
name: is-unsafe
|
||||||
version: 2.0.0
|
version: 1.0.1
|
||||||
type: npm
|
type: npm
|
||||||
summary: Zero-dependency, DOM-free, pure predicate for detecting unsafe strings across
|
summary: Zero-dependency, DOM-free, pure predicate for detecting unsafe strings across
|
||||||
HTML, XML, SVG, SQL, SHELL, and REGEX contexts
|
HTML, XML, SVG, SQL, SHELL, and REGEX contexts
|
||||||
|
|||||||
Generated
+32
@@ -0,0 +1,32 @@
|
|||||||
|
---
|
||||||
|
name: js-yaml
|
||||||
|
version: 4.3.0
|
||||||
|
type: npm
|
||||||
|
summary: YAML 1.2 parser and serializer
|
||||||
|
homepage:
|
||||||
|
license: mit
|
||||||
|
licenses:
|
||||||
|
- sources: LICENSE
|
||||||
|
text: |
|
||||||
|
(The MIT License)
|
||||||
|
|
||||||
|
Copyright (C) 2011-2015 by Vitaly Puzrin
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
notices: []
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: minimatch
|
name: minimatch
|
||||||
version: 10.2.6
|
version: 10.2.5
|
||||||
type: npm
|
type: npm
|
||||||
summary: a glob matcher in javascript
|
summary: a glob matcher in javascript
|
||||||
homepage:
|
homepage:
|
||||||
Generated
+26
@@ -0,0 +1,26 @@
|
|||||||
|
---
|
||||||
|
name: minimatch
|
||||||
|
version: 3.1.5
|
||||||
|
type: npm
|
||||||
|
summary: a glob matcher in javascript
|
||||||
|
homepage:
|
||||||
|
license: isc
|
||||||
|
licenses:
|
||||||
|
- sources: LICENSE
|
||||||
|
text: |
|
||||||
|
The ISC License
|
||||||
|
|
||||||
|
Copyright (c) Isaac Z. Schlueter and Contributors
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||||
|
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
notices: []
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: path-expression-matcher
|
name: path-expression-matcher
|
||||||
version: 1.6.2
|
version: 1.6.1
|
||||||
type: npm
|
type: npm
|
||||||
summary: Efficient path tracking and pattern matching for XML/JSON parsers
|
summary: Efficient path tracking and pattern matching for XML/JSON parsers
|
||||||
homepage: https://github.com/NaturalIntelligence/path-expression-matcher#readme
|
homepage: https://github.com/NaturalIntelligence/path-expression-matcher#readme
|
||||||
|
|||||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: undici
|
name: undici
|
||||||
version: 6.28.0
|
version: 6.27.0
|
||||||
type: npm
|
type: npm
|
||||||
summary: An HTTP/1.1 client, written from scratch for Node.js
|
summary: An HTTP/1.1 client, written from scratch for Node.js
|
||||||
homepage: https://undici.nodejs.org
|
homepage: https://undici.nodejs.org
|
||||||
|
|||||||
Generated
+1
-24
@@ -1,35 +1,12 @@
|
|||||||
---
|
---
|
||||||
name: xml-naming
|
name: xml-naming
|
||||||
version: 0.3.0
|
version: 0.1.0
|
||||||
type: npm
|
type: npm
|
||||||
summary: Validates XML name productions — Name, NCName, QName, NMToken, NMTokens —
|
summary: Validates XML name productions — Name, NCName, QName, NMToken, NMTokens —
|
||||||
for XML 1.0 and 1.1
|
for XML 1.0 and 1.1
|
||||||
homepage:
|
homepage:
|
||||||
license: mit
|
license: mit
|
||||||
licenses:
|
licenses:
|
||||||
- sources: LICENSE
|
|
||||||
text: |
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2026 Natural Intelligence
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
- sources: README.md
|
- sources: README.md
|
||||||
text: MIT
|
text: MIT
|
||||||
notices: []
|
notices: []
|
||||||
|
|||||||
Generated
+32
@@ -0,0 +1,32 @@
|
|||||||
|
---
|
||||||
|
name: xmlbuilder2
|
||||||
|
version: 4.0.3
|
||||||
|
type: npm
|
||||||
|
summary: An XML builder for node.js
|
||||||
|
homepage: https://github.com/oozcitak/xmlbuilder2
|
||||||
|
license: mit
|
||||||
|
licenses:
|
||||||
|
- sources: LICENSE.txt
|
||||||
|
text: |
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2019 Ozgur Ozcitak
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
notices: []
|
||||||
@@ -4,471 +4,332 @@
|
|||||||
[](https://github.com/actions/setup-java/actions/workflows/e2e-versions.yml)
|
[](https://github.com/actions/setup-java/actions/workflows/e2e-versions.yml)
|
||||||
[](https://github.com/actions/setup-java/actions/workflows/e2e-cache.yml)
|
[](https://github.com/actions/setup-java/actions/workflows/e2e-cache.yml)
|
||||||
|
|
||||||
Set up Java for GitHub Actions workflows. `setup-java` installs a requested Java distribution, adds it to `PATH`, configures `JAVA_HOME`, and can optionally cache build dependencies for Apache Maven, Gradle, and sbt; generate Maven publishing configuration, verify JDK package signatures, manage multiple JDKs, and manage Maven toolchains.
|
The `setup-java` action provides the following functionality for GitHub Actions runners:
|
||||||
|
- Downloading and setting up a requested version of Java. See [Usage](#usage) for a list of supported distributions.
|
||||||
|
- Extracting and caching custom version of Java from a local file.
|
||||||
|
- Configuring runner for publishing using Apache Maven.
|
||||||
|
- Configuring runner for publishing using Gradle.
|
||||||
|
- Configuring runner for using GPG private key.
|
||||||
|
- Registering problem matchers for error output.
|
||||||
|
- Caching dependencies managed by Apache Maven.
|
||||||
|
- Caching dependencies managed by Gradle.
|
||||||
|
- Caching dependencies managed by sbt.
|
||||||
|
- [Maven Toolchains declaration](https://maven.apache.org/guides/mini/guide-using-toolchains.html) for specified JDK versions.
|
||||||
|
|
||||||
```yaml
|
This action allows you to work with Java and Scala projects.
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v7
|
|
||||||
- uses: actions/setup-java@v5
|
|
||||||
with:
|
|
||||||
distribution: temurin
|
|
||||||
java-version: '25'
|
|
||||||
- run: java --version
|
|
||||||
```
|
|
||||||
|
|
||||||
> [!NOTE]
|
## What's new in V6
|
||||||
> V6 is still in development on the `main` branch and is not yet recommended for production workflows. To use it, you must explicitly reference the `main` branch in your workflow, as in
|
|
||||||
>
|
|
||||||
> ```yaml
|
|
||||||
> - uses: actions/setup-java@main
|
|
||||||
> ```
|
|
||||||
>
|
|
||||||
> For production workflows, it is recommended to use the latest stable release `v5`.
|
|
||||||
|
|
||||||
## Contents
|
- **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.
|
||||||
|
|
||||||
- [What it does](#what-it-does)
|
## Breaking changes in V5
|
||||||
- [What's new](#whats-new)
|
|
||||||
- [Usage](#usage)
|
|
||||||
- [Inputs](#inputs)
|
|
||||||
- [Supported distributions](#supported-distributions)
|
|
||||||
- [Supported version syntax](#supported-version-syntax)
|
|
||||||
- [Caching](#caching)
|
|
||||||
- [Multiple JDKs and Maven toolchains](#multiple-jdks-and-maven-toolchains)
|
|
||||||
- [Publishing packages](#publishing-packages)
|
|
||||||
- [Advanced usage](#advanced-usage)
|
|
||||||
|
|
||||||
## What it does
|
- Upgraded action from node20 to node24
|
||||||
|
> Make sure your runner is on version v2.327.1 or later to ensure compatibility with this release [Release Notes](https://github.com/actions/runner/releases/tag/v2.327.1)
|
||||||
|
|
||||||
- Downloads and installs Java from a supported distribution.
|
For more details, see the full release notes on the [releases page](https://github.com/actions/setup-java/releases/tag/v5.0.0)
|
||||||
- Uses a requested Java version, a version file, or the `latest` stable release alias.
|
|
||||||
- Extracts and caches a custom JDK archive from a local file.
|
|
||||||
- Configures Maven `settings.xml`, Maven Toolchains, Maven GPG signing inputs, and environment-variable based credentials for publishing workflows.
|
|
||||||
- Registers Java problem matchers for compiler diagnostics and uncaught exceptions.
|
|
||||||
- Caches dependencies for Maven, Gradle, and sbt.
|
|
||||||
- Caches downloaded JDK installations between jobs.
|
|
||||||
- Verifies downloaded archive checksums when a distribution publishes authoritative checksums.
|
|
||||||
- Optionally verifies package signatures for supported distributions.
|
|
||||||
|
|
||||||
`setup-java` works with Java, Scala, Kotlin, Gradle, Maven, and sbt projects.
|
|
||||||
|
|
||||||
## What's new
|
|
||||||
|
|
||||||
### V6 (in development)
|
|
||||||
|
|
||||||
- Migrated the action implementation to ESM to support the latest `@actions/*` packages.
|
|
||||||
- Added the `oracle-openjdk` distribution for OpenJDK builds from Oracle.
|
|
||||||
- Added `java-version: latest` to resolve the newest stable GA release from the distribution's remote metadata.
|
|
||||||
- JDK downloads now automatically verify authoritative checksums for [supported distributions](#download-integrity-and-signatures).
|
|
||||||
- Added `force-download: true` to bypass the tool cache and perform a reproducible fresh install.
|
|
||||||
- Dependency caching now supports custom paths with `cache-path` and restore-only operation with `cache-read-only: true`.
|
|
||||||
- Downloaded JDKs are now [cached](#caching-jdk-installations) automatically when `cache` is set; use `cache-jdk` to enable or disable it independently.
|
|
||||||
- Set `problem-matcher: false` to disable Java compiler and uncaught-exception annotations.
|
|
||||||
- GraalVM distributions now set `GRAALVM_HOME` in addition to `JAVA_HOME`.
|
|
||||||
- Invalid boolean values, unsupported distribution/package/platform combinations, and mismatched Maven toolchain ID counts now fail with targeted errors.
|
|
||||||
- Renamed environment-variable-name inputs so they are not mistaken for secret values:
|
|
||||||
- `server-username` -> `server-username-env-var`
|
|
||||||
- `server-password` -> `server-password-env-var`
|
|
||||||
- `gpg-passphrase` -> `gpg-passphrase-env-var`
|
|
||||||
- Deprecated aliases still work, but emit warnings.
|
|
||||||
- Maven GPG passphrases are now passed through `gpg.passphraseEnvName` instead of a deprecated `gpg.passphrase` server entry in `settings.xml`. This requires `maven-gpg-plugin` 3.2.0 or newer. See [GPG](docs/advanced-usage.md#gpg).
|
|
||||||
- Legacy AdoptOpenJDK distributions were removed. Use `temurin` instead of `adopt` or `adopt-hotspot`, and `semeru` instead of `adopt-openj9`.
|
|
||||||
|
|
||||||
### V5
|
|
||||||
|
|
||||||
- Upgraded the action runtime from Node 20 to Node 24. Self-hosted runners must use version `v2.327.1` or later. See the [runner release notes](https://github.com/actions/runner/releases/tag/v2.327.1).
|
|
||||||
- Added support for [GraalVM Community](#supported-distributions) and [Tencent Kona](#supported-distributions).
|
|
||||||
- Expanded `java-version-file` support with `.sdkmanrc` files and automatic distribution detection from SDKMAN and asdf vendor identifiers.
|
|
||||||
- Added optional package-signature verification for Eclipse Temurin and Microsoft Build of OpenJDK downloads.
|
|
||||||
- Added `set-default: false` for installing a JDK without changing `JAVA_HOME` or `PATH`.
|
|
||||||
- Improved dependency caching with separate Maven and Gradle wrapper caches, Maven extension-aware cache keys, and the `cache-primary-key` output.
|
|
||||||
- Improved Maven and Java build behavior by preserving toolchain entries across repeated action invocations, suppressing transfer progress by default, generating non-interactive Maven settings, and matching `javac` compiler errors.
|
|
||||||
- Renamed the `jdkFile` input to `jdk-file`; the old name remains available as a deprecated alias.
|
|
||||||
- See the [complete V5 release history](https://github.com/actions/setup-java/releases?q=v5&expanded=true) for enhancements and fixes across all V5 releases.
|
|
||||||
|
|
||||||
### Older versions
|
|
||||||
|
|
||||||
> [!WARNING]
|
|
||||||
> `actions/setup-java` versions `v1` through `v4` are deprecated. Upgrade workflows to `actions/setup-java@v5`, the latest stable release.
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
### Install Eclipse Temurin
|
- `java-version`: The Java version that is going to be set up. Takes a whole or [semver](#supported-version-syntax) Java version. If not specified, the action will expect `java-version-file` input to be specified.
|
||||||
|
|
||||||
|
- `java-version-file`: The path to a file containing java version. Supported file types are `.java-version`, `.tool-versions`, and `.sdkmanrc`. See more details in [about .java-version-file](docs/advanced-usage.md#Java-version-file).
|
||||||
|
|
||||||
|
- `distribution`: Java [distribution](#supported-distributions). Required unless `java-version-file` points to `.sdkmanrc` with a recognized distribution suffix (for example `java=21.0.5-tem`).
|
||||||
|
|
||||||
|
- `java-package`: The packaging variant of the chosen distribution. Possible values: `jdk`, `jre`, `jdk+fx`, `jre+fx`. For Azul Zulu, `jdk+crac` and `jre+crac` are also supported. Default value: `jdk`.
|
||||||
|
|
||||||
|
- `architecture`: The target architecture of the package. Possible values: `x86`, `x64`, `armv7`, `aarch64`, `ppc64le`. Default value: Derived from the runner machine.
|
||||||
|
|
||||||
|
- `jdk-file`: If a use-case requires a custom distribution setup-java uses the compressed JDK from the location pointed by this input and will take care of the installation and caching on the VM. Note: `distribution` must be set to 'jdkfile' (case-sensitive; all lowercase) when using this option. (The camelCase `jdkFile` input is still accepted as a deprecated alias and may be removed in a future release.)
|
||||||
|
|
||||||
|
- `check-latest`: Setting this option makes the action to check for the latest available version for the version spec.
|
||||||
|
|
||||||
|
- `set-default`: Set to `false` to install a JDK without making it the default. When `false`, `JAVA_HOME` and `PATH` are not updated, but `JAVA_HOME_<major>_<arch>` is still set so the JDK remains discoverable. Default value: `true`. See [Installing JDK without setting as default](docs/advanced-usage.md#Installing-JDK-without-setting-as-default) for more details.
|
||||||
|
|
||||||
|
- `verify-signature`: Verifies downloaded Java package signatures when supported by the selected distribution. Currently supported for `temurin` and `microsoft`. If set to `true` for unsupported distributions, the action fails.
|
||||||
|
|
||||||
|
- `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.
|
||||||
|
|
||||||
|
- `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.
|
||||||
|
|
||||||
|
#### Maven options
|
||||||
|
The action has a bunch of inputs to generate maven's [settings.xml](https://maven.apache.org/settings.html) on the fly and pass the values to Apache Maven GPG Plugin as well as Apache Maven Toolchains. See [advanced usage](docs/advanced-usage.md) for more.
|
||||||
|
|
||||||
|
- `overwrite-settings`: By default action overwrites the settings.xml. In order to skip generation of file if it exists, set this to `false`.
|
||||||
|
|
||||||
|
- `server-id`: ID of the distributionManagement repository in the pom.xml file. Default is `github`.
|
||||||
|
|
||||||
|
- `server-username`: Environment variable name for the username for authentication to the Apache Maven repository. Default is GITHUB_ACTOR.
|
||||||
|
|
||||||
|
- `server-password`: Environment variable name for password or token for authentication to the Apache Maven repository. Default is GITHUB_TOKEN.
|
||||||
|
|
||||||
|
- `settings-path`: Maven related setting to point to the directory where the settings.xml file will be written. Default is ~/.m2.
|
||||||
|
|
||||||
|
- `gpg-private-key`: GPG private key to import. Default is empty string.
|
||||||
|
|
||||||
|
- `gpg-passphrase`: Environment variable name for the GPG private key passphrase. Default is GPG_PASSPHRASE.
|
||||||
|
|
||||||
|
- `mvn-toolchain-id`: Name of Maven Toolchain ID if the default name of `${distribution}_${java-version}` is not wanted.
|
||||||
|
|
||||||
|
- `mvn-toolchain-vendor`: Name of Maven Toolchain Vendor if the default name of `${distribution}` is not wanted.
|
||||||
|
|
||||||
|
### Basic Configuration
|
||||||
|
|
||||||
|
#### Eclipse Temurin
|
||||||
```yaml
|
```yaml
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v7
|
- uses: actions/checkout@v6
|
||||||
- uses: actions/setup-java@v5
|
- uses: actions/setup-java@v5
|
||||||
with:
|
with:
|
||||||
distribution: temurin
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
java-version: '25'
|
java-version: '25'
|
||||||
- run: java --version
|
- run: java --version
|
||||||
```
|
```
|
||||||
|
|
||||||
### Install Microsoft Build of OpenJDK
|
#### Azul Zulu OpenJDK
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v7
|
- uses: actions/checkout@v6
|
||||||
- uses: actions/setup-java@v5
|
- uses: actions/setup-java@v5
|
||||||
with:
|
with:
|
||||||
distribution: microsoft
|
distribution: 'zulu' # See 'Supported distributions' for available options
|
||||||
java-version: '25'
|
java-version: '25'
|
||||||
- run: java --version
|
- run: java --version
|
||||||
```
|
```
|
||||||
|
|
||||||
### Read the version from a file
|
#### Supported version syntax
|
||||||
|
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:
|
||||||
```yaml
|
- major versions, such as: `8`, `11`, `16`, `17`, `21`, `25`
|
||||||
steps:
|
- more specific versions: `8.0.282+8`, `8.0.232`, `11.0`, `11.0.4`, `17.0`
|
||||||
- uses: actions/checkout@v7
|
- multi-field Java versions (JEP 322), such as: `11.0.9.1`, `18.0.1.1`
|
||||||
- uses: actions/setup-java@v5
|
- early access (EA) versions: `15-ea`, `15.0.0-ea`
|
||||||
with:
|
- the `latest` alias, which floats to the newest available stable (GA) release
|
||||||
distribution: temurin
|
|
||||||
java-version-file: .java-version
|
|
||||||
- run: java --version
|
|
||||||
```
|
|
||||||
|
|
||||||
Supported version files are `.java-version`, `.tool-versions`, and `.sdkmanrc`. A `.sdkmanrc` file can also provide the distribution when it contains a recognized suffix, such as `java=21.0.5-tem`.
|
|
||||||
|
|
||||||
### Use the newest stable Java
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v7
|
|
||||||
- uses: actions/setup-java@v5
|
|
||||||
with:
|
|
||||||
distribution: temurin
|
|
||||||
java-version: latest
|
|
||||||
- run: java --version
|
|
||||||
```
|
|
||||||
|
|
||||||
`latest` resolves the newest stable GA release from remote metadata rather than from the runner tool cache. Distributions that do not publish a release listing (such as `oracle` and `graalvm`) resolve the newest GA feature version from the Adoptium available-releases API and then request that version from their own catalog. `latest` is not supported with `java-version-file`, early-access versions, or `distribution: jdkfile`.
|
|
||||||
|
|
||||||
## Inputs
|
|
||||||
|
|
||||||
| Input | Description | Default |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| `java-version` | Java version to install. Supports whole versions, semver ranges, early-access versions, and `latest`. Required unless `java-version-file` is set. | |
|
|
||||||
| `java-version-file` | Path to `.java-version`, `.tool-versions`, or `.sdkmanrc`. Used when `java-version` is not set. | |
|
|
||||||
| `distribution` | Java distribution keyword. Values are case-sensitive and must match one of the supported keywords below. Required unless `java-version-file` points to `.sdkmanrc` with a recognized distribution suffix. | |
|
|
||||||
| `java-package` | Package variant such as `jdk`, `jre`, `jdk+fx`, `jre+fx`, `jdk+crac`, `jre+crac`, `jdk+jmods`, `jdk+jcef`, `jre+jcef`, `jdk+ft`, or `jre+ft`. Support varies by distribution. | `jdk` |
|
|
||||||
| `architecture` | Package architecture. Canonical values are `x86`, `x64`, `armv7`, `aarch64`, `ppc64le`, `ppc64`, and `s390x`. Aliases `ia32`, `amd64`, `arm`, and `arm64` are normalized. | Runner architecture |
|
|
||||||
| `jdk-file` | Local compressed JDK archive. Requires `distribution: jdkfile`. | |
|
|
||||||
| `check-latest` | Check remote metadata for the latest version satisfying the version spec before using the runner tool cache. | `false` |
|
|
||||||
| `force-download` | Always download Java and replace any matching version in the tool cache. | `false` |
|
|
||||||
| `set-default` | Add Java to `PATH` and set `JAVA_HOME`. When `false`, only version-specific `JAVA_HOME_<major>_<arch>` variables are set. | `true` |
|
|
||||||
| `problem-matcher` | Register Java compiler and uncaught exception problem matchers. | `true` |
|
|
||||||
| `verify-signature` | Verify downloaded Java package signatures when supported. Currently supported for `temurin` and `microsoft`. | `false` |
|
|
||||||
| `verify-signature-public-key` | ASCII-armored GPG public key to use for signature verification. Overrides the bundled key. | |
|
|
||||||
| `token` | Token for fetching GitHub.com-hosted version manifests, useful on GitHub Enterprise Server when unauthenticated requests are rate-limited. | `${{ github.token }}` on GitHub.com; empty string on GHES |
|
|
||||||
| `cache` | Enable dependency caching for `maven`, `gradle`, or `sbt`. | |
|
|
||||||
| `cache-jdk` | Cache downloaded JDK installations between jobs. When omitted, JDK caching is enabled only if `cache` is set. Set explicitly to `true` or `false` to override. | Enabled when `cache` is set |
|
|
||||||
| `cache-dependency-path` | Dependency file paths used for cache key hashing. Supports globs and multiline values. | Auto-detected by package manager |
|
|
||||||
| `cache-path` | Cache paths to use instead of the package manager's default dependency cache path. Supports multiline values and exclusions. | |
|
|
||||||
| `cache-read-only` | Restore dependency, wrapper, and JDK caches without saving changes in the post step. | `false` |
|
|
||||||
| `server-id` | Maven repository ID used in generated `settings.xml`. | `github` |
|
|
||||||
| `server-username-env-var` | Environment variable name for Maven repository username. | `GITHUB_ACTOR` |
|
|
||||||
| `server-password-env-var` | Environment variable name for Maven repository password or token. | `GITHUB_TOKEN` |
|
|
||||||
| `settings-path` | Directory where `settings.xml` is written. | `~/.m2` |
|
|
||||||
| `overwrite-settings` | Overwrite an existing `settings.xml`. | `true` |
|
|
||||||
| `gpg-private-key` | GPG private key to import. | |
|
|
||||||
| `gpg-passphrase-env-var` | Environment variable name for the GPG private key passphrase. | `GPG_PASSPHRASE` when a key is set |
|
|
||||||
| `mvn-toolchain-id` | Maven Toolchain ID. When multiple Java versions are installed, the number of IDs must match the number of versions. | `${mvn-toolchain-vendor}_${java-version}` |
|
|
||||||
| `mvn-toolchain-vendor` | Maven Toolchain vendor value. | `${distribution}` |
|
|
||||||
| `show-download-progress` | Keep Maven artifact download and transfer progress in logs. When `false`, the action adds `-ntp` to `MAVEN_ARGS`. | `false` |
|
|
||||||
|
|
||||||
- `java-package`: Supported package types are `jdk`, `jre`, `jdk+fx`, `jre+fx`, `jdk+crac`, `jre+crac`, `jdk+jmods`, `jdk+jcef`, `jre+jcef`, `jdk+ft`, and `jre+ft`. Availability varies by distribution.
|
|
||||||
|
|
||||||
Deprecated aliases `jdkFile`, `server-username`, `server-password`, and `gpg-passphrase` remain accepted for compatibility, but should be replaced with the current input names.
|
|
||||||
|
|
||||||
## Outputs
|
|
||||||
|
|
||||||
| Output | Description |
|
|
||||||
| --- | --- |
|
|
||||||
| `distribution` | Distribution that was installed. |
|
|
||||||
| `version` | Actual Java version that was installed. |
|
|
||||||
| `path` | Installation path, also used for `JAVA_HOME` when `set-default` is enabled. |
|
|
||||||
| `cache-hit` | Whether an exact dependency cache match was restored. |
|
|
||||||
| `cache-primary-key` | Primary cache key computed for the selected package manager. Empty when caching is disabled or skipped. |
|
|
||||||
|
|
||||||
## Supported distributions
|
|
||||||
|
|
||||||
| Keyword | Distribution | License |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| `corretto` | [Amazon Corretto](https://aws.amazon.com/corretto/) | [License](https://aws.amazon.com/corretto/faqs/) |
|
|
||||||
| `dragonwell` | [Alibaba Dragonwell JDK](https://dragonwell-jdk.io/) | [License](https://www.aliyun.com/product/dragonwell/) |
|
|
||||||
| `graalvm` | [Oracle GraalVM](https://www.graalvm.org/) | [License](https://www.oracle.com/downloads/licenses/graal-free-license.html) |
|
|
||||||
| `graalvm-community` | [GraalVM Community](https://github.com/graalvm/graalvm-ce-builds/releases) | [License](https://github.com/oracle/graal/blob/master/LICENSE) |
|
|
||||||
| `jetbrains` | [JetBrains Runtime](https://github.com/JetBrains/JetBrainsRuntime/) | [License](https://github.com/JetBrains/JetBrainsRuntime/blob/main/LICENSE) |
|
|
||||||
| `kona` | [Tencent Kona JDK](https://tencent.github.io/konajdk/) | [License](https://tencent.github.io/konajdk/LICENSE.txt) |
|
|
||||||
| `liberica` | [Liberica JDK](https://bell-sw.com/) | [License](https://bell-sw.com/liberica_eula/) |
|
|
||||||
| `liberica-nik` | [Liberica Native Image Kit](https://bell-sw.com/pages/downloads/native-image-kit/) | [License](https://bell-sw.com/liberica_nik_eula/) |
|
|
||||||
| `microsoft` | [Microsoft Build of OpenJDK](https://www.microsoft.com/openjdk) | [License](https://docs.microsoft.com/java/openjdk/faq) |
|
|
||||||
| `oracle` | [Oracle JDK](https://www.oracle.com/java/technologies/downloads/) | [License](https://java.com/freeuselicense) |
|
|
||||||
| `oracle-openjdk` | [Oracle OpenJDK](https://jdk.java.net/) | [License](https://openjdk.org/legal/gplv2+ce.html) |
|
|
||||||
| `sapmachine` | [SAP SapMachine JDK/JRE](https://sapmachine.io/) | [License](https://github.com/SAP/SapMachine/blob/sapmachine/LICENSE) |
|
|
||||||
| `semeru` | [IBM Semeru Runtime Open Edition](https://developer.ibm.com/languages/java/semeru-runtimes/downloads/) | [License](https://openjdk.java.net/legal/gplv2+ce.html) |
|
|
||||||
| `temurin` | [Eclipse Temurin](https://adoptium.net/) | [License](https://adoptium.net/about.html) |
|
|
||||||
| `zulu` | [Azul Zulu OpenJDK](https://www.azul.com/downloads/zulu-community/?package=jdk) | [License](https://www.azul.com/products/zulu-and-zulu-enterprise/zulu-terms-of-use/) |
|
|
||||||
| `jdkfile` | Custom JDK archive | |
|
|
||||||
|
|
||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
> Distribution availability, package variants, architectures, and version metadata differ by vendor. Check the vendor documentation when a specific version or platform matters.
|
> - `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.
|
||||||
|
|
||||||
Additional distribution notes:
|
#### Supported distributions
|
||||||
|
Currently, the following distributions are supported:
|
||||||
|
| Keyword | Distribution / Official site | License
|
||||||
|
|-|-|-|
|
||||||
|
| `temurin` | [Eclipse Temurin](https://adoptium.net/) | [`temurin` license](https://adoptium.net/about.html)
|
||||||
|
| `zulu` | [Azul Zulu OpenJDK](https://www.azul.com/downloads/zulu-community/?package=jdk) | [`zulu` license](https://www.azul.com/products/zulu-and-zulu-enterprise/zulu-terms-of-use/) |
|
||||||
|
| `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) |
|
||||||
|
| `oracle` | [Oracle JDK](https://www.oracle.com/java/technologies/downloads/) | [`oracle` license](https://java.com/freeuselicense)
|
||||||
|
| `dragonwell` | [Alibaba Dragonwell JDK](https://dragonwell-jdk.io/) | [`dragonwell` license](https://www.aliyun.com/product/dragonwell/)
|
||||||
|
| `sapmachine` | [SAP SapMachine JDK/JRE](https://sapmachine.io/) | [`sapmachine` license](https://github.com/SAP/SapMachine/blob/sapmachine/LICENSE)
|
||||||
|
| `graalvm` | [Oracle GraalVM](https://www.graalvm.org/) | [`graalvm` license](https://www.oracle.com/downloads/licenses/graal-free-license.html)
|
||||||
|
| `graalvm-community` | [GraalVM Community](https://github.com/graalvm/graalvm-ce-builds/releases) | [`graalvm-community` license](https://github.com/oracle/graal/blob/master/LICENSE)
|
||||||
|
| `jetbrains` | [JetBrains Runtime](https://github.com/JetBrains/JetBrainsRuntime/) | [`jetbrains` license](https://github.com/JetBrains/JetBrainsRuntime/blob/main/LICENSE)
|
||||||
|
| `kona` | [Tencent Kona JDK](https://tencent.github.io/konajdk/) | [`kona` license](https://tencent.github.io/konajdk/LICENSE.txt)
|
||||||
|
| `jdkfile` | Custom JDK Installation | |
|
||||||
|
|
||||||
- Oracle OpenJDK builds are archived after a limited number of releases and no longer receive security updates. To continue receiving security patches, use Oracle JDK or another vendor.
|
> [!NOTE]
|
||||||
- Azul Zulu maps `arm64` to `aarch64` when querying the Azul Metadata API.
|
> - The different distributors can provide discrepant list of available versions / supported configurations. Please refer to the official documentation to see the list of supported versions.
|
||||||
- GraalVM Community is available as `distribution: graalvm-community` for stable JDK 17 and later releases.
|
> - AdoptOpenJDK got moved to Eclipse Temurin and won't be updated anymore. It is highly recommended to migrate workflows from `adopt` and `adopt-openj9`, to `temurin` and `semeru` respectively, to keep receiving software and security updates. See more details in the [Good-bye AdoptOpenJDK post](https://blog.adoptopenjdk.net/2021/08/goodbye-adoptopenjdk-hello-adoptium/).
|
||||||
- On Ubuntu runners, commands executed with `sudo` do not inherit the `JAVA_HOME` and `PATH` set by `setup-java` and may fall back to the system-default JDK.
|
> - For Azul Zulu OpenJDK, architecture `arm64` is mapped to `aarch64` when querying the Azul Metadata API.
|
||||||
|
> - To comply with the GraalVM Free Terms and Conditions (GFTC) license, it is recommended to use GraalVM JDK 17 version 17.0.12, as this is the only version of GraalVM JDK 17 available under the GFTC license. Additionally, it is encouraged to consider upgrading to GraalVM JDK 21, which offers the latest features and improvements.
|
||||||
|
> - GraalVM Community is available as `distribution: 'graalvm-community'` for stable JDK 17 and later releases published on GitHub.
|
||||||
|
|
||||||
## Supported version syntax
|
**NOTE:** Oracle JDK 17 licensing varies by patch level. As shown on the [JDK 17 Archive](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html) (versions up to 17.0.12 are under the [NFTC](https://www.oracle.com/downloads/licenses/no-fee-license.html) license) and the [JDK 17.0.13+ Archive](https://www.oracle.com/java/technologies/javase/jdk17-0-13-later-archive-downloads.html) (versions 17.0.13 and later are under the [OTN](https://www.oracle.com/downloads/licenses/javase-license1.html) license). To stay on the free NFTC license, use `distribution: 'oracle'` with `java-version: '17.0.12'` (or earlier) instead of the floating `'17'`. Alternatively, upgrade to Oracle JDK 21+, which remains under the NFTC license.
|
||||||
|
|
||||||
`java-version` accepts exact versions, version ranges, early-access versions, and `latest`.
|
**NOTE:** On Ubuntu runners, commands executed via `sudo` do not inherit the `JAVA_HOME` and `PATH` set by `setup-java` and will fall back to the runner image's system-default JDK.
|
||||||
|
|
||||||
| Syntax | Examples |
|
### Caching packages dependencies
|
||||||
| --- | --- |
|
The action has a built-in functionality for caching and restoring dependencies. It uses [toolkit/cache](https://github.com/actions/toolkit/tree/main/packages/cache) under hood for caching dependencies but requires less configuration settings. Supported package managers are gradle, maven and sbt. The format of the used cache key is `setup-java-${{ platform }}-${{ packageManager }}-${{ fileHash }}`, where the hash is based on the following files:
|
||||||
| Major version | `8`, `11`, `17`, `21`, `25` |
|
|
||||||
| Specific feature or patch version | `11.0`, `11.0.4`, `17.0`, `8.0.282+8` |
|
|
||||||
| JEP 322 multi-field versions | `11.0.9.1`, `18.0.1.1` |
|
|
||||||
| Early access | `15-ea`, `15.0.0-ea`, `27-ea` |
|
|
||||||
| Latest stable GA release | `latest` |
|
|
||||||
|
|
||||||
When `check-latest` is `false`, the action first tries the runner tool cache for the requested distribution, package type, architecture, and version range. It downloads Java only when no matching cached version is found. When `check-latest` is `true`, the action checks remote metadata first and downloads if the cached version is not current.
|
- gradle: `**/*.gradle*`, `**/gradle-wrapper.properties`, `buildSrc/**/Versions.kt`, `buildSrc/**/Dependencies.kt`, `gradle/*.versions.toml`, and `**/versions.properties`
|
||||||
|
- maven: `**/pom.xml`, `**/.mvn/wrapper/maven-wrapper.properties`, and `**/.mvn/extensions.xml`
|
||||||
|
- sbt: all sbt build definition files `**/*.sbt`, `**/project/build.properties`, `**/project/**.scala`, `**/project/**.sbt`
|
||||||
|
|
||||||
GitHub-hosted runners primarily pre-cache Eclipse Temurin JDKs. See the installed Java versions for [Ubuntu](https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2404-Readme.md#java), [Windows](https://github.com/actions/runner-images/blob/main/images/windows/Windows2025-Readme.md#java), and [macOS](https://github.com/actions/runner-images/blob/main/images/macos/macos-15-Readme.md#java). On a fresh GitHub-hosted runner, requests for other distributions usually miss the tool cache and resolve from remote metadata. For broad version ranges such as a major version (`21`, `25`), this often behaves similarly to `check-latest: true` because the action downloads the latest available release that satisfies the range.
|
When the option `cache-dependency-path` is specified, the hash is based on the matching file. This option supports wildcards and a list of file names, and is especially useful for monorepos.
|
||||||
|
|
||||||
## Download integrity and signatures
|
The workflow output `cache-hit` is set to indicate if an exact match was found for the key [as actions/cache does](https://github.com/actions/cache/tree/main#outputs).
|
||||||
|
|
||||||
`setup-java` automatically verifies downloaded archive checksums when a selected distribution publishes an authoritative checksum. Automatic checksum verification currently applies to `temurin`, `semeru`, `corretto`, `dragonwell`, `kona`, `sapmachine`, `graalvm`, `graalvm-community`, `zulu`, `oracle`, `oracle-openjdk`, `microsoft`, and `jetbrains`.
|
The workflow output `cache-primary-key` exposes the primary cache key computed by the action for the configured build tool. It is useful for composing with [`actions/cache`](https://github.com/actions/cache) or [`actions/cache/restore`](https://github.com/actions/cache/tree/main/restore) in later steps or dependent jobs that need to reuse the exact same key. It is empty when caching is not enabled or when caching is skipped (for example, when the cache service is unavailable).
|
||||||
|
|
||||||
Distributions or individual releases without an authoritative checksum continue to install normally, with the omission reported in debug logs. Installations resolved directly from the runner tool cache — including JDKs preinstalled on the runner image and JDKs installed by an earlier step of the same job — are not downloaded again and are not reverified, even when `verify-signature: true` is set. Use `force-download: true` to always download and verify the archive.
|
The cache input is optional, and caching is turned off by default.
|
||||||
|
|
||||||
Use `verify-signature: true` to verify package signatures for distributions that support it. Currently supported distributions are `temurin` and `microsoft`; setting it for an unsupported distribution fails the workflow.
|
**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.
|
||||||
|
|
||||||
## Caching
|
|
||||||
|
|
||||||
`setup-java` manages three kinds of caches. Each one is restored and saved as a separate cache entry.
|
|
||||||
|
|
||||||
| Cache | What it stores | Key based on | How it is enabled |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| Dependency cache | Downloaded dependencies, such as `~/.m2/repository`, `~/.gradle/caches`, or the sbt cache paths | Runner OS, architecture, package manager, and a hash of the dependency files | Set `cache` to `maven`, `gradle`, or `sbt` |
|
|
||||||
| Wrapper caches | Maven and Gradle wrapper distributions (`~/.m2/wrapper/dists`, `~/.gradle/wrapper`) | Runner OS, architecture, wrapper cache name, and a hash of the wrapper properties | Set `cache` to `maven` or `gradle` |
|
|
||||||
| JDK cache | The downloaded JDK installation | Runner OS, architecture, distribution, package type, resolved version, release identity, and signature-verification identity | Enabled implicitly whenever `cache` is set, or explicitly with `cache-jdk: true`. Opt out with `cache-jdk: false` |
|
|
||||||
|
|
||||||
Set `cache` to `maven`, `gradle`, or `sbt` to cache dependencies with minimal configuration.
|
|
||||||
|
|
||||||
|
#### Caching gradle dependencies
|
||||||
```yaml
|
```yaml
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v7
|
- uses: actions/checkout@v6
|
||||||
- uses: actions/setup-java@v5
|
|
||||||
with:
|
|
||||||
distribution: temurin
|
|
||||||
java-version: '25'
|
|
||||||
cache: maven
|
|
||||||
- run: mvn verify
|
|
||||||
```
|
|
||||||
|
|
||||||
The primary dependency cache key is `setup-java-<runner-os>-<node-arch>-<package-manager>-<file-hash>`, where `<node-arch>` is the runner's Node.js process architecture. The primary cache stores dependency directories such as `~/.m2/repository`, `~/.gradle/caches`, or the sbt cache paths. Its file hash is based on these files by default:
|
|
||||||
|
|
||||||
| Package manager | Files used for the primary dependency-cache key |
|
|
||||||
| --- | --- |
|
|
||||||
| Gradle | `**/*.gradle*`, `**/gradle-wrapper.properties`, `buildSrc/**/Versions.kt`, `buildSrc/**/Dependencies.kt`, `gradle/*.versions.toml`, `**/versions.properties` |
|
|
||||||
| Maven | `**/pom.xml`, `**/.mvn/wrapper/maven-wrapper.properties`, `**/.mvn/extensions.xml` |
|
|
||||||
| sbt | `**/*.sbt`, `**/project/build.properties`, `**/project/**.scala`, `**/project/**.sbt` |
|
|
||||||
|
|
||||||
Use `cache-dependency-path` to override the files used for key hashing, especially in monorepos:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- uses: actions/setup-java@v5
|
- uses: actions/setup-java@v5
|
||||||
with:
|
with:
|
||||||
distribution: temurin
|
distribution: 'temurin'
|
||||||
java-version: '25'
|
java-version: '25'
|
||||||
cache: gradle
|
cache: 'gradle'
|
||||||
cache-dependency-path: |
|
cache-dependency-path: | # optional
|
||||||
sub-project/*.gradle*
|
sub-project/*.gradle*
|
||||||
sub-project/**/gradle-wrapper.properties
|
sub-project/**/gradle-wrapper.properties
|
||||||
|
- run: ./gradlew build --no-daemon
|
||||||
```
|
```
|
||||||
|
Using the `cache: gradle` provides a simple and effective way to cache Gradle dependencies with minimal configuration.
|
||||||
|
|
||||||
Use `cache-path` when the build tool stores dependencies outside the default location:
|
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).
|
||||||
|
|
||||||
|
#### Caching maven dependencies
|
||||||
```yaml
|
```yaml
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
- uses: actions/setup-java@v5
|
- uses: actions/setup-java@v5
|
||||||
with:
|
with:
|
||||||
distribution: temurin
|
distribution: 'temurin'
|
||||||
java-version: '25'
|
java-version: '25'
|
||||||
cache: maven
|
cache: 'maven'
|
||||||
cache-path: |
|
cache-dependency-path: 'sub-project/pom.xml' # optional
|
||||||
/custom/maven/repository
|
- name: Build with Maven
|
||||||
!/custom/maven/repository/**/*.lastUpdated
|
run: mvn -B package --file pom.xml
|
||||||
- run: mvn -Dmaven.repo.local=/custom/maven/repository verify
|
|
||||||
```
|
```
|
||||||
|
|
||||||
`cache-path` changes what is restored and saved, but not the cache key. Jobs that should share a cache key must use the same OS, architecture, package manager, dependency files, and cache paths.
|
> [!NOTE]
|
||||||
|
> Maven resolves plugin dependencies lazily, so a cache created by a "thin" goal
|
||||||
### Wrapper caches
|
> (e.g. `mvn compile`) can be missing plugin dependencies that later
|
||||||
|
> `test`/`verify`/`package` jobs then re-download on every run. See
|
||||||
Maven and Gradle wrapper distributions are restored and saved as additional cache entries, separate from the primary dependency cache. These entries have their own keys in the form `setup-java-<runner-os>-<node-arch>-<wrapper-cache-name>-<file-hash>`.
|
> [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.
|
||||||
| Package manager | Wrapper cache name | Cached path | Files used for wrapper-cache key |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| Maven | `maven-wrapper` | `~/.m2/wrapper/dists` | `**/.mvn/wrapper/maven-wrapper.properties` |
|
|
||||||
| Gradle | `gradle-wrapper` | `~/.gradle/wrapper` | `**/gradle-wrapper.properties` |
|
|
||||||
|
|
||||||
These wrapper caches are independent from dependency caches, so they remain useful even when dependency files change frequently. The wrapper properties are also part of the Maven and Gradle primary dependency-cache key because wrapper changes can affect how dependencies are resolved, but the wrapper distribution files themselves are stored in the separate wrapper cache entries above.
|
|
||||||
|
|
||||||
For advanced Gradle caching features such as build output caching, configuration cache support, encrypted cache storage, cleanup, and fine-grained cache control, consider [`gradle/actions/setup-gradle`](https://github.com/gradle/actions/tree/main/setup-gradle).
|
|
||||||
|
|
||||||
### Caching JDK installations
|
|
||||||
|
|
||||||
The JDK cache stores the downloaded JDK installation so later runs skip the download. It is enabled implicitly whenever dependency `cache` is set, so most workflows that cache dependencies are already caching the JDK. Set `cache-jdk: true` to enable it without dependency caching, or `cache-jdk: false` to opt out while keeping dependency caching. With neither `cache` nor `cache-jdk` set, nothing is cached.
|
|
||||||
|
|
||||||
> [!IMPORTANT]
|
|
||||||
> Because JDK caching is on by default whenever `cache` is set, review [Caching JDK installations](docs/advanced-usage.md#caching-jdk-installations)
|
|
||||||
> for the full `cache`/`cache-jdk` matrix, cache identity and storage impact.
|
|
||||||
|
|
||||||
### Read-only caches
|
|
||||||
|
|
||||||
Set `cache-read-only: true` to restore dependency, wrapper, and JDK caches without saving changes in the post action. This is useful for pull requests, merge queues, short-lived branches, and matrix fan-out jobs that should only consume caches produced elsewhere.
|
|
||||||
|
|
||||||
|
#### Caching sbt dependencies
|
||||||
```yaml
|
```yaml
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
- uses: actions/setup-java@v5
|
- uses: actions/setup-java@v5
|
||||||
with:
|
with:
|
||||||
distribution: temurin
|
distribution: 'temurin'
|
||||||
java-version: '25'
|
java-version: '25'
|
||||||
cache: maven
|
cache: 'sbt'
|
||||||
cache-read-only: ${{ github.ref != 'refs/heads/main' }}
|
cache-dependency-path: | # optional
|
||||||
|
sub-project/build.sbt
|
||||||
|
sub-project/project/build.properties
|
||||||
|
- name: Build with SBT
|
||||||
|
run: sbt package
|
||||||
```
|
```
|
||||||
|
|
||||||
For matrix fan-out, seed the cache once and make matrix jobs read-only consumers:
|
#### Cache segment restore timeout
|
||||||
|
Usually, cache gets downloaded in multiple segments of fixed sizes. Sometimes, a segment download gets stuck, which causes the workflow job to be stuck. The cache segment download timeout [was introduced](https://github.com/actions/toolkit/tree/main/packages/cache#cache-segment-restore-timeout) to solve this issue as it allows the segment download to get aborted and hence allows the job to proceed with a cache miss. The default value of the cache segment download timeout is set to 10 minutes and can be customized by specifying an environment variable named `SEGMENT_DOWNLOAD_TIMEOUT_MINS` with a timeout value in minutes.
|
||||||
```yaml
|
|
||||||
jobs:
|
|
||||||
seed-cache:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v7
|
|
||||||
- uses: actions/setup-java@v5
|
|
||||||
with:
|
|
||||||
distribution: temurin
|
|
||||||
java-version: '25'
|
|
||||||
cache: maven
|
|
||||||
- run: mvn dependency:go-offline dependency:resolve-plugins
|
|
||||||
|
|
||||||
build:
|
|
||||||
needs: seed-cache
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
goal: [test, verify, package]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v7
|
|
||||||
- uses: actions/setup-java@v5
|
|
||||||
with:
|
|
||||||
distribution: temurin
|
|
||||||
java-version: '25'
|
|
||||||
cache: maven
|
|
||||||
cache-read-only: true
|
|
||||||
- run: mvn ${{ matrix.goal }}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Cache segment restore timeout
|
|
||||||
|
|
||||||
Cache downloads are split into segments. To reduce the chance of a stuck segment blocking a workflow, set `SEGMENT_DOWNLOAD_TIMEOUT_MINS`:
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
env:
|
env:
|
||||||
SEGMENT_DOWNLOAD_TIMEOUT_MINS: '5'
|
SEGMENT_DOWNLOAD_TIMEOUT_MINS: '5'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v7
|
- uses: actions/checkout@v6
|
||||||
- uses: actions/setup-java@v5
|
- uses: actions/setup-java@v5
|
||||||
with:
|
with:
|
||||||
distribution: temurin
|
distribution: 'temurin'
|
||||||
java-version: '25'
|
java-version: '25'
|
||||||
cache: gradle
|
cache: 'gradle'
|
||||||
- run: ./gradlew build --no-daemon
|
- run: ./gradlew build --no-daemon
|
||||||
```
|
```
|
||||||
|
|
||||||
## Multiple JDKs and Maven toolchains
|
### Check latest
|
||||||
|
|
||||||
|
In the basic examples above, the `check-latest` flag defaults to `false`. When set to `false`, the action tries to first resolve a version of Java from the local tool cache on the runner. If unable to find a specific version in the cache, the action will download a version of Java. Use the default or set `check-latest` to `false` if you prefer a faster more consistent setup experience that prioritizes trying to use the cached versions at the expense of newer versions sometimes being available for download.
|
||||||
|
|
||||||
|
If `check-latest` is set to `true`, the action first checks if the cached version is the latest one. If the locally cached version is not the most up-to-date, the latest version of Java will be downloaded. Set `check-latest` to `true` if you want the most up-to-date version of Java to always be used. Setting `check-latest` to `true` has performance implications as downloading versions of Java is slower than using cached versions.
|
||||||
|
|
||||||
|
For Java distributions that are not cached on Hosted images, `check-latest` always behaves as `true` and downloads Java on the fly. Check out [Hosted Tool Cache](docs/advanced-usage.md#Hosted-Tool-Cache) for more details about pre-cached Java versions.
|
||||||
|
|
||||||
Install multiple Java versions by providing a multiline `java-version` value. All configured JDKs are installed. The last one added to `PATH` becomes the default.
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/setup-java@v5
|
- uses: actions/checkout@v6
|
||||||
|
- uses: actions/setup-java@v5
|
||||||
with:
|
with:
|
||||||
distribution: temurin
|
distribution: 'temurin'
|
||||||
java-version: |
|
java-version: '25'
|
||||||
8
|
check-latest: true
|
||||||
11
|
- run: java --version
|
||||||
17
|
|
||||||
21
|
|
||||||
25
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Other installed JDKs are available through version-specific variables such as `JAVA_HOME_17_X64`. To use a specific version later in the job, set `JAVA_HOME` and prepend its `bin` directory to `PATH`.
|
### Testing against different Java versions
|
||||||
|
|
||||||
`setup-java` writes a Maven Toolchains declaration for each installed JDK. When multiple JDKs are installed, the declaration contains all of them. Customize the generated toolchain values with `mvn-toolchain-id` and `mvn-toolchain-vendor`.
|
|
||||||
|
|
||||||
## Testing with a Java matrix
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-20.04
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
java: ['8', '11', '17', '21', '25']
|
java: [ '8', '11', '17', '21', '25' ]
|
||||||
name: Java ${{ matrix.java }}
|
name: Java ${{ matrix.Java }} sample
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v7
|
- uses: actions/checkout@v6
|
||||||
- uses: actions/setup-java@v5
|
- name: Setup java
|
||||||
|
uses: actions/setup-java@v5
|
||||||
with:
|
with:
|
||||||
distribution: temurin
|
distribution: '<distribution>'
|
||||||
java-version: ${{ matrix.java }}
|
java-version: ${{ matrix.java }}
|
||||||
- run: java --version
|
- run: java --version
|
||||||
- run: mvn verify
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Publishing packages
|
### Install multiple JDKs
|
||||||
|
|
||||||
`setup-java` generates Maven `settings.xml` and Maven Toolchains configuration. For Gradle publishing, it installs Java for the workflow; the Gradle build file remains responsible for reading credentials from environment variables.
|
All configured Java versions are added to the PATH. The last one added to the PATH (i.e., the last JDK set up by this action) will be used as the default and available globally. Other Java versions can be accessed through environment variables such as 'JAVA_HOME_{{ MAJOR_VERSION }}_{{ ARCHITECTURE }}'. To use a specific Java version, set the JAVA_HOME environment variable accordingly and prepend its bin directory to the PATH to ensure it takes priority during execution.
|
||||||
|
|
||||||
### Maven
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v7
|
|
||||||
- uses: actions/setup-java@v5
|
- uses: actions/setup-java@v5
|
||||||
with:
|
with:
|
||||||
distribution: temurin
|
distribution: '<distribution>'
|
||||||
java-version: '25'
|
java-version: |
|
||||||
server-id: github
|
8
|
||||||
server-username-env-var: GITHUB_ACTOR
|
11
|
||||||
server-password-env-var: GITHUB_TOKEN
|
15
|
||||||
- run: mvn --batch-mode deploy
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### GPG signing
|
### Using Maven Toolchains
|
||||||
|
In the example above multiple JDKs are installed for the same job. The result after the last JDK is installed is a Maven Toolchains declaration containing references to all three JDKs. The values for `id`, `version`, and `vendor` of the individual Toolchain entries are the given input values for `distribution` and `java-version` (`vendor` being the combination of `${distribution}_${java-version}`) by default.
|
||||||
|
|
||||||
```yaml
|
### Advanced Configuration
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v7
|
|
||||||
- uses: actions/setup-java@v5
|
|
||||||
with:
|
|
||||||
distribution: temurin
|
|
||||||
java-version: '25'
|
|
||||||
gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }}
|
|
||||||
gpg-passphrase-env-var: GPG_PASSPHRASE
|
|
||||||
- run: mvn --batch-mode deploy
|
|
||||||
env:
|
|
||||||
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
|
|
||||||
```
|
|
||||||
|
|
||||||
Maven GPG signing requires `maven-gpg-plugin` 3.2.0 or newer because `setup-java` passes the passphrase through `gpg.passphraseEnvName`.
|
- [Selecting a Java distribution](docs/advanced-usage.md#Selecting-a-Java-distribution)
|
||||||
|
- [Eclipse Temurin](docs/advanced-usage.md#Eclipse-Temurin)
|
||||||
|
- [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)
|
||||||
|
- [Alibaba Dragonwell](docs/advanced-usage.md#Alibaba-Dragonwell)
|
||||||
|
- [SapMachine](docs/advanced-usage.md#SapMachine)
|
||||||
|
- [GraalVM](docs/advanced-usage.md#GraalVM)
|
||||||
|
- [JetBrains](docs/advanced-usage.md#JetBrains)
|
||||||
|
- [Tencent Kona](docs/advanced-usage.md#Tencent-Kona)
|
||||||
|
- [Installing custom Java package type](docs/advanced-usage.md#Installing-custom-Java-package-type)
|
||||||
|
- [Installing custom Java architecture](docs/advanced-usage.md#Installing-custom-Java-architecture)
|
||||||
|
- [Installing custom Java distribution from local file](docs/advanced-usage.md#Installing-Java-from-local-file)
|
||||||
|
- [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)
|
||||||
|
- [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)
|
||||||
|
- [Java Version File](docs/advanced-usage.md#Java-version-file)
|
||||||
|
|
||||||
|
## V2 vs V1
|
||||||
|
|
||||||
|
Examples in this README use `actions/setup-java@v5`, but the main migration note from V1 still applies to all later major versions (`v2`, `v3`, `v4`, and `v5`):
|
||||||
|
|
||||||
|
- Starting with V2, the action supports custom distributions. V1 supports only Azul Zulu OpenJDK.
|
||||||
|
- Starting with V2, you must specify distribution along with the version. V1 defaults to Azul Zulu OpenJDK, so only version input is required. Follow [the migration guide](docs/switching-to-v2.md) to switch from V1 to V2.
|
||||||
|
|
||||||
|
For information about the latest releases, recent updates, and newly supported distributions, please refer to the `setup-java` [Releases](https://github.com/actions/setup-java/releases).
|
||||||
|
|
||||||
## Recommended permissions
|
## Recommended permissions
|
||||||
|
|
||||||
@@ -479,41 +340,10 @@ permissions:
|
|||||||
contents: read # access to check out code and install dependencies
|
contents: read # access to check out code and install dependencies
|
||||||
```
|
```
|
||||||
|
|
||||||
Publishing workflows may require additional permissions depending on the target registry.
|
|
||||||
|
|
||||||
## Advanced usage
|
|
||||||
|
|
||||||
See [advanced usage](docs/advanced-usage.md) for detailed examples:
|
|
||||||
|
|
||||||
- [Selecting a Java distribution](docs/advanced-usage.md#selecting-a-java-distribution)
|
|
||||||
- [Installing custom Java package types](docs/advanced-usage.md#installing-custom-java-package-type)
|
|
||||||
- [Package compatibility](docs/advanced-usage.md#package-compatibility)
|
|
||||||
- [Ensuring the Maven cache is complete](docs/advanced-usage.md#ensuring-the-maven-cache-is-complete-plugin-dependencies)
|
|
||||||
- [Caching JDK installations](docs/advanced-usage.md#caching-jdk-installations)
|
|
||||||
- [Platform and architecture compatibility](docs/advanced-usage.md#platform-and-architecture-compatibility)
|
|
||||||
- [Installing custom Java architecture](docs/advanced-usage.md#installing-custom-java-architecture)
|
|
||||||
- [Installing a JDK without setting it as default](docs/advanced-usage.md#installing-jdk-without-setting-as-default)
|
|
||||||
- [Installing Java from a local file](docs/advanced-usage.md#installing-java-from-local-file)
|
|
||||||
- [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)
|
|
||||||
- [Apache Maven with a settings path](docs/advanced-usage.md#apache-maven-with-a-settings-path)
|
|
||||||
- [Maven transfer progress](docs/advanced-usage.md#maven-transfer-progress-download-logs)
|
|
||||||
- [Java problem matcher](docs/advanced-usage.md#java-problem-matcher-compiler-annotations)
|
|
||||||
- [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)
|
|
||||||
- [Java version files](docs/advanced-usage.md#java-version-file)
|
|
||||||
- [Self-signed certificates and internal CAs on GitHub Enterprise](docs/advanced-usage.md#self-signed-certificates-and-internal-cas-github-enterprise)
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
The scripts and documentation in this project are released under the [MIT License](LICENSE).
|
The scripts and documentation in this project are released under the [MIT License](LICENSE).
|
||||||
|
|
||||||
## Contributions
|
## Contributions
|
||||||
|
|
||||||
Contributions are welcome. See our [Contributor's Guide](docs/contributors.md).
|
Contributions are welcome! See [Contributor's Guide](docs/contributors.md)
|
||||||
|
|
||||||
## Code of Conduct
|
|
||||||
|
|
||||||
:wave: Be nice. See [our code of conduct](CODE_OF_CONDUCT.md)
|
|
||||||
|
|||||||
+2
-120
@@ -13,7 +13,6 @@ import * as io from '@actions/io';
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import os from 'os';
|
import os from 'os';
|
||||||
import {XMLParser} from 'fast-xml-parser';
|
|
||||||
|
|
||||||
// Mock @actions/core before importing source modules that depend on it
|
// Mock @actions/core before importing source modules that depend on it
|
||||||
jest.unstable_mockModule('@actions/core', () => ({
|
jest.unstable_mockModule('@actions/core', () => ({
|
||||||
@@ -229,40 +228,9 @@ describe('auth tests', () => {
|
|||||||
<username>\${env.${username}}</username>
|
<username>\${env.${username}}</username>
|
||||||
<password>\${env.&<>"''"><&}</password>
|
<password>\${env.&<>"''"><&}</password>
|
||||||
</server>
|
</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>
|
<server>
|
||||||
<id>${id}</id>
|
<id>gpg.passphrase</id>
|
||||||
<username>\${env.${username}}</username>
|
<passphrase>\${env.${gpgPassphrase}}</passphrase>
|
||||||
<password>\${env.&<>"''"><&}</password>
|
|
||||||
</server>
|
</server>
|
||||||
</servers>
|
</servers>
|
||||||
</settings>`;
|
</settings>`;
|
||||||
@@ -271,90 +239,4 @@ describe('auth tests', () => {
|
|||||||
expectedSettings
|
expectedSettings
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('escapes settings.xml values while preserving parsed semantics', () => {
|
|
||||||
const id = `packages&<>"'é`;
|
|
||||||
const username = `USER&<>"'é`;
|
|
||||||
const password = `TOKEN&<>"'é`;
|
|
||||||
const gpgPassphrase = `GPG&<>"'é`;
|
|
||||||
|
|
||||||
const xml = auth.generate(id, username, password, gpgPassphrase);
|
|
||||||
const parsed = parseXmlObject(xml) as any;
|
|
||||||
|
|
||||||
expect(parsed.settings.interactiveMode).toBe('false');
|
|
||||||
expect(xmlElementText(xml, 'id')).toBe(id);
|
|
||||||
expect(xmlElementText(xml, 'username')).toBe(`\${env.${username}}`);
|
|
||||||
expect(xmlElementText(xml, 'password')).toBe(`\${env.${password}}`);
|
|
||||||
expect(xmlElementText(xml, 'gpg.passphraseEnvName')).toBe(gpgPassphrase);
|
|
||||||
expect(parsed.settings.activeProfiles.activeProfile).toBe('setup-java-gpg');
|
|
||||||
});
|
|
||||||
|
|
||||||
function xmlElementText(xml: string, tagName: string): string {
|
|
||||||
const match = new RegExp(`<${tagName}>([\\s\\S]*?)</${tagName}>`).exec(xml);
|
|
||||||
expect(match).not.toBeNull();
|
|
||||||
return (parseXmlObject(`<value>${match?.[1]}</value>`) as {value: string})
|
|
||||||
.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseXmlObject(xml: string): unknown {
|
|
||||||
const parser = new XMLParser({
|
|
||||||
ignoreAttributes: false,
|
|
||||||
attributeNamePrefix: '@',
|
|
||||||
parseAttributeValue: false,
|
|
||||||
parseTagValue: false,
|
|
||||||
trimValues: true
|
|
||||||
});
|
|
||||||
return parser.parse(xml);
|
|
||||||
}
|
|
||||||
|
|
||||||
it('uses deprecated input aliases and warns', () => {
|
|
||||||
const mockGetInput = core.getInput as jest.MockedFunction<
|
|
||||||
typeof core.getInput
|
|
||||||
>;
|
|
||||||
const mockWarning = core.warning as jest.MockedFunction<
|
|
||||||
typeof core.warning
|
|
||||||
>;
|
|
||||||
mockGetInput.mockImplementation(name =>
|
|
||||||
name === 'server-username' ? 'LEGACY_USERNAME' : ''
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(
|
|
||||||
auth.getInputWithDeprecatedAlias(
|
|
||||||
'server-username-env-var',
|
|
||||||
'server-username',
|
|
||||||
'GITHUB_ACTOR'
|
|
||||||
)
|
|
||||||
).toBe('LEGACY_USERNAME');
|
|
||||||
expect(mockWarning).toHaveBeenCalledWith(
|
|
||||||
"The 'server-username' input is deprecated and may be removed in a future release. Please use 'server-username-env-var' instead."
|
|
||||||
);
|
|
||||||
|
|
||||||
mockGetInput.mockReset();
|
|
||||||
mockWarning.mockReset();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('prefers the replacement input over its deprecated alias', () => {
|
|
||||||
const mockGetInput = core.getInput as jest.MockedFunction<
|
|
||||||
typeof core.getInput
|
|
||||||
>;
|
|
||||||
mockGetInput.mockImplementation(name => {
|
|
||||||
const inputs: Record<string, string> = {
|
|
||||||
'server-password-env-var': 'NEW_PASSWORD',
|
|
||||||
'server-password': 'LEGACY_PASSWORD'
|
|
||||||
};
|
|
||||||
return inputs[name] || '';
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(
|
|
||||||
auth.getInputWithDeprecatedAlias(
|
|
||||||
'server-password-env-var',
|
|
||||||
'server-password',
|
|
||||||
'GITHUB_TOKEN'
|
|
||||||
)
|
|
||||||
).toBe('NEW_PASSWORD');
|
|
||||||
expect(core.warning).toHaveBeenCalled();
|
|
||||||
|
|
||||||
mockGetInput.mockReset();
|
|
||||||
(core.warning as jest.Mock).mockReset();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,135 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
command=${1:?command is required}
|
|
||||||
tool=${2:?tool is required}
|
|
||||||
|
|
||||||
case "$tool" in
|
|
||||||
maven)
|
|
||||||
dependency_cache="$HOME/.m2/repository"
|
|
||||||
wrapper_cache="$HOME/.m2/wrapper/dists"
|
|
||||||
dependency_file="benchmark/pom.xml"
|
|
||||||
wrapper_file="benchmark/.mvn/wrapper/maven-wrapper.properties"
|
|
||||||
;;
|
|
||||||
gradle)
|
|
||||||
dependency_cache="$HOME/.gradle/caches"
|
|
||||||
wrapper_cache="$HOME/.gradle/wrapper"
|
|
||||||
dependency_file="benchmark/build.gradle"
|
|
||||||
wrapper_file="benchmark/gradle/wrapper/gradle-wrapper.properties"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Unsupported tool: $tool" >&2
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
case "$command" in
|
|
||||||
prepare)
|
|
||||||
profile=${3:?profile is required}
|
|
||||||
mkdir -p "$(dirname "$dependency_file")" "$(dirname "$wrapper_file")"
|
|
||||||
printf '// setup-java cache benchmark v1: %s\n' "$profile" > "$dependency_file"
|
|
||||||
printf '# setup-java cache benchmark v1: %s\n' "$profile" > "$wrapper_file"
|
|
||||||
;;
|
|
||||||
reset)
|
|
||||||
rm -rf "$dependency_cache" "$wrapper_cache"
|
|
||||||
;;
|
|
||||||
populate)
|
|
||||||
profile=${3:?profile is required}
|
|
||||||
case "$profile" in
|
|
||||||
small)
|
|
||||||
dependency_megabytes=8
|
|
||||||
wrapper_megabytes=2
|
|
||||||
;;
|
|
||||||
large)
|
|
||||||
dependency_megabytes=128
|
|
||||||
wrapper_megabytes=32
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Unsupported profile: $profile" >&2
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
mkdir -p "$dependency_cache/setup-java-benchmark"
|
|
||||||
mkdir -p "$wrapper_cache/setup-java-benchmark"
|
|
||||||
dd if=/dev/urandom \
|
|
||||||
of="$dependency_cache/setup-java-benchmark/payload" \
|
|
||||||
bs=1048576 count="$dependency_megabytes" 2>/dev/null
|
|
||||||
dd if=/dev/urandom \
|
|
||||||
of="$wrapper_cache/setup-java-benchmark/payload" \
|
|
||||||
bs=1048576 count="$wrapper_megabytes" 2>/dev/null
|
|
||||||
;;
|
|
||||||
start)
|
|
||||||
node -e "require('fs').writeFileSync('.benchmark-start', String(Date.now()))"
|
|
||||||
;;
|
|
||||||
record)
|
|
||||||
os=${3:?os is required}
|
|
||||||
profile=${4:?profile is required}
|
|
||||||
implementation=${5:?implementation is required}
|
|
||||||
iteration=${6:?iteration is required}
|
|
||||||
cache_hit=${7:?cache-hit output is required}
|
|
||||||
if [ "$cache_hit" != "true" ]; then
|
|
||||||
echo "Expected an exact dependency-cache hit for $implementation" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
test -f "$dependency_cache/setup-java-benchmark/payload"
|
|
||||||
started=$(cat .benchmark-start)
|
|
||||||
finished=$(node -e "process.stdout.write(String(Date.now()))")
|
|
||||||
elapsed=$((finished - started))
|
|
||||||
mkdir -p .benchmark-results
|
|
||||||
printf '%s,%s,%s,%s,%s,%s\n' \
|
|
||||||
"$os" "$tool" "$profile" "$implementation" "$iteration" "$elapsed" \
|
|
||||||
>> .benchmark-results/timings.csv
|
|
||||||
;;
|
|
||||||
summarize)
|
|
||||||
summary_file=${3:?summary file is required}
|
|
||||||
results_file=".benchmark-results/timings.csv"
|
|
||||||
node --input-type=module - "$results_file" "$summary_file" <<'NODE'
|
|
||||||
import fs from 'node:fs';
|
|
||||||
|
|
||||||
const [, , resultsFile, summaryFile] = process.argv;
|
|
||||||
const rows = fs
|
|
||||||
.readFileSync(resultsFile, 'utf8')
|
|
||||||
.trim()
|
|
||||||
.split('\n')
|
|
||||||
.map(line => {
|
|
||||||
const [os, tool, profile, implementation, iteration, elapsed] =
|
|
||||||
line.split(',');
|
|
||||||
return {os, tool, profile, implementation, iteration, elapsed: +elapsed};
|
|
||||||
});
|
|
||||||
const average = implementation => {
|
|
||||||
const values = rows
|
|
||||||
.filter(row => row.implementation === implementation)
|
|
||||||
.map(row => row.elapsed);
|
|
||||||
if (values.length === 0) {
|
|
||||||
throw new Error(`No ${implementation} benchmark results were recorded`);
|
|
||||||
}
|
|
||||||
return Math.round(values.reduce((sum, value) => sum + value, 0) / values.length);
|
|
||||||
};
|
|
||||||
const baseline = average('baseline');
|
|
||||||
const candidate = average('candidate');
|
|
||||||
const change = (((candidate - baseline) / baseline) * 100).toFixed(1);
|
|
||||||
const {os, tool, profile} = rows[0];
|
|
||||||
const lines = [
|
|
||||||
`### ${tool} ${profile} cache restore on ${os}`,
|
|
||||||
'',
|
|
||||||
'| Implementation | Iteration | Wall time (ms) |',
|
|
||||||
'| --- | ---: | ---: |',
|
|
||||||
...rows.map(
|
|
||||||
row =>
|
|
||||||
`| ${row.implementation} | ${row.iteration} | ${row.elapsed} |`
|
|
||||||
),
|
|
||||||
`| **baseline average** | | **${baseline}** |`,
|
|
||||||
`| **candidate average** | | **${candidate}** |`,
|
|
||||||
'',
|
|
||||||
`Candidate change from baseline: **${change}%**`,
|
|
||||||
''
|
|
||||||
];
|
|
||||||
fs.appendFileSync(summaryFile, `${lines.join('\n')}\n`);
|
|
||||||
NODE
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Unsupported command: $command" >&2
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
import {jest, describe, it, expect, afterEach} from '@jest/globals';
|
|
||||||
|
|
||||||
jest.unstable_mockModule('@actions/cache', () => ({
|
|
||||||
isFeatureAvailable: jest.fn()
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.unstable_mockModule('@actions/core', () => ({
|
|
||||||
warning: jest.fn(),
|
|
||||||
debug: jest.fn(),
|
|
||||||
getInput: jest.fn(),
|
|
||||||
getBooleanInput: jest.fn(),
|
|
||||||
getMultilineInput: jest.fn(),
|
|
||||||
info: jest.fn(),
|
|
||||||
error: jest.fn(),
|
|
||||||
notice: jest.fn(),
|
|
||||||
setFailed: jest.fn(),
|
|
||||||
setOutput: 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)
|
|
||||||
}));
|
|
||||||
|
|
||||||
const cache = await import('@actions/cache');
|
|
||||||
const core = await import('@actions/core');
|
|
||||||
const {isCacheFeatureAvailable} = await import('../src/cache-feature.js');
|
|
||||||
|
|
||||||
describe('isCacheFeatureAvailable', () => {
|
|
||||||
it('is disabled on GHES when cache feature is unavailable', () => {
|
|
||||||
(cache.isFeatureAvailable as jest.Mock<any>).mockImplementation(
|
|
||||||
() => false
|
|
||||||
);
|
|
||||||
const warningMock = core.warning as jest.Mock;
|
|
||||||
const message =
|
|
||||||
'Caching is only supported on GHES version >= 3.5. If you are on a version >= 3.5, please check with your GHES admin if the Actions cache service is enabled or not.';
|
|
||||||
|
|
||||||
try {
|
|
||||||
process.env['GITHUB_SERVER_URL'] = 'http://example.com';
|
|
||||||
expect(isCacheFeatureAvailable()).toBe(false);
|
|
||||||
expect(warningMock).toHaveBeenCalledWith(message);
|
|
||||||
} finally {
|
|
||||||
delete process.env['GITHUB_SERVER_URL'];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('is disabled on dotcom when cache feature is unavailable', () => {
|
|
||||||
(cache.isFeatureAvailable as jest.Mock<any>).mockImplementation(
|
|
||||||
() => false
|
|
||||||
);
|
|
||||||
const warningMock = core.warning as jest.Mock;
|
|
||||||
const message =
|
|
||||||
'The runner was not able to contact the cache service. Caching will be skipped';
|
|
||||||
|
|
||||||
try {
|
|
||||||
process.env['GITHUB_SERVER_URL'] = 'http://github.com';
|
|
||||||
expect(isCacheFeatureAvailable()).toBe(false);
|
|
||||||
expect(warningMock).toHaveBeenCalledWith(message);
|
|
||||||
} finally {
|
|
||||||
delete process.env['GITHUB_SERVER_URL'];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('is enabled when cache feature is available', () => {
|
|
||||||
(cache.isFeatureAvailable as jest.Mock<any>).mockImplementation(() => true);
|
|
||||||
expect(isCacheFeatureAvailable()).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
jest.resetAllMocks();
|
|
||||||
jest.clearAllMocks();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
+12
-463
@@ -166,7 +166,10 @@ describe('dependency cache', () => {
|
|||||||
|
|
||||||
await restore('maven', '');
|
await restore('maven', '');
|
||||||
expect(spyCacheRestore).toHaveBeenCalledWith(
|
expect(spyCacheRestore).toHaveBeenCalledWith(
|
||||||
[join(os.homedir(), '.m2', 'repository')],
|
[
|
||||||
|
join(os.homedir(), '.m2', 'repository'),
|
||||||
|
join(os.homedir(), '.m2', 'wrapper', 'dists')
|
||||||
|
],
|
||||||
expect.any(String)
|
expect.any(String)
|
||||||
);
|
);
|
||||||
expect(spyGlobHashFiles).toHaveBeenCalledWith(
|
expect(spyGlobHashFiles).toHaveBeenCalledWith(
|
||||||
@@ -193,7 +196,10 @@ describe('dependency cache', () => {
|
|||||||
|
|
||||||
await restore('maven', '');
|
await restore('maven', '');
|
||||||
expect(spyCacheRestore).toHaveBeenCalledWith(
|
expect(spyCacheRestore).toHaveBeenCalledWith(
|
||||||
[join(os.homedir(), '.m2', 'repository')],
|
[
|
||||||
|
join(os.homedir(), '.m2', 'repository'),
|
||||||
|
join(os.homedir(), '.m2', 'wrapper', 'dists')
|
||||||
|
],
|
||||||
expect.any(String)
|
expect.any(String)
|
||||||
);
|
);
|
||||||
expect(spyGlobHashFiles).toHaveBeenCalledWith(
|
expect(spyGlobHashFiles).toHaveBeenCalledWith(
|
||||||
@@ -208,7 +214,10 @@ describe('dependency cache', () => {
|
|||||||
|
|
||||||
await restore('maven', '');
|
await restore('maven', '');
|
||||||
expect(spyCacheRestore).toHaveBeenCalledWith(
|
expect(spyCacheRestore).toHaveBeenCalledWith(
|
||||||
[join(os.homedir(), '.m2', 'repository')],
|
[
|
||||||
|
join(os.homedir(), '.m2', 'repository'),
|
||||||
|
join(os.homedir(), '.m2', 'wrapper', 'dists')
|
||||||
|
],
|
||||||
expect.any(String)
|
expect.any(String)
|
||||||
);
|
);
|
||||||
expect(spyGlobHashFiles).toHaveBeenCalledWith(
|
expect(spyGlobHashFiles).toHaveBeenCalledWith(
|
||||||
@@ -217,124 +226,6 @@ describe('dependency cache', () => {
|
|||||||
expect(spyWarning).not.toHaveBeenCalled();
|
expect(spyWarning).not.toHaveBeenCalled();
|
||||||
expect(spyInfo).toHaveBeenCalledWith('maven cache is not found');
|
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', '', ['/custom/maven/repository']);
|
|
||||||
// Main dependency cache no longer carries the wrapper dists path.
|
|
||||||
expect(spyCacheRestore).toHaveBeenCalledWith(
|
|
||||||
['/custom/maven/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'
|
|
||||||
);
|
|
||||||
expect(spyInfo).toHaveBeenCalledWith(
|
|
||||||
'maven-wrapper cache is not found'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it('starts maven dependency and wrapper restores before either completes', async () => {
|
|
||||||
createDirectory(join(workspace, '.mvn'));
|
|
||||||
createDirectory(join(workspace, '.mvn', 'wrapper'));
|
|
||||||
createFile(
|
|
||||||
join(workspace, '.mvn', 'wrapper', 'maven-wrapper.properties')
|
|
||||||
);
|
|
||||||
const dependencyRestore = deferred<string | undefined>();
|
|
||||||
const wrapperRestore = deferred<string | undefined>();
|
|
||||||
const bothRestoresStarted = deferred<void>();
|
|
||||||
let restoreCount = 0;
|
|
||||||
spyCacheRestore.mockImplementation((paths: string[]) => {
|
|
||||||
restoreCount++;
|
|
||||||
if (restoreCount === 2) {
|
|
||||||
bothRestoresStarted.resolve();
|
|
||||||
}
|
|
||||||
return paths.includes(join(os.homedir(), '.m2', 'repository'))
|
|
||||||
? dependencyRestore.promise
|
|
||||||
: wrapperRestore.promise;
|
|
||||||
});
|
|
||||||
|
|
||||||
const restorePromise = restore('maven', '');
|
|
||||||
await bothRestoresStarted.promise;
|
|
||||||
|
|
||||||
expect(spyCacheRestore).toHaveBeenCalledTimes(2);
|
|
||||||
expect(spySaveState).toHaveBeenCalledWith(
|
|
||||||
'cache-primary-key',
|
|
||||||
expect.any(String)
|
|
||||||
);
|
|
||||||
expect(spySaveState).toHaveBeenCalledWith(
|
|
||||||
'cache-primary-key-maven-wrapper',
|
|
||||||
expect.any(String)
|
|
||||||
);
|
|
||||||
|
|
||||||
wrapperRestore.resolve('maven-wrapper-hit');
|
|
||||||
dependencyRestore.resolve('maven-dependency-hit');
|
|
||||||
await restorePromise;
|
|
||||||
|
|
||||||
expect(spySaveState).toHaveBeenCalledWith(
|
|
||||||
'cache-matched-key-maven-wrapper',
|
|
||||||
'maven-wrapper-hit'
|
|
||||||
);
|
|
||||||
expect(spySaveState).toHaveBeenCalledWith(
|
|
||||||
'cache-matched-key',
|
|
||||||
'maven-dependency-hit'
|
|
||||||
);
|
|
||||||
expect(spySetOutput).toHaveBeenCalledWith('cache-hit', false);
|
|
||||||
});
|
|
||||||
it('propagates a wrapper restore failure after starting both restores', async () => {
|
|
||||||
createDirectory(join(workspace, '.mvn'));
|
|
||||||
createDirectory(join(workspace, '.mvn', 'wrapper'));
|
|
||||||
createFile(
|
|
||||||
join(workspace, '.mvn', 'wrapper', 'maven-wrapper.properties')
|
|
||||||
);
|
|
||||||
const dependencyRestore = deferred<string | undefined>();
|
|
||||||
const wrapperRestore = deferred<string | undefined>();
|
|
||||||
const bothRestoresStarted = deferred<void>();
|
|
||||||
let restoreCount = 0;
|
|
||||||
spyCacheRestore.mockImplementation((paths: string[]) => {
|
|
||||||
restoreCount++;
|
|
||||||
if (restoreCount === 2) {
|
|
||||||
bothRestoresStarted.resolve();
|
|
||||||
}
|
|
||||||
return paths.includes(join(os.homedir(), '.m2', 'repository'))
|
|
||||||
? dependencyRestore.promise
|
|
||||||
: wrapperRestore.promise;
|
|
||||||
});
|
|
||||||
|
|
||||||
const restorePromise = restore('maven', '');
|
|
||||||
await bothRestoresStarted.promise;
|
|
||||||
wrapperRestore.reject(new Error('wrapper restore failed'));
|
|
||||||
dependencyRestore.resolve(undefined);
|
|
||||||
|
|
||||||
await expect(restorePromise).rejects.toThrow('wrapper restore failed');
|
|
||||||
});
|
|
||||||
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', () => {
|
describe('for gradle', () => {
|
||||||
it('throws error if no build.gradle found', async () => {
|
it('throws error if no build.gradle found', async () => {
|
||||||
@@ -391,87 +282,6 @@ describe('dependency cache', () => {
|
|||||||
expect(spyWarning).not.toHaveBeenCalled();
|
expect(spyWarning).not.toHaveBeenCalled();
|
||||||
expect(spyInfo).toHaveBeenCalledWith('gradle cache is not found');
|
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', '', ['/custom/gradle/caches']);
|
|
||||||
// Main dependency cache no longer carries the wrapper path.
|
|
||||||
expect(spyCacheRestore).toHaveBeenCalledWith(
|
|
||||||
['/custom/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('starts gradle dependency and wrapper restores before either completes', async () => {
|
|
||||||
createFile(join(workspace, 'build.gradle'));
|
|
||||||
createFile(join(workspace, 'gradle-wrapper.properties'));
|
|
||||||
const dependencyRestore = deferred<string | undefined>();
|
|
||||||
const wrapperRestore = deferred<string | undefined>();
|
|
||||||
const bothRestoresStarted = deferred<void>();
|
|
||||||
let restoreCount = 0;
|
|
||||||
spyCacheRestore.mockImplementation((paths: string[]) => {
|
|
||||||
restoreCount++;
|
|
||||||
if (restoreCount === 2) {
|
|
||||||
bothRestoresStarted.resolve();
|
|
||||||
}
|
|
||||||
return paths.includes(join(os.homedir(), '.gradle', 'caches'))
|
|
||||||
? dependencyRestore.promise
|
|
||||||
: wrapperRestore.promise;
|
|
||||||
});
|
|
||||||
|
|
||||||
const restorePromise = restore('gradle', '');
|
|
||||||
await bothRestoresStarted.promise;
|
|
||||||
|
|
||||||
expect(spyCacheRestore).toHaveBeenCalledTimes(2);
|
|
||||||
expect(spySaveState).toHaveBeenCalledWith(
|
|
||||||
'cache-primary-key',
|
|
||||||
expect.any(String)
|
|
||||||
);
|
|
||||||
expect(spySaveState).toHaveBeenCalledWith(
|
|
||||||
'cache-primary-key-gradle-wrapper',
|
|
||||||
expect.any(String)
|
|
||||||
);
|
|
||||||
|
|
||||||
dependencyRestore.resolve('gradle-dependency-hit');
|
|
||||||
wrapperRestore.resolve('gradle-wrapper-hit');
|
|
||||||
await restorePromise;
|
|
||||||
|
|
||||||
expect(spySaveState).toHaveBeenCalledWith(
|
|
||||||
'cache-matched-key',
|
|
||||||
'gradle-dependency-hit'
|
|
||||||
);
|
|
||||||
expect(spySaveState).toHaveBeenCalledWith(
|
|
||||||
'cache-matched-key-gradle-wrapper',
|
|
||||||
'gradle-wrapper-hit'
|
|
||||||
);
|
|
||||||
expect(spySetOutput).toHaveBeenCalledWith('cache-hit', false);
|
|
||||||
});
|
|
||||||
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', () => {
|
describe('for sbt', () => {
|
||||||
it('throws error if no build.sbt found', async () => {
|
it('throws error if no build.sbt found', async () => {
|
||||||
@@ -576,47 +386,14 @@ describe('dependency cache', () => {
|
|||||||
expect(spyInfo).toHaveBeenCalledWith('gradle cache is not found');
|
expect(spyInfo).toHaveBeenCalledWith('gradle cache is not found');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('cache-path', () => {
|
|
||||||
it.each([
|
|
||||||
['maven', ['/custom/maven/repository']],
|
|
||||||
['gradle', ['/custom/gradle/caches']],
|
|
||||||
[
|
|
||||||
'sbt',
|
|
||||||
[
|
|
||||||
'/custom/ivy/cache',
|
|
||||||
'/custom/coursier/cache',
|
|
||||||
'!/custom/ivy/cache/*.lock'
|
|
||||||
]
|
|
||||||
]
|
|
||||||
])(
|
|
||||||
'restores and persists custom paths for %s',
|
|
||||||
async (packageManager, cachePaths) => {
|
|
||||||
await restore(packageManager, '', cachePaths);
|
|
||||||
|
|
||||||
expect(spyCacheRestore).toHaveBeenCalledWith(
|
|
||||||
cachePaths,
|
|
||||||
expect.any(String)
|
|
||||||
);
|
|
||||||
expect(spySaveState).toHaveBeenCalledWith(
|
|
||||||
'cache-paths',
|
|
||||||
JSON.stringify(cachePaths)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
describe('save', () => {
|
describe('save', () => {
|
||||||
let spyCacheSave: any;
|
let spyCacheSave: any;
|
||||||
let spyGlobCreate: jest.Mock;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
spyCacheSave = (cache.saveCache as any).mockImplementation(
|
spyCacheSave = (cache.saveCache as any).mockImplementation(
|
||||||
(paths: string[], key: string) => Promise.resolve(0)
|
(paths: string[], key: string) => Promise.resolve(0)
|
||||||
);
|
);
|
||||||
spyGlobCreate = glob.create as jest.Mock;
|
|
||||||
spyGlobCreate.mockResolvedValue({
|
|
||||||
glob: jest.fn(() => Promise.resolve(['wrapper-path']))
|
|
||||||
});
|
|
||||||
spyWarning.mockImplementation(() => null);
|
spyWarning.mockImplementation(() => null);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -653,42 +430,6 @@ describe('dependency cache', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it.each([
|
|
||||||
['maven', ['/custom/maven/repository']],
|
|
||||||
['gradle', ['/custom/gradle/caches']],
|
|
||||||
[
|
|
||||||
'sbt',
|
|
||||||
[
|
|
||||||
'/custom/ivy/cache',
|
|
||||||
'/custom/coursier/cache',
|
|
||||||
'!/custom/ivy/cache/*.lock'
|
|
||||||
]
|
|
||||||
]
|
|
||||||
])(
|
|
||||||
'saves the persisted custom paths for %s',
|
|
||||||
async (packageManager, cachePaths) => {
|
|
||||||
(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-paths':
|
|
||||||
return JSON.stringify(cachePaths);
|
|
||||||
default:
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await save(packageManager);
|
|
||||||
|
|
||||||
expect(spyCacheSave).toHaveBeenCalledWith(
|
|
||||||
cachePaths,
|
|
||||||
'setup-java-cache-primary-key'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
describe('for maven', () => {
|
describe('for maven', () => {
|
||||||
it('uploads cache even if no pom.xml found', async () => {
|
it('uploads cache even if no pom.xml found', async () => {
|
||||||
createStateForMissingBuildFile();
|
createStateForMissingBuildFile();
|
||||||
@@ -716,114 +457,6 @@ describe('dependency cache', () => {
|
|||||||
expect.stringMatching(/^Cache saved with the key:.*/)
|
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(
|
|
||||||
['wrapper-path'],
|
|
||||||
'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'));
|
|
||||||
createDirectory(join(workspace, '.mvn'));
|
|
||||||
createDirectory(join(workspace, '.mvn', 'wrapper'));
|
|
||||||
createFile(
|
|
||||||
join(workspace, '.mvn', 'wrapper', 'maven-wrapper.properties')
|
|
||||||
);
|
|
||||||
(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 '';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
spyGlobCreate.mockResolvedValue({
|
|
||||||
glob: jest.fn(() => Promise.resolve([]))
|
|
||||||
});
|
|
||||||
|
|
||||||
await expect(save('maven')).resolves.toBeUndefined();
|
|
||||||
expect(spyCacheSave).not.toHaveBeenCalledWith(
|
|
||||||
[join(os.homedir(), '.m2', 'wrapper', 'dists')],
|
|
||||||
expect.any(String)
|
|
||||||
);
|
|
||||||
expect(spyCacheSave).toHaveBeenCalledWith(
|
|
||||||
[join(os.homedir(), '.m2', 'repository')],
|
|
||||||
'setup-java-cache-primary-key'
|
|
||||||
);
|
|
||||||
expect(spyWarning).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
it('continues with primary cache save when additional cache save fails unexpectedly', 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[], key: string) => {
|
|
||||||
if (paths[0] === 'wrapper-path') {
|
|
||||||
return Promise.reject(new Error('wrapper save exploded'));
|
|
||||||
}
|
|
||||||
return Promise.resolve(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
await expect(save('maven')).resolves.toBeUndefined();
|
|
||||||
expect(spyWarning).toHaveBeenCalledWith(
|
|
||||||
'Failed to save maven-wrapper cache: wrapper save exploded. Continuing with primary cache save.'
|
|
||||||
);
|
|
||||||
expect(spyCacheSave).toHaveBeenCalledWith(
|
|
||||||
[join(os.homedir(), '.m2', 'repository')],
|
|
||||||
'setup-java-cache-primary-key'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
describe('for gradle', () => {
|
describe('for gradle', () => {
|
||||||
it('uploads cache even if no build.gradle found', async () => {
|
it('uploads cache even if no build.gradle found', async () => {
|
||||||
@@ -876,80 +509,6 @@ describe('dependency cache', () => {
|
|||||||
expect.stringMatching(/^Cache saved with the key:.*/)
|
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(
|
|
||||||
['wrapper-path'],
|
|
||||||
'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)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it('does not fail the post step when the wrapper distribution path is missing', async () => {
|
|
||||||
createFile(join(workspace, 'build.gradle'));
|
|
||||||
createFile(join(workspace, 'gradle-wrapper.properties'));
|
|
||||||
(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 '';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
spyGlobCreate.mockResolvedValue({
|
|
||||||
glob: jest.fn(() => Promise.resolve([]))
|
|
||||||
});
|
|
||||||
|
|
||||||
await expect(save('gradle')).resolves.toBeUndefined();
|
|
||||||
expect(spyCacheSave).not.toHaveBeenCalledWith(
|
|
||||||
[join(os.homedir(), '.gradle', 'wrapper')],
|
|
||||||
expect.any(String)
|
|
||||||
);
|
|
||||||
expect(spyCacheSave).toHaveBeenCalledWith(
|
|
||||||
[join(os.homedir(), '.gradle', 'caches')],
|
|
||||||
'setup-java-cache-primary-key'
|
|
||||||
);
|
|
||||||
expect(spyWarning).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
describe('for sbt', () => {
|
describe('for sbt', () => {
|
||||||
it('uploads cache even if no build.sbt found', async () => {
|
it('uploads cache even if no build.sbt found', async () => {
|
||||||
@@ -1032,16 +591,6 @@ function createFile(path: string) {
|
|||||||
fs.writeFileSync(path, '');
|
fs.writeFileSync(path, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
function deferred<T>() {
|
|
||||||
let resolve!: (value: T | PromiseLike<T>) => void;
|
|
||||||
let reject!: (reason?: unknown) => void;
|
|
||||||
const promise = new Promise<T>((promiseResolve, promiseReject) => {
|
|
||||||
resolve = promiseResolve;
|
|
||||||
reject = promiseReject;
|
|
||||||
});
|
|
||||||
return {promise, resolve, reject};
|
|
||||||
}
|
|
||||||
|
|
||||||
function createDirectory(path: string) {
|
function createDirectory(path: string) {
|
||||||
core.info(`created a directory at ${path}`);
|
core.info(`created a directory at ${path}`);
|
||||||
fs.mkdirSync(path);
|
fs.mkdirSync(path);
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.12/apache-maven-3.9.12-bin.zip
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
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
@@ -1,15 +0,0 @@
|
|||||||
<?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>
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
target/
|
|
||||||
Vendored
-3
@@ -1,3 +0,0 @@
|
|||||||
ThisBuild / scalaVersion := "2.12.15"
|
|
||||||
|
|
||||||
libraryDependencies += "org.scala-lang.modules" %% "scala-parser-combinators" % "2.1.1"
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
#!/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
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
import {afterEach, describe, expect, it, jest} from '@jest/globals';
|
|
||||||
import {createHash} from 'crypto';
|
|
||||||
import fs from 'fs';
|
|
||||||
import os from 'os';
|
|
||||||
import path from 'path';
|
|
||||||
|
|
||||||
import {calculateChecksum, verifyChecksum} from '../src/checksum.js';
|
|
||||||
import type {ChecksumMetadata} from '../src/distributions/base-models.js';
|
|
||||||
|
|
||||||
const temporaryPaths: string[] = [];
|
|
||||||
|
|
||||||
async function temporaryFile(contents: string): Promise<string> {
|
|
||||||
const directory = await fs.promises.mkdtemp(
|
|
||||||
path.join(os.tmpdir(), 'setup-java-checksum-')
|
|
||||||
);
|
|
||||||
const file = path.join(directory, 'archive');
|
|
||||||
await fs.promises.writeFile(file, contents);
|
|
||||||
temporaryPaths.push(directory);
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
await Promise.all(
|
|
||||||
temporaryPaths
|
|
||||||
.splice(0)
|
|
||||||
.map(item => fs.promises.rm(item, {recursive: true, force: true}))
|
|
||||||
);
|
|
||||||
jest.restoreAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('verifyChecksum', () => {
|
|
||||||
it.each(['sha256', 'sha512'] as const)(
|
|
||||||
'verifies a matching %s digest',
|
|
||||||
async algorithm => {
|
|
||||||
const contents = `jdk archive for ${algorithm}`;
|
|
||||||
const file = await temporaryFile(contents);
|
|
||||||
const value = createHash(algorithm).update(contents).digest('hex');
|
|
||||||
|
|
||||||
await expect(
|
|
||||||
verifyChecksum(
|
|
||||||
file,
|
|
||||||
{algorithm, value: value.toUpperCase()},
|
|
||||||
{distribution: 'Test', version: '21.0.1'}
|
|
||||||
)
|
|
||||||
).resolves.toBeUndefined();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
it('reports mismatch context and both digests', async () => {
|
|
||||||
const file = await temporaryFile('corrupt archive');
|
|
||||||
const expected = 'a'.repeat(64);
|
|
||||||
const actual = await calculateChecksum(file, 'sha256');
|
|
||||||
|
|
||||||
await expect(
|
|
||||||
verifyChecksum(
|
|
||||||
file,
|
|
||||||
{algorithm: 'sha256', value: expected},
|
|
||||||
{distribution: 'Corretto', version: '21.0.8'}
|
|
||||||
)
|
|
||||||
).rejects.toThrow(
|
|
||||||
`Checksum verification failed for Corretto version 21.0.8: sha256 expected ${expected}, actual ${actual}.`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('rejects malformed digest metadata before reading the file', async () => {
|
|
||||||
await expect(
|
|
||||||
verifyChecksum(
|
|
||||||
'/missing/archive',
|
|
||||||
{algorithm: 'sha512', value: 'not-a-digest'},
|
|
||||||
{distribution: 'Test', version: '17'}
|
|
||||||
)
|
|
||||||
).rejects.toThrow(
|
|
||||||
'Malformed sha512 checksum metadata: expected a 128-character hexadecimal digest.'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each([undefined, null, 123])(
|
|
||||||
'reports a malformed digest when the value is %p',
|
|
||||||
async value => {
|
|
||||||
const checksum = {
|
|
||||||
algorithm: 'sha256',
|
|
||||||
value
|
|
||||||
} as unknown as ChecksumMetadata;
|
|
||||||
|
|
||||||
await expect(
|
|
||||||
verifyChecksum('/missing/archive', checksum, {
|
|
||||||
distribution: 'Test',
|
|
||||||
version: '17'
|
|
||||||
})
|
|
||||||
).rejects.toThrow(
|
|
||||||
'Malformed sha256 checksum metadata: expected a 64-character hexadecimal digest.'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
it('rejects unsupported algorithms without leaking source query parameters', async () => {
|
|
||||||
const checksum = {
|
|
||||||
algorithm: 'md5',
|
|
||||||
value: 'a'.repeat(32),
|
|
||||||
source: 'https://vendor.example/checksum.txt?token=secret-value#private'
|
|
||||||
} as unknown as ChecksumMetadata;
|
|
||||||
|
|
||||||
let message = '';
|
|
||||||
try {
|
|
||||||
await verifyChecksum('/missing/archive', checksum, {
|
|
||||||
distribution: 'Test',
|
|
||||||
version: '17'
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
message = (error as Error).message;
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(message).toContain(
|
|
||||||
"Unsupported checksum algorithm 'md5' from https://vendor.example/checksum.txt"
|
|
||||||
);
|
|
||||||
expect(message).not.toContain('secret-value');
|
|
||||||
expect(message).not.toContain('token=');
|
|
||||||
expect(message).not.toContain('#private');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('surfaces file read errors', async () => {
|
|
||||||
await expect(
|
|
||||||
verifyChecksum(
|
|
||||||
'/missing/archive',
|
|
||||||
{algorithm: 'sha256', value: 'a'.repeat(64)},
|
|
||||||
{distribution: 'Test', version: '17'}
|
|
||||||
)
|
|
||||||
).rejects.toMatchObject({code: 'ENOENT'});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -8,9 +8,6 @@ import {
|
|||||||
beforeAll,
|
beforeAll,
|
||||||
afterAll
|
afterAll
|
||||||
} from '@jest/globals';
|
} from '@jest/globals';
|
||||||
import fs from 'fs';
|
|
||||||
import os from 'os';
|
|
||||||
import path from 'path';
|
|
||||||
|
|
||||||
// Mock @actions/cache before importing source modules
|
// Mock @actions/cache before importing source modules
|
||||||
const real_cache_module = await import('@actions/cache');
|
const real_cache_module = await import('@actions/cache');
|
||||||
@@ -63,9 +60,6 @@ const core = await import('@actions/core');
|
|||||||
const cache = await import('@actions/cache');
|
const cache = await import('@actions/cache');
|
||||||
const {run: cleanup} = await import('../src/cleanup-java.js');
|
const {run: cleanup} = await import('../src/cleanup-java.js');
|
||||||
const util = await import('../src/util.js');
|
const util = await import('../src/util.js');
|
||||||
const {registerJdk, buildJdkCacheKey} = await import('../src/jdk-cache.js');
|
|
||||||
|
|
||||||
const jdkTempRoots: string[] = [];
|
|
||||||
|
|
||||||
describe('cleanup', () => {
|
describe('cleanup', () => {
|
||||||
let spyWarning: any;
|
let spyWarning: any;
|
||||||
@@ -94,9 +88,6 @@ describe('cleanup', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
while (jdkTempRoots.length) {
|
|
||||||
fs.rmSync(jdkTempRoots.pop()!, {recursive: true, force: true});
|
|
||||||
}
|
|
||||||
resetState();
|
resetState();
|
||||||
jest.resetAllMocks();
|
jest.resetAllMocks();
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
@@ -129,146 +120,6 @@ describe('cleanup', () => {
|
|||||||
await cleanup();
|
await cleanup();
|
||||||
expect(spyCacheSave).toHaveBeenCalled();
|
expect(spyCacheSave).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it.each(['maven', 'gradle', 'sbt'])(
|
|
||||||
'does not save the %s cache in read-only mode',
|
|
||||||
async packageManager => {
|
|
||||||
createStateForSuccessfulRestoreWithWrapper(packageManager);
|
|
||||||
(core.getInput as jest.Mock<any>).mockImplementation((name: string) => {
|
|
||||||
switch (name) {
|
|
||||||
case 'cache':
|
|
||||||
return packageManager;
|
|
||||||
case 'cache-read-only':
|
|
||||||
return 'true';
|
|
||||||
default:
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await cleanup();
|
|
||||||
|
|
||||||
expect(spyCacheSave).not.toHaveBeenCalled();
|
|
||||||
expect(core.getState).not.toHaveBeenCalled();
|
|
||||||
expect(spyInfo).toHaveBeenCalledWith(
|
|
||||||
'Cache saving is skipped because cache-read-only is enabled.'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
it('saves the cache when read-only mode is explicitly disabled', async () => {
|
|
||||||
spyCacheSave.mockResolvedValue(0);
|
|
||||||
(core.getInput as jest.Mock<any>).mockImplementation((name: string) => {
|
|
||||||
switch (name) {
|
|
||||||
case 'cache':
|
|
||||||
return 'maven';
|
|
||||||
case 'cache-read-only':
|
|
||||||
return 'false';
|
|
||||||
default:
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await cleanup();
|
|
||||||
|
|
||||||
expect(spyCacheSave).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('saves the JDK cache without dependency caching', async () => {
|
|
||||||
const {key, path: jdkPath, state} = createRegisteredJdk();
|
|
||||||
(core.getInput as jest.Mock<any>).mockImplementation((name: string) =>
|
|
||||||
name === 'cache-jdk' ? 'true' : ''
|
|
||||||
);
|
|
||||||
(core.getState as jest.Mock<any>).mockImplementation((name: string) =>
|
|
||||||
name === 'jdk-caches' ? state : ''
|
|
||||||
);
|
|
||||||
spyCacheSave.mockResolvedValue(1);
|
|
||||||
|
|
||||||
await cleanup();
|
|
||||||
|
|
||||||
expect(spyCacheSave).toHaveBeenCalledWith([jdkPath], key);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not save a JDK cache when cache-jdk is disabled', async () => {
|
|
||||||
(core.getInput as jest.Mock<any>).mockImplementation((name: string) =>
|
|
||||||
name === 'cache-jdk' ? 'false' : ''
|
|
||||||
);
|
|
||||||
|
|
||||||
await cleanup();
|
|
||||||
|
|
||||||
expect(spyCacheSave).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each([
|
|
||||||
['', '', false],
|
|
||||||
['', 'true', true],
|
|
||||||
['', 'false', false],
|
|
||||||
['maven', '', true],
|
|
||||||
['maven', 'true', true],
|
|
||||||
['maven', 'false', false]
|
|
||||||
])(
|
|
||||||
'uses effective JDK caching for cache=%j and cache-jdk=%j',
|
|
||||||
async (cacheInput, cacheJdkInput, expectedJdkSave) => {
|
|
||||||
const {key: jdkKey, path: jdkPath, state} = createRegisteredJdk();
|
|
||||||
(core.getInput as jest.Mock<any>).mockImplementation((name: string) => {
|
|
||||||
if (name === 'cache') return cacheInput;
|
|
||||||
if (name === 'cache-jdk') return cacheJdkInput;
|
|
||||||
return '';
|
|
||||||
});
|
|
||||||
(core.getState as jest.Mock<any>).mockImplementation((name: string) =>
|
|
||||||
name === 'jdk-caches' ? state : ''
|
|
||||||
);
|
|
||||||
spyCacheSave.mockResolvedValue(1);
|
|
||||||
|
|
||||||
await cleanup();
|
|
||||||
|
|
||||||
const jdkSaveCalls = spyCacheSave.mock.calls.filter(
|
|
||||||
([, key]) => key === jdkKey
|
|
||||||
);
|
|
||||||
expect(jdkSaveCalls).toHaveLength(expectedJdkSave ? 1 : 0);
|
|
||||||
if (expectedJdkSave) {
|
|
||||||
expect(spyCacheSave).toHaveBeenCalledWith([jdkPath], jdkKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
it('keeps saving the remaining JDK caches when one save fails', async () => {
|
|
||||||
const first = createRegisteredJdk();
|
|
||||||
const second = createRegisteredJdk('17.0.19+9');
|
|
||||||
(core.getInput as jest.Mock<any>).mockImplementation((name: string) =>
|
|
||||||
name === 'cache-jdk' ? 'true' : ''
|
|
||||||
);
|
|
||||||
(core.getState as jest.Mock<any>).mockImplementation((name: string) =>
|
|
||||||
name === 'jdk-caches' ? second.state : ''
|
|
||||||
);
|
|
||||||
spyCacheSave.mockImplementation(async (paths: string[]) => {
|
|
||||||
if (paths[0] === first.path) {
|
|
||||||
throw new Error('Unexpected save failure');
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
});
|
|
||||||
|
|
||||||
await cleanup();
|
|
||||||
|
|
||||||
expect(spyCacheSave).toHaveBeenCalledWith([first.path], first.key);
|
|
||||||
expect(spyCacheSave).toHaveBeenCalledWith([second.path], second.key);
|
|
||||||
expect(spyCoreError).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not save a JDK installation that was replaced after registration', async () => {
|
|
||||||
const {key, path: jdkPath, state, replace} = createRegisteredJdk();
|
|
||||||
(core.getInput as jest.Mock<any>).mockImplementation((name: string) =>
|
|
||||||
name === 'cache-jdk' ? 'true' : ''
|
|
||||||
);
|
|
||||||
(core.getState as jest.Mock<any>).mockImplementation((name: string) =>
|
|
||||||
name === 'jdk-caches' ? state : ''
|
|
||||||
);
|
|
||||||
spyCacheSave.mockResolvedValue(1);
|
|
||||||
replace();
|
|
||||||
|
|
||||||
await cleanup();
|
|
||||||
|
|
||||||
expect(spyCacheSave).not.toHaveBeenCalledWith([jdkPath], key);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function resetState() {
|
function resetState() {
|
||||||
@@ -290,64 +141,3 @@ function createStateForSuccessfulRestore() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function createStateForSuccessfulRestoreWithWrapper(packageManager: string) {
|
|
||||||
(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-${packageManager}-wrapper`:
|
|
||||||
return `setup-java-${packageManager}-wrapper-primary-key`;
|
|
||||||
default:
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a real JDK installation in a temporary tool cache so the post-job
|
|
||||||
* save sees the same installation identity that setup recorded.
|
|
||||||
*/
|
|
||||||
function createRegisteredJdk(version = '21.0.8+9') {
|
|
||||||
const root = fs.mkdtempSync(
|
|
||||||
path.join(os.tmpdir(), 'setup-java-cleanup-jdk-')
|
|
||||||
);
|
|
||||||
jdkTempRoots.push(root);
|
|
||||||
const jdkPath = path.join(
|
|
||||||
root,
|
|
||||||
'Java_temurin_jdk',
|
|
||||||
version.replace('+', '-')
|
|
||||||
);
|
|
||||||
const write = (marker: string) => {
|
|
||||||
const architecturePath = path.join(jdkPath, 'x64');
|
|
||||||
fs.rmSync(architecturePath, {recursive: true, force: true});
|
|
||||||
fs.rmSync(`${architecturePath}.complete`, {force: true});
|
|
||||||
fs.mkdirSync(architecturePath, {recursive: true});
|
|
||||||
fs.writeFileSync(path.join(architecturePath, 'release'), marker);
|
|
||||||
fs.writeFileSync(`${architecturePath}.complete`, marker);
|
|
||||||
};
|
|
||||||
write('installed');
|
|
||||||
|
|
||||||
const jdk = {
|
|
||||||
distribution: 'temurin',
|
|
||||||
packageType: 'jdk',
|
|
||||||
architecture: 'x64',
|
|
||||||
version,
|
|
||||||
source: `sha256:${path.basename(root)}`,
|
|
||||||
verification: 'unverified',
|
|
||||||
path: jdkPath
|
|
||||||
};
|
|
||||||
registerJdk(jdk);
|
|
||||||
const state = (
|
|
||||||
(core.saveState as jest.Mock).mock.calls.at(-1) as string[]
|
|
||||||
)[1];
|
|
||||||
|
|
||||||
return {
|
|
||||||
key: buildJdkCacheKey(jdk),
|
|
||||||
path: jdkPath,
|
|
||||||
state,
|
|
||||||
replace: () => write('replaced-by-a-later-step')
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,909 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"binaries": [
|
||||||
|
{
|
||||||
|
"architecture": "x64",
|
||||||
|
"download_count": 74181,
|
||||||
|
"heap_size": "normal",
|
||||||
|
"image_type": "jdk",
|
||||||
|
"jvm_impl": "hotspot",
|
||||||
|
"os": "mac",
|
||||||
|
"package": {
|
||||||
|
"checksum": "09b7e6ab5d5eb4b73813f4caa793a0b616d33794a17988fa6a6b7c972e8f3dd3",
|
||||||
|
"checksum_link": "https://github.com/AdoptOpenJDK/openjdk14-binaries/releases/download/jdk-14.0.2%2B12/OpenJDK14U-jdk_x64_mac_hotspot_14.0.2_12.tar.gz.sha256.txt",
|
||||||
|
"download_count": 23872,
|
||||||
|
"link": "https://github.com/AdoptOpenJDK/openjdk14-binaries/releases/download/jdk-14.0.2%2B12/OpenJDK14U-jdk_x64_mac_hotspot_14.0.2_12.tar.gz",
|
||||||
|
"metadata_link": "https://github.com/AdoptOpenJDK/openjdk14-binaries/releases/download/jdk-14.0.2%2B12/OpenJDK14U-jdk_x64_mac_hotspot_14.0.2_12.tar.gz.json",
|
||||||
|
"name": "OpenJDK14U-jdk_x64_mac_hotspot_14.0.2_12.tar.gz",
|
||||||
|
"size": 195705010
|
||||||
|
},
|
||||||
|
"project": "jdk",
|
||||||
|
"scm_ref": "jdk-14.0.2+12_adopt",
|
||||||
|
"updated_at": "2020-07-16T08:55:45Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"download_count": 477080,
|
||||||
|
"id": "MDc6UmVsZWFzZTI4NjIyMDc4.+ve8KojpqJUpsA==",
|
||||||
|
"release_link": "https://github.com/AdoptOpenJDK/openjdk14-binaries/releases/tag/jdk-14.0.2%2B12",
|
||||||
|
"release_name": "jdk-14.0.2+12",
|
||||||
|
"release_type": "ga",
|
||||||
|
"timestamp": "2020-07-16T08:54:16Z",
|
||||||
|
"updated_at": "2020-07-16T08:54:16Z",
|
||||||
|
"vendor": "adoptopenjdk",
|
||||||
|
"version_data": {
|
||||||
|
"build": 12,
|
||||||
|
"major": 14,
|
||||||
|
"minor": 0,
|
||||||
|
"openjdk_version": "14.0.2+12",
|
||||||
|
"security": 2,
|
||||||
|
"semver": "14.0.2+12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binaries": [
|
||||||
|
{
|
||||||
|
"architecture": "x64",
|
||||||
|
"download_count": 58023,
|
||||||
|
"heap_size": "normal",
|
||||||
|
"image_type": "jdk",
|
||||||
|
"jvm_impl": "hotspot",
|
||||||
|
"os": "mac",
|
||||||
|
"package": {
|
||||||
|
"checksum": "b11cb192312530bcd84607631203d0c1727e672af12813078e6b525e3cce862d",
|
||||||
|
"checksum_link": "https://github.com/AdoptOpenJDK/openjdk14-binaries/releases/download/jdk-14.0.1%2B7/OpenJDK14U-jdk_x64_mac_hotspot_14.0.1_7.tar.gz.sha256.txt",
|
||||||
|
"download_count": 25276,
|
||||||
|
"link": "https://github.com/AdoptOpenJDK/openjdk14-binaries/releases/download/jdk-14.0.1%2B7/OpenJDK14U-jdk_x64_mac_hotspot_14.0.1_7.tar.gz",
|
||||||
|
"metadata_link": "https://github.com/AdoptOpenJDK/openjdk14-binaries/releases/download/jdk-14.0.1%2B7/OpenJDK14U-jdk_x64_mac_hotspot_14.0.1_7.tar.gz.json",
|
||||||
|
"name": "OpenJDK14U-jdk_x64_mac_hotspot_14.0.1_7.tar.gz",
|
||||||
|
"size": 195769653
|
||||||
|
},
|
||||||
|
"project": "jdk",
|
||||||
|
"scm_ref": "jdk-14.0.1+7_adopt",
|
||||||
|
"updated_at": "2020-04-20T12:54:23Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"download_count": 198607,
|
||||||
|
"id": "MDc6UmVsZWFzZTI1Njc4MzEw.z3NqYG25PFlG+Q==",
|
||||||
|
"release_link": "https://github.com/AdoptOpenJDK/openjdk14-binaries/releases/tag/jdk-14.0.1%2B7",
|
||||||
|
"release_name": "jdk-14.0.1+7",
|
||||||
|
"release_type": "ga",
|
||||||
|
"timestamp": "2020-04-20T12:52:51Z",
|
||||||
|
"updated_at": "2020-04-20T12:52:51Z",
|
||||||
|
"vendor": "adoptopenjdk",
|
||||||
|
"version_data": {
|
||||||
|
"adopt_build_number": 1,
|
||||||
|
"build": 7,
|
||||||
|
"major": 14,
|
||||||
|
"minor": 0,
|
||||||
|
"openjdk_version": "14.0.1+7",
|
||||||
|
"security": 1,
|
||||||
|
"semver": "14.0.1+7.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binaries": [
|
||||||
|
{
|
||||||
|
"architecture": "x64",
|
||||||
|
"download_count": 30069,
|
||||||
|
"heap_size": "normal",
|
||||||
|
"image_type": "jdk",
|
||||||
|
"jvm_impl": "hotspot",
|
||||||
|
"os": "mac",
|
||||||
|
"package": {
|
||||||
|
"checksum": "d358a7ff03905282348c6c80562a4da2e04eb377b60ad2152be4c90f8d580b7f",
|
||||||
|
"checksum_link": "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15.0.2%2B7/OpenJDK15U-jdk_x64_mac_hotspot_15.0.2_7.tar.gz.sha256.txt",
|
||||||
|
"download_count": 3718,
|
||||||
|
"link": "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15.0.2%2B7/OpenJDK15U-jdk_x64_mac_hotspot_15.0.2_7.tar.gz",
|
||||||
|
"metadata_link": "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15.0.2%2B7/OpenJDK15U-jdk_x64_mac_hotspot_15.0.2_7.tar.gz.json",
|
||||||
|
"name": "OpenJDK15U-jdk_x64_mac_hotspot_15.0.2_7.tar.gz",
|
||||||
|
"size": 195232978
|
||||||
|
},
|
||||||
|
"project": "jdk",
|
||||||
|
"scm_ref": "jdk-15.0.2+7_adopt",
|
||||||
|
"updated_at": "2021-01-22T17:33:20Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"download_count": 124226,
|
||||||
|
"id": "MDc6UmVsZWFzZTM2NzgwOTAw.X2+6VqPND3E8CA==",
|
||||||
|
"release_link": "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/tag/jdk-15.0.2%2B7",
|
||||||
|
"release_name": "jdk-15.0.2+7",
|
||||||
|
"release_type": "ga",
|
||||||
|
"timestamp": "2021-01-22T17:31:37Z",
|
||||||
|
"updated_at": "2021-01-22T17:31:37Z",
|
||||||
|
"vendor": "adoptopenjdk",
|
||||||
|
"version_data": {
|
||||||
|
"build": 7,
|
||||||
|
"major": 15,
|
||||||
|
"minor": 0,
|
||||||
|
"openjdk_version": "15.0.2+7",
|
||||||
|
"security": 2,
|
||||||
|
"semver": "15.0.2+7"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binaries": [
|
||||||
|
{
|
||||||
|
"architecture": "x64",
|
||||||
|
"download_count": 24542,
|
||||||
|
"heap_size": "normal",
|
||||||
|
"image_type": "jdk",
|
||||||
|
"jvm_impl": "hotspot",
|
||||||
|
"os": "mac",
|
||||||
|
"package": {
|
||||||
|
"checksum": "b8c2e2ad31f3d6676ea665d9505b06df15e23741847556612b40e3ee329fc046",
|
||||||
|
"checksum_link": "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15.0.1%2B9.1/OpenJDK15U-jdk_x64_mac_hotspot_15.0.1_9.tar.gz.sha256.txt",
|
||||||
|
"download_count": 3274,
|
||||||
|
"link": "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15.0.1%2B9.1/OpenJDK15U-jdk_x64_mac_hotspot_15.0.1_9.tar.gz",
|
||||||
|
"metadata_link": "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15.0.1%2B9.1/OpenJDK15U-jdk_x64_mac_hotspot_15.0.1_9.tar.gz.json",
|
||||||
|
"name": "OpenJDK15U-jdk_x64_mac_hotspot_15.0.1_9.tar.gz",
|
||||||
|
"size": 195872839
|
||||||
|
},
|
||||||
|
"project": "jdk",
|
||||||
|
"scm_ref": "jdk-15.0.1+9_adopt",
|
||||||
|
"updated_at": "2020-12-01T16:57:47Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"download_count": 25378,
|
||||||
|
"id": "MDc6UmVsZWFzZTM0NjQ2MDU4.Yj2XZf+VBGAPtw==",
|
||||||
|
"release_link": "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/tag/jdk-15.0.1%2B9.1",
|
||||||
|
"release_name": "jdk-15.0.1+9.1",
|
||||||
|
"release_type": "ga",
|
||||||
|
"timestamp": "2020-12-01T16:57:26Z",
|
||||||
|
"updated_at": "2020-12-01T16:57:26Z",
|
||||||
|
"vendor": "adoptopenjdk",
|
||||||
|
"version_data": {
|
||||||
|
"adopt_build_number": 1,
|
||||||
|
"build": 9,
|
||||||
|
"major": 15,
|
||||||
|
"minor": 0,
|
||||||
|
"openjdk_version": "15.0.1+9",
|
||||||
|
"security": 1,
|
||||||
|
"semver": "15.0.1+9.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binaries": [
|
||||||
|
{
|
||||||
|
"architecture": "x64",
|
||||||
|
"download_count": 21675,
|
||||||
|
"heap_size": "normal",
|
||||||
|
"image_type": "jdk",
|
||||||
|
"jvm_impl": "hotspot",
|
||||||
|
"os": "mac",
|
||||||
|
"package": {
|
||||||
|
"checksum": "d32f9429c4992cef7be559a15c542011503d6bc38c89379800cd209a9d7ec539",
|
||||||
|
"checksum_link": "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15.0.1%2B9/OpenJDK15U-jdk_x64_mac_hotspot_15.0.1_9.tar.gz.sha256.txt",
|
||||||
|
"download_count": 11935,
|
||||||
|
"link": "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15.0.1%2B9/OpenJDK15U-jdk_x64_mac_hotspot_15.0.1_9.tar.gz",
|
||||||
|
"metadata_link": "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15.0.1%2B9/OpenJDK15U-jdk_x64_mac_hotspot_15.0.1_9.tar.gz.json",
|
||||||
|
"name": "OpenJDK15U-jdk_x64_mac_hotspot_15.0.1_9.tar.gz",
|
||||||
|
"size": 195773522
|
||||||
|
},
|
||||||
|
"project": "jdk",
|
||||||
|
"scm_ref": "jdk-15.0.1+9_adopt",
|
||||||
|
"updated_at": "2020-10-23T20:48:09Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"download_count": 308690,
|
||||||
|
"id": "MDc6UmVsZWFzZTMyOTk4MTUx.3oazo3YGfHhF3w==",
|
||||||
|
"release_link": "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/tag/jdk-15.0.1%2B9",
|
||||||
|
"release_name": "jdk-15.0.1+9",
|
||||||
|
"release_type": "ga",
|
||||||
|
"timestamp": "2020-10-23T20:46:22Z",
|
||||||
|
"updated_at": "2020-10-23T20:46:22Z",
|
||||||
|
"vendor": "adoptopenjdk",
|
||||||
|
"version_data": {
|
||||||
|
"build": 9,
|
||||||
|
"major": 15,
|
||||||
|
"minor": 0,
|
||||||
|
"openjdk_version": "15.0.1+9",
|
||||||
|
"security": 1,
|
||||||
|
"semver": "15.0.1+9"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binaries": [
|
||||||
|
{
|
||||||
|
"architecture": "x64",
|
||||||
|
"download_count": 51254,
|
||||||
|
"heap_size": "normal",
|
||||||
|
"image_type": "jdk",
|
||||||
|
"jvm_impl": "hotspot",
|
||||||
|
"os": "mac",
|
||||||
|
"package": {
|
||||||
|
"checksum": "bd1fc774232e2dfee93056a01f5765bd92ffb19d68dd548c233a82bb5c162be4",
|
||||||
|
"checksum_link": "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15%2B36/OpenJDK15U-jdk_x64_mac_hotspot_15_36.tar.gz.sha256.txt",
|
||||||
|
"download_count": 5325,
|
||||||
|
"link": "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15%2B36/OpenJDK15U-jdk_x64_mac_hotspot_15_36.tar.gz",
|
||||||
|
"metadata_link": "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15%2B36/OpenJDK15U-jdk_x64_mac_hotspot_15_36.tar.gz.json",
|
||||||
|
"name": "OpenJDK15U-jdk_x64_mac_hotspot_15_36.tar.gz",
|
||||||
|
"size": 195853361
|
||||||
|
},
|
||||||
|
"project": "jdk",
|
||||||
|
"scm_ref": "jdk-15+36_adopt",
|
||||||
|
"updated_at": "2020-09-17T07:43:54Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"download_count": 157313,
|
||||||
|
"id": "MDc6UmVsZWFzZTMxNDUwMjA0.eYpt0EBEjldfEQ==",
|
||||||
|
"release_link": "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/tag/jdk-15%2B36",
|
||||||
|
"release_name": "jdk-15+36",
|
||||||
|
"release_type": "ga",
|
||||||
|
"timestamp": "2020-09-17T07:42:21Z",
|
||||||
|
"updated_at": "2020-09-17T07:42:21Z",
|
||||||
|
"vendor": "adoptopenjdk",
|
||||||
|
"version_data": {
|
||||||
|
"build": 36,
|
||||||
|
"major": 15,
|
||||||
|
"minor": 0,
|
||||||
|
"openjdk_version": "15+36",
|
||||||
|
"security": 0,
|
||||||
|
"semver": "15.0.0+36"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binaries": [
|
||||||
|
{
|
||||||
|
"architecture": "x64",
|
||||||
|
"download_count": 27428,
|
||||||
|
"heap_size": "normal",
|
||||||
|
"image_type": "jdk",
|
||||||
|
"jvm_impl": "hotspot",
|
||||||
|
"os": "mac",
|
||||||
|
"package": {
|
||||||
|
"checksum": "aabc3aebb0abf1ba64d9bd5796d0c7eb7239983f6e4c0f015b5b88be5616e4bd",
|
||||||
|
"checksum_link": "https://github.com/AdoptOpenJDK/openjdk14-binaries/releases/download/jdk-14%2B36/OpenJDK14U-jdk_x64_mac_hotspot_14_36.tar.gz.sha256.txt",
|
||||||
|
"download_count": 19544,
|
||||||
|
"link": "https://github.com/AdoptOpenJDK/openjdk14-binaries/releases/download/jdk-14%2B36/OpenJDK14U-jdk_x64_mac_hotspot_14_36.tar.gz",
|
||||||
|
"metadata_link": "https://github.com/AdoptOpenJDK/openjdk14-binaries/releases/download/jdk-14%2B36/OpenJDK14U-jdk_x64_mac_hotspot_14_36.tar.gz.json",
|
||||||
|
"name": "OpenJDK14U-jdk_x64_mac_hotspot_14_36.tar.gz",
|
||||||
|
"size": 201087797
|
||||||
|
},
|
||||||
|
"project": "jdk",
|
||||||
|
"scm_ref": "jdk-14+36_adopt",
|
||||||
|
"updated_at": "2020-03-18T12:13:05Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"download_count": 364816,
|
||||||
|
"id": "MDc6UmVsZWFzZTI0NjMxMDAy.AY7rtvmrnWWlIg==",
|
||||||
|
"release_link": "https://github.com/AdoptOpenJDK/openjdk14-binaries/releases/tag/jdk-14%2B36",
|
||||||
|
"release_name": "jdk-14+36",
|
||||||
|
"release_type": "ga",
|
||||||
|
"timestamp": "2020-03-18T12:11:08Z",
|
||||||
|
"updated_at": "2020-03-18T12:11:08Z",
|
||||||
|
"vendor": "adoptopenjdk",
|
||||||
|
"version_data": {
|
||||||
|
"adopt_build_number": 1,
|
||||||
|
"build": 36,
|
||||||
|
"major": 14,
|
||||||
|
"minor": 0,
|
||||||
|
"openjdk_version": "14+36",
|
||||||
|
"security": 0,
|
||||||
|
"semver": "14.0.0+36.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binaries": [
|
||||||
|
{
|
||||||
|
"architecture": "x64",
|
||||||
|
"download_count": 63201,
|
||||||
|
"heap_size": "normal",
|
||||||
|
"image_type": "jdk",
|
||||||
|
"jvm_impl": "hotspot",
|
||||||
|
"os": "mac",
|
||||||
|
"package": {
|
||||||
|
"checksum": "0ddb24efdf5aab541898d19b7667b149a1a64a8bd039b708fc58ee0284fa7e07",
|
||||||
|
"checksum_link": "https://github.com/AdoptOpenJDK/openjdk13-binaries/releases/download/jdk-13.0.2%2B8/OpenJDK13U-jdk_x64_mac_hotspot_13.0.2_8.tar.gz.sha256.txt",
|
||||||
|
"download_count": 32531,
|
||||||
|
"link": "https://github.com/AdoptOpenJDK/openjdk13-binaries/releases/download/jdk-13.0.2%2B8/OpenJDK13U-jdk_x64_mac_hotspot_13.0.2_8.tar.gz",
|
||||||
|
"metadata_link": "https://github.com/AdoptOpenJDK/openjdk13-binaries/releases/download/jdk-13.0.2%2B8/OpenJDK13U-jdk_x64_mac_hotspot_13.0.2_8.tar.gz.json",
|
||||||
|
"name": "OpenJDK13U-jdk_x64_mac_hotspot_13.0.2_8.tar.gz",
|
||||||
|
"size": 198206427
|
||||||
|
},
|
||||||
|
"project": "jdk",
|
||||||
|
"scm_ref": "jdk-13.0.2+8_adopt",
|
||||||
|
"updated_at": "2020-01-20T16:46:24Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"download_count": 349677,
|
||||||
|
"id": "MDc6UmVsZWFzZTIyOTgxNTM1.gtZYwGfBgkb3Gg==",
|
||||||
|
"release_link": "https://github.com/AdoptOpenJDK/openjdk13-binaries/releases/tag/jdk-13.0.2%2B8",
|
||||||
|
"release_name": "jdk-13.0.2+8",
|
||||||
|
"release_type": "ga",
|
||||||
|
"timestamp": "2020-01-20T16:42:35Z",
|
||||||
|
"updated_at": "2020-01-20T16:42:35Z",
|
||||||
|
"vendor": "adoptopenjdk",
|
||||||
|
"version_data": {
|
||||||
|
"adopt_build_number": 1,
|
||||||
|
"build": 8,
|
||||||
|
"major": 13,
|
||||||
|
"minor": 0,
|
||||||
|
"openjdk_version": "13.0.2+8",
|
||||||
|
"security": 2,
|
||||||
|
"semver": "13.0.2+8.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binaries": [
|
||||||
|
{
|
||||||
|
"architecture": "x64",
|
||||||
|
"download_count": 41508,
|
||||||
|
"heap_size": "normal",
|
||||||
|
"image_type": "jdk",
|
||||||
|
"jvm_impl": "hotspot",
|
||||||
|
"os": "mac",
|
||||||
|
"package": {
|
||||||
|
"checksum": "9c82de98ce9bc2353bcf314d85366c9a2c572db034e10a71aa47e804e13748c1",
|
||||||
|
"checksum_link": "https://github.com/AdoptOpenJDK/openjdk13-binaries/releases/download/jdk-13.0.1%2B9/OpenJDK13U-jdk_x64_mac_hotspot_13.0.1_9.tar.gz.sha256.txt",
|
||||||
|
"download_count": 32262,
|
||||||
|
"link": "https://github.com/AdoptOpenJDK/openjdk13-binaries/releases/download/jdk-13.0.1%2B9/OpenJDK13U-jdk_x64_mac_hotspot_13.0.1_9.tar.gz",
|
||||||
|
"metadata_link": "https://github.com/AdoptOpenJDK/openjdk13-binaries/releases/download/jdk-13.0.1%2B9/OpenJDK13U-jdk_x64_mac_hotspot_13.0.1_9.tar.gz.json",
|
||||||
|
"name": "OpenJDK13U-jdk_x64_mac_hotspot_13.0.1_9.tar.gz",
|
||||||
|
"size": 198205689
|
||||||
|
},
|
||||||
|
"project": "jdk",
|
||||||
|
"scm_ref": "jdk-13.0.1+9_adopt",
|
||||||
|
"updated_at": "2019-10-26T14:44:27Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"download_count": 680021,
|
||||||
|
"id": "MDc6UmVsZWFzZTIwOTk4NDA0.srlG2TmLho/j0w==",
|
||||||
|
"release_link": "https://github.com/AdoptOpenJDK/openjdk13-binaries/releases/tag/jdk-13.0.1%2B9",
|
||||||
|
"release_name": "jdk-13.0.1+9",
|
||||||
|
"release_type": "ga",
|
||||||
|
"timestamp": "2019-10-26T14:43:52Z",
|
||||||
|
"updated_at": "2019-10-26T14:43:52Z",
|
||||||
|
"vendor": "adoptopenjdk",
|
||||||
|
"version_data": {
|
||||||
|
"adopt_build_number": 1,
|
||||||
|
"build": 9,
|
||||||
|
"major": 13,
|
||||||
|
"minor": 0,
|
||||||
|
"openjdk_version": "13.0.1+9",
|
||||||
|
"security": 1,
|
||||||
|
"semver": "13.0.1+9.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binaries": [
|
||||||
|
{
|
||||||
|
"architecture": "x64",
|
||||||
|
"download_count": 37738,
|
||||||
|
"heap_size": "normal",
|
||||||
|
"image_type": "jdk",
|
||||||
|
"jvm_impl": "hotspot",
|
||||||
|
"os": "mac",
|
||||||
|
"package": {
|
||||||
|
"checksum": "f948be96daba250b6695e22cb51372d2ba3060e4d778dd09c89548889783099f",
|
||||||
|
"checksum_link": "https://github.com/AdoptOpenJDK/openjdk13-binaries/releases/download/jdk-13%2B33/OpenJDK13U-jdk_x64_mac_hotspot_13_33.tar.gz.sha256.txt",
|
||||||
|
"download_count": 37738,
|
||||||
|
"link": "https://github.com/AdoptOpenJDK/openjdk13-binaries/releases/download/jdk-13%2B33/OpenJDK13U-jdk_x64_mac_hotspot_13_33.tar.gz",
|
||||||
|
"metadata_link": "https://github.com/AdoptOpenJDK/openjdk13-binaries/releases/download/jdk-13%2B33/OpenJDK13U-jdk_x64_mac_hotspot_13_33.tar.gz.json",
|
||||||
|
"name": "OpenJDK13U-jdk_x64_mac_hotspot_13_33.tar.gz",
|
||||||
|
"size": 198189530
|
||||||
|
},
|
||||||
|
"project": "jdk",
|
||||||
|
"scm_ref": "jdk-13+33_adopt",
|
||||||
|
"updated_at": "2019-09-19T10:20:21Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"download_count": 226200,
|
||||||
|
"id": "MDc6UmVsZWFzZTIwMTA0MTUy.trK7qCbNtlMWFw==",
|
||||||
|
"release_link": "https://github.com/AdoptOpenJDK/openjdk13-binaries/releases/tag/jdk-13%2B33",
|
||||||
|
"release_name": "jdk-13+33",
|
||||||
|
"release_type": "ga",
|
||||||
|
"timestamp": "2019-09-19T10:19:58Z",
|
||||||
|
"updated_at": "2019-09-19T10:19:58Z",
|
||||||
|
"vendor": "adoptopenjdk",
|
||||||
|
"version_data": {
|
||||||
|
"adopt_build_number": 1,
|
||||||
|
"build": 33,
|
||||||
|
"major": 13,
|
||||||
|
"minor": 0,
|
||||||
|
"openjdk_version": "13+33",
|
||||||
|
"security": 0,
|
||||||
|
"semver": "13.0.0+33.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binaries": [
|
||||||
|
{
|
||||||
|
"architecture": "x64",
|
||||||
|
"download_count": 24493,
|
||||||
|
"heap_size": "normal",
|
||||||
|
"image_type": "jdk",
|
||||||
|
"jvm_impl": "hotspot",
|
||||||
|
"os": "mac",
|
||||||
|
"package": {
|
||||||
|
"checksum": "9919eee037554d40c7d2f219bbd654f2bf119e16a2f4d284d8dedaf525ee59e6",
|
||||||
|
"checksum_link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/download/jdk-12.0.2%2B10/OpenJDK12U-jdk_x64_mac_hotspot_12.0.2_10.tar.gz.sha256.txt",
|
||||||
|
"download_count": 22907,
|
||||||
|
"link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/download/jdk-12.0.2%2B10/OpenJDK12U-jdk_x64_mac_hotspot_12.0.2_10.tar.gz",
|
||||||
|
"metadata_link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/download/jdk-12.0.2%2B10/OpenJDK12U-jdk_x64_mac_hotspot_12.0.2_10.tar.gz.json",
|
||||||
|
"name": "OpenJDK12U-jdk_x64_mac_hotspot_12.0.2_10.tar.gz",
|
||||||
|
"size": 198392994
|
||||||
|
},
|
||||||
|
"project": "jdk",
|
||||||
|
"scm_ref": "jdk-12.0.2+10_adopt",
|
||||||
|
"updated_at": "2019-07-18T20:27:24Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"download_count": 396318,
|
||||||
|
"id": "MDc6UmVsZWFzZTE4NzE2Mzk5.S/VUFSgnrVIv8A==",
|
||||||
|
"release_link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/tag/jdk-12.0.2%2B10",
|
||||||
|
"release_name": "jdk-12.0.2+10",
|
||||||
|
"release_type": "ga",
|
||||||
|
"timestamp": "2019-07-18T20:26:29Z",
|
||||||
|
"updated_at": "2019-07-18T20:26:29Z",
|
||||||
|
"vendor": "adoptopenjdk",
|
||||||
|
"version_data": {
|
||||||
|
"adopt_build_number": 1,
|
||||||
|
"build": 10,
|
||||||
|
"major": 12,
|
||||||
|
"minor": 0,
|
||||||
|
"openjdk_version": "12.0.2+10",
|
||||||
|
"security": 2,
|
||||||
|
"semver": "12.0.2+10.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binaries": [
|
||||||
|
{
|
||||||
|
"architecture": "x64",
|
||||||
|
"download_count": 5539,
|
||||||
|
"heap_size": "normal",
|
||||||
|
"image_type": "jdk",
|
||||||
|
"jvm_impl": "hotspot",
|
||||||
|
"os": "mac",
|
||||||
|
"package": {
|
||||||
|
"checksum": "7acd697e816491d31b24d0ae1867fd63060aa738cfa388757946ae312a60b4f2",
|
||||||
|
"checksum_link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/download/jdk-12.0.2%2B10.3/OpenJDK12U-jdk_x64_mac_hotspot_12.0.2_10.tar.gz.sha256.txt",
|
||||||
|
"download_count": 5539,
|
||||||
|
"link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/download/jdk-12.0.2%2B10.3/OpenJDK12U-jdk_x64_mac_hotspot_12.0.2_10.tar.gz",
|
||||||
|
"metadata_link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/download/jdk-12.0.2%2B10.3/OpenJDK12U-jdk_x64_mac_hotspot_12.0.2_10.tar.gz.json",
|
||||||
|
"name": "OpenJDK12U-jdk_x64_mac_hotspot_12.0.2_10.tar.gz",
|
||||||
|
"size": 198429049
|
||||||
|
},
|
||||||
|
"project": "jdk",
|
||||||
|
"scm_ref": "jdk-12.0.2+10_adopt",
|
||||||
|
"updated_at": "2019-09-19T17:17:37Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"download_count": 5879,
|
||||||
|
"id": "MDc6UmVsZWFzZTIwMTE2ODQ3.QGQl8Nj1qkma4Q==",
|
||||||
|
"release_link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/tag/jdk-12.0.2%2B10.3",
|
||||||
|
"release_name": "jdk-12.0.2+10.3",
|
||||||
|
"release_type": "ga",
|
||||||
|
"timestamp": "2019-09-19T17:17:26Z",
|
||||||
|
"updated_at": "2019-12-06T15:10:37Z",
|
||||||
|
"vendor": "adoptopenjdk",
|
||||||
|
"version_data": {
|
||||||
|
"adopt_build_number": 3,
|
||||||
|
"build": 10,
|
||||||
|
"major": 12,
|
||||||
|
"minor": 0,
|
||||||
|
"openjdk_version": "12.0.2+10",
|
||||||
|
"security": 2,
|
||||||
|
"semver": "12.0.2+10.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binaries": [
|
||||||
|
{
|
||||||
|
"architecture": "x64",
|
||||||
|
"download_count": 22794,
|
||||||
|
"heap_size": "normal",
|
||||||
|
"image_type": "jdk",
|
||||||
|
"jvm_impl": "hotspot",
|
||||||
|
"os": "mac",
|
||||||
|
"package": {
|
||||||
|
"checksum": "2c1a46c0fab6d4bdbc443f23c3f6a313c2de47fbbd9c16b5c1133a88f6c1ab8f",
|
||||||
|
"checksum_link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/download/jdk-12.0.2%2B10.2/OpenJDK12U-jdk_x64_mac_hotspot_12.0.2_10.tar.gz.sha256.txt",
|
||||||
|
"download_count": 637,
|
||||||
|
"link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/download/jdk-12.0.2%2B10.2/OpenJDK12U-jdk_x64_mac_hotspot_12.0.2_10.tar.gz",
|
||||||
|
"metadata_link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/download/jdk-12.0.2%2B10.2/OpenJDK12U-jdk_x64_mac_hotspot_12.0.2_10.tar.gz.json",
|
||||||
|
"name": "OpenJDK12U-jdk_x64_mac_hotspot_12.0.2_10.tar.gz",
|
||||||
|
"size": 198862174
|
||||||
|
},
|
||||||
|
"project": "jdk",
|
||||||
|
"scm_ref": "jdk-12.0.2+10_adopt",
|
||||||
|
"updated_at": "2019-08-06T10:41:10Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"download_count": 23563,
|
||||||
|
"id": "MDc6UmVsZWFzZTE5MTAzMTI3.in65dKG+veAxOg==",
|
||||||
|
"release_link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/tag/jdk-12.0.2%2B10.2",
|
||||||
|
"release_name": "jdk-12.0.2+10.2",
|
||||||
|
"release_type": "ga",
|
||||||
|
"timestamp": "2019-08-06T10:40:44Z",
|
||||||
|
"updated_at": "2019-08-06T10:40:44Z",
|
||||||
|
"vendor": "adoptopenjdk",
|
||||||
|
"version_data": {
|
||||||
|
"adopt_build_number": 2,
|
||||||
|
"build": 10,
|
||||||
|
"major": 12,
|
||||||
|
"minor": 0,
|
||||||
|
"openjdk_version": "12.0.2+10",
|
||||||
|
"security": 2,
|
||||||
|
"semver": "12.0.2+10.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binaries": [
|
||||||
|
{
|
||||||
|
"architecture": "x64",
|
||||||
|
"download_count": 24493,
|
||||||
|
"heap_size": "normal",
|
||||||
|
"image_type": "jdk",
|
||||||
|
"jvm_impl": "hotspot",
|
||||||
|
"os": "mac",
|
||||||
|
"package": {
|
||||||
|
"checksum": "9919eee037554d40c7d2f219bbd654f2bf119e16a2f4d284d8dedaf525ee59e6",
|
||||||
|
"checksum_link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/download/jdk-12.0.2%2B10/OpenJDK12U-jdk_x64_mac_hotspot_12.0.2_10.tar.gz.sha256.txt",
|
||||||
|
"download_count": 22907,
|
||||||
|
"link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/download/jdk-12.0.2%2B10/OpenJDK12U-jdk_x64_mac_hotspot_12.0.2_10.tar.gz",
|
||||||
|
"metadata_link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/download/jdk-12.0.2%2B10/OpenJDK12U-jdk_x64_mac_hotspot_12.0.2_10.tar.gz.json",
|
||||||
|
"name": "OpenJDK12U-jdk_x64_mac_hotspot_12.0.2_10.tar.gz",
|
||||||
|
"size": 198392994
|
||||||
|
},
|
||||||
|
"project": "jdk",
|
||||||
|
"scm_ref": "jdk-12.0.2+9_adopt",
|
||||||
|
"updated_at": "2019-07-18T20:27:24Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"download_count": 396318,
|
||||||
|
"id": "MDc6UmVsZWFzZTE4NzE2Mzk5.S/VUFSgnrVIv8A==",
|
||||||
|
"release_link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/tag/jdk-12.0.2%2B10",
|
||||||
|
"release_name": "jdk-12.0.2+9",
|
||||||
|
"release_type": "ga",
|
||||||
|
"timestamp": "2019-07-18T20:26:29Z",
|
||||||
|
"updated_at": "2019-07-18T20:26:29Z",
|
||||||
|
"vendor": "adoptopenjdk",
|
||||||
|
"version_data": {
|
||||||
|
"adopt_build_number": 1,
|
||||||
|
"build": 10,
|
||||||
|
"major": 12,
|
||||||
|
"minor": 0,
|
||||||
|
"openjdk_version": "12.0.2+9",
|
||||||
|
"security": 2,
|
||||||
|
"semver": "12.0.2+9.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binaries": [
|
||||||
|
{
|
||||||
|
"architecture": "x64",
|
||||||
|
"download_count": 39519,
|
||||||
|
"heap_size": "normal",
|
||||||
|
"image_type": "jdk",
|
||||||
|
"jvm_impl": "hotspot",
|
||||||
|
"os": "mac",
|
||||||
|
"package": {
|
||||||
|
"checksum": "dcb2ab681247298eda018df24166ba01674127083fb02892acf087e6181d8c56",
|
||||||
|
"checksum_link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/download/jdk-12.0.1%2B12/OpenJDK12U-jdk_x64_mac_hotspot_12.0.1_12.tar.gz.sha256.txt",
|
||||||
|
"download_count": 33306,
|
||||||
|
"link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/download/jdk-12.0.1%2B12/OpenJDK12U-jdk_x64_mac_hotspot_12.0.1_12.tar.gz",
|
||||||
|
"name": "OpenJDK12U-jdk_x64_mac_hotspot_12.0.1_12.tar.gz",
|
||||||
|
"size": 198112975
|
||||||
|
},
|
||||||
|
"project": "jdk",
|
||||||
|
"updated_at": "2019-04-21T15:12:34Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"download_count": 1038669,
|
||||||
|
"id": "MDc6UmVsZWFzZTE2ODg3NDU3",
|
||||||
|
"release_link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/tag/jdk-12.0.1%2B12",
|
||||||
|
"release_name": "jdk-12.0.1+12",
|
||||||
|
"release_type": "ga",
|
||||||
|
"timestamp": "2019-04-21T15:11:56Z",
|
||||||
|
"updated_at": "2019-04-21T15:11:56Z",
|
||||||
|
"vendor": "adoptopenjdk",
|
||||||
|
"version_data": {
|
||||||
|
"build": 12,
|
||||||
|
"major": 12,
|
||||||
|
"minor": 0,
|
||||||
|
"openjdk_version": "12.0.1+12",
|
||||||
|
"security": 1,
|
||||||
|
"semver": "12.0.1+12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binaries": [
|
||||||
|
{
|
||||||
|
"architecture": "x64",
|
||||||
|
"download_count": 3136,
|
||||||
|
"heap_size": "normal",
|
||||||
|
"image_type": "jdk",
|
||||||
|
"jvm_impl": "hotspot",
|
||||||
|
"os": "mac",
|
||||||
|
"package": {
|
||||||
|
"checksum": "985036459d4ef0867a3fe83b0bf87877d8e66a121c7b9c145bb97bd921aaf3f1",
|
||||||
|
"checksum_link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/download/jdk-12%2B33/OpenJDK12U-jdk_x64_mac_hotspot_12_33.tar.gz.sha256.txt",
|
||||||
|
"download_count": 1905,
|
||||||
|
"link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/download/jdk-12%2B33/OpenJDK12U-jdk_x64_mac_hotspot_12_33.tar.gz",
|
||||||
|
"name": "OpenJDK12U-jdk_x64_mac_hotspot_12_33.tar.gz",
|
||||||
|
"size": 198099074
|
||||||
|
},
|
||||||
|
"project": "jdk",
|
||||||
|
"updated_at": "2019-03-22T12:09:13Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"download_count": 757289,
|
||||||
|
"id": "MDc6UmVsZWFzZTE2MjgyMjM2",
|
||||||
|
"release_link": "https://github.com/AdoptOpenJDK/openjdk12-binaries/releases/tag/jdk-12%2B33",
|
||||||
|
"release_name": "jdk-12+33",
|
||||||
|
"release_type": "ga",
|
||||||
|
"timestamp": "2019-03-22T12:08:43Z",
|
||||||
|
"updated_at": "2019-03-22T12:08:43Z",
|
||||||
|
"vendor": "adoptopenjdk",
|
||||||
|
"version_data": {
|
||||||
|
"build": 33,
|
||||||
|
"major": 12,
|
||||||
|
"minor": 0,
|
||||||
|
"openjdk_version": "12+33",
|
||||||
|
"security": 0,
|
||||||
|
"semver": "12.0.0+33"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binaries": [
|
||||||
|
{
|
||||||
|
"architecture": "x64",
|
||||||
|
"download_count": 75576,
|
||||||
|
"heap_size": "normal",
|
||||||
|
"image_type": "jdk",
|
||||||
|
"jvm_impl": "hotspot",
|
||||||
|
"os": "mac",
|
||||||
|
"package": {
|
||||||
|
"checksum": "ee7c98c9d79689aca6e717965747b8bf4eec5413e89d5444cc2bd6dbd59e3811",
|
||||||
|
"checksum_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.10%2B9/OpenJDK11U-jdk_x64_mac_hotspot_11.0.10_9.tar.gz.sha256.txt",
|
||||||
|
"download_count": 17426,
|
||||||
|
"link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.10%2B9/OpenJDK11U-jdk_x64_mac_hotspot_11.0.10_9.tar.gz",
|
||||||
|
"metadata_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.10%2B9/OpenJDK11U-jdk_x64_mac_hotspot_11.0.10_9.tar.gz.json",
|
||||||
|
"name": "OpenJDK11U-jdk_x64_mac_hotspot_11.0.10_9.tar.gz",
|
||||||
|
"size": 186160219
|
||||||
|
},
|
||||||
|
"project": "jdk",
|
||||||
|
"scm_ref": "jdk-11.0.10+9_adopt",
|
||||||
|
"updated_at": "2021-01-22T14:16:47Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"download_count": 636180,
|
||||||
|
"id": "MDc6UmVsZWFzZTM2NzcwNDUy.hAVJRiZZTufG+w==",
|
||||||
|
"release_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/tag/jdk-11.0.10%2B9",
|
||||||
|
"release_name": "jdk-11.0.10+9",
|
||||||
|
"release_type": "ga",
|
||||||
|
"timestamp": "2021-01-22T14:15:12Z",
|
||||||
|
"updated_at": "2021-01-22T14:15:12Z",
|
||||||
|
"vendor": "adoptopenjdk",
|
||||||
|
"version_data": {
|
||||||
|
"build": 9,
|
||||||
|
"major": 11,
|
||||||
|
"minor": 0,
|
||||||
|
"openjdk_version": "11.0.10+9",
|
||||||
|
"security": 10,
|
||||||
|
"semver": "11.0.10+9"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binaries": [
|
||||||
|
{
|
||||||
|
"architecture": "x64",
|
||||||
|
"download_count": 108441,
|
||||||
|
"heap_size": "normal",
|
||||||
|
"image_type": "jdk",
|
||||||
|
"jvm_impl": "hotspot",
|
||||||
|
"os": "mac",
|
||||||
|
"package": {
|
||||||
|
"checksum": "96bc469f9b02a3b84382a0685b0bd7935e1ad1bd82a0aab9befb5b42a17cbd77",
|
||||||
|
"checksum_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.9.1%2B1/OpenJDK11U-jdk_x64_mac_hotspot_11.0.9.1_1.tar.gz.sha256.txt",
|
||||||
|
"download_count": 22211,
|
||||||
|
"link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.9.1%2B1/OpenJDK11U-jdk_x64_mac_hotspot_11.0.9.1_1.tar.gz",
|
||||||
|
"metadata_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.9.1%2B1/OpenJDK11U-jdk_x64_mac_hotspot_11.0.9.1_1.tar.gz.json",
|
||||||
|
"name": "OpenJDK11U-jdk_x64_mac_hotspot_11.0.9.1_1.tar.gz",
|
||||||
|
"size": 185368626
|
||||||
|
},
|
||||||
|
"project": "jdk",
|
||||||
|
"scm_ref": "jdk-11.0.9.1+1_adopt",
|
||||||
|
"updated_at": "2020-11-12T14:10:45Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"download_count": 815676,
|
||||||
|
"id": "MDc6UmVsZWFzZTMzODU4MDE1.94IbKUd3vvhzsA==",
|
||||||
|
"release_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/tag/jdk-11.0.9.1%2B1",
|
||||||
|
"release_name": "jdk-11.0.9.1+1",
|
||||||
|
"release_type": "ga",
|
||||||
|
"timestamp": "2020-11-12T14:08:55Z",
|
||||||
|
"updated_at": "2020-11-12T14:08:55Z",
|
||||||
|
"vendor": "adoptopenjdk",
|
||||||
|
"version_data": {
|
||||||
|
"build": 1,
|
||||||
|
"major": 11,
|
||||||
|
"minor": 0,
|
||||||
|
"openjdk_version": "11.0.9.1+1",
|
||||||
|
"patch": 1,
|
||||||
|
"security": 9,
|
||||||
|
"semver": "11.0.9+101"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binaries": [
|
||||||
|
{
|
||||||
|
"architecture": "x64",
|
||||||
|
"download_count": 45450,
|
||||||
|
"heap_size": "normal",
|
||||||
|
"image_type": "jdk",
|
||||||
|
"jvm_impl": "hotspot",
|
||||||
|
"os": "mac",
|
||||||
|
"package": {
|
||||||
|
"checksum": "7b21961ffb2649e572721a0dfad64169b490e987937b661cb4e13a594c21e764",
|
||||||
|
"checksum_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.9%2B11.1/OpenJDK11U-jdk_x64_mac_hotspot_11.0.9_11.tar.gz.sha256.txt",
|
||||||
|
"download_count": 11117,
|
||||||
|
"link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.9%2B11.1/OpenJDK11U-jdk_x64_mac_hotspot_11.0.9_11.tar.gz",
|
||||||
|
"metadata_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.9%2B11.1/OpenJDK11U-jdk_x64_mac_hotspot_11.0.9_11.tar.gz.json",
|
||||||
|
"name": "OpenJDK11U-jdk_x64_mac_hotspot_11.0.9_11.tar.gz",
|
||||||
|
"size": 186006796
|
||||||
|
},
|
||||||
|
"project": "jdk",
|
||||||
|
"scm_ref": "jdk-11.0.9+11_adopt",
|
||||||
|
"updated_at": "2020-10-25T14:43:54Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"download_count": 423635,
|
||||||
|
"id": "MDc6UmVsZWFzZTMzMDI4MDcz.dRvNNRwJCgY3Xw==",
|
||||||
|
"release_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/tag/jdk-11.0.9%2B11.1",
|
||||||
|
"release_name": "jdk-11.0.9+11.1",
|
||||||
|
"release_type": "ga",
|
||||||
|
"timestamp": "2020-10-25T13:31:15Z",
|
||||||
|
"updated_at": "2020-10-25T13:31:15Z",
|
||||||
|
"vendor": "adoptopenjdk",
|
||||||
|
"version_data": {
|
||||||
|
"adopt_build_number": 1,
|
||||||
|
"build": 11,
|
||||||
|
"major": 11,
|
||||||
|
"minor": 0,
|
||||||
|
"openjdk_version": "11.0.9+11",
|
||||||
|
"security": 9,
|
||||||
|
"semver": "11.0.9+11.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binaries": [
|
||||||
|
{
|
||||||
|
"architecture": "x64",
|
||||||
|
"download_count": 2456,
|
||||||
|
"heap_size": "normal",
|
||||||
|
"image_type": "jdk",
|
||||||
|
"jvm_impl": "hotspot",
|
||||||
|
"os": "mac",
|
||||||
|
"package": {
|
||||||
|
"checksum": "e84b00d74f08f059829bbf121c8423dc37ff65135968c1fcda5839600be4f542",
|
||||||
|
"checksum_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.9%2B11/OpenJDK11U-jdk_x64_mac_hotspot_11.0.9_11.tar.gz.sha256.txt",
|
||||||
|
"download_count": 1046,
|
||||||
|
"link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.9%2B11/OpenJDK11U-jdk_x64_mac_hotspot_11.0.9_11.tar.gz",
|
||||||
|
"metadata_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.9%2B11/OpenJDK11U-jdk_x64_mac_hotspot_11.0.9_11.tar.gz.json",
|
||||||
|
"name": "OpenJDK11U-jdk_x64_mac_hotspot_11.0.9_11.tar.gz",
|
||||||
|
"size": 185532704
|
||||||
|
},
|
||||||
|
"project": "jdk",
|
||||||
|
"scm_ref": "jdk-11.0.9+11_adopt",
|
||||||
|
"updated_at": "2020-10-25T13:28:33Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"download_count": 359580,
|
||||||
|
"id": "MDc6UmVsZWFzZTMyOTk4MzM5.6h9TT9pzYTK2Kg==",
|
||||||
|
"release_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/tag/jdk-11.0.9%2B11",
|
||||||
|
"release_name": "jdk-11.0.9+11",
|
||||||
|
"release_type": "ga",
|
||||||
|
"timestamp": "2020-10-23T20:52:14Z",
|
||||||
|
"updated_at": "2020-10-23T20:52:14Z",
|
||||||
|
"vendor": "adoptopenjdk",
|
||||||
|
"version_data": {
|
||||||
|
"build": 11,
|
||||||
|
"major": 11,
|
||||||
|
"minor": 0,
|
||||||
|
"openjdk_version": "11.0.9+11",
|
||||||
|
"security": 9,
|
||||||
|
"semver": "11.0.9+11"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binaries": [
|
||||||
|
{
|
||||||
|
"architecture": "x64",
|
||||||
|
"download_count": 149393,
|
||||||
|
"heap_size": "normal",
|
||||||
|
"image_type": "jdk",
|
||||||
|
"jvm_impl": "hotspot",
|
||||||
|
"os": "mac",
|
||||||
|
"package": {
|
||||||
|
"checksum": "4a8dadd58cdc32c7e59978971d56aec610be7ee0ddf0dc1d137bb8b78456499f",
|
||||||
|
"checksum_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.8%2B10/OpenJDK11U-jdk_x64_mac_hotspot_11.0.8_10.tar.gz.sha256.txt",
|
||||||
|
"download_count": 40158,
|
||||||
|
"link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.8%2B10/OpenJDK11U-jdk_x64_mac_hotspot_11.0.8_10.tar.gz",
|
||||||
|
"metadata_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.8%2B10/OpenJDK11U-jdk_x64_mac_hotspot_11.0.8_10.tar.gz.json",
|
||||||
|
"name": "OpenJDK11U-jdk_x64_mac_hotspot_11.0.8_10.tar.gz",
|
||||||
|
"size": 185054456
|
||||||
|
},
|
||||||
|
"project": "jdk",
|
||||||
|
"scm_ref": "jdk-11.0.8+10_adopt",
|
||||||
|
"updated_at": "2020-07-15T14:30:51Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"download_count": 1968658,
|
||||||
|
"id": "MDc6UmVsZWFzZTI4NTg5Nzcz.pCNBA7G9E1o7pw==",
|
||||||
|
"release_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/tag/jdk-11.0.8%2B10",
|
||||||
|
"release_name": "jdk-11.0.8+10",
|
||||||
|
"release_type": "ga",
|
||||||
|
"timestamp": "2020-07-15T14:29:27Z",
|
||||||
|
"updated_at": "2020-07-15T14:29:27Z",
|
||||||
|
"vendor": "adoptopenjdk",
|
||||||
|
"version_data": {
|
||||||
|
"build": 10,
|
||||||
|
"major": 11,
|
||||||
|
"minor": 0,
|
||||||
|
"openjdk_version": "11.0.8+10",
|
||||||
|
"security": 8,
|
||||||
|
"semver": "11.0.8+10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binaries": [],
|
||||||
|
"download_count": 1968658,
|
||||||
|
"id": "MDc6UmVsZWFzZTI4NTg5Nzcz.pCNBA7G9E1o7pw==",
|
||||||
|
"release_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/tag/jdk-11.0.8%2B10",
|
||||||
|
"release_name": "jdk-11.0.8+10",
|
||||||
|
"release_type": "ga",
|
||||||
|
"timestamp": "2020-07-15T14:29:27Z",
|
||||||
|
"updated_at": "2020-07-15T14:29:27Z",
|
||||||
|
"vendor": "adoptopenjdk",
|
||||||
|
"version_data": {
|
||||||
|
"build": 10,
|
||||||
|
"major": 9,
|
||||||
|
"minor": 0,
|
||||||
|
"openjdk_version": "9.0.8+10",
|
||||||
|
"security": 8,
|
||||||
|
"semver": "9.0.8+10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"binaries": [
|
||||||
|
{
|
||||||
|
"architecture": "x64",
|
||||||
|
"download_count": 149393,
|
||||||
|
"heap_size": "normal",
|
||||||
|
"image_type": "jdk",
|
||||||
|
"jvm_impl": "hotspot",
|
||||||
|
"os": "mac",
|
||||||
|
"package": {
|
||||||
|
"checksum": "4a8dadd58cdc32c7e59978971d56aec610be7ee0ddf0dc1d137bb8b78456499f",
|
||||||
|
"checksum_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.8%2B10/OpenJDK11U-jdk_x64_mac_hotspot_11.0.8_10.tar.gz.sha256.txt",
|
||||||
|
"download_count": 40158,
|
||||||
|
"link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.8%2B10/OpenJDK11U-jdk_x64_mac_hotspot_11.0.8_10.tar.gz",
|
||||||
|
"metadata_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.8%2B10/OpenJDK11U-jdk_x64_mac_hotspot_11.0.8_10.tar.gz.json",
|
||||||
|
"name": "OpenJDK11U-jdk_x64_mac_hotspot_11.0.8_10.tar.gz",
|
||||||
|
"size": 185054456
|
||||||
|
},
|
||||||
|
"project": "jdk",
|
||||||
|
"scm_ref": "jdk-11.0.8+10_adopt",
|
||||||
|
"updated_at": "2020-07-15T14:30:51Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"download_count": 1968658,
|
||||||
|
"id": "MDc6UmVsZWFzZTI4NTg5Nzcz.pCNBA7G9E1o7pw==",
|
||||||
|
"release_link": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/tag/jdk-11.0.8%2B10",
|
||||||
|
"release_name": "jdk-11.0.8+10",
|
||||||
|
"release_type": "ga",
|
||||||
|
"timestamp": "2020-07-15T14:29:27Z",
|
||||||
|
"updated_at": "2020-07-15T14:29:27Z",
|
||||||
|
"vendor": "adoptopenjdk",
|
||||||
|
"version_data": {
|
||||||
|
"build": 10,
|
||||||
|
"major": 9,
|
||||||
|
"minor": 0,
|
||||||
|
"openjdk_version": "9.0.8+10",
|
||||||
|
"security": 8,
|
||||||
|
"semver": "9.0.7+10"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,424 @@
|
|||||||
|
import {
|
||||||
|
jest,
|
||||||
|
describe,
|
||||||
|
it,
|
||||||
|
expect,
|
||||||
|
beforeEach,
|
||||||
|
afterEach,
|
||||||
|
beforeAll,
|
||||||
|
afterAll
|
||||||
|
} from '@jest/globals';
|
||||||
|
import {HttpClient} from '@actions/http-client';
|
||||||
|
import os from 'os';
|
||||||
|
|
||||||
|
import manifestData from '../data/adopt.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 core = await import('@actions/core');
|
||||||
|
const {AdoptDistribution, AdoptImplementation} =
|
||||||
|
await import('../../src/distributions/adopt/installer.js');
|
||||||
|
const {TemurinDistribution} =
|
||||||
|
await import('../../src/distributions/temurin/installer.js');
|
||||||
|
|
||||||
|
import type {IAdoptAvailableVersions} from '../../src/distributions/adopt/models.js';
|
||||||
|
import type {AdoptImplementation as AdoptImplementationType} from '../../src/distributions/adopt/installer.js';
|
||||||
|
import type {JavaInstallerOptions} from '../../src/distributions/base-models.js';
|
||||||
|
|
||||||
|
describe('getAvailableVersions', () => {
|
||||||
|
let spyHttpClient: any;
|
||||||
|
let spyCoreError: any;
|
||||||
|
let spyCoreWarning: any;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
|
||||||
|
spyHttpClient.mockReturnValue({
|
||||||
|
statusCode: 200,
|
||||||
|
headers: {},
|
||||||
|
result: []
|
||||||
|
});
|
||||||
|
|
||||||
|
// Mock core.error to suppress error logs
|
||||||
|
spyCoreError = core.error as jest.Mock;
|
||||||
|
spyCoreError.mockImplementation(() => {});
|
||||||
|
spyCoreWarning = core.warning as jest.Mock;
|
||||||
|
spyCoreWarning.mockImplementation(() => {});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.resetAllMocks();
|
||||||
|
jest.clearAllMocks();
|
||||||
|
jest.restoreAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
[
|
||||||
|
{
|
||||||
|
version: '11',
|
||||||
|
architecture: 'x64',
|
||||||
|
packageType: 'jdk',
|
||||||
|
checkLatest: false
|
||||||
|
},
|
||||||
|
AdoptImplementation.Hotspot,
|
||||||
|
'os=mac&architecture=x64&image_type=jdk&release_type=ga&jvm_impl=hotspot&page_size=20&page=0'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
version: '11',
|
||||||
|
architecture: 'x86',
|
||||||
|
packageType: 'jdk',
|
||||||
|
checkLatest: false
|
||||||
|
},
|
||||||
|
AdoptImplementation.Hotspot,
|
||||||
|
'os=mac&architecture=x86&image_type=jdk&release_type=ga&jvm_impl=hotspot&page_size=20&page=0'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
version: '11',
|
||||||
|
architecture: 'x64',
|
||||||
|
packageType: 'jre',
|
||||||
|
checkLatest: false
|
||||||
|
},
|
||||||
|
AdoptImplementation.Hotspot,
|
||||||
|
'os=mac&architecture=x64&image_type=jre&release_type=ga&jvm_impl=hotspot&page_size=20&page=0'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
version: '11-ea',
|
||||||
|
architecture: 'x64',
|
||||||
|
packageType: 'jdk',
|
||||||
|
checkLatest: false
|
||||||
|
},
|
||||||
|
AdoptImplementation.Hotspot,
|
||||||
|
'os=mac&architecture=x64&image_type=jdk&release_type=ea&jvm_impl=hotspot&page_size=20&page=0'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
version: '11',
|
||||||
|
architecture: 'x64',
|
||||||
|
packageType: 'jdk',
|
||||||
|
checkLatest: false
|
||||||
|
},
|
||||||
|
AdoptImplementation.OpenJ9,
|
||||||
|
'os=mac&architecture=x64&image_type=jdk&release_type=ga&jvm_impl=openj9&page_size=20&page=0'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
version: '11',
|
||||||
|
architecture: 'x86',
|
||||||
|
packageType: 'jdk',
|
||||||
|
checkLatest: false
|
||||||
|
},
|
||||||
|
AdoptImplementation.OpenJ9,
|
||||||
|
'os=mac&architecture=x86&image_type=jdk&release_type=ga&jvm_impl=openj9&page_size=20&page=0'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
version: '11',
|
||||||
|
architecture: 'x64',
|
||||||
|
packageType: 'jre',
|
||||||
|
checkLatest: false
|
||||||
|
},
|
||||||
|
AdoptImplementation.OpenJ9,
|
||||||
|
'os=mac&architecture=x64&image_type=jre&release_type=ga&jvm_impl=openj9&page_size=20&page=0'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
version: '11-ea',
|
||||||
|
architecture: 'x64',
|
||||||
|
packageType: 'jdk',
|
||||||
|
checkLatest: false
|
||||||
|
},
|
||||||
|
AdoptImplementation.OpenJ9,
|
||||||
|
'os=mac&architecture=x64&image_type=jdk&release_type=ea&jvm_impl=openj9&page_size=20&page=0'
|
||||||
|
]
|
||||||
|
])(
|
||||||
|
'build correct url for %s',
|
||||||
|
async (
|
||||||
|
installerOptions: JavaInstallerOptions,
|
||||||
|
impl: AdoptImplementationType,
|
||||||
|
expectedParameters
|
||||||
|
) => {
|
||||||
|
const distribution = new AdoptDistribution(installerOptions, impl);
|
||||||
|
const baseUrl =
|
||||||
|
'https://api.adoptopenjdk.net/v3/assets/version/%5B1.0,100.0%5D';
|
||||||
|
const expectedUrl = `${baseUrl}?project=jdk&vendor=adoptopenjdk&heap_size=normal&sort_method=DEFAULT&sort_order=DESC&${expectedParameters}`;
|
||||||
|
distribution['getPlatformOption'] = () => 'mac';
|
||||||
|
|
||||||
|
await distribution['getAvailableVersions']();
|
||||||
|
|
||||||
|
expect(spyHttpClient.mock.calls).toHaveLength(1);
|
||||||
|
expect(spyHttpClient.mock.calls[0][0]).toBe(expectedUrl);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it('load available versions', async () => {
|
||||||
|
const nextPageUrl =
|
||||||
|
'https://api.adoptopenjdk.net/v3/assets/version/%5B1.0,100.0%5D?page=1&page_size=20';
|
||||||
|
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
|
||||||
|
spyHttpClient
|
||||||
|
.mockReturnValueOnce({
|
||||||
|
statusCode: 200,
|
||||||
|
headers: {link: `<${nextPageUrl}>; rel="next"`},
|
||||||
|
result: manifestData as any
|
||||||
|
})
|
||||||
|
.mockReturnValueOnce({
|
||||||
|
statusCode: 200,
|
||||||
|
headers: {},
|
||||||
|
result: manifestData as any
|
||||||
|
});
|
||||||
|
|
||||||
|
const distribution = new AdoptDistribution(
|
||||||
|
{
|
||||||
|
version: '11',
|
||||||
|
architecture: 'x64',
|
||||||
|
packageType: 'jdk',
|
||||||
|
checkLatest: false
|
||||||
|
},
|
||||||
|
AdoptImplementation.Hotspot
|
||||||
|
);
|
||||||
|
const availableVersions = await distribution['getAvailableVersions']();
|
||||||
|
expect(availableVersions).not.toBeNull();
|
||||||
|
expect(availableVersions.length).toBe(manifestData.length * 2);
|
||||||
|
expect(spyHttpClient).toHaveBeenNthCalledWith(2, nextPageUrl);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('stops pagination after 1000 pages as a safeguard', async () => {
|
||||||
|
const nextPageUrl =
|
||||||
|
'https://api.adoptopenjdk.net/v3/assets/version/%5B1.0,100.0%5D?page=2&page_size=20';
|
||||||
|
spyHttpClient.mockReturnValue({
|
||||||
|
statusCode: 200,
|
||||||
|
headers: {link: `<${nextPageUrl}>; rel="next"`},
|
||||||
|
result: [{version_data: {semver: '17.0.1'}, binaries: []}] as any
|
||||||
|
});
|
||||||
|
|
||||||
|
const distribution = new AdoptDistribution(
|
||||||
|
{
|
||||||
|
version: '11',
|
||||||
|
architecture: 'x64',
|
||||||
|
packageType: 'jdk',
|
||||||
|
checkLatest: false
|
||||||
|
},
|
||||||
|
AdoptImplementation.Hotspot
|
||||||
|
);
|
||||||
|
|
||||||
|
await distribution['getAvailableVersions']();
|
||||||
|
|
||||||
|
expect(spyHttpClient).toHaveBeenCalledTimes(1000);
|
||||||
|
expect(spyCoreWarning).toHaveBeenCalledWith(
|
||||||
|
expect.stringContaining('Reached pagination safeguard limit (1000 pages)')
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
[AdoptImplementation.Hotspot, 'jdk', 'Java_Adopt_jdk'],
|
||||||
|
[AdoptImplementation.Hotspot, 'jre', 'Java_Adopt_jre'],
|
||||||
|
[AdoptImplementation.OpenJ9, 'jdk', 'Java_Adopt-OpenJ9_jdk'],
|
||||||
|
[AdoptImplementation.OpenJ9, 'jre', 'Java_Adopt-OpenJ9_jre']
|
||||||
|
])(
|
||||||
|
'find right toolchain folder',
|
||||||
|
(impl: AdoptImplementationType, packageType: string, expected: string) => {
|
||||||
|
const distribution = new AdoptDistribution(
|
||||||
|
{
|
||||||
|
version: '11',
|
||||||
|
architecture: 'x64',
|
||||||
|
packageType: packageType,
|
||||||
|
checkLatest: false
|
||||||
|
},
|
||||||
|
impl
|
||||||
|
);
|
||||||
|
|
||||||
|
// @ts-ignore - because it is protected
|
||||||
|
expect(distribution.toolcacheFolderName).toBe(expected);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
['amd64', 'x64'],
|
||||||
|
['arm64', 'aarch64']
|
||||||
|
])(
|
||||||
|
'defaults to os.arch(): %s mapped to distro arch: %s',
|
||||||
|
async (osArch: string, distroArch: string) => {
|
||||||
|
jest
|
||||||
|
.spyOn(os, 'arch')
|
||||||
|
.mockReturnValue(osArch as ReturnType<typeof os.arch>);
|
||||||
|
|
||||||
|
const installerOptions: JavaInstallerOptions = {
|
||||||
|
version: '17',
|
||||||
|
architecture: '', // to get default value
|
||||||
|
packageType: 'jdk',
|
||||||
|
checkLatest: false
|
||||||
|
};
|
||||||
|
|
||||||
|
const expectedParameters = `os=mac&architecture=${distroArch}&image_type=jdk&release_type=ga&jvm_impl=hotspot&page_size=20&page=0`;
|
||||||
|
|
||||||
|
const distribution = new AdoptDistribution(
|
||||||
|
installerOptions,
|
||||||
|
AdoptImplementation.Hotspot
|
||||||
|
);
|
||||||
|
const baseUrl =
|
||||||
|
'https://api.adoptopenjdk.net/v3/assets/version/%5B1.0,100.0%5D';
|
||||||
|
const expectedUrl = `${baseUrl}?project=jdk&vendor=adoptopenjdk&heap_size=normal&sort_method=DEFAULT&sort_order=DESC&${expectedParameters}`;
|
||||||
|
distribution['getPlatformOption'] = () => 'mac';
|
||||||
|
|
||||||
|
await distribution['getAvailableVersions']();
|
||||||
|
|
||||||
|
expect(spyHttpClient.mock.calls).toHaveLength(1);
|
||||||
|
expect(spyHttpClient.mock.calls[0][0]).toBe(expectedUrl);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('findPackageForDownload', () => {
|
||||||
|
it('returns Temurin result and does not query Adopt API when Temurin succeeds', async () => {
|
||||||
|
const temurinRelease = {
|
||||||
|
version: '11.0.31+11',
|
||||||
|
url: 'https://example.test/temurin-11.tar.gz'
|
||||||
|
};
|
||||||
|
const temurinFindPackageForDownload = jest
|
||||||
|
.fn<any>()
|
||||||
|
.mockResolvedValue(temurinRelease);
|
||||||
|
const temurinDistribution = {
|
||||||
|
findPackageForDownload: temurinFindPackageForDownload
|
||||||
|
} as any;
|
||||||
|
|
||||||
|
const distribution = new AdoptDistribution(
|
||||||
|
{
|
||||||
|
version: '11',
|
||||||
|
architecture: 'x64',
|
||||||
|
packageType: 'jdk',
|
||||||
|
checkLatest: false
|
||||||
|
},
|
||||||
|
AdoptImplementation.Hotspot,
|
||||||
|
temurinDistribution
|
||||||
|
);
|
||||||
|
const adoptLookupSpy = jest.fn<any>();
|
||||||
|
distribution['getAvailableVersions'] = adoptLookupSpy;
|
||||||
|
|
||||||
|
const resolvedVersion = await distribution['findPackageForDownload']('11');
|
||||||
|
|
||||||
|
expect(resolvedVersion).toEqual(temurinRelease);
|
||||||
|
expect(temurinFindPackageForDownload).toHaveBeenCalledWith('11');
|
||||||
|
expect(adoptLookupSpy).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
['9', '9.0.7+10'],
|
||||||
|
['15', '15.0.2+7'],
|
||||||
|
['15.0', '15.0.2+7'],
|
||||||
|
['15.0.2', '15.0.2+7'],
|
||||||
|
['15.0.1', '15.0.1+9.1'],
|
||||||
|
['11.x', '11.0.10+9'],
|
||||||
|
['x', '15.0.2+7'],
|
||||||
|
['12', '12.0.2+10.3'], // make sure that '12.0.2+10.1', '12.0.2+10.3', '12.0.2+10.2' are sorted correctly
|
||||||
|
['12.0.2+10.1', '12.0.2+10.1'],
|
||||||
|
['15.0.1+9', '15.0.1+9'],
|
||||||
|
['15.0.1+9.1', '15.0.1+9.1']
|
||||||
|
])('version is resolved correctly %s -> %s', async (input, expected) => {
|
||||||
|
const distribution = new AdoptDistribution(
|
||||||
|
{
|
||||||
|
version: '11',
|
||||||
|
architecture: 'x64',
|
||||||
|
packageType: 'jdk',
|
||||||
|
checkLatest: false
|
||||||
|
},
|
||||||
|
AdoptImplementation.Hotspot
|
||||||
|
);
|
||||||
|
// Mock Temurin to fail so fallback to AdoptOpenJDK is tested
|
||||||
|
distribution['temurinDistribution']!['findPackageForDownload'] =
|
||||||
|
async () => {
|
||||||
|
throw new Error('No matching version found for SemVer');
|
||||||
|
};
|
||||||
|
distribution['getAvailableVersions'] = async () => manifestData as any;
|
||||||
|
const resolvedVersion = await distribution['findPackageForDownload'](input);
|
||||||
|
expect(resolvedVersion.version).toBe(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('version is found but binaries list is empty', async () => {
|
||||||
|
const distribution = new AdoptDistribution(
|
||||||
|
{
|
||||||
|
version: '11',
|
||||||
|
architecture: 'x64',
|
||||||
|
packageType: 'jdk',
|
||||||
|
checkLatest: false
|
||||||
|
},
|
||||||
|
AdoptImplementation.Hotspot
|
||||||
|
);
|
||||||
|
// Mock Temurin to fail so fallback to AdoptOpenJDK is tested
|
||||||
|
distribution['temurinDistribution']!['findPackageForDownload'] =
|
||||||
|
async () => {
|
||||||
|
throw new Error('No matching version found for SemVer');
|
||||||
|
};
|
||||||
|
distribution['getAvailableVersions'] = async () => manifestData as any;
|
||||||
|
await expect(
|
||||||
|
distribution['findPackageForDownload']('9.0.8')
|
||||||
|
).rejects.toThrow(/No matching version found for SemVer */);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('version is not found', async () => {
|
||||||
|
const distribution = new AdoptDistribution(
|
||||||
|
{
|
||||||
|
version: '11',
|
||||||
|
architecture: 'x64',
|
||||||
|
packageType: 'jdk',
|
||||||
|
checkLatest: false
|
||||||
|
},
|
||||||
|
AdoptImplementation.Hotspot
|
||||||
|
);
|
||||||
|
// Mock Temurin to fail so fallback to AdoptOpenJDK is tested
|
||||||
|
distribution['temurinDistribution']!['findPackageForDownload'] =
|
||||||
|
async () => {
|
||||||
|
throw new Error('No matching version found for SemVer');
|
||||||
|
};
|
||||||
|
distribution['getAvailableVersions'] = async () => manifestData as any;
|
||||||
|
await expect(distribution['findPackageForDownload']('7.x')).rejects.toThrow(
|
||||||
|
/No matching version found for SemVer */
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('version list is empty', async () => {
|
||||||
|
const distribution = new AdoptDistribution(
|
||||||
|
{
|
||||||
|
version: '11',
|
||||||
|
architecture: 'x64',
|
||||||
|
packageType: 'jdk',
|
||||||
|
checkLatest: false
|
||||||
|
},
|
||||||
|
AdoptImplementation.Hotspot
|
||||||
|
);
|
||||||
|
// Mock Temurin to fail so fallback to AdoptOpenJDK is tested
|
||||||
|
distribution['temurinDistribution']!['findPackageForDownload'] =
|
||||||
|
async () => {
|
||||||
|
throw new Error('No matching version found for SemVer');
|
||||||
|
};
|
||||||
|
distribution['getAvailableVersions'] = async () => [];
|
||||||
|
await expect(distribution['findPackageForDownload']('11')).rejects.toThrow(
|
||||||
|
/No matching version found for SemVer */
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -16,9 +16,6 @@ import type {
|
|||||||
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import * as semver from 'semver';
|
import * as semver from 'semver';
|
||||||
import fs from 'fs';
|
|
||||||
import {createHash} from 'crypto';
|
|
||||||
import {HttpClient} from '@actions/http-client';
|
|
||||||
|
|
||||||
import os from 'os';
|
import os from 'os';
|
||||||
|
|
||||||
@@ -70,19 +67,6 @@ jest.unstable_mockModule('@actions/tool-cache', () => ({
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
jest.unstable_mockModule('../../src/jdk-cache.js', () => ({
|
|
||||||
getJdkVerificationIdentity: jest.fn((verified: boolean, key?: string) =>
|
|
||||||
verified ? (key ? 'verified:custom' : 'verified:bundled') : 'unverified'
|
|
||||||
),
|
|
||||||
registerJdk: jest.fn(),
|
|
||||||
restoreJdk: jest.fn()
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.unstable_mockModule('../../src/jdk-resolution-cache.js', () => ({
|
|
||||||
registerJdkResolution: jest.fn(),
|
|
||||||
restoreJdkResolution: jest.fn()
|
|
||||||
}));
|
|
||||||
|
|
||||||
const real_util_module = await import('../../src/util.js');
|
const real_util_module = await import('../../src/util.js');
|
||||||
jest.unstable_mockModule('../../src/util.js', () => ({
|
jest.unstable_mockModule('../../src/util.js', () => ({
|
||||||
...real_util_module,
|
...real_util_module,
|
||||||
@@ -99,8 +83,6 @@ jest.unstable_mockModule('../../src/util.js', () => ({
|
|||||||
const core = await import('@actions/core');
|
const core = await import('@actions/core');
|
||||||
const tc = await import('@actions/tool-cache');
|
const tc = await import('@actions/tool-cache');
|
||||||
const util = await import('../../src/util.js');
|
const util = await import('../../src/util.js');
|
||||||
const jdkCache = await import('../../src/jdk-cache.js');
|
|
||||||
const jdkResolutionCache = await import('../../src/jdk-resolution-cache.js');
|
|
||||||
const {JavaBase} = await import('../../src/distributions/base-installer.js');
|
const {JavaBase} = await import('../../src/distributions/base-installer.js');
|
||||||
|
|
||||||
class EmptyJavaBase extends JavaBase {
|
class EmptyJavaBase extends JavaBase {
|
||||||
@@ -135,17 +117,6 @@ class EmptyJavaBase extends JavaBase {
|
|||||||
url: `some/random_url/java/${availableVersion}`
|
url: `some/random_url/java/${availableVersion}`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public downloadRelease(javaRelease: JavaDownloadRelease): Promise<string> {
|
|
||||||
return this.downloadAndVerify(javaRelease);
|
|
||||||
}
|
|
||||||
|
|
||||||
public fetchChecksumForTest(
|
|
||||||
checksumUrl: string,
|
|
||||||
algorithm: 'sha256' | 'sha512' | ('sha256' | 'sha512')[]
|
|
||||||
) {
|
|
||||||
return this.fetchChecksum(checksumUrl, algorithm);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('findInToolcache', () => {
|
describe('findInToolcache', () => {
|
||||||
@@ -351,10 +322,6 @@ describe('setupJava', () => {
|
|||||||
let spyCoreError: any;
|
let spyCoreError: any;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
(jdkCache.getJdkVerificationIdentity as jest.Mock).mockImplementation(
|
|
||||||
(verified: boolean, key?: string) =>
|
|
||||||
verified ? (key ? 'verified:custom' : 'verified:bundled') : 'unverified'
|
|
||||||
);
|
|
||||||
spyGetToolcachePath = util.getToolcachePath as jest.Mock;
|
spyGetToolcachePath = util.getToolcachePath as jest.Mock;
|
||||||
spyGetToolcachePath.mockImplementation(
|
spyGetToolcachePath.mockImplementation(
|
||||||
(toolname: string, javaVersion: string, architecture: string) => {
|
(toolname: string, javaVersion: string, architecture: string) => {
|
||||||
@@ -476,142 +443,6 @@ describe('setupJava', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should download java when force-download is enabled, even if the version is cached', async () => {
|
|
||||||
mockJavaBase = new EmptyJavaBase({
|
|
||||||
version: actualJavaVersion,
|
|
||||||
architecture: 'x86',
|
|
||||||
packageType: 'jdk',
|
|
||||||
checkLatest: false,
|
|
||||||
forceDownload: true,
|
|
||||||
cacheJdk: true
|
|
||||||
});
|
|
||||||
|
|
||||||
const findInToolcache = jest.fn(() => ({
|
|
||||||
version: actualJavaVersion,
|
|
||||||
path: javaPathInstalled
|
|
||||||
}));
|
|
||||||
mockJavaBase['findInToolcache'] = findInToolcache;
|
|
||||||
|
|
||||||
await expect(mockJavaBase.setupJava()).resolves.toEqual({
|
|
||||||
version: actualJavaVersion,
|
|
||||||
path: javaPathInstalled
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(findInToolcache).not.toHaveBeenCalled();
|
|
||||||
expect(spyCoreInfo).toHaveBeenCalledWith('Trying to download...');
|
|
||||||
expect(spyCoreInfo).toHaveBeenCalledWith(
|
|
||||||
`Java ${actualJavaVersion} was downloaded`
|
|
||||||
);
|
|
||||||
expect(spyCoreInfo).not.toHaveBeenCalledWith(
|
|
||||||
`Resolved Java ${actualJavaVersion} from tool-cache`
|
|
||||||
);
|
|
||||||
expect(jdkCache.restoreJdk).not.toHaveBeenCalled();
|
|
||||||
expect(jdkCache.registerJdk).toHaveBeenCalledWith(
|
|
||||||
expect.objectContaining({
|
|
||||||
version: actualJavaVersion,
|
|
||||||
verification: 'unverified'
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each([
|
|
||||||
[false, false, false, false],
|
|
||||||
[false, true, true, true],
|
|
||||||
[true, false, false, false],
|
|
||||||
[true, true, false, true]
|
|
||||||
])(
|
|
||||||
'handles force-download=%s and cache-jdk=%s',
|
|
||||||
async (forceDownload, cacheJdkEnabled, restores, registers) => {
|
|
||||||
mockJavaBase = new EmptyJavaBase({
|
|
||||||
version: actualJavaVersion,
|
|
||||||
architecture: 'x86',
|
|
||||||
packageType: 'jdk',
|
|
||||||
checkLatest: true,
|
|
||||||
forceDownload,
|
|
||||||
cacheJdk: cacheJdkEnabled
|
|
||||||
});
|
|
||||||
(jdkCache.restoreJdk as jest.Mock).mockResolvedValue(false);
|
|
||||||
|
|
||||||
await mockJavaBase.setupJava();
|
|
||||||
|
|
||||||
expect(jdkCache.restoreJdk).toHaveBeenCalledTimes(restores ? 1 : 0);
|
|
||||||
expect(jdkCache.registerJdk).toHaveBeenCalledTimes(registers ? 1 : 0);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
it('restores the exact resolved JDK before downloading', async () => {
|
|
||||||
const toolCachePath = path.join('toolcache');
|
|
||||||
jest.replaceProperty(process, 'env', {
|
|
||||||
...process.env,
|
|
||||||
RUNNER_TOOL_CACHE: toolCachePath
|
|
||||||
});
|
|
||||||
mockJavaBase = new EmptyJavaBase({
|
|
||||||
version: '11',
|
|
||||||
architecture: 'x86',
|
|
||||||
packageType: 'jdk',
|
|
||||||
checkLatest: true,
|
|
||||||
cacheJdk: true
|
|
||||||
});
|
|
||||||
const downloadTool = jest.spyOn(mockJavaBase as any, 'downloadTool');
|
|
||||||
(jdkCache.restoreJdk as jest.Mock).mockResolvedValue(true);
|
|
||||||
jest
|
|
||||||
.spyOn(mockJavaBase as any, 'getRestoredJdkPath')
|
|
||||||
.mockReturnValue(javaPathInstalled);
|
|
||||||
|
|
||||||
await expect(mockJavaBase.setupJava()).resolves.toEqual({
|
|
||||||
version: actualJavaVersion,
|
|
||||||
path: javaPathInstalled
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(jdkCache.restoreJdk).toHaveBeenCalledWith({
|
|
||||||
distribution: 'Empty',
|
|
||||||
packageType: 'jdk',
|
|
||||||
architecture: 'x86',
|
|
||||||
version: actualJavaVersion,
|
|
||||||
source: `some/random_url/java/${actualJavaVersion}`,
|
|
||||||
verification: 'unverified',
|
|
||||||
path: path.join(toolCachePath, 'Java_Empty_jdk', actualJavaVersion)
|
|
||||||
});
|
|
||||||
expect(downloadTool).not.toHaveBeenCalled();
|
|
||||||
expect(spyCoreInfo).not.toHaveBeenCalledWith('Trying to download...');
|
|
||||||
// A restored entry is already stored under its key; it must not be
|
|
||||||
// re-registered for a post-job save.
|
|
||||||
expect(jdkCache.registerJdk).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('registers the downloaded JDK identity after a JDK cache miss', async () => {
|
|
||||||
const toolCachePath = path.join('toolcache');
|
|
||||||
jest.replaceProperty(process, 'env', {
|
|
||||||
...process.env,
|
|
||||||
RUNNER_TOOL_CACHE: toolCachePath
|
|
||||||
});
|
|
||||||
mockJavaBase = new EmptyJavaBase({
|
|
||||||
version: '11',
|
|
||||||
architecture: 'x86',
|
|
||||||
packageType: 'jdk',
|
|
||||||
checkLatest: true,
|
|
||||||
cacheJdk: true
|
|
||||||
});
|
|
||||||
(jdkCache.restoreJdk as jest.Mock).mockResolvedValue(false);
|
|
||||||
|
|
||||||
await mockJavaBase.setupJava();
|
|
||||||
|
|
||||||
const expectedIdentity = {
|
|
||||||
distribution: 'Empty',
|
|
||||||
packageType: 'jdk',
|
|
||||||
architecture: 'x86',
|
|
||||||
version: actualJavaVersion,
|
|
||||||
source: `some/random_url/java/${actualJavaVersion}`,
|
|
||||||
verification: 'unverified',
|
|
||||||
path: path.join(toolCachePath, 'Java_Empty_jdk', actualJavaVersion)
|
|
||||||
};
|
|
||||||
expect(jdkCache.restoreJdk).toHaveBeenCalledWith(expectedIdentity);
|
|
||||||
// Registration happens after the installation exists, so the post-job save
|
|
||||||
// can detect a later step replacing it.
|
|
||||||
expect(jdkCache.registerJdk).toHaveBeenCalledWith(expectedIdentity);
|
|
||||||
expect(spyCoreInfo).toHaveBeenCalledWith('Trying to download...');
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each([
|
it.each([
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
@@ -745,31 +576,6 @@ describe('setupJava', () => {
|
|||||||
expect(spyCoreSetOutput).not.toHaveBeenCalled();
|
expect(spyCoreSetOutput).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not repeat version resolution when downloadTool fails', async () => {
|
|
||||||
mockJavaBase = new EmptyJavaBase({
|
|
||||||
version: '11',
|
|
||||||
architecture: 'x86',
|
|
||||||
packageType: 'jdk',
|
|
||||||
checkLatest: false,
|
|
||||||
forceDownload: true
|
|
||||||
});
|
|
||||||
const findPackageForDownload = jest.fn(async () => ({
|
|
||||||
version: '11.0.9',
|
|
||||||
url: 'https://example.com/jdk.tar.gz'
|
|
||||||
}));
|
|
||||||
const downloadError = new Error('download failed');
|
|
||||||
const downloadTool = jest.fn(async () => {
|
|
||||||
throw downloadError;
|
|
||||||
});
|
|
||||||
mockJavaBase['findPackageForDownload'] = findPackageForDownload;
|
|
||||||
mockJavaBase['downloadTool'] = downloadTool;
|
|
||||||
|
|
||||||
await expect(mockJavaBase.setupJava()).rejects.toBe(downloadError);
|
|
||||||
|
|
||||||
expect(findPackageForDownload).toHaveBeenCalledTimes(1);
|
|
||||||
expect(downloadTool).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each([
|
it.each([
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
@@ -955,455 +761,6 @@ describe('setupJava', () => {
|
|||||||
'Installing Java 11.0.9 (not setting as default)'
|
'Installing Java 11.0.9 (not setting as default)'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('resolution cache', () => {
|
|
||||||
// 11.0.9 is not in the mocked tool-cache, so the tool-cache short-circuit
|
|
||||||
// misses and the release has to be resolved, exactly as it does for every
|
|
||||||
// distribution that is not preinstalled on hosted runners.
|
|
||||||
const options: JavaInstallerOptions = {
|
|
||||||
version: '11.0.9',
|
|
||||||
architecture: 'x86',
|
|
||||||
packageType: 'jdk',
|
|
||||||
checkLatest: false,
|
|
||||||
cacheJdk: true
|
|
||||||
};
|
|
||||||
const cachedRelease = {
|
|
||||||
version: '11.0.9',
|
|
||||||
url: 'https://example.com/java/11.0.9'
|
|
||||||
};
|
|
||||||
|
|
||||||
const expectedRequest = {
|
|
||||||
distribution: 'Empty',
|
|
||||||
packageType: 'jdk',
|
|
||||||
architecture: 'x86',
|
|
||||||
versionSpec: '11.0.9',
|
|
||||||
stable: true
|
|
||||||
};
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
(jdkCache.restoreJdk as jest.Mock).mockResolvedValue(false);
|
|
||||||
(jdkResolutionCache.restoreJdkResolution as jest.Mock).mockResolvedValue(
|
|
||||||
undefined
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('skips the metadata API on a fresh cached resolution', async () => {
|
|
||||||
mockJavaBase = new EmptyJavaBase(options);
|
|
||||||
const findPackageForDownload = jest.spyOn(
|
|
||||||
mockJavaBase as any,
|
|
||||||
'findPackageForDownload'
|
|
||||||
);
|
|
||||||
(jdkResolutionCache.restoreJdkResolution as jest.Mock).mockResolvedValue({
|
|
||||||
release: cachedRelease,
|
|
||||||
fresh: true
|
|
||||||
});
|
|
||||||
|
|
||||||
await mockJavaBase.setupJava();
|
|
||||||
|
|
||||||
expect(jdkResolutionCache.restoreJdkResolution).toHaveBeenCalledWith(
|
|
||||||
expectedRequest
|
|
||||||
);
|
|
||||||
expect(findPackageForDownload).not.toHaveBeenCalled();
|
|
||||||
expect(jdkResolutionCache.registerJdkResolution).not.toHaveBeenCalled();
|
|
||||||
expect(spyCoreInfo).toHaveBeenCalledWith(
|
|
||||||
'Resolved Empty 11.0.9 from the resolution cache'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('re-resolves and records the release on a miss', async () => {
|
|
||||||
mockJavaBase = new EmptyJavaBase(options);
|
|
||||||
|
|
||||||
await mockJavaBase.setupJava();
|
|
||||||
|
|
||||||
expect(jdkResolutionCache.registerJdkResolution).toHaveBeenCalledWith(
|
|
||||||
expectedRequest,
|
|
||||||
{version: '11.0.9', url: 'some/random_url/java/11.0.9'}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('re-resolves when the cached resolution is stale', async () => {
|
|
||||||
mockJavaBase = new EmptyJavaBase(options);
|
|
||||||
const findPackageForDownload = jest.spyOn(
|
|
||||||
mockJavaBase as any,
|
|
||||||
'findPackageForDownload'
|
|
||||||
);
|
|
||||||
(jdkResolutionCache.restoreJdkResolution as jest.Mock).mockResolvedValue({
|
|
||||||
release: cachedRelease,
|
|
||||||
fresh: false
|
|
||||||
});
|
|
||||||
|
|
||||||
await mockJavaBase.setupJava();
|
|
||||||
|
|
||||||
expect(findPackageForDownload).toHaveBeenCalled();
|
|
||||||
expect(jdkResolutionCache.registerJdkResolution).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('falls back to a stale resolution when the metadata API fails', async () => {
|
|
||||||
mockJavaBase = new EmptyJavaBase(options);
|
|
||||||
const downloadTool = jest
|
|
||||||
.spyOn(mockJavaBase as any, 'downloadTool')
|
|
||||||
.mockResolvedValue({version: '11.0.9', path: javaPathInstalled});
|
|
||||||
jest
|
|
||||||
.spyOn(mockJavaBase as any, 'findPackageForDownload')
|
|
||||||
.mockRejectedValue(new Error('503 Service Unavailable'));
|
|
||||||
(jdkResolutionCache.restoreJdkResolution as jest.Mock).mockResolvedValue({
|
|
||||||
release: cachedRelease,
|
|
||||||
fresh: false
|
|
||||||
});
|
|
||||||
|
|
||||||
await expect(mockJavaBase.setupJava()).resolves.toEqual({
|
|
||||||
version: '11.0.9',
|
|
||||||
path: javaPathInstalled
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(downloadTool).toHaveBeenCalledWith(cachedRelease);
|
|
||||||
expect(jdkResolutionCache.registerJdkResolution).not.toHaveBeenCalled();
|
|
||||||
expect(core.warning).toHaveBeenCalledWith(
|
|
||||||
expect.stringContaining('falling back to the cached resolution')
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fails when the metadata API fails and nothing was cached', async () => {
|
|
||||||
mockJavaBase = new EmptyJavaBase(options);
|
|
||||||
jest
|
|
||||||
.spyOn(mockJavaBase as any, 'findPackageForDownload')
|
|
||||||
.mockRejectedValue(new Error('503 Service Unavailable'));
|
|
||||||
|
|
||||||
await expect(mockJavaBase.setupJava()).rejects.toThrow(
|
|
||||||
'503 Service Unavailable'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not record a floating release', async () => {
|
|
||||||
mockJavaBase = new EmptyJavaBase(options);
|
|
||||||
jest
|
|
||||||
.spyOn(mockJavaBase as any, 'findPackageForDownload')
|
|
||||||
.mockResolvedValue({
|
|
||||||
version: '11.0.9',
|
|
||||||
url: 'https://example.com/java/11/latest/jdk-11.tar.gz',
|
|
||||||
checksum: {algorithm: 'sha256', value: 'abc'},
|
|
||||||
floating: true
|
|
||||||
});
|
|
||||||
|
|
||||||
await mockJavaBase.setupJava();
|
|
||||||
|
|
||||||
expect(jdkResolutionCache.registerJdkResolution).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each([
|
|
||||||
['cache-jdk is disabled', {cacheJdk: false}],
|
|
||||||
['check-latest is enabled', {checkLatest: true}],
|
|
||||||
['force-download is enabled', {forceDownload: true}],
|
|
||||||
['java-version is "latest"', {version: 'latest'}]
|
|
||||||
])('is bypassed when %s', async (_name, overrides) => {
|
|
||||||
mockJavaBase = new EmptyJavaBase({...options, ...overrides});
|
|
||||||
|
|
||||||
await mockJavaBase.setupJava();
|
|
||||||
|
|
||||||
expect(jdkResolutionCache.restoreJdkResolution).not.toHaveBeenCalled();
|
|
||||||
expect(jdkResolutionCache.registerJdkResolution).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('downloadAndVerify', () => {
|
|
||||||
const options: JavaInstallerOptions = {
|
|
||||||
version: '21',
|
|
||||||
architecture: 'x64',
|
|
||||||
packageType: 'jdk',
|
|
||||||
checkLatest: false
|
|
||||||
};
|
|
||||||
let temporaryDirectory: string;
|
|
||||||
let archivePath: string;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
temporaryDirectory = await fs.promises.mkdtemp(
|
|
||||||
path.join(os.tmpdir(), 'setup-java-base-')
|
|
||||||
);
|
|
||||||
archivePath = path.join(temporaryDirectory, 'archive');
|
|
||||||
await fs.promises.writeFile(archivePath, 'downloaded archive');
|
|
||||||
(tc.downloadTool as jest.Mock<any>).mockResolvedValue(archivePath);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
await fs.promises.rm(temporaryDirectory, {recursive: true, force: true});
|
|
||||||
jest.resetAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns a download after successful verification', async () => {
|
|
||||||
const distribution = new EmptyJavaBase(options);
|
|
||||||
const result = await distribution.downloadRelease({
|
|
||||||
version: '21.0.8',
|
|
||||||
url: 'https://vendor.example/jdk.tar.gz',
|
|
||||||
checksum: {
|
|
||||||
algorithm: 'sha256',
|
|
||||||
value: createHash('sha256').update('downloaded archive').digest('hex')
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(result).toBe(archivePath);
|
|
||||||
expect(fs.existsSync(archivePath)).toBe(true);
|
|
||||||
expect(core.debug).toHaveBeenCalledWith(
|
|
||||||
'Verified sha256 checksum for Empty version 21.0.8.'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('removes the download after verification failure', async () => {
|
|
||||||
const distribution = new EmptyJavaBase(options);
|
|
||||||
|
|
||||||
await expect(
|
|
||||||
distribution.downloadRelease({
|
|
||||||
version: '21.0.8',
|
|
||||||
url: 'https://vendor.example/jdk.tar.gz?token=secret',
|
|
||||||
checksum: {algorithm: 'sha256', value: 'a'.repeat(64)}
|
|
||||||
})
|
|
||||||
).rejects.toThrow('Checksum verification failed for Empty version 21.0.8');
|
|
||||||
|
|
||||||
expect(fs.existsSync(archivePath)).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('preserves the verification error when removing the download fails', async () => {
|
|
||||||
const distribution = new EmptyJavaBase(options);
|
|
||||||
const cleanupError = new Error('cleanup failed');
|
|
||||||
jest.spyOn(fs.promises, 'rm').mockRejectedValueOnce(cleanupError);
|
|
||||||
|
|
||||||
const result = distribution.downloadRelease({
|
|
||||||
version: '21.0.8',
|
|
||||||
url: 'https://vendor.example/jdk.tar.gz',
|
|
||||||
checksum: {algorithm: 'sha256', value: 'a'.repeat(64)}
|
|
||||||
});
|
|
||||||
|
|
||||||
await expect(result).rejects.toMatchObject({
|
|
||||||
message: expect.stringContaining(
|
|
||||||
'Failed to remove the downloaded archive after verification failure: cleanup failed'
|
|
||||||
),
|
|
||||||
cause: expect.objectContaining({
|
|
||||||
message: expect.stringContaining(
|
|
||||||
'Checksum verification failed for Empty version 21.0.8'
|
|
||||||
)
|
|
||||||
})
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('logs when authoritative checksum metadata is unavailable', async () => {
|
|
||||||
const distribution = new EmptyJavaBase(options);
|
|
||||||
|
|
||||||
await expect(
|
|
||||||
distribution.downloadRelease({
|
|
||||||
version: '21.0.8',
|
|
||||||
url: 'https://vendor.example/jdk.tar.gz'
|
|
||||||
})
|
|
||||||
).resolves.toBe(archivePath);
|
|
||||||
|
|
||||||
expect(core.debug).toHaveBeenCalledWith(
|
|
||||||
'No authoritative checksum is available for Empty version 21.0.8; skipping checksum verification.'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each([undefined, '', ' '])(
|
|
||||||
'skips verification when the vendor digest is %p',
|
|
||||||
async value => {
|
|
||||||
const distribution = new EmptyJavaBase(options);
|
|
||||||
|
|
||||||
await expect(
|
|
||||||
distribution.downloadRelease({
|
|
||||||
version: '21.0.8',
|
|
||||||
url: 'https://vendor.example/jdk.tar.gz',
|
|
||||||
checksum: {
|
|
||||||
algorithm: 'sha256',
|
|
||||||
value
|
|
||||||
} as JavaDownloadRelease['checksum']
|
|
||||||
})
|
|
||||||
).resolves.toBe(archivePath);
|
|
||||||
|
|
||||||
expect(core.debug).toHaveBeenCalledWith(
|
|
||||||
'No authoritative checksum is available for Empty version 21.0.8; skipping checksum verification.'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('fetchChecksum', () => {
|
|
||||||
const options: JavaInstallerOptions = {
|
|
||||||
version: '21',
|
|
||||||
architecture: 'x64',
|
|
||||||
packageType: 'jdk',
|
|
||||||
checkLatest: false
|
|
||||||
};
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
jest.restoreAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
function mockGet(statusCode: number, body: string) {
|
|
||||||
return jest.spyOn(HttpClient.prototype, 'get').mockResolvedValue({
|
|
||||||
message: {statusCode},
|
|
||||||
readBody: async () => body
|
|
||||||
} as any);
|
|
||||||
}
|
|
||||||
|
|
||||||
it('parses a bare hex digest', async () => {
|
|
||||||
const digest = 'a'.repeat(64);
|
|
||||||
const spy = mockGet(200, digest);
|
|
||||||
const distribution = new EmptyJavaBase(options);
|
|
||||||
|
|
||||||
const checksum = await distribution.fetchChecksumForTest(
|
|
||||||
'https://vendor.example/jdk.tar.gz.sha256',
|
|
||||||
'sha256'
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(spy).toHaveBeenCalledWith(
|
|
||||||
'https://vendor.example/jdk.tar.gz.sha256'
|
|
||||||
);
|
|
||||||
expect(checksum).toEqual({
|
|
||||||
algorithm: 'sha256',
|
|
||||||
value: digest,
|
|
||||||
source: 'https://vendor.example/jdk.tar.gz.sha256'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('parses only the first token of a GNU-style checksum file', async () => {
|
|
||||||
const digest = 'b'.repeat(128);
|
|
||||||
mockGet(200, `${digest} jbrsdk-21.0.3-linux-x64-b465.3.tar.gz\n`);
|
|
||||||
const distribution = new EmptyJavaBase(options);
|
|
||||||
|
|
||||||
const checksum = await distribution.fetchChecksumForTest(
|
|
||||||
'https://vendor.example/jdk.tar.gz.checksum',
|
|
||||||
'sha512'
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(checksum).toEqual({
|
|
||||||
algorithm: 'sha512',
|
|
||||||
value: digest,
|
|
||||||
source: 'https://vendor.example/jdk.tar.gz.checksum'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('trims surrounding whitespace and newlines', async () => {
|
|
||||||
const digest = 'c'.repeat(64);
|
|
||||||
mockGet(200, `\n ${digest} \n`);
|
|
||||||
const distribution = new EmptyJavaBase(options);
|
|
||||||
|
|
||||||
const checksum = await distribution.fetchChecksumForTest(
|
|
||||||
'https://vendor.example/jdk.tar.gz.sha256',
|
|
||||||
'sha256'
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(checksum.value).toBe(digest);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('skips verification when the sibling checksum is not published', async () => {
|
|
||||||
mockGet(404, 'Not Found');
|
|
||||||
const distribution = new EmptyJavaBase(options);
|
|
||||||
|
|
||||||
await expect(
|
|
||||||
distribution.fetchChecksumForTest(
|
|
||||||
'https://vendor.example/jdk.tar.gz.sha256',
|
|
||||||
'sha256'
|
|
||||||
)
|
|
||||||
).resolves.toBeUndefined();
|
|
||||||
expect(core.debug).toHaveBeenCalledWith(
|
|
||||||
'No authoritative sha256 checksum is available for Empty from https://vendor.example/jdk.tar.gz.sha256; skipping checksum verification.'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('surfaces unexpected HTTP failures without query parameters', async () => {
|
|
||||||
mockGet(500, 'Server Error');
|
|
||||||
const distribution = new EmptyJavaBase(options);
|
|
||||||
|
|
||||||
await expect(
|
|
||||||
distribution.fetchChecksumForTest(
|
|
||||||
'https://vendor.example/jdk.tar.gz.sha256?token=secret',
|
|
||||||
'sha256'
|
|
||||||
)
|
|
||||||
).rejects.toThrow(
|
|
||||||
'Failed to fetch the authoritative sha256 checksum for Empty from https://vendor.example/jdk.tar.gz.sha256 (HTTP 500).'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('rejects an empty successful checksum response', async () => {
|
|
||||||
mockGet(200, ' \n');
|
|
||||||
const distribution = new EmptyJavaBase(options);
|
|
||||||
|
|
||||||
await expect(
|
|
||||||
distribution.fetchChecksumForTest(
|
|
||||||
'https://vendor.example/jdk.tar.gz.sha256',
|
|
||||||
'sha256'
|
|
||||||
)
|
|
||||||
).rejects.toThrow(
|
|
||||||
'Received an empty authoritative sha256 checksum for Empty from https://vendor.example/jdk.tar.gz.sha256.'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('with a list of candidate algorithms', () => {
|
|
||||||
it('infers sha512 when the digest is 128 hex characters', async () => {
|
|
||||||
const digest = 'd'.repeat(128);
|
|
||||||
mockGet(200, `${digest} jbrsdk.tar.gz\n`);
|
|
||||||
const distribution = new EmptyJavaBase(options);
|
|
||||||
|
|
||||||
const checksum = await distribution.fetchChecksumForTest(
|
|
||||||
'https://vendor.example/jbrsdk.tar.gz.checksum',
|
|
||||||
['sha512', 'sha256']
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(checksum).toEqual({
|
|
||||||
algorithm: 'sha512',
|
|
||||||
value: digest,
|
|
||||||
source: 'https://vendor.example/jbrsdk.tar.gz.checksum'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('infers sha256 when the digest is 64 hex characters, even though sha512 was preferred', async () => {
|
|
||||||
// Reproduces older JetBrains JBR builds (e.g. JBR 11), which publish a
|
|
||||||
// SHA-256 digest at the generic `.checksum` sibling instead of SHA-512.
|
|
||||||
const digest = 'e'.repeat(64);
|
|
||||||
mockGet(200, `${digest} jbrsdk_nomod-11_0_16-osx-x64-b2043.64.tar.gz\n`);
|
|
||||||
const distribution = new EmptyJavaBase(options);
|
|
||||||
|
|
||||||
const checksum = await distribution.fetchChecksumForTest(
|
|
||||||
'https://vendor.example/jbrsdk_nomod-11_0_16-osx-x64-b2043.64.tar.gz.checksum',
|
|
||||||
['sha512', 'sha256']
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(checksum).toEqual({
|
|
||||||
algorithm: 'sha256',
|
|
||||||
value: digest,
|
|
||||||
source:
|
|
||||||
'https://vendor.example/jbrsdk_nomod-11_0_16-osx-x64-b2043.64.tar.gz.checksum'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('falls back to the first candidate algorithm when the digest length matches none of them', async () => {
|
|
||||||
const digest = 'f'.repeat(40); // e.g. sha1, not supported
|
|
||||||
mockGet(200, `${digest} jbrsdk.tar.gz\n`);
|
|
||||||
const distribution = new EmptyJavaBase(options);
|
|
||||||
|
|
||||||
const checksum = await distribution.fetchChecksumForTest(
|
|
||||||
'https://vendor.example/jbrsdk.tar.gz.checksum',
|
|
||||||
['sha512', 'sha256']
|
|
||||||
);
|
|
||||||
|
|
||||||
// No candidate algorithm matches, so the first-listed one is kept;
|
|
||||||
// downstream verification will reject it as malformed.
|
|
||||||
expect(checksum.algorithm).toBe('sha512');
|
|
||||||
expect(checksum.value).toBe(digest);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('reports the checksum as unavailable using a combined algorithm label on 404', async () => {
|
|
||||||
mockGet(404, 'Not Found');
|
|
||||||
const distribution = new EmptyJavaBase(options);
|
|
||||||
|
|
||||||
await expect(
|
|
||||||
distribution.fetchChecksumForTest(
|
|
||||||
'https://vendor.example/jbrsdk.tar.gz.checksum',
|
|
||||||
['sha512', 'sha256']
|
|
||||||
)
|
|
||||||
).resolves.toBeUndefined();
|
|
||||||
expect(core.debug).toHaveBeenCalledWith(
|
|
||||||
'No authoritative sha512 or sha256 checksum is available for Empty from https://vendor.example/jbrsdk.tar.gz.checksum; skipping checksum verification.'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('normalizeVersion', () => {
|
describe('normalizeVersion', () => {
|
||||||
|
|||||||
@@ -202,12 +202,6 @@ describe('getAvailableVersions', () => {
|
|||||||
await distribution['findPackageForDownload'](version);
|
await distribution['findPackageForDownload'](version);
|
||||||
expect(availableVersion).not.toBeNull();
|
expect(availableVersion).not.toBeNull();
|
||||||
expect(availableVersion.url).toBe(expectedLink);
|
expect(availableVersion.url).toBe(expectedLink);
|
||||||
expect(availableVersion.checksum).toEqual({
|
|
||||||
algorithm: 'sha256',
|
|
||||||
value: expect.stringMatching(/^[a-f0-9]{64}$/),
|
|
||||||
source:
|
|
||||||
'https://corretto.github.io/corretto-downloads/latest_links/indexmap_with_checksum.json'
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('with latest resolves to the newest available major version', async () => {
|
it('with latest resolves to the newest available major version', async () => {
|
||||||
@@ -299,19 +293,6 @@ describe('getAvailableVersions', () => {
|
|||||||
expect(availableVersion.url).toBe(expectedLink);
|
expect(availableVersion.url).toBe(expectedLink);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
it('keeps the canonical ARM runner value separate from the vendor value', () => {
|
|
||||||
jest.spyOn(os, 'arch').mockReturnValue('arm');
|
|
||||||
const distribution = new CorrettoDistribution({
|
|
||||||
version: '11',
|
|
||||||
architecture: '',
|
|
||||||
packageType: 'jdk',
|
|
||||||
checkLatest: false
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(distribution['architecture']).toBe('armv7');
|
|
||||||
expect(distribution['distributionArchitecture']()).toBe('arm');
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const mockPlatform = (
|
const mockPlatform = (
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
import {jest, describe, it, expect} from '@jest/globals';
|
|
||||||
|
|
||||||
jest.unstable_mockModule('../../src/distributions/zulu/installer.js', () => {
|
|
||||||
throw new Error(
|
|
||||||
'Zulu installer module must not be imported on the Temurin fast path'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
const {getJavaDistribution} =
|
|
||||||
await import('../../src/distributions/distribution-factory.js');
|
|
||||||
|
|
||||||
describe('distribution factory lazy loading', () => {
|
|
||||||
it('does not load non-selected distribution installers for Temurin', async () => {
|
|
||||||
const distribution = await getJavaDistribution('temurin', {
|
|
||||||
version: '21',
|
|
||||||
architecture: 'x64',
|
|
||||||
packageType: 'jdk',
|
|
||||||
checkLatest: false
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(distribution).not.toBeNull();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,160 +0,0 @@
|
|||||||
import {getJavaDistribution} from '../../src/distributions/distribution-factory.js';
|
|
||||||
import {RetryingHttpClient} from '../../src/retrying-http-client.js';
|
|
||||||
import {
|
|
||||||
JAVA_PACKAGE_CAPABILITIES,
|
|
||||||
JavaDistribution
|
|
||||||
} from '../../src/distributions/package-types.js';
|
|
||||||
import os from 'os';
|
|
||||||
import {validateJavaPlatform} from '../../src/distributions/platform-types.js';
|
|
||||||
import {normalizeArchitecture} from '../../src/distributions/platform-types.js';
|
|
||||||
|
|
||||||
const supportedDistributionsOnCurrentPlatform = Object.values(
|
|
||||||
JavaDistribution
|
|
||||||
).filter(distributionName => {
|
|
||||||
try {
|
|
||||||
validateJavaPlatform(distributionName, process.platform, 'x64', '25');
|
|
||||||
return distributionName !== JavaDistribution.JdkFile;
|
|
||||||
} catch {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const installerOptions = (packageType: string, version = '25') => ({
|
|
||||||
version,
|
|
||||||
architecture: 'x64',
|
|
||||||
packageType,
|
|
||||||
checkLatest: false
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getJavaDistribution', () => {
|
|
||||||
it.each(supportedDistributionsOnCurrentPlatform)(
|
|
||||||
'uses the shared retrying HTTP client for %s',
|
|
||||||
async distributionName => {
|
|
||||||
const distribution = await getJavaDistribution(distributionName, {
|
|
||||||
version: '25',
|
|
||||||
architecture: 'x64',
|
|
||||||
packageType: 'jdk',
|
|
||||||
checkLatest: false
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(distribution).not.toBeNull();
|
|
||||||
expect(distribution!['http']).toBeInstanceOf(RetryingHttpClient);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
it.each(
|
|
||||||
Object.entries(JAVA_PACKAGE_CAPABILITIES).flatMap(
|
|
||||||
([distributionName, packageTypes]) =>
|
|
||||||
supportedDistributionsOnCurrentPlatform.includes(
|
|
||||||
distributionName as JavaDistribution
|
|
||||||
) || distributionName === JavaDistribution.JdkFile
|
|
||||||
? packageTypes.map(packageType => [distributionName, packageType])
|
|
||||||
: []
|
|
||||||
)
|
|
||||||
)(
|
|
||||||
'accepts %s with java-package %s',
|
|
||||||
async (distributionName, packageType) => {
|
|
||||||
expect(
|
|
||||||
await getJavaDistribution(
|
|
||||||
distributionName,
|
|
||||||
installerOptions(packageType as string)
|
|
||||||
)
|
|
||||||
).not.toBeNull();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
it.each(Object.entries(JAVA_PACKAGE_CAPABILITIES))(
|
|
||||||
'rejects unsupported java-package values for %s',
|
|
||||||
async (distributionName, packageTypes) => {
|
|
||||||
await expect(
|
|
||||||
getJavaDistribution(distributionName, installerOptions('jdk+typo'))
|
|
||||||
).rejects.toThrow(
|
|
||||||
`Java package 'jdk+typo' is not supported for distribution '${distributionName}'. Supported package types: ${packageTypes.join(', ')}.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
it("rejects java-package 'jdk+jmods' for non-Temurin distributions", async () => {
|
|
||||||
await expect(
|
|
||||||
getJavaDistribution('zulu', installerOptions('jdk+jmods'))
|
|
||||||
).rejects.toThrow(
|
|
||||||
"Java package 'jdk+jmods' is not supported for distribution 'zulu'. Supported package types: jdk, jre, jdk+fx, jre+fx, jdk+crac, jre+crac."
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each(['8', '23.x', '23.0.1.1', '<24'])(
|
|
||||||
"rejects Temurin java-package 'jdk+jmods' for version %s",
|
|
||||||
async version => {
|
|
||||||
await expect(
|
|
||||||
getJavaDistribution(
|
|
||||||
JavaDistribution.Temurin,
|
|
||||||
installerOptions('jdk+jmods', version)
|
|
||||||
)
|
|
||||||
).rejects.toThrow(
|
|
||||||
`Java package 'jdk+jmods' is not supported for distribution 'temurin'. Supported package types: jdk, jre, jdk+jmods. Package 'jdk+jmods' requires Java 24 or later; requested version '${version}'.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
it.each(['24', '24.0.1.1', '25-ea', '>=21', 'latest'])(
|
|
||||||
"accepts Temurin java-package 'jdk+jmods' for version %s",
|
|
||||||
async version => {
|
|
||||||
expect(
|
|
||||||
await getJavaDistribution(
|
|
||||||
JavaDistribution.Temurin,
|
|
||||||
installerOptions('jdk+jmods', version)
|
|
||||||
)
|
|
||||||
).not.toBeNull();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
it('preserves unsupported distribution handling', async () => {
|
|
||||||
expect(
|
|
||||||
await getJavaDistribution(
|
|
||||||
'not-a-distribution',
|
|
||||||
installerOptions('not-a-package')
|
|
||||||
)
|
|
||||||
).toBeNull();
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each(['adopt', 'adopt-hotspot', 'adopt-openj9'])(
|
|
||||||
'does not support legacy Adopt distribution %s',
|
|
||||||
async distributionName => {
|
|
||||||
expect(
|
|
||||||
await getJavaDistribution(distributionName, installerOptions('jdk'))
|
|
||||||
).toBeNull();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
it.each([
|
|
||||||
['amd64', 'x64'],
|
|
||||||
['ia32', 'x86'],
|
|
||||||
['arm64', 'aarch64']
|
|
||||||
])('passes normalized architecture %s as %s', async (input, expected) => {
|
|
||||||
const normalized = await getJavaDistribution(JavaDistribution.JdkFile, {
|
|
||||||
...installerOptions('jdk'),
|
|
||||||
architecture: input
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(normalized!['architecture']).toBe(expected);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('uses the runner architecture when the input is empty', async () => {
|
|
||||||
const distribution = await getJavaDistribution(JavaDistribution.Temurin, {
|
|
||||||
...installerOptions('jdk'),
|
|
||||||
architecture: ''
|
|
||||||
});
|
|
||||||
|
|
||||||
const expected = normalizeArchitecture(os.arch());
|
|
||||||
expect(distribution!['architecture']).toBe(expected);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('rejects an unsupported combination before creating an HTTP client', async () => {
|
|
||||||
await expect(
|
|
||||||
getJavaDistribution(JavaDistribution.Oracle, {
|
|
||||||
...installerOptions('jdk'),
|
|
||||||
architecture: 'x86'
|
|
||||||
})
|
|
||||||
).rejects.toThrow(/does not support operating system/);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -259,10 +259,6 @@ describe('getAvailableVersions', () => {
|
|||||||
await distribution['findPackageForDownload'](jdkVersion);
|
await distribution['findPackageForDownload'](jdkVersion);
|
||||||
expect(availableVersion).not.toBeNull();
|
expect(availableVersion).not.toBeNull();
|
||||||
expect(availableVersion.url).toBe(expectedLink);
|
expect(availableVersion.url).toBe(expectedLink);
|
||||||
expect(availableVersion.checksum).toEqual({
|
|
||||||
algorithm: 'sha256',
|
|
||||||
value: expect.stringMatching(/^[a-f0-9]{64}$/)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -129,14 +129,6 @@ describe('GraalVMDistribution', () => {
|
|||||||
(distribution as any).http = mockHttpClient;
|
(distribution as any).http = mockHttpClient;
|
||||||
(communityDistribution as any).http = mockHttpClient;
|
(communityDistribution as any).http = mockHttpClient;
|
||||||
|
|
||||||
// Default checksum sibling response for `${url}.sha256` requests made by
|
|
||||||
// GraalVM (Oracle) and GraalVM EA. Individual tests override this when
|
|
||||||
// they need to assert the exact URL/digest contract.
|
|
||||||
mockHttpClient.get.mockResolvedValue({
|
|
||||||
message: {statusCode: 200},
|
|
||||||
readBody: jest.fn().mockResolvedValue('a'.repeat(64))
|
|
||||||
});
|
|
||||||
|
|
||||||
(util.getDownloadArchiveExtension as jest.Mock<any>).mockReturnValue(
|
(util.getDownloadArchiveExtension as jest.Mock<any>).mockReturnValue(
|
||||||
'tar.gz'
|
'tar.gz'
|
||||||
);
|
);
|
||||||
@@ -174,29 +166,6 @@ describe('GraalVMDistribution', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('setJavaDefault', () => {
|
|
||||||
it('should set GRAALVM_HOME for Oracle GraalVM', () => {
|
|
||||||
(distribution as any).setJavaDefault('17.0.5', '/cached/java/path');
|
|
||||||
|
|
||||||
expect(core.exportVariable).toHaveBeenCalledWith(
|
|
||||||
'GRAALVM_HOME',
|
|
||||||
'/cached/java/path'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should set GRAALVM_HOME for GraalVM Community', () => {
|
|
||||||
(communityDistribution as any).setJavaDefault(
|
|
||||||
'17.0.5',
|
|
||||||
'/cached/java/path'
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(core.exportVariable).toHaveBeenCalledWith(
|
|
||||||
'GRAALVM_HOME',
|
|
||||||
'/cached/java/path'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('downloadTool', () => {
|
describe('downloadTool', () => {
|
||||||
const javaRelease = {
|
const javaRelease = {
|
||||||
version: '17.0.5',
|
version: '17.0.5',
|
||||||
@@ -415,17 +384,9 @@ describe('GraalVMDistribution', () => {
|
|||||||
|
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
url: 'https://download.oracle.com/graalvm/17/archive/graalvm-jdk-17.0.5_linux-x64_bin.tar.gz',
|
url: 'https://download.oracle.com/graalvm/17/archive/graalvm-jdk-17.0.5_linux-x64_bin.tar.gz',
|
||||||
version: '17.0.5',
|
version: '17.0.5'
|
||||||
checksum: {
|
|
||||||
algorithm: 'sha256',
|
|
||||||
value: 'a'.repeat(64),
|
|
||||||
source:
|
|
||||||
'https://download.oracle.com/graalvm/17/archive/graalvm-jdk-17.0.5_linux-x64_bin.tar.gz.sha256'
|
|
||||||
},
|
|
||||||
floating: false
|
|
||||||
});
|
});
|
||||||
expect(mockHttpClient.head).toHaveBeenCalledWith(result.url);
|
expect(mockHttpClient.head).toHaveBeenCalledWith(result.url);
|
||||||
expect(mockHttpClient.get).toHaveBeenCalledWith(`${result.url}.sha256`);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should construct correct URL for major version (latest)', async () => {
|
it('should construct correct URL for major version (latest)', async () => {
|
||||||
@@ -438,16 +399,7 @@ describe('GraalVMDistribution', () => {
|
|||||||
|
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
url: 'https://download.oracle.com/graalvm/21/latest/graalvm-jdk-21_linux-x64_bin.tar.gz',
|
url: 'https://download.oracle.com/graalvm/21/latest/graalvm-jdk-21_linux-x64_bin.tar.gz',
|
||||||
version: '21',
|
version: '21'
|
||||||
checksum: {
|
|
||||||
algorithm: 'sha256',
|
|
||||||
value: 'a'.repeat(64),
|
|
||||||
source:
|
|
||||||
'https://download.oracle.com/graalvm/21/latest/graalvm-jdk-21_linux-x64_bin.tar.gz.sha256'
|
|
||||||
},
|
|
||||||
// A major-only range resolves to the floating `/latest/` URL, so the
|
|
||||||
// release must not be reused by a later job.
|
|
||||||
floating: true
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -490,14 +442,7 @@ describe('GraalVMDistribution', () => {
|
|||||||
|
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
url: 'https://download.oracle.com/graalvm/25/latest/graalvm-jdk-25_linux-x64_bin.tar.gz',
|
url: 'https://download.oracle.com/graalvm/25/latest/graalvm-jdk-25_linux-x64_bin.tar.gz',
|
||||||
version: '25',
|
version: '25'
|
||||||
checksum: {
|
|
||||||
algorithm: 'sha256',
|
|
||||||
value: 'a'.repeat(64),
|
|
||||||
source:
|
|
||||||
'https://download.oracle.com/graalvm/25/latest/graalvm-jdk-25_linux-x64_bin.tar.gz.sha256'
|
|
||||||
},
|
|
||||||
floating: true
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -669,20 +614,13 @@ describe('GraalVMDistribution', () => {
|
|||||||
|
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
url: 'https://example.com/download/graalvm-jdk-23_linux-x64_bin.tar.gz',
|
url: 'https://example.com/download/graalvm-jdk-23_linux-x64_bin.tar.gz',
|
||||||
version: '23-ea-20240716',
|
version: '23-ea-20240716'
|
||||||
checksum: {
|
|
||||||
algorithm: 'sha256',
|
|
||||||
value: 'a'.repeat(64),
|
|
||||||
source:
|
|
||||||
'https://example.com/download/graalvm-jdk-23_linux-x64_bin.tar.gz.sha256'
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(mockHttpClient.getJson).toHaveBeenCalledWith(
|
expect(mockHttpClient.getJson).toHaveBeenCalledWith(
|
||||||
'https://api.github.com/repos/graalvm/oracle-graalvm-ea-builds/contents/versions/23-ea.json?ref=main',
|
'https://api.github.com/repos/graalvm/oracle-graalvm-ea-builds/contents/versions/23-ea.json?ref=main',
|
||||||
{Accept: 'application/json'}
|
{Accept: 'application/json'}
|
||||||
);
|
);
|
||||||
expect(mockHttpClient.get).toHaveBeenCalledWith(`${result.url}.sha256`);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw error when no latest EA version found', async () => {
|
it('should throw error when no latest EA version found', async () => {
|
||||||
@@ -915,15 +853,8 @@ describe('GraalVMDistribution', () => {
|
|||||||
expect(fetchEASpy).toHaveBeenCalledWith('23-ea');
|
expect(fetchEASpy).toHaveBeenCalledWith('23-ea');
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
url: 'https://example.com/download/graalvm-jdk-23_linux-x64_bin.tar.gz',
|
url: 'https://example.com/download/graalvm-jdk-23_linux-x64_bin.tar.gz',
|
||||||
version: '23-ea-20240716',
|
version: '23-ea-20240716'
|
||||||
checksum: {
|
|
||||||
algorithm: 'sha256',
|
|
||||||
value: 'a'.repeat(64),
|
|
||||||
source:
|
|
||||||
'https://example.com/download/graalvm-jdk-23_linux-x64_bin.tar.gz.sha256'
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
expect(mockHttpClient.get).toHaveBeenCalledWith(`${result.url}.sha256`);
|
|
||||||
|
|
||||||
// Verify debug logging
|
// Verify debug logging
|
||||||
expect(core.debug).toHaveBeenCalledWith('Searching for EA build: 23-ea');
|
expect(core.debug).toHaveBeenCalledWith('Searching for EA build: 23-ea');
|
||||||
@@ -1022,13 +953,7 @@ describe('GraalVMDistribution', () => {
|
|||||||
|
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
url: 'https://example.com/download/graalvm-jdk-23_linux-aarch64_bin.tar.gz',
|
url: 'https://example.com/download/graalvm-jdk-23_linux-aarch64_bin.tar.gz',
|
||||||
version: '23-ea-20240716',
|
version: '23-ea-20240716'
|
||||||
checksum: {
|
|
||||||
algorithm: 'sha256',
|
|
||||||
value: 'a'.repeat(64),
|
|
||||||
source:
|
|
||||||
'https://example.com/download/graalvm-jdk-23_linux-aarch64_bin.tar.gz.sha256'
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1203,80 +1128,6 @@ describe('GraalVMDistribution', () => {
|
|||||||
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',
|
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',
|
||||||
version: '21.0.2'
|
version: '21.0.2'
|
||||||
});
|
});
|
||||||
// The asset had no `digest` field, so no checksum should be attached,
|
|
||||||
// and the checksum sibling-URL fetch path (used by Oracle GraalVM)
|
|
||||||
// must not be consulted for GraalVM Community.
|
|
||||||
expect(result.checksum).toBeUndefined();
|
|
||||||
expect(mockHttpClient.get).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('strips the `sha256:` prefix from a GitHub release asset digest', async () => {
|
|
||||||
const digest = 'd'.repeat(64);
|
|
||||||
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',
|
|
||||||
digest: `sha256:${digest}`
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
statusCode: 200,
|
|
||||||
headers: {}
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = await (
|
|
||||||
communityDistribution as any
|
|
||||||
).findPackageForDownload('21.0.2');
|
|
||||||
|
|
||||||
expect(result.checksum).toEqual({
|
|
||||||
algorithm: 'sha256',
|
|
||||||
value: digest,
|
|
||||||
source:
|
|
||||||
'https://api.github.com/repos/graalvm/graalvm-ce-builds/releases?per_page=100'
|
|
||||||
});
|
|
||||||
// The digest came from the release listing itself, so no additional
|
|
||||||
// HTTP request should be made to resolve the checksum.
|
|
||||||
expect(mockHttpClient.get).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('safely skips a missing or malformed release asset digest', async () => {
|
|
||||||
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',
|
|
||||||
digest: 'md5:not-a-sha256-digest'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
statusCode: 200,
|
|
||||||
headers: {}
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = await (
|
|
||||||
communityDistribution as any
|
|
||||||
).findPackageForDownload('21.0.2');
|
|
||||||
|
|
||||||
expect(result.checksum).toBeUndefined();
|
|
||||||
expect(mockHttpClient.get).not.toHaveBeenCalled();
|
|
||||||
expect(core.debug).toHaveBeenCalledWith(
|
|
||||||
expect.stringContaining(
|
|
||||||
'No authoritative sha256 digest is available for graalvm-community-jdk-21.0.2_linux-x64_bin.tar.gz'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should resolve the latest GraalVM Community release for a major version', async () => {
|
it('should resolve the latest GraalVM Community release for a major version', async () => {
|
||||||
@@ -1408,11 +1259,8 @@ describe('distribution factory', () => {
|
|||||||
checkLatest: false
|
checkLatest: false
|
||||||
};
|
};
|
||||||
|
|
||||||
it('should map graalvm-community to the community installer', async () => {
|
it('should map graalvm-community to the community installer', () => {
|
||||||
const community = await getJavaDistribution(
|
const community = getJavaDistribution('graalvm-community', defaultOptions);
|
||||||
'graalvm-community',
|
|
||||||
defaultOptions
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(community).toBeInstanceOf(GraalVMCommunityDistribution);
|
expect(community).toBeInstanceOf(GraalVMCommunityDistribution);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -9,9 +9,7 @@ import {
|
|||||||
afterAll
|
afterAll
|
||||||
} from '@jest/globals';
|
} from '@jest/globals';
|
||||||
import https from 'https';
|
import https from 'https';
|
||||||
import {HttpClient, HttpClientResponse} from '@actions/http-client';
|
import {HttpClient} from '@actions/http-client';
|
||||||
import type {IncomingMessage} from 'http';
|
|
||||||
import {Readable} from 'stream';
|
|
||||||
|
|
||||||
import manifestData from '../data/jetbrains.json' with {type: 'json'};
|
import manifestData from '../data/jetbrains.json' with {type: 'json'};
|
||||||
import os from 'os';
|
import os from 'os';
|
||||||
@@ -46,18 +44,6 @@ jest.unstable_mockModule('@actions/core', () => ({
|
|||||||
const core = await import('@actions/core');
|
const core = await import('@actions/core');
|
||||||
const {JetBrainsDistribution} =
|
const {JetBrainsDistribution} =
|
||||||
await import('../../src/distributions/jetbrains/installer.js');
|
await import('../../src/distributions/jetbrains/installer.js');
|
||||||
const {RetryingHttpClient} = await import('../../src/retrying-http-client.js');
|
|
||||||
|
|
||||||
function response(
|
|
||||||
statusCode: number,
|
|
||||||
body = '',
|
|
||||||
headers: IncomingMessage['headers'] = {}
|
|
||||||
): HttpClientResponse {
|
|
||||||
const message = Readable.from([Buffer.from(body)]) as IncomingMessage;
|
|
||||||
message.statusCode = statusCode;
|
|
||||||
message.headers = headers;
|
|
||||||
return new HttpClientResponse(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('getAvailableVersions', () => {
|
describe('getAvailableVersions', () => {
|
||||||
let spyHttpClient: any;
|
let spyHttpClient: any;
|
||||||
@@ -109,66 +95,9 @@ describe('getAvailableVersions', () => {
|
|||||||
os.platform() === 'win32' ? manifestData.length : manifestData.length + 2;
|
os.platform() === 'win32' ? manifestData.length : manifestData.length + 2;
|
||||||
expect(availableVersions.length).toBe(length);
|
expect(availableVersions.length).toBe(length);
|
||||||
}, 10_000);
|
}, 10_000);
|
||||||
|
|
||||||
it('retries a GitHub rate limit using Retry-After', async () => {
|
|
||||||
spyHttpClient.mockRestore();
|
|
||||||
const sleep = jest.fn(async () => undefined);
|
|
||||||
const requestRaw = jest
|
|
||||||
.spyOn(HttpClient.prototype, 'requestRaw')
|
|
||||||
.mockResolvedValueOnce(response(429, '', {'retry-after': '2'}))
|
|
||||||
.mockResolvedValueOnce(response(200, '[]'))
|
|
||||||
.mockResolvedValueOnce(response(200))
|
|
||||||
.mockResolvedValueOnce(response(200));
|
|
||||||
const distribution = new JetBrainsDistribution({
|
|
||||||
version: '17',
|
|
||||||
architecture: 'x64',
|
|
||||||
packageType: 'jdk',
|
|
||||||
checkLatest: false
|
|
||||||
});
|
|
||||||
distribution['http'] = new RetryingHttpClient('test', {
|
|
||||||
sleep,
|
|
||||||
random: () => 0
|
|
||||||
});
|
|
||||||
|
|
||||||
const availableVersions = await distribution['getAvailableVersions']();
|
|
||||||
|
|
||||||
expect(availableVersions).toHaveLength(2);
|
|
||||||
expect(requestRaw).toHaveBeenCalledTimes(4);
|
|
||||||
expect(requestRaw.mock.calls[0][0].options.path).toBe(
|
|
||||||
requestRaw.mock.calls[1][0].options.path
|
|
||||||
);
|
|
||||||
expect(requestRaw.mock.calls[0][0].options.path).toContain(
|
|
||||||
'/repos/JetBrains/JetBrainsRuntime/releases'
|
|
||||||
);
|
|
||||||
expect(sleep).toHaveBeenCalledWith(2000);
|
|
||||||
expect(core.info).toHaveBeenCalledWith(
|
|
||||||
'Request attempt 1 of 4 failed (HTTP 429); retrying in 2000 ms'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('findPackageForDownload', () => {
|
describe('findPackageForDownload', () => {
|
||||||
let spyHttpClientGet: any;
|
|
||||||
|
|
||||||
const JETBRAINS_CHECKSUM = 'c'.repeat(128);
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
// Every resolved release fetches `${url}.checksum` (sha512, GNU
|
|
||||||
// `<hex> <filename>` format); stub it so tests never reach the real
|
|
||||||
// network, except the dedicated 'version %s can be downloaded' test
|
|
||||||
// below which intentionally exercises real HTTPS HEAD requests.
|
|
||||||
spyHttpClientGet = jest
|
|
||||||
.spyOn(HttpClient.prototype, 'get')
|
|
||||||
.mockResolvedValue({
|
|
||||||
message: {statusCode: 200},
|
|
||||||
readBody: async () => `${JETBRAINS_CHECKSUM} jbrsdk.tar.gz\n`
|
|
||||||
} as any);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
jest.restoreAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each([
|
it.each([
|
||||||
['17', '17.0.11+1207.24'],
|
['17', '17.0.11+1207.24'],
|
||||||
['11.0', '11.0.16+2043.64'],
|
['11.0', '11.0.16+2043.64'],
|
||||||
@@ -252,72 +181,4 @@ describe('findPackageForDownload', () => {
|
|||||||
/No matching version found for SemVer */
|
/No matching version found for SemVer */
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('fetches the authoritative sha512 checksum only for the resolved version', async () => {
|
|
||||||
const distribution = new JetBrainsDistribution({
|
|
||||||
version: '21',
|
|
||||||
architecture: 'x64',
|
|
||||||
packageType: 'jdk',
|
|
||||||
checkLatest: false
|
|
||||||
});
|
|
||||||
distribution['getAvailableVersions'] = async () => manifestData as any;
|
|
||||||
|
|
||||||
const result = await distribution['findPackageForDownload']('21');
|
|
||||||
|
|
||||||
expect(result.checksum).toEqual({
|
|
||||||
algorithm: 'sha512',
|
|
||||||
value: JETBRAINS_CHECKSUM,
|
|
||||||
source: `${result.url}.checksum`
|
|
||||||
});
|
|
||||||
// Only the single resolved/winning version's checksum is requested,
|
|
||||||
// not one per candidate considered during version resolution.
|
|
||||||
expect(spyHttpClientGet).toHaveBeenCalledWith(`${result.url}.checksum`);
|
|
||||||
expect(spyHttpClientGet).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('parses only the first whitespace-delimited token from the GNU checksum payload', async () => {
|
|
||||||
spyHttpClientGet.mockResolvedValue({
|
|
||||||
message: {statusCode: 200},
|
|
||||||
readBody: async () => `${JETBRAINS_CHECKSUM} jbrsdk-21.tar.gz\n`
|
|
||||||
} as any);
|
|
||||||
|
|
||||||
const distribution = new JetBrainsDistribution({
|
|
||||||
version: '21',
|
|
||||||
architecture: 'x64',
|
|
||||||
packageType: 'jdk',
|
|
||||||
checkLatest: false
|
|
||||||
});
|
|
||||||
distribution['getAvailableVersions'] = async () => manifestData as any;
|
|
||||||
|
|
||||||
const result = await distribution['findPackageForDownload']('21');
|
|
||||||
|
|
||||||
expect(result.checksum?.value).toBe(JETBRAINS_CHECKSUM);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('falls back to a sha256 checksum for older JBR builds that only publish one', async () => {
|
|
||||||
// Older JBR 11 builds (e.g. jbrsdk_nomod-11_0_16-*-b2043.64.tar.gz) publish
|
|
||||||
// a SHA-256 digest at the generic `.checksum` sibling instead of SHA-512.
|
|
||||||
const sha256Checksum = 'a'.repeat(64);
|
|
||||||
spyHttpClientGet.mockResolvedValue({
|
|
||||||
message: {statusCode: 200},
|
|
||||||
readBody: async () =>
|
|
||||||
`${sha256Checksum} jbrsdk_nomod-11_0_16-osx-x64-b2043.64.tar.gz\n`
|
|
||||||
} as any);
|
|
||||||
|
|
||||||
const distribution = new JetBrainsDistribution({
|
|
||||||
version: '21',
|
|
||||||
architecture: 'x64',
|
|
||||||
packageType: 'jdk',
|
|
||||||
checkLatest: false
|
|
||||||
});
|
|
||||||
distribution['getAvailableVersions'] = async () => manifestData as any;
|
|
||||||
|
|
||||||
const result = await distribution['findPackageForDownload']('21');
|
|
||||||
|
|
||||||
expect(result.checksum).toEqual({
|
|
||||||
algorithm: 'sha256',
|
|
||||||
value: sha256Checksum,
|
|
||||||
source: `${result.url}.checksum`
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -216,15 +216,6 @@ describe('Check findPackageForDownload', () => {
|
|||||||
await distribution['findPackageForDownload'](version);
|
await distribution['findPackageForDownload'](version);
|
||||||
expect(availableRelease).not.toBeNull();
|
expect(availableRelease).not.toBeNull();
|
||||||
expect(availableRelease.url).toBe(expectedUrl);
|
expect(availableRelease.url).toBe(expectedUrl);
|
||||||
if (availableRelease.checksum) {
|
|
||||||
expect(availableRelease.checksum).toEqual({
|
|
||||||
algorithm: 'sha256',
|
|
||||||
value: expect.stringMatching(/^[a-f0-9]{64}$/),
|
|
||||||
source: 'https://tencent.github.io/konajdk/releases/kona-v1.json'
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
expect(version).toBe('8.0.20');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,9 +12,6 @@ import fs from 'fs';
|
|||||||
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import * as semver from 'semver';
|
import * as semver from 'semver';
|
||||||
import os from 'os';
|
|
||||||
|
|
||||||
const realStatSync = fs.statSync;
|
|
||||||
|
|
||||||
// Mock @actions/core before importing source modules that depend on it
|
// Mock @actions/core before importing source modules that depend on it
|
||||||
jest.unstable_mockModule('@actions/core', () => ({
|
jest.unstable_mockModule('@actions/core', () => ({
|
||||||
@@ -57,12 +54,6 @@ jest.unstable_mockModule('@actions/tool-cache', () => ({
|
|||||||
evaluateVersions: jest.fn()
|
evaluateVersions: jest.fn()
|
||||||
}));
|
}));
|
||||||
|
|
||||||
jest.unstable_mockModule('../../src/jdk-cache.js', () => ({
|
|
||||||
getJdkVerificationIdentity: jest.fn(() => 'unverified'),
|
|
||||||
registerJdk: jest.fn(),
|
|
||||||
restoreJdk: jest.fn()
|
|
||||||
}));
|
|
||||||
|
|
||||||
const real_util_module = await import('../../src/util.js');
|
const real_util_module = await import('../../src/util.js');
|
||||||
jest.unstable_mockModule('../../src/util.js', () => ({
|
jest.unstable_mockModule('../../src/util.js', () => ({
|
||||||
...real_util_module,
|
...real_util_module,
|
||||||
@@ -79,7 +70,6 @@ jest.unstable_mockModule('../../src/util.js', () => ({
|
|||||||
const core = await import('@actions/core');
|
const core = await import('@actions/core');
|
||||||
const tc = await import('@actions/tool-cache');
|
const tc = await import('@actions/tool-cache');
|
||||||
const util = await import('../../src/util.js');
|
const util = await import('../../src/util.js');
|
||||||
const jdkCache = await import('../../src/jdk-cache.js');
|
|
||||||
const {LocalDistribution} =
|
const {LocalDistribution} =
|
||||||
await import('../../src/distributions/local/installer.js');
|
await import('../../src/distributions/local/installer.js');
|
||||||
|
|
||||||
@@ -105,9 +95,6 @@ describe('setupJava', () => {
|
|||||||
const expectedJdkFile = 'JavaLocalJdkFile';
|
const expectedJdkFile = 'JavaLocalJdkFile';
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
(jdkCache.getJdkVerificationIdentity as jest.Mock).mockReturnValue(
|
|
||||||
'unverified'
|
|
||||||
);
|
|
||||||
spyGetToolcachePath = util.getToolcachePath as jest.Mock;
|
spyGetToolcachePath = util.getToolcachePath as jest.Mock;
|
||||||
spyGetToolcachePath.mockImplementation(
|
spyGetToolcachePath.mockImplementation(
|
||||||
(toolname: string, javaVersion: string, architecture: string) => {
|
(toolname: string, javaVersion: string, architecture: string) => {
|
||||||
@@ -221,95 +208,6 @@ describe('setupJava', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('java is unpacked from jdkfile when force-download is enabled', async () => {
|
|
||||||
const inputs = {
|
|
||||||
version: actualJavaVersion,
|
|
||||||
architecture: 'x86',
|
|
||||||
packageType: 'jdk',
|
|
||||||
checkLatest: false,
|
|
||||||
forceDownload: true
|
|
||||||
};
|
|
||||||
|
|
||||||
mockJavaBase = new LocalDistribution(inputs, expectedJdkFile);
|
|
||||||
await expect(mockJavaBase.setupJava()).resolves.toEqual({
|
|
||||||
version: actualJavaVersion,
|
|
||||||
path: javaPath
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(spyGetToolcachePath).not.toHaveBeenCalled();
|
|
||||||
expect(spyUtilsExtractJdkFile).toHaveBeenCalledWith(expectedJdkFile);
|
|
||||||
expect(spyTcCacheDir).toHaveBeenCalled();
|
|
||||||
expect(spyCoreInfo).not.toHaveBeenCalledWith(
|
|
||||||
`Resolved Java ${actualJavaVersion} from tool-cache`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each([
|
|
||||||
[false, true, true],
|
|
||||||
[true, false, true]
|
|
||||||
])(
|
|
||||||
'handles jdkfile caching with force-download=%s',
|
|
||||||
async (forceDownload, restores, registers) => {
|
|
||||||
const temporaryDirectory = fs.mkdtempSync(
|
|
||||||
path.join(os.tmpdir(), 'setup-java-local-cache-')
|
|
||||||
);
|
|
||||||
const jdkFile = path.join(temporaryDirectory, 'java.tar.gz');
|
|
||||||
fs.writeFileSync(jdkFile, 'jdk archive');
|
|
||||||
spyGetToolcachePath.mockReturnValue('');
|
|
||||||
spyFsStat.mockImplementation((file: string) => realStatSync(file));
|
|
||||||
(jdkCache.restoreJdk as jest.Mock).mockResolvedValue(false);
|
|
||||||
|
|
||||||
try {
|
|
||||||
mockJavaBase = new LocalDistribution(
|
|
||||||
{
|
|
||||||
version: actualJavaVersion,
|
|
||||||
architecture: 'x86',
|
|
||||||
packageType: 'jdk',
|
|
||||||
checkLatest: false,
|
|
||||||
forceDownload,
|
|
||||||
cacheJdk: true
|
|
||||||
},
|
|
||||||
jdkFile
|
|
||||||
);
|
|
||||||
|
|
||||||
await mockJavaBase.setupJava();
|
|
||||||
|
|
||||||
expect(jdkCache.restoreJdk).toHaveBeenCalledTimes(restores ? 1 : 0);
|
|
||||||
expect(jdkCache.registerJdk).toHaveBeenCalledTimes(registers ? 1 : 0);
|
|
||||||
expect(
|
|
||||||
(jdkCache.restoreJdk as jest.Mock).mock.calls[0]?.[0] ??
|
|
||||||
(jdkCache.registerJdk as jest.Mock).mock.calls[0]?.[0]
|
|
||||||
).toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
distribution: 'jdkfile',
|
|
||||||
version: actualJavaVersion,
|
|
||||||
verification: 'unverified'
|
|
||||||
})
|
|
||||||
);
|
|
||||||
} finally {
|
|
||||||
fs.rmSync(temporaryDirectory, {recursive: true});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
it('rejects signature verification for jdkfile archives', async () => {
|
|
||||||
mockJavaBase = new LocalDistribution(
|
|
||||||
{
|
|
||||||
version: actualJavaVersion,
|
|
||||||
architecture: 'x86',
|
|
||||||
packageType: 'jdk',
|
|
||||||
checkLatest: false,
|
|
||||||
verifySignature: true
|
|
||||||
},
|
|
||||||
expectedJdkFile
|
|
||||||
);
|
|
||||||
|
|
||||||
await expect(mockJavaBase.setupJava()).rejects.toThrow(
|
|
||||||
"Input 'verify-signature' is not supported for distribution 'jdkfile'."
|
|
||||||
);
|
|
||||||
expect(spyGetToolcachePath).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("java is resolved from toolcache, jdkfile doesn't exist", async () => {
|
it("java is resolved from toolcache, jdkfile doesn't exist", async () => {
|
||||||
const inputs = {
|
const inputs = {
|
||||||
version: actualJavaVersion,
|
version: actualJavaVersion,
|
||||||
|
|||||||
@@ -103,12 +103,9 @@ const util = await import('../../src/util.js');
|
|||||||
describe('findPackageForDownload', () => {
|
describe('findPackageForDownload', () => {
|
||||||
let distribution: InstanceType<typeof MicrosoftDistributions>;
|
let distribution: InstanceType<typeof MicrosoftDistributions>;
|
||||||
let spyGetManifestFromRepo: any;
|
let spyGetManifestFromRepo: any;
|
||||||
let spyHttpClientGet: any;
|
|
||||||
let spyDebug: any;
|
let spyDebug: any;
|
||||||
let spyCoreError: any;
|
let spyCoreError: any;
|
||||||
|
|
||||||
const MICROSOFT_CHECKSUM = 'b'.repeat(64);
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mockOsArch.mockReturnValue('x64');
|
mockOsArch.mockReturnValue('x64');
|
||||||
mockOsPlatform.mockReturnValue(process.platform);
|
mockOsPlatform.mockReturnValue(process.platform);
|
||||||
@@ -127,15 +124,6 @@ describe('findPackageForDownload', () => {
|
|||||||
headers: {}
|
headers: {}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Every resolved release fetches `${download_url}.sha256sum.txt`; stub
|
|
||||||
// it with a GNU-style `<hex> <filename>` payload so tests never reach
|
|
||||||
// the real network.
|
|
||||||
spyHttpClientGet = jest.spyOn(HttpClient.prototype, 'get');
|
|
||||||
spyHttpClientGet.mockResolvedValue({
|
|
||||||
message: {statusCode: 200},
|
|
||||||
readBody: async () => `${MICROSOFT_CHECKSUM} microsoft-jdk.tar.gz\n`
|
|
||||||
});
|
|
||||||
|
|
||||||
spyDebug = core.debug as jest.Mock;
|
spyDebug = core.debug as jest.Mock;
|
||||||
spyDebug.mockImplementation(() => {});
|
spyDebug.mockImplementation(() => {});
|
||||||
|
|
||||||
@@ -323,34 +311,6 @@ describe('findPackageForDownload', () => {
|
|||||||
'https://example.test/jdk.tar.gz.custom.sig'
|
'https://example.test/jdk.tar.gz.custom.sig'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('fetches the authoritative sha256 checksum from the GNU-style sibling file', async () => {
|
|
||||||
mockOsPlatform.mockReturnValue(process.platform);
|
|
||||||
|
|
||||||
const result = await distribution['findPackageForDownload']('17.0.7');
|
|
||||||
|
|
||||||
expect(result.checksum).toEqual({
|
|
||||||
algorithm: 'sha256',
|
|
||||||
value: MICROSOFT_CHECKSUM,
|
|
||||||
source: `${result.url}.sha256sum.txt`
|
|
||||||
});
|
|
||||||
expect(spyHttpClientGet).toHaveBeenCalledWith(
|
|
||||||
`${result.url}.sha256sum.txt`
|
|
||||||
);
|
|
||||||
expect(spyHttpClientGet).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('parses only the first whitespace-delimited token from the GNU checksum payload', async () => {
|
|
||||||
spyHttpClientGet.mockResolvedValue({
|
|
||||||
message: {statusCode: 200},
|
|
||||||
readBody: async () =>
|
|
||||||
`${MICROSOFT_CHECKSUM} microsoft-jdk-17.0.7-linux-x64.tar.gz\n`
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = await distribution['findPackageForDownload']('17.0.7');
|
|
||||||
|
|
||||||
expect(result.checksum?.value).toBe(MICROSOFT_CHECKSUM);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('downloadTool', () => {
|
describe('downloadTool', () => {
|
||||||
|
|||||||
@@ -1,246 +0,0 @@
|
|||||||
import {afterEach, beforeEach, describe, expect, it, jest} from '@jest/globals';
|
|
||||||
import {HttpClient} from '@actions/http-client';
|
|
||||||
|
|
||||||
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((value: string) => value),
|
|
||||||
toWin32Path: jest.fn((value: string) => value),
|
|
||||||
toPosixPath: jest.fn((value: string) => value)
|
|
||||||
}));
|
|
||||||
|
|
||||||
const {OpenJdkDistribution} =
|
|
||||||
await import('../../src/distributions/openjdk/installer.js');
|
|
||||||
const {getJavaDistribution} =
|
|
||||||
await import('../../src/distributions/distribution-factory.js');
|
|
||||||
|
|
||||||
const homePage = `
|
|
||||||
<a href="/26/">JDK 26</a>
|
|
||||||
<a href="/27/">JDK
|
|
||||||
27</a>
|
|
||||||
`;
|
|
||||||
const currentPage = `
|
|
||||||
<a href="https://download.java.net/java/GA/jdk26.0.2/hash/10/GPL/openjdk-26.0.2_linux-x64_bin.tar.gz">tar.gz</a>
|
|
||||||
<a href="https://download.java.net/java/GA/jdk26.0.2/hash/10/GPL/openjdk-26.0.2_linux-aarch64_bin.tar.gz">tar.gz</a>
|
|
||||||
`;
|
|
||||||
const earlyAccessPage = `
|
|
||||||
<a href="https://download.java.net/java/early_access/jdk27/32/GPL/openjdk-27-ea+32_linux-x64_bin.tar.gz">tar.gz</a>
|
|
||||||
`;
|
|
||||||
const archivePage = `
|
|
||||||
<a href="https://download.java.net/java/GA/jdk26.0.1/hash/8/GPL/openjdk-26.0.1_linux-x64_bin.tar.gz">tar.gz</a>
|
|
||||||
<a href="https://download.java.net/java/GA/jdk25/hash/36/GPL/openjdk-25_linux-x64_bin.tar.gz">tar.gz</a>
|
|
||||||
<a href="https://download.java.net/java/GA/jdk18.0.1.1/hash/2/GPL/openjdk-18.0.1.1_linux-x64_bin.tar.gz">tar.gz</a>
|
|
||||||
<th>9.0.4 (build 9.0.4+11)</th>
|
|
||||||
<a href="https://download.java.net/java/GA/jdk9/9.0.4/binaries/openjdk-9.0.4_linux-x64_bin.tar.gz">tar.gz</a>
|
|
||||||
`;
|
|
||||||
const GA_CHECKSUM = 'c'.repeat(64);
|
|
||||||
const EA_CHECKSUM = 'd'.repeat(64);
|
|
||||||
const checksumPages: Record<string, string> = {
|
|
||||||
'https://download.java.net/java/GA/jdk26.0.2/hash/10/GPL/openjdk-26.0.2_linux-x64_bin.tar.gz.sha256':
|
|
||||||
GA_CHECKSUM,
|
|
||||||
'https://download.java.net/java/early_access/jdk27/32/GPL/openjdk-27-ea+32_linux-x64_bin.tar.gz.sha256':
|
|
||||||
EA_CHECKSUM
|
|
||||||
};
|
|
||||||
|
|
||||||
function createDistribution(
|
|
||||||
version = '26',
|
|
||||||
architecture = 'x64',
|
|
||||||
packageType = 'jdk',
|
|
||||||
useFixturePlatform = true
|
|
||||||
) {
|
|
||||||
const distribution = new OpenJdkDistribution({
|
|
||||||
version,
|
|
||||||
architecture,
|
|
||||||
packageType,
|
|
||||||
checkLatest: false
|
|
||||||
});
|
|
||||||
if (useFixturePlatform) {
|
|
||||||
distribution['getPlatform'] = jest.fn(() => 'linux');
|
|
||||||
}
|
|
||||||
return distribution;
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('OpenJdkDistribution', () => {
|
|
||||||
let getSpy: jest.SpiedFunction<HttpClient['get']>;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
getSpy = jest
|
|
||||||
.spyOn(HttpClient.prototype, 'get')
|
|
||||||
.mockImplementation(async url => {
|
|
||||||
const pages: Record<string, string> = {
|
|
||||||
'https://jdk.java.net/': homePage,
|
|
||||||
'https://jdk.java.net/26/': currentPage,
|
|
||||||
'https://jdk.java.net/27/': earlyAccessPage,
|
|
||||||
'https://jdk.java.net/archive/': archivePage
|
|
||||||
};
|
|
||||||
if (url in pages) {
|
|
||||||
return {
|
|
||||||
message: {statusCode: 200},
|
|
||||||
readBody: async () => pages[url]
|
|
||||||
} as Awaited<ReturnType<HttpClient['get']>>;
|
|
||||||
}
|
|
||||||
// Any other GET is a `${archiveUrl}.sha256` checksum sibling request.
|
|
||||||
return {
|
|
||||||
message: {statusCode: 200},
|
|
||||||
readBody: async () => checksumPages[url] ?? 'e'.repeat(64)
|
|
||||||
} as Awaited<ReturnType<HttpClient['get']>>;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
jest.restoreAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('resolves the newest matching GA release', async () => {
|
|
||||||
const result = await createDistribution()['findPackageForDownload']('26');
|
|
||||||
|
|
||||||
expect(result).toEqual({
|
|
||||||
version: '26.0.2+10',
|
|
||||||
url: 'https://download.java.net/java/GA/jdk26.0.2/hash/10/GPL/openjdk-26.0.2_linux-x64_bin.tar.gz',
|
|
||||||
checksum: {
|
|
||||||
algorithm: 'sha256',
|
|
||||||
value: GA_CHECKSUM,
|
|
||||||
source:
|
|
||||||
'https://download.java.net/java/GA/jdk26.0.2/hash/10/GPL/openjdk-26.0.2_linux-x64_bin.tar.gz.sha256'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
expect(getSpy).toHaveBeenCalledWith(`${result.url}.sha256`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('resolves an archived GA release', async () => {
|
|
||||||
const result =
|
|
||||||
await createDistribution('26.0.1')['findPackageForDownload']('26.0.1');
|
|
||||||
|
|
||||||
expect(result.version).toBe('26.0.1+8');
|
|
||||||
expect(result.url).toContain('/openjdk-26.0.1_linux-x64_bin.tar.gz');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('resolves an exact GA build', async () => {
|
|
||||||
const result =
|
|
||||||
await createDistribution('26.0.2+10')['findPackageForDownload'](
|
|
||||||
'26.0.2+10'
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(result.version).toBe('26.0.2+10');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('resolves an exact build from a legacy archive heading', async () => {
|
|
||||||
const result =
|
|
||||||
await createDistribution('9.0.4+11')['findPackageForDownload'](
|
|
||||||
'9.0.4+11'
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(result.version).toBe('9.0.4+11');
|
|
||||||
expect(result.url).toContain('/binaries/openjdk-9.0.4_linux-x64_bin');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('resolves a four-field Java version', async () => {
|
|
||||||
const result =
|
|
||||||
await createDistribution('18.0.1.1')['findPackageForDownload'](
|
|
||||||
'18.0.1+1'
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(result.version).toBe('18.0.1+1');
|
|
||||||
expect(result.url).toContain('/openjdk-18.0.1.1_linux-x64_bin.tar.gz');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('resolves an early-access release without requesting the archive', async () => {
|
|
||||||
const result =
|
|
||||||
await createDistribution('27-ea')['findPackageForDownload']('27');
|
|
||||||
|
|
||||||
expect(result).toEqual({
|
|
||||||
version: '27.0.0+32',
|
|
||||||
url: 'https://download.java.net/java/early_access/jdk27/32/GPL/openjdk-27-ea+32_linux-x64_bin.tar.gz',
|
|
||||||
checksum: {
|
|
||||||
algorithm: 'sha256',
|
|
||||||
value: EA_CHECKSUM,
|
|
||||||
source:
|
|
||||||
'https://download.java.net/java/early_access/jdk27/32/GPL/openjdk-27-ea+32_linux-x64_bin.tar.gz.sha256'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
expect(getSpy).not.toHaveBeenCalledWith('https://jdk.java.net/archive/');
|
|
||||||
expect(getSpy).toHaveBeenCalledWith(`${result.url}.sha256`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('reports available versions when no release matches', async () => {
|
|
||||||
await expect(
|
|
||||||
createDistribution()['findPackageForDownload']('24')
|
|
||||||
).rejects.toThrow(
|
|
||||||
"No matching version found for SemVer '24'.\nDistribution: Oracle OpenJDK"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each([
|
|
||||||
['jre', 'Oracle OpenJDK provides only the `jdk` package type'],
|
|
||||||
['jdk+fx', 'Oracle OpenJDK provides only the `jdk` package type']
|
|
||||||
])('rejects the %s package type', async (packageType, message) => {
|
|
||||||
await expect(
|
|
||||||
createDistribution('26', 'x64', packageType)['findPackageForDownload'](
|
|
||||||
'26'
|
|
||||||
)
|
|
||||||
).rejects.toThrow(message);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('rejects unsupported architectures', async () => {
|
|
||||||
await expect(
|
|
||||||
createDistribution('26', 'x86')['findPackageForDownload']('26')
|
|
||||||
).rejects.toThrow('Unsupported architecture: x86');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('maps supported platforms', () => {
|
|
||||||
const distribution = createDistribution('26', 'x64', 'jdk', false);
|
|
||||||
|
|
||||||
expect(distribution['getPlatform']('linux')).toBe('linux');
|
|
||||||
expect(distribution['getPlatform']('darwin')).toBe('macos');
|
|
||||||
expect(distribution['getPlatform']('win32')).toBe('windows');
|
|
||||||
expect(() => distribution['getPlatform']('freebsd')).toThrow(
|
|
||||||
"Platform 'freebsd' is not supported"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('parses legacy platform names and archive formats', () => {
|
|
||||||
const distribution = createDistribution();
|
|
||||||
const macRelease = distribution['parseReleases'](
|
|
||||||
'<a href="https://download.java.net/java/GA/jdk16/hash/7/GPL/openjdk-16_osx-x64_bin.tar.gz">tar.gz</a>',
|
|
||||||
'macos',
|
|
||||||
'x64'
|
|
||||||
);
|
|
||||||
const windowsRelease = distribution['parseReleases'](
|
|
||||||
'<a href="https://download.java.net/java/GA/jdk10/hash/13/openjdk-10.0.2_windows-x64_bin.tar.gz">tar.gz</a>',
|
|
||||||
'windows',
|
|
||||||
'x64'
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(macRelease[0].version).toBe('16.0.0+7');
|
|
||||||
expect(windowsRelease[0].version).toBe('10.0.2+13');
|
|
||||||
expect(windowsRelease[0].url.endsWith('.tar.gz')).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('is registered in the distribution factory', async () => {
|
|
||||||
const distribution = await getJavaDistribution('oracle-openjdk', {
|
|
||||||
version: '26',
|
|
||||||
architecture: 'x64',
|
|
||||||
packageType: 'jdk',
|
|
||||||
checkLatest: false
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(distribution).toBeInstanceOf(OpenJdkDistribution);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -47,11 +47,8 @@ describe('findPackageForDownload', () => {
|
|||||||
let distribution: InstanceType<typeof OracleDistribution>;
|
let distribution: InstanceType<typeof OracleDistribution>;
|
||||||
let spyDebug: any;
|
let spyDebug: any;
|
||||||
let spyHttpClient: any;
|
let spyHttpClient: any;
|
||||||
let spyHttpClientGet: any;
|
|
||||||
let spyCoreError: any;
|
let spyCoreError: any;
|
||||||
|
|
||||||
const ORACLE_CHECKSUM = 'f'.repeat(64);
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
distribution = new OracleDistribution({
|
distribution = new OracleDistribution({
|
||||||
version: '',
|
version: '',
|
||||||
@@ -66,14 +63,6 @@ describe('findPackageForDownload', () => {
|
|||||||
// Mock core.error to suppress error logs
|
// Mock core.error to suppress error logs
|
||||||
spyCoreError = core.error as jest.Mock;
|
spyCoreError = core.error as jest.Mock;
|
||||||
spyCoreError.mockImplementation(() => {});
|
spyCoreError.mockImplementation(() => {});
|
||||||
|
|
||||||
// Every resolved release fetches its `${url}.sha256` sibling checksum;
|
|
||||||
// stub it so tests never reach the real network.
|
|
||||||
spyHttpClientGet = jest.spyOn(HttpClient.prototype, 'get');
|
|
||||||
spyHttpClientGet.mockResolvedValue({
|
|
||||||
message: {statusCode: 200},
|
|
||||||
readBody: async () => ORACLE_CHECKSUM
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it.each([
|
it.each([
|
||||||
@@ -142,26 +131,6 @@ describe('findPackageForDownload', () => {
|
|||||||
.replace('{{OS_TYPE}}', osType)
|
.replace('{{OS_TYPE}}', osType)
|
||||||
.replace('{{ARCHIVE_TYPE}}', archiveType);
|
.replace('{{ARCHIVE_TYPE}}', archiveType);
|
||||||
expect(result.url).toBe(url);
|
expect(result.url).toBe(url);
|
||||||
// Only the `/latest/` path serves changing contents, so only it must be
|
|
||||||
// excluded from the resolution cache.
|
|
||||||
expect(result.floating).toBe(url.includes('/latest/'));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fetches the authoritative sha256 checksum for the resolved archive', async () => {
|
|
||||||
spyHttpClient = jest.spyOn(HttpClient.prototype, 'head');
|
|
||||||
spyHttpClient.mockResolvedValue({message: {statusCode: 200}});
|
|
||||||
|
|
||||||
const result = await distribution['findPackageForDownload']('21');
|
|
||||||
|
|
||||||
jest.restoreAllMocks();
|
|
||||||
|
|
||||||
expect(result.checksum).toEqual({
|
|
||||||
algorithm: 'sha256',
|
|
||||||
value: ORACLE_CHECKSUM,
|
|
||||||
source: `${result.url}.sha256`
|
|
||||||
});
|
|
||||||
expect(spyHttpClientGet).toHaveBeenCalledWith(`${result.url}.sha256`);
|
|
||||||
expect(spyHttpClientGet).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it.each([
|
it.each([
|
||||||
@@ -227,10 +196,6 @@ describe('findPackageForDownload with latest', () => {
|
|||||||
it('resolves the newest major version from the Adoptium API', async () => {
|
it('resolves the newest major version from the Adoptium API', async () => {
|
||||||
spyHttpClientHead = jest.spyOn(HttpClient.prototype, 'head');
|
spyHttpClientHead = jest.spyOn(HttpClient.prototype, 'head');
|
||||||
spyHttpClientHead.mockResolvedValue({message: {statusCode: 200}});
|
spyHttpClientHead.mockResolvedValue({message: {statusCode: 200}});
|
||||||
jest.spyOn(HttpClient.prototype, 'get').mockResolvedValue({
|
|
||||||
message: {statusCode: 200},
|
|
||||||
readBody: async () => 'f'.repeat(64)
|
|
||||||
} as any);
|
|
||||||
|
|
||||||
const distribution = new OracleDistribution({
|
const distribution = new OracleDistribution({
|
||||||
version: 'latest',
|
version: 'latest',
|
||||||
|
|||||||
@@ -52,10 +52,8 @@ const utils = await import('../../src/util.js');
|
|||||||
|
|
||||||
describe('getAvailableVersions', () => {
|
describe('getAvailableVersions', () => {
|
||||||
let spyHttpClient: any;
|
let spyHttpClient: any;
|
||||||
let spyHttpGet: any;
|
|
||||||
let spyUtilGetDownloadArchiveExtension: any;
|
let spyUtilGetDownloadArchiveExtension: any;
|
||||||
let spyCoreError: any;
|
let spyCoreError: any;
|
||||||
const archiveChecksum = 'f'.repeat(64);
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
|
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
|
||||||
@@ -64,11 +62,6 @@ describe('getAvailableVersions', () => {
|
|||||||
headers: {},
|
headers: {},
|
||||||
result: manifestData
|
result: manifestData
|
||||||
});
|
});
|
||||||
spyHttpGet = jest.spyOn(HttpClient.prototype, 'get');
|
|
||||||
spyHttpGet.mockResolvedValue({
|
|
||||||
message: {statusCode: 200},
|
|
||||||
readBody: async () => `${archiveChecksum} archive`
|
|
||||||
});
|
|
||||||
|
|
||||||
spyUtilGetDownloadArchiveExtension =
|
spyUtilGetDownloadArchiveExtension =
|
||||||
utils.getDownloadArchiveExtension as jest.Mock<any>;
|
utils.getDownloadArchiveExtension as jest.Mock<any>;
|
||||||
@@ -289,31 +282,9 @@ describe('getAvailableVersions', () => {
|
|||||||
await distribution['findPackageForDownload'](normalizedVersion);
|
await distribution['findPackageForDownload'](normalizedVersion);
|
||||||
expect(availableVersion).not.toBeNull();
|
expect(availableVersion).not.toBeNull();
|
||||||
expect(availableVersion.url).toBe(expectedLink);
|
expect(availableVersion.url).toBe(expectedLink);
|
||||||
expect(availableVersion.checksum).toEqual({
|
|
||||||
algorithm: 'sha256',
|
|
||||||
value: archiveChecksum,
|
|
||||||
source: expectedLink.replace(/\.(?:tar\.gz|zip)$/, '.sha256.txt')
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
it('uses the checksum published beside the selected EA archive', async () => {
|
|
||||||
const distribution = new SapMachineDistribution({
|
|
||||||
version: '21-ea',
|
|
||||||
architecture: 'x64',
|
|
||||||
packageType: 'jdk',
|
|
||||||
checkLatest: false
|
|
||||||
});
|
|
||||||
mockPlatform(distribution, 'linux');
|
|
||||||
|
|
||||||
const release = await distribution['findPackageForDownload']('21');
|
|
||||||
|
|
||||||
expect(spyHttpGet).toHaveBeenCalledWith(
|
|
||||||
release.url.replace(/\.(?:tar\.gz|zip)$/, '.sha256.txt')
|
|
||||||
);
|
|
||||||
expect(release.checksum?.value).toBe(archiveChecksum);
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each([
|
it.each([
|
||||||
['8', 'linux', 'x64'],
|
['8', 'linux', 'x64'],
|
||||||
['8', 'macos', 'aarch64'],
|
['8', 'macos', 'aarch64'],
|
||||||
|
|||||||
@@ -208,14 +208,6 @@ describe('findPackageForDownload', () => {
|
|||||||
distribution['getAvailableVersions'] = async () => manifestData as any;
|
distribution['getAvailableVersions'] = async () => manifestData as any;
|
||||||
const resolvedVersion = await distribution['findPackageForDownload'](input);
|
const resolvedVersion = await distribution['findPackageForDownload'](input);
|
||||||
expect(resolvedVersion.version).toBe(expected);
|
expect(resolvedVersion.version).toBe(expected);
|
||||||
const vendorPackage = (manifestData as any[]).find(
|
|
||||||
item => item.version_data.semver === expected
|
|
||||||
).binaries[0].package;
|
|
||||||
expect(resolvedVersion.checksum).toEqual({
|
|
||||||
algorithm: 'sha256',
|
|
||||||
value: vendorPackage.checksum,
|
|
||||||
source: vendorPackage.checksum_link
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('version is found but binaries list is empty', async () => {
|
it('version is found but binaries list is empty', async () => {
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import type {TemurinImplementation as TemurinImplementationType} from '../../src
|
|||||||
import {HttpClient} from '@actions/http-client';
|
import {HttpClient} from '@actions/http-client';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import os from 'os';
|
import os from 'os';
|
||||||
import path from 'path';
|
|
||||||
|
|
||||||
import manifestData from '../data/temurin.json' with {type: 'json'};
|
import manifestData from '../data/temurin.json' with {type: 'json'};
|
||||||
|
|
||||||
@@ -120,16 +119,6 @@ describe('getAvailableVersions', () => {
|
|||||||
TemurinImplementation.Hotspot,
|
TemurinImplementation.Hotspot,
|
||||||
'os=mac&architecture=x64&image_type=jdk&release_type=ga&jvm_impl=hotspot&page_size=20&page=0'
|
'os=mac&architecture=x64&image_type=jdk&release_type=ga&jvm_impl=hotspot&page_size=20&page=0'
|
||||||
],
|
],
|
||||||
[
|
|
||||||
{
|
|
||||||
version: '25',
|
|
||||||
architecture: 'x64',
|
|
||||||
packageType: 'jdk+jmods',
|
|
||||||
checkLatest: false
|
|
||||||
},
|
|
||||||
TemurinImplementation.Hotspot,
|
|
||||||
'os=mac&architecture=x64&image_type=jdk&release_type=ga&jvm_impl=hotspot&page_size=20&page=0'
|
|
||||||
],
|
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
version: '16',
|
version: '16',
|
||||||
@@ -180,27 +169,6 @@ describe('getAvailableVersions', () => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
it('requests the JMOD image type', async () => {
|
|
||||||
const distribution = new TemurinDistribution(
|
|
||||||
{
|
|
||||||
version: '25',
|
|
||||||
architecture: 'x64',
|
|
||||||
packageType: 'jdk+jmods',
|
|
||||||
checkLatest: false
|
|
||||||
},
|
|
||||||
TemurinImplementation.Hotspot
|
|
||||||
);
|
|
||||||
distribution['getPlatformOption'] = () => 'linux';
|
|
||||||
|
|
||||||
await distribution['getAvailableVersions']('jmods');
|
|
||||||
|
|
||||||
expect(spyHttpClient).toHaveBeenCalledWith(
|
|
||||||
expect.stringContaining(
|
|
||||||
'os=linux&architecture=x64&image_type=jmods&release_type=ga'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('load available versions', async () => {
|
it('load available versions', async () => {
|
||||||
const nextPageUrl =
|
const nextPageUrl =
|
||||||
'https://api.adoptium.net/v3/assets/version/%5B1.0,100.0%5D?page=1&page_size=20';
|
'https://api.adoptium.net/v3/assets/version/%5B1.0,100.0%5D?page=1&page_size=20';
|
||||||
@@ -261,12 +229,7 @@ describe('getAvailableVersions', () => {
|
|||||||
|
|
||||||
it.each([
|
it.each([
|
||||||
[TemurinImplementation.Hotspot, 'jdk', 'Java_Temurin-Hotspot_jdk'],
|
[TemurinImplementation.Hotspot, 'jdk', 'Java_Temurin-Hotspot_jdk'],
|
||||||
[TemurinImplementation.Hotspot, 'jre', 'Java_Temurin-Hotspot_jre'],
|
[TemurinImplementation.Hotspot, 'jre', 'Java_Temurin-Hotspot_jre']
|
||||||
[
|
|
||||||
TemurinImplementation.Hotspot,
|
|
||||||
'jdk+jmods',
|
|
||||||
'Java_Temurin-Hotspot_jdk+jmods'
|
|
||||||
]
|
|
||||||
])(
|
])(
|
||||||
'find right toolchain folder',
|
'find right toolchain folder',
|
||||||
(
|
(
|
||||||
@@ -291,7 +254,6 @@ describe('getAvailableVersions', () => {
|
|||||||
|
|
||||||
it.each([
|
it.each([
|
||||||
['amd64', 'x64'],
|
['amd64', 'x64'],
|
||||||
['arm', 'arm'],
|
|
||||||
['arm64', 'aarch64']
|
['arm64', 'aarch64']
|
||||||
])(
|
])(
|
||||||
'defaults to os.arch(): %s mapped to distro arch: %s',
|
'defaults to os.arch(): %s mapped to distro arch: %s',
|
||||||
@@ -348,14 +310,6 @@ describe('findPackageForDownload', () => {
|
|||||||
const resolvedVersion = await distribution['findPackageForDownload'](input);
|
const resolvedVersion = await distribution['findPackageForDownload'](input);
|
||||||
expect(resolvedVersion.version).toBe(expected);
|
expect(resolvedVersion.version).toBe(expected);
|
||||||
expect(resolvedVersion.signatureUrl).toBeDefined();
|
expect(resolvedVersion.signatureUrl).toBeDefined();
|
||||||
const vendorPackage = (manifestData as any[]).find(
|
|
||||||
item => item.version_data.semver === expected
|
|
||||||
).binaries[0].package;
|
|
||||||
expect(resolvedVersion.checksum).toEqual({
|
|
||||||
algorithm: 'sha256',
|
|
||||||
value: vendorPackage.checksum,
|
|
||||||
source: vendorPackage.checksum_link
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('version "latest" is normalized to the newest available version', async () => {
|
it('version "latest" is normalized to the newest available version', async () => {
|
||||||
@@ -432,7 +386,6 @@ describe('downloadTool', () => {
|
|||||||
let spyCacheDir: any;
|
let spyCacheDir: any;
|
||||||
let spyReadDirSync: any;
|
let spyReadDirSync: any;
|
||||||
let spyRenameWinArchive: any;
|
let spyRenameWinArchive: any;
|
||||||
let spyCopySync: any;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
spyDownloadTool = tc.downloadTool as jest.Mock;
|
spyDownloadTool = tc.downloadTool as jest.Mock;
|
||||||
@@ -447,8 +400,6 @@ describe('downloadTool', () => {
|
|||||||
spyReadDirSync.mockReturnValue(['jdk-17'] as any);
|
spyReadDirSync.mockReturnValue(['jdk-17'] as any);
|
||||||
spyRenameWinArchive = util.renameWinArchive as jest.Mock;
|
spyRenameWinArchive = util.renameWinArchive as jest.Mock;
|
||||||
spyRenameWinArchive.mockReturnValue('/tmp/jdk.tar.gz.zip');
|
spyRenameWinArchive.mockReturnValue('/tmp/jdk.tar.gz.zip');
|
||||||
spyCopySync = jest.spyOn(fs, 'cpSync');
|
|
||||||
spyCopySync.mockImplementation(() => undefined);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
@@ -482,60 +433,6 @@ describe('downloadTool', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('downloads and adds matching JMODs to the JDK', async () => {
|
|
||||||
spyDownloadTool
|
|
||||||
.mockResolvedValueOnce('/tmp/jdk.tar.gz')
|
|
||||||
.mockResolvedValueOnce('/tmp/jmods.tar.gz');
|
|
||||||
spyExtractJdkFile
|
|
||||||
.mockResolvedValueOnce('/tmp/extracted')
|
|
||||||
.mockResolvedValueOnce('/tmp/extracted-jmods');
|
|
||||||
spyReadDirSync
|
|
||||||
.mockReturnValueOnce(['jdk-25'] as any)
|
|
||||||
.mockReturnValueOnce(['jdk-25-jmods'] as any);
|
|
||||||
jest.spyOn(fs, 'existsSync').mockReturnValue(false);
|
|
||||||
|
|
||||||
const distribution = new TemurinDistribution(
|
|
||||||
{
|
|
||||||
version: '25',
|
|
||||||
architecture: 'x64',
|
|
||||||
packageType: 'jdk+jmods',
|
|
||||||
checkLatest: false
|
|
||||||
},
|
|
||||||
TemurinImplementation.Hotspot
|
|
||||||
);
|
|
||||||
distribution['resolvePackage'] = jest.fn().mockResolvedValue({
|
|
||||||
version: '25.0.3+9',
|
|
||||||
url: 'https://example.com/jmods.tar.gz'
|
|
||||||
});
|
|
||||||
|
|
||||||
await distribution['downloadTool']({
|
|
||||||
version: '25.0.3+9',
|
|
||||||
url: 'https://example.com/jdk.tar.gz'
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(distribution['resolvePackage']).toHaveBeenCalledWith(
|
|
||||||
'25.0.3+9',
|
|
||||||
'jmods'
|
|
||||||
);
|
|
||||||
expect(spyDownloadTool).toHaveBeenNthCalledWith(
|
|
||||||
2,
|
|
||||||
'https://example.com/jmods.tar.gz'
|
|
||||||
);
|
|
||||||
expect(spyCopySync).toHaveBeenCalledWith(
|
|
||||||
path.join('/tmp/extracted-jmods', 'jdk-25-jmods'),
|
|
||||||
process.platform === 'darwin'
|
|
||||||
? path.join('/tmp/extracted', 'jdk-25', 'Contents', 'Home', 'jmods')
|
|
||||||
: path.join('/tmp/extracted', 'jdk-25', 'jmods'),
|
|
||||||
{recursive: true}
|
|
||||||
);
|
|
||||||
expect(spyCacheDir).toHaveBeenCalledWith(
|
|
||||||
path.join('/tmp/extracted', 'jdk-25'),
|
|
||||||
'Java_Temurin-Hotspot_jdk+jmods',
|
|
||||||
'25.0.3-9',
|
|
||||||
'x64'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fails when signature is missing and verification is enabled', async () => {
|
it('fails when signature is missing and verification is enabled', async () => {
|
||||||
const distribution = new TemurinDistribution(
|
const distribution = new TemurinDistribution(
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -241,26 +241,6 @@ describe('getArchitectureOptions', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('findPackageForDownload', () => {
|
describe('findPackageForDownload', () => {
|
||||||
let spyPackageDetails: any;
|
|
||||||
|
|
||||||
const ZULU_CHECKSUM = 'a'.repeat(64);
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
// The resolved winning package fetches sha256_hash from the Azul
|
|
||||||
// package-details endpoint; stub it so tests never reach the real
|
|
||||||
// network.
|
|
||||||
spyPackageDetails = jest.spyOn(HttpClient.prototype, 'getJson');
|
|
||||||
spyPackageDetails.mockResolvedValue({
|
|
||||||
statusCode: 200,
|
|
||||||
headers: {},
|
|
||||||
result: {sha256_hash: ZULU_CHECKSUM}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
jest.restoreAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each([
|
it.each([
|
||||||
['8', '8.0.282+8'],
|
['8', '8.0.282+8'],
|
||||||
['11.x', '11.0.10+9'],
|
['11.x', '11.0.10+9'],
|
||||||
@@ -299,38 +279,6 @@ describe('findPackageForDownload', () => {
|
|||||||
expect(result.url).toBe(
|
expect(result.url).toBe(
|
||||||
'https://cdn.azul.com/zulu/bin/zulu11.35.15-ca-jdk11.0.5-macosx_x64.tar.gz'
|
'https://cdn.azul.com/zulu/bin/zulu11.35.15-ca-jdk11.0.5-macosx_x64.tar.gz'
|
||||||
);
|
);
|
||||||
expect(result.checksum).toEqual({
|
|
||||||
algorithm: 'sha256',
|
|
||||||
value: ZULU_CHECKSUM,
|
|
||||||
source: 'https://api.azul.com/metadata/v1/zulu/packages/test-uuid-10933'
|
|
||||||
});
|
|
||||||
// Only the winning package's UUID triggers a details request.
|
|
||||||
expect(spyPackageDetails).toHaveBeenCalledWith(
|
|
||||||
'https://api.azul.com/metadata/v1/zulu/packages/test-uuid-10933'
|
|
||||||
);
|
|
||||||
expect(spyPackageDetails).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('skips checksum verification when sha256_hash is missing or malformed', async () => {
|
|
||||||
spyPackageDetails.mockResolvedValue({
|
|
||||||
statusCode: 200,
|
|
||||||
headers: {},
|
|
||||||
result: {sha256_hash: 'not-a-valid-digest'}
|
|
||||||
});
|
|
||||||
|
|
||||||
const distribution = new ZuluDistribution({
|
|
||||||
version: '',
|
|
||||||
architecture: 'x86',
|
|
||||||
packageType: 'jdk',
|
|
||||||
checkLatest: false
|
|
||||||
});
|
|
||||||
distribution['getAvailableVersions'] = async () => manifestData;
|
|
||||||
const result = await distribution['findPackageForDownload']('11.0.5');
|
|
||||||
|
|
||||||
expect(result.checksum).toBeUndefined();
|
|
||||||
expect(core.debug).toHaveBeenCalledWith(
|
|
||||||
expect.stringContaining('No authoritative sha256 checksum')
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw an error', async () => {
|
it('should throw an error', async () => {
|
||||||
|
|||||||
@@ -245,26 +245,6 @@ describe('getArchitectureOptions', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('findPackageForDownload', () => {
|
describe('findPackageForDownload', () => {
|
||||||
let spyPackageDetails: any;
|
|
||||||
|
|
||||||
const ZULU_CHECKSUM = 'a'.repeat(64);
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
// The resolved winning package fetches sha256_hash from the Azul
|
|
||||||
// package-details endpoint; stub it so tests never reach the real
|
|
||||||
// network.
|
|
||||||
spyPackageDetails = jest.spyOn(HttpClient.prototype, 'getJson');
|
|
||||||
spyPackageDetails.mockResolvedValue({
|
|
||||||
statusCode: 200,
|
|
||||||
headers: {},
|
|
||||||
result: {sha256_hash: ZULU_CHECKSUM}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
jest.restoreAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each([
|
it.each([
|
||||||
['8', '8.0.282+8'],
|
['8', '8.0.282+8'],
|
||||||
['11.x', '11.0.10+9'],
|
['11.x', '11.0.10+9'],
|
||||||
@@ -303,38 +283,6 @@ describe('findPackageForDownload', () => {
|
|||||||
expect(result.url).toBe(
|
expect(result.url).toBe(
|
||||||
'https://cdn.azul.com/zulu/bin/zulu21.32.17-ca-jdk21.0.2-linux_aarch64.tar.gz'
|
'https://cdn.azul.com/zulu/bin/zulu21.32.17-ca-jdk21.0.2-linux_aarch64.tar.gz'
|
||||||
);
|
);
|
||||||
expect(result.checksum).toEqual({
|
|
||||||
algorithm: 'sha256',
|
|
||||||
value: ZULU_CHECKSUM,
|
|
||||||
source: 'https://api.azul.com/metadata/v1/zulu/packages/test-uuid-12447'
|
|
||||||
});
|
|
||||||
// Only the winning package's UUID triggers a details request.
|
|
||||||
expect(spyPackageDetails).toHaveBeenCalledWith(
|
|
||||||
'https://api.azul.com/metadata/v1/zulu/packages/test-uuid-12447'
|
|
||||||
);
|
|
||||||
expect(spyPackageDetails).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('skips checksum verification when sha256_hash is missing or malformed', async () => {
|
|
||||||
spyPackageDetails.mockResolvedValue({
|
|
||||||
statusCode: 200,
|
|
||||||
headers: {},
|
|
||||||
result: {}
|
|
||||||
});
|
|
||||||
|
|
||||||
const distribution = new ZuluDistribution({
|
|
||||||
version: '',
|
|
||||||
architecture: 'arm64',
|
|
||||||
packageType: 'jdk',
|
|
||||||
checkLatest: false
|
|
||||||
});
|
|
||||||
distribution['getAvailableVersions'] = async () => manifestData;
|
|
||||||
const result = await distribution['findPackageForDownload']('21.0.2');
|
|
||||||
|
|
||||||
expect(result.checksum).toBeUndefined();
|
|
||||||
expect(core.debug).toHaveBeenCalledWith(
|
|
||||||
expect.stringContaining('No authoritative sha256 checksum')
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw an error', async () => {
|
it('should throw an error', async () => {
|
||||||
|
|||||||
@@ -242,26 +242,6 @@ describe('getArchitectureOptions', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('findPackageForDownload', () => {
|
describe('findPackageForDownload', () => {
|
||||||
let spyPackageDetails: any;
|
|
||||||
|
|
||||||
const ZULU_CHECKSUM = 'a'.repeat(64);
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
// The resolved winning package fetches sha256_hash from the Azul
|
|
||||||
// package-details endpoint; stub it so tests never reach the real
|
|
||||||
// network.
|
|
||||||
spyPackageDetails = jest.spyOn(HttpClient.prototype, 'getJson');
|
|
||||||
spyPackageDetails.mockResolvedValue({
|
|
||||||
statusCode: 200,
|
|
||||||
headers: {},
|
|
||||||
result: {sha256_hash: ZULU_CHECKSUM}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
jest.restoreAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each([
|
it.each([
|
||||||
['8', '8.0.282+8'],
|
['8', '8.0.282+8'],
|
||||||
['11.x', '11.0.10+9'],
|
['11.x', '11.0.10+9'],
|
||||||
@@ -300,38 +280,6 @@ describe('findPackageForDownload', () => {
|
|||||||
expect(result.url).toBe(
|
expect(result.url).toBe(
|
||||||
'https://cdn.azul.com/zulu/bin/zulu17.48.15-ca-jdk17.0.10-windows_aarch64.zip'
|
'https://cdn.azul.com/zulu/bin/zulu17.48.15-ca-jdk17.0.10-windows_aarch64.zip'
|
||||||
);
|
);
|
||||||
expect(result.checksum).toEqual({
|
|
||||||
algorithm: 'sha256',
|
|
||||||
value: ZULU_CHECKSUM,
|
|
||||||
source: 'https://api.azul.com/metadata/v1/zulu/packages/test-uuid-12446'
|
|
||||||
});
|
|
||||||
// Only the winning package's UUID triggers a details request.
|
|
||||||
expect(spyPackageDetails).toHaveBeenCalledWith(
|
|
||||||
'https://api.azul.com/metadata/v1/zulu/packages/test-uuid-12446'
|
|
||||||
);
|
|
||||||
expect(spyPackageDetails).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('skips checksum verification when sha256_hash is missing or malformed', async () => {
|
|
||||||
spyPackageDetails.mockResolvedValue({
|
|
||||||
statusCode: 200,
|
|
||||||
headers: {},
|
|
||||||
result: {sha256_hash: '123'}
|
|
||||||
});
|
|
||||||
|
|
||||||
const distribution = new ZuluDistribution({
|
|
||||||
version: '',
|
|
||||||
architecture: 'arm64',
|
|
||||||
packageType: 'jdk',
|
|
||||||
checkLatest: false
|
|
||||||
});
|
|
||||||
distribution['getAvailableVersions'] = async () => manifestData;
|
|
||||||
const result = await distribution['findPackageForDownload']('17.0.10');
|
|
||||||
|
|
||||||
expect(result.checksum).toBeUndefined();
|
|
||||||
expect(core.debug).toHaveBeenCalledWith(
|
|
||||||
expect.stringContaining('No authoritative sha256 checksum')
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw an error', async () => {
|
it('should throw an error', async () => {
|
||||||
|
|||||||
@@ -1,82 +0,0 @@
|
|||||||
import fs from 'fs';
|
|
||||||
import path from 'path';
|
|
||||||
import {
|
|
||||||
JAVA_PACKAGE_CAPABILITIES,
|
|
||||||
JavaDistribution
|
|
||||||
} from '../src/distributions/package-types.js';
|
|
||||||
|
|
||||||
const repositoryRoot = process.cwd();
|
|
||||||
const readRepositoryFile = (filePath: string) =>
|
|
||||||
fs.readFileSync(path.join(repositoryRoot, filePath), 'utf8');
|
|
||||||
const allPackageTypes = [
|
|
||||||
...new Set(Object.values(JAVA_PACKAGE_CAPABILITIES).flat())
|
|
||||||
];
|
|
||||||
|
|
||||||
describe('java-package published contract', () => {
|
|
||||||
it.each(['action.yml', 'README.md'])(
|
|
||||||
'documents every supported package type in %s',
|
|
||||||
filePath => {
|
|
||||||
const content = readRepositoryFile(filePath);
|
|
||||||
const contractLine =
|
|
||||||
filePath === 'action.yml'
|
|
||||||
? content.match(/ {2}java-package:\n(?: {4}.+\n)+/)?.[0]
|
|
||||||
: content
|
|
||||||
.split('\n')
|
|
||||||
.find(line => line.includes('| `java-package` |'));
|
|
||||||
|
|
||||||
expect(contractLine).toBeDefined();
|
|
||||||
for (const packageType of allPackageTypes) {
|
|
||||||
expect(contractLine).toContain(`\`${packageType}\``);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
it.each(Object.entries(JAVA_PACKAGE_CAPABILITIES))(
|
|
||||||
'keeps the advanced compatibility table aligned for %s',
|
|
||||||
(distributionName, packageTypes) => {
|
|
||||||
const advancedUsage = readRepositoryFile('docs/advanced-usage.md');
|
|
||||||
const compatibilityTable = advancedUsage.slice(
|
|
||||||
advancedUsage.indexOf('### Package compatibility')
|
|
||||||
);
|
|
||||||
const compatibilityRow = compatibilityTable
|
|
||||||
.split('\n')
|
|
||||||
.find(
|
|
||||||
line =>
|
|
||||||
line.startsWith('|') && line.includes(`\`${distributionName}\``)
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(compatibilityRow).toBeDefined();
|
|
||||||
for (const packageType of packageTypes) {
|
|
||||||
expect(compatibilityRow).toContain(`\`${packageType}\``);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
it('only exercises supported distribution/package combinations in E2E', () => {
|
|
||||||
const workflow = readRepositoryFile('.github/workflows/e2e-versions.yml');
|
|
||||||
const defaultMatrix = workflow.match(
|
|
||||||
/distribution:\s*\n\s*\[([^\]]+)\]\s*\n\s*java-package:\s*\['([^']+)'\]/
|
|
||||||
);
|
|
||||||
expect(defaultMatrix).not.toBeNull();
|
|
||||||
|
|
||||||
const defaultDistributions = [
|
|
||||||
...defaultMatrix![1].matchAll(/'([^']+)'/g)
|
|
||||||
].map(match => match[1]);
|
|
||||||
const defaultPackage = defaultMatrix![2];
|
|
||||||
for (const distributionName of defaultDistributions) {
|
|
||||||
expect(supportedPackagesFor(distributionName)).toContain(defaultPackage);
|
|
||||||
}
|
|
||||||
|
|
||||||
const includedPackages = workflow.matchAll(
|
|
||||||
/- distribution: '([^']+)'\s*\n\s*java-package: ([^\s]+)/g
|
|
||||||
);
|
|
||||||
for (const match of includedPackages) {
|
|
||||||
const [, distributionName, packageType] = match;
|
|
||||||
expect(supportedPackagesFor(distributionName)).toContain(packageType);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function supportedPackagesFor(distributionName: string): readonly string[] {
|
|
||||||
return JAVA_PACKAGE_CAPABILITIES[distributionName as JavaDistribution] ?? [];
|
|
||||||
}
|
|
||||||
@@ -1,124 +0,0 @@
|
|||||||
import fs from 'fs';
|
|
||||||
import path from 'path';
|
|
||||||
import {
|
|
||||||
JAVA_PLATFORM_CAPABILITIES,
|
|
||||||
normalizeArchitecture,
|
|
||||||
validateJavaPlatform
|
|
||||||
} from '../src/distributions/platform-types.js';
|
|
||||||
import {JavaDistribution} from '../src/distributions/package-types.js';
|
|
||||||
|
|
||||||
describe('Java platform capabilities', () => {
|
|
||||||
it('declares a capability for every distribution', () => {
|
|
||||||
expect(Object.keys(JAVA_PLATFORM_CAPABILITIES).sort()).toEqual(
|
|
||||||
Object.values(JavaDistribution).sort()
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each([
|
|
||||||
['x64', 'x64'],
|
|
||||||
['amd64', 'x64'],
|
|
||||||
['x86', 'x86'],
|
|
||||||
['ia32', 'x86'],
|
|
||||||
['arm', 'armv7'],
|
|
||||||
['aarch64', 'aarch64'],
|
|
||||||
['arm64', 'aarch64'],
|
|
||||||
['ppc64le', 'ppc64le'],
|
|
||||||
['s390x', 's390x']
|
|
||||||
])('normalizes architecture %s to %s', (input, expected) => {
|
|
||||||
expect(normalizeArchitecture(input)).toBe(expected);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('uses the normalized architecture for validation', () => {
|
|
||||||
expect(validateJavaPlatform('microsoft', 'linux', 'arm64', '25')).toBe(
|
|
||||||
'aarch64'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('rejects OS-specific restrictions with a consistent diagnostic', () => {
|
|
||||||
expect(() =>
|
|
||||||
validateJavaPlatform('oracle', 'win32', 'arm64', '21')
|
|
||||||
).toThrow(
|
|
||||||
"Distribution 'oracle' does not support operating system 'windows' with architecture 'aarch64' for Java version '21'. Supported combinations: linux (x64, aarch64); macos (x64, aarch64); windows (x64)."
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('rejects version-dependent architecture restrictions', () => {
|
|
||||||
expect(() =>
|
|
||||||
validateJavaPlatform('corretto', 'linux', 'x86', '17')
|
|
||||||
).toThrow(/x86 \(<12\)/);
|
|
||||||
expect(() =>
|
|
||||||
validateJavaPlatform('corretto', 'linux', 'x86', '17.0.2.8.1')
|
|
||||||
).toThrow(/x86 \(<12\)/);
|
|
||||||
expect(validateJavaPlatform('corretto', 'linux', 'x86', '11')).toBe('x86');
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each(['corretto', 'kona'])(
|
|
||||||
'rejects Windows aarch64 for %s',
|
|
||||||
distributionName => {
|
|
||||||
expect(() =>
|
|
||||||
validateJavaPlatform(distributionName, 'win32', 'arm64', '21')
|
|
||||||
).toThrow(/does not support operating system 'windows'/);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
it('allows local archives on any platform and architecture', () => {
|
|
||||||
expect(validateJavaPlatform('jdkfile', 'aix', 'mips64', '21')).toBe(
|
|
||||||
'mips64'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('keeps the documented architecture contract aligned', () => {
|
|
||||||
const repositoryRoot = process.cwd();
|
|
||||||
const readRepositoryFile = (filePath: string) =>
|
|
||||||
fs.readFileSync(path.join(repositoryRoot, filePath), 'utf8');
|
|
||||||
|
|
||||||
for (const filePath of ['action.yml', 'README.md']) {
|
|
||||||
const content = readRepositoryFile(filePath);
|
|
||||||
for (const architecture of [
|
|
||||||
'x86',
|
|
||||||
'x64',
|
|
||||||
'armv7',
|
|
||||||
'aarch64',
|
|
||||||
'ppc64le',
|
|
||||||
'ppc64',
|
|
||||||
's390x'
|
|
||||||
]) {
|
|
||||||
expect(content).toContain(architecture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each(Object.entries(JAVA_PLATFORM_CAPABILITIES))(
|
|
||||||
'keeps the advanced compatibility table aligned for %s',
|
|
||||||
(distributionName, capability) => {
|
|
||||||
const advancedUsage = fs.readFileSync(
|
|
||||||
path.join(process.cwd(), 'docs/advanced-usage.md'),
|
|
||||||
'utf8'
|
|
||||||
);
|
|
||||||
const compatibilityTable = advancedUsage.slice(
|
|
||||||
advancedUsage.indexOf('## Platform and architecture compatibility')
|
|
||||||
);
|
|
||||||
const compatibilityRow = compatibilityTable
|
|
||||||
.split('\n')
|
|
||||||
.find(
|
|
||||||
line =>
|
|
||||||
line.startsWith('|') && line.includes(`\`${distributionName}\``)
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(compatibilityRow).toBeDefined();
|
|
||||||
if (!('platforms' in capability)) {
|
|
||||||
expect(compatibilityRow).toContain('Any');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const architectures = new Set(
|
|
||||||
Object.values(capability.platforms)
|
|
||||||
.flat()
|
|
||||||
.map(item => (typeof item === 'string' ? item : item.architecture))
|
|
||||||
);
|
|
||||||
for (const architecture of architectures) {
|
|
||||||
expect(compatibilityRow).toContain(`\`${architecture}\``);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
@@ -1,325 +0,0 @@
|
|||||||
import {jest, describe, it, expect, beforeEach, afterEach} from '@jest/globals';
|
|
||||||
import fs from 'fs';
|
|
||||||
import os from 'os';
|
|
||||||
import path from 'path';
|
|
||||||
|
|
||||||
jest.unstable_mockModule('@actions/cache', () => ({
|
|
||||||
restoreCache: jest.fn(),
|
|
||||||
saveCache: jest.fn(),
|
|
||||||
ReserveCacheError: class ReserveCacheError extends Error {
|
|
||||||
constructor(message: string) {
|
|
||||||
super(message);
|
|
||||||
this.name = 'ReserveCacheError';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.unstable_mockModule('@actions/core', () => ({
|
|
||||||
info: jest.fn(),
|
|
||||||
warning: jest.fn(),
|
|
||||||
debug: jest.fn(),
|
|
||||||
saveState: jest.fn(),
|
|
||||||
getState: jest.fn()
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.unstable_mockModule('../src/cache-feature.js', () => ({
|
|
||||||
isCacheFeatureAvailable: jest.fn()
|
|
||||||
}));
|
|
||||||
|
|
||||||
const cache = await import('@actions/cache');
|
|
||||||
const core = await import('@actions/core');
|
|
||||||
const cacheFeature = await import('../src/cache-feature.js');
|
|
||||||
const {
|
|
||||||
buildJdkCacheKey,
|
|
||||||
getJdkVerificationIdentity,
|
|
||||||
registerJdk,
|
|
||||||
restoreJdk,
|
|
||||||
saveJdkCaches
|
|
||||||
} = await import('../src/jdk-cache.js');
|
|
||||||
|
|
||||||
const jdk = {
|
|
||||||
distribution: 'temurin',
|
|
||||||
packageType: 'jdk',
|
|
||||||
architecture: 'x64',
|
|
||||||
version: '21.0.8+9',
|
|
||||||
source: 'sha256:abc123',
|
|
||||||
verification: 'unverified',
|
|
||||||
path: '/toolcache/Java_temurin_jdk/21.0.8-9'
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('JDK cache', () => {
|
|
||||||
const tempRoots: string[] = [];
|
|
||||||
|
|
||||||
const createInstallation = (marker = 'a'): string => {
|
|
||||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'setup-java-jdk-'));
|
|
||||||
tempRoots.push(root);
|
|
||||||
const jdkPath = path.join(root, 'Java_temurin_jdk', '21.0.8-9');
|
|
||||||
writeInstallation(jdkPath, marker);
|
|
||||||
return jdkPath;
|
|
||||||
};
|
|
||||||
|
|
||||||
const writeInstallation = (jdkPath: string, marker: string): void => {
|
|
||||||
const architecturePath = path.join(jdkPath, 'x64');
|
|
||||||
fs.rmSync(architecturePath, {recursive: true, force: true});
|
|
||||||
fs.rmSync(`${architecturePath}.complete`, {force: true});
|
|
||||||
fs.mkdirSync(path.join(architecturePath, 'bin'), {recursive: true});
|
|
||||||
fs.writeFileSync(path.join(architecturePath, 'bin', 'java'), marker);
|
|
||||||
fs.writeFileSync(`${architecturePath}.complete`, marker);
|
|
||||||
};
|
|
||||||
|
|
||||||
const lastState = (): string =>
|
|
||||||
((core.saveState as jest.Mock).mock.calls.at(-1) as string[])[1];
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
jest.resetAllMocks();
|
|
||||||
(cacheFeature.isCacheFeatureAvailable as jest.Mock).mockReturnValue(true);
|
|
||||||
process.env['RUNNER_OS'] = 'Linux';
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
jest.restoreAllMocks();
|
|
||||||
delete process.env['RUNNER_OS'];
|
|
||||||
while (tempRoots.length) {
|
|
||||||
fs.rmSync(tempRoots.pop()!, {recursive: true, force: true});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('builds distinct keys for incompatible JDK identities', () => {
|
|
||||||
const key = buildJdkCacheKey(jdk);
|
|
||||||
|
|
||||||
expect(key).toMatch(/^setup-java-jdk-v1-Linux-x64-[a-f0-9]{64}$/);
|
|
||||||
expect(buildJdkCacheKey({...jdk, architecture: 'aarch64'})).not.toBe(key);
|
|
||||||
expect(buildJdkCacheKey({...jdk, distribution: 'zulu'})).not.toBe(key);
|
|
||||||
expect(buildJdkCacheKey({...jdk, packageType: 'jre'})).not.toBe(key);
|
|
||||||
expect(buildJdkCacheKey({...jdk, version: '21.0.7+6'})).not.toBe(key);
|
|
||||||
expect(buildJdkCacheKey({...jdk, source: 'sha256:def456'})).not.toBe(key);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('preserves canonical runner OS values and separates operating systems', () => {
|
|
||||||
process.env['RUNNER_OS'] = 'Linux';
|
|
||||||
const linux = buildJdkCacheKey(jdk);
|
|
||||||
process.env['RUNNER_OS'] = 'Windows';
|
|
||||||
const windows = buildJdkCacheKey(jdk);
|
|
||||||
process.env['RUNNER_OS'] = 'macOS';
|
|
||||||
const macos = buildJdkCacheKey(jdk);
|
|
||||||
|
|
||||||
expect(new Set([linux, windows, macos])).toHaveProperty('size', 3);
|
|
||||||
expect(linux).toMatch(/^setup-java-jdk-v1-Linux-x64-/);
|
|
||||||
expect(windows).toMatch(/^setup-java-jdk-v1-Windows-x64-/);
|
|
||||||
expect(macos).toMatch(/^setup-java-jdk-v1-macOS-x64-/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('falls back to process.platform without RUNNER_OS', () => {
|
|
||||||
delete process.env['RUNNER_OS'];
|
|
||||||
|
|
||||||
expect(buildJdkCacheKey(jdk)).toMatch(
|
|
||||||
new RegExp(`^setup-java-jdk-v1-${process.platform}-x64-`)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('separates unverified, bundled-key, and custom-key caches', () => {
|
|
||||||
const unverified = getJdkVerificationIdentity(false);
|
|
||||||
const bundled = getJdkVerificationIdentity(true);
|
|
||||||
const customA = getJdkVerificationIdentity(
|
|
||||||
true,
|
|
||||||
'-----BEGIN PGP PUBLIC KEY BLOCK-----\r\nkey-a\r\n-----END PGP PUBLIC KEY BLOCK-----\r\n'
|
|
||||||
);
|
|
||||||
const customANormalized = getJdkVerificationIdentity(
|
|
||||||
true,
|
|
||||||
'-----BEGIN PGP PUBLIC KEY BLOCK-----\nkey-a\n-----END PGP PUBLIC KEY BLOCK-----'
|
|
||||||
);
|
|
||||||
const customB = getJdkVerificationIdentity(true, 'different-key');
|
|
||||||
|
|
||||||
expect(new Set([unverified, bundled, customA, customB])).toHaveProperty(
|
|
||||||
'size',
|
|
||||||
4
|
|
||||||
);
|
|
||||||
expect(customA).toBe(customANormalized);
|
|
||||||
expect(customA).not.toContain('key-a');
|
|
||||||
expect(
|
|
||||||
new Set(
|
|
||||||
[unverified, bundled, customA, customB].map(verification =>
|
|
||||||
buildJdkCacheKey({...jdk, verification})
|
|
||||||
)
|
|
||||||
)
|
|
||||||
).toHaveProperty('size', 4);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('restores and records an exact JDK cache hit', async () => {
|
|
||||||
(cache.restoreCache as jest.Mock).mockResolvedValue(buildJdkCacheKey(jdk));
|
|
||||||
jest.spyOn(fs, 'existsSync').mockReturnValue(true);
|
|
||||||
|
|
||||||
await expect(restoreJdk(jdk)).resolves.toBe(true);
|
|
||||||
|
|
||||||
expect(cache.restoreCache).toHaveBeenCalledWith(
|
|
||||||
[jdk.path],
|
|
||||||
buildJdkCacheKey(jdk)
|
|
||||||
);
|
|
||||||
const architecturePath = path.join(jdk.path, 'x64');
|
|
||||||
expect(fs.existsSync).toHaveBeenCalledWith(architecturePath);
|
|
||||||
expect(fs.existsSync).toHaveBeenCalledWith(`${architecturePath}.complete`);
|
|
||||||
expect(core.saveState).toHaveBeenCalledWith(
|
|
||||||
'jdk-caches',
|
|
||||||
expect.stringContaining(buildJdkCacheKey(jdk))
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('falls back to download when restoration fails', async () => {
|
|
||||||
(cache.restoreCache as jest.Mock).mockRejectedValue(
|
|
||||||
new Error('cache unavailable')
|
|
||||||
);
|
|
||||||
|
|
||||||
await expect(restoreJdk(jdk)).resolves.toBe(false);
|
|
||||||
expect(core.warning).toHaveBeenCalledWith(
|
|
||||||
'Failed to restore JDK cache: cache unavailable'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('saves a downloaded JDK registered after installation', async () => {
|
|
||||||
const jdkPath = createInstallation();
|
|
||||||
const installed = {...jdk, path: jdkPath};
|
|
||||||
const key = buildJdkCacheKey(installed);
|
|
||||||
(cache.restoreCache as jest.Mock).mockResolvedValue(undefined);
|
|
||||||
|
|
||||||
await restoreJdk(installed);
|
|
||||||
registerJdk(installed);
|
|
||||||
(core.getState as jest.Mock).mockReturnValue(lastState());
|
|
||||||
(cache.saveCache as jest.Mock).mockResolvedValue(1);
|
|
||||||
|
|
||||||
await saveJdkCaches();
|
|
||||||
|
|
||||||
expect(cache.saveCache).toHaveBeenCalledWith([jdkPath], key);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not save an installation that was replaced after registration', async () => {
|
|
||||||
const jdkPath = createInstallation();
|
|
||||||
const installed = {...jdk, path: jdkPath};
|
|
||||||
const key = buildJdkCacheKey(installed);
|
|
||||||
|
|
||||||
registerJdk(installed);
|
|
||||||
(core.getState as jest.Mock).mockReturnValue(lastState());
|
|
||||||
writeInstallation(jdkPath, 'replaced-by-a-later-step');
|
|
||||||
|
|
||||||
await saveJdkCaches();
|
|
||||||
|
|
||||||
expect(cache.saveCache).not.toHaveBeenCalledWith([jdkPath], key);
|
|
||||||
expect(core.warning).toHaveBeenCalledWith(
|
|
||||||
expect.stringContaining('was replaced after it was registered')
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('saves only the key matching the installation that occupies the path', async () => {
|
|
||||||
const jdkPath = createInstallation();
|
|
||||||
const verified = {...jdk, path: jdkPath, verification: 'verified:bundled'};
|
|
||||||
const unverified = {...jdk, path: jdkPath};
|
|
||||||
|
|
||||||
registerJdk(verified);
|
|
||||||
writeInstallation(jdkPath, 'force-downloaded-without-verification');
|
|
||||||
registerJdk(unverified);
|
|
||||||
(core.getState as jest.Mock).mockReturnValue(lastState());
|
|
||||||
(cache.saveCache as jest.Mock).mockResolvedValue(1);
|
|
||||||
|
|
||||||
await saveJdkCaches();
|
|
||||||
|
|
||||||
expect(cache.saveCache).not.toHaveBeenCalledWith(
|
|
||||||
[jdkPath],
|
|
||||||
buildJdkCacheKey(verified)
|
|
||||||
);
|
|
||||||
expect(cache.saveCache).toHaveBeenCalledWith(
|
|
||||||
[jdkPath],
|
|
||||||
buildJdkCacheKey(unverified)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not save a path that was never registered as installed', async () => {
|
|
||||||
const jdkPath = createInstallation();
|
|
||||||
const installed = {...jdk, path: jdkPath};
|
|
||||||
(cache.restoreCache as jest.Mock).mockResolvedValue(undefined);
|
|
||||||
|
|
||||||
await restoreJdk(installed);
|
|
||||||
(core.getState as jest.Mock).mockReturnValue(lastState());
|
|
||||||
|
|
||||||
await saveJdkCaches();
|
|
||||||
|
|
||||||
expect(cache.saveCache).not.toHaveBeenCalledWith(
|
|
||||||
[jdkPath],
|
|
||||||
buildJdkCacheKey(installed)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('keeps saving the remaining JDK caches when one save fails', async () => {
|
|
||||||
const failingPath = createInstallation();
|
|
||||||
const succeedingPath = createInstallation();
|
|
||||||
const failing = {...jdk, path: failingPath};
|
|
||||||
const succeeding = {...jdk, path: succeedingPath, version: '17.0.19+9'};
|
|
||||||
|
|
||||||
registerJdk(failing);
|
|
||||||
registerJdk(succeeding);
|
|
||||||
(core.getState as jest.Mock).mockReturnValue(lastState());
|
|
||||||
(cache.saveCache as jest.Mock).mockImplementation(
|
|
||||||
async (paths: unknown) => {
|
|
||||||
if ((paths as string[])[0] === failingPath) {
|
|
||||||
throw new Error('cache service unavailable');
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
await expect(saveJdkCaches()).resolves.toBeUndefined();
|
|
||||||
|
|
||||||
expect(cache.saveCache).toHaveBeenCalledWith(
|
|
||||||
[succeedingPath],
|
|
||||||
buildJdkCacheKey(succeeding)
|
|
||||||
);
|
|
||||||
expect(core.warning).toHaveBeenCalledWith(
|
|
||||||
expect.stringContaining('cache service unavailable')
|
|
||||||
);
|
|
||||||
expect(core.info).toHaveBeenCalledWith(
|
|
||||||
`JDK cache saved with the key: ${buildJdkCacheKey(succeeding)}`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('reports a reserved cache key without failing the remaining saves', async () => {
|
|
||||||
const reservedPath = createInstallation();
|
|
||||||
const reserved = {...jdk, path: reservedPath};
|
|
||||||
|
|
||||||
registerJdk(reserved);
|
|
||||||
(core.getState as jest.Mock).mockReturnValue(lastState());
|
|
||||||
(cache.saveCache as jest.Mock).mockRejectedValue(
|
|
||||||
new cache.ReserveCacheError('Unable to reserve cache')
|
|
||||||
);
|
|
||||||
|
|
||||||
await expect(saveJdkCaches()).resolves.toBeUndefined();
|
|
||||||
|
|
||||||
expect(core.info).toHaveBeenCalledWith('Unable to reserve cache');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('registers a force-downloaded JDK without restoring it', () => {
|
|
||||||
const jdkPath = createInstallation();
|
|
||||||
registerJdk({...jdk, path: jdkPath});
|
|
||||||
|
|
||||||
expect(cache.restoreCache).not.toHaveBeenCalled();
|
|
||||||
expect(core.saveState).toHaveBeenCalledWith(
|
|
||||||
'jdk-caches',
|
|
||||||
expect.stringContaining(buildJdkCacheKey({...jdk, path: jdkPath}))
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not save an exact JDK cache hit again', async () => {
|
|
||||||
const key = buildJdkCacheKey(jdk);
|
|
||||||
(core.getState as jest.Mock).mockReturnValue(
|
|
||||||
JSON.stringify([
|
|
||||||
{
|
|
||||||
key,
|
|
||||||
path: jdk.path,
|
|
||||||
architecture: jdk.architecture,
|
|
||||||
matchedKey: key
|
|
||||||
}
|
|
||||||
])
|
|
||||||
);
|
|
||||||
|
|
||||||
await saveJdkCaches();
|
|
||||||
|
|
||||||
expect(cache.saveCache).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,387 +0,0 @@
|
|||||||
import {jest, describe, it, expect, beforeEach, afterEach} from '@jest/globals';
|
|
||||||
import fs from 'fs';
|
|
||||||
import os from 'os';
|
|
||||||
import path from 'path';
|
|
||||||
|
|
||||||
jest.unstable_mockModule('@actions/cache', () => ({
|
|
||||||
isFeatureAvailable: jest.fn(),
|
|
||||||
restoreCache: jest.fn(),
|
|
||||||
saveCache: jest.fn()
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.unstable_mockModule('@actions/core', () => ({
|
|
||||||
info: jest.fn(),
|
|
||||||
warning: jest.fn(),
|
|
||||||
debug: jest.fn(),
|
|
||||||
saveState: jest.fn(),
|
|
||||||
getState: jest.fn()
|
|
||||||
}));
|
|
||||||
|
|
||||||
const cache = await import('@actions/cache');
|
|
||||||
const core = await import('@actions/core');
|
|
||||||
const {restoreJdkResolution, registerJdkResolution, saveJdkResolutionCaches} =
|
|
||||||
await import('../src/jdk-resolution-cache.js');
|
|
||||||
|
|
||||||
const request = {
|
|
||||||
distribution: 'Temurin-Hotspot',
|
|
||||||
packageType: 'jdk',
|
|
||||||
architecture: 'x64',
|
|
||||||
versionSpec: '21',
|
|
||||||
stable: true
|
|
||||||
};
|
|
||||||
|
|
||||||
const release = {
|
|
||||||
version: '21.0.8+9',
|
|
||||||
url: 'https://example.com/jdk-21.0.8.tar.gz',
|
|
||||||
checksum: {algorithm: 'sha256' as const, value: 'abc123'}
|
|
||||||
};
|
|
||||||
|
|
||||||
const WEEK = 7 * 24 * 60 * 60 * 1000;
|
|
||||||
const bucket = () =>
|
|
||||||
new Date(Math.floor(Date.now() / WEEK) * WEEK).toISOString().slice(0, 10);
|
|
||||||
|
|
||||||
describe('JDK resolution cache', () => {
|
|
||||||
const tempRoots: string[] = [];
|
|
||||||
let originalTemp: string | undefined;
|
|
||||||
let originalOs: string | undefined;
|
|
||||||
|
|
||||||
const createRunnerTemp = (): string => {
|
|
||||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'setup-java-res-'));
|
|
||||||
tempRoots.push(root);
|
|
||||||
process.env['RUNNER_TEMP'] = root;
|
|
||||||
return root;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Emulates the cache service materializing the entry at the requested path. */
|
|
||||||
const restoreWith = (contents: string, matchedKey: string) => {
|
|
||||||
jest
|
|
||||||
.mocked(cache.restoreCache)
|
|
||||||
.mockImplementation(async (paths: string[]) => {
|
|
||||||
fs.mkdirSync(paths[0], {recursive: true});
|
|
||||||
fs.writeFileSync(path.join(paths[0], 'release.json'), contents);
|
|
||||||
return matchedKey;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
originalTemp = process.env['RUNNER_TEMP'];
|
|
||||||
originalOs = process.env['RUNNER_OS'];
|
|
||||||
process.env['RUNNER_OS'] = 'Linux';
|
|
||||||
jest.mocked(cache.isFeatureAvailable).mockReturnValue(true);
|
|
||||||
jest.mocked(cache.restoreCache).mockResolvedValue(undefined);
|
|
||||||
jest.mocked(cache.saveCache).mockResolvedValue(1);
|
|
||||||
jest.mocked(core.getState).mockReturnValue('');
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
process.env['RUNNER_TEMP'] = originalTemp;
|
|
||||||
process.env['RUNNER_OS'] = originalOs;
|
|
||||||
if (originalTemp === undefined) {
|
|
||||||
delete process.env['RUNNER_TEMP'];
|
|
||||||
}
|
|
||||||
if (originalOs === undefined) {
|
|
||||||
delete process.env['RUNNER_OS'];
|
|
||||||
}
|
|
||||||
while (tempRoots.length > 0) {
|
|
||||||
fs.rmSync(tempRoots.pop()!, {recursive: true, force: true});
|
|
||||||
}
|
|
||||||
jest.resetAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('restoreJdkResolution', () => {
|
|
||||||
it('looks the entry up with a bucket-independent path', async () => {
|
|
||||||
const runnerTemp = createRunnerTemp();
|
|
||||||
await restoreJdkResolution(request);
|
|
||||||
|
|
||||||
const [paths, primaryKey, restoreKeys] = jest.mocked(cache.restoreCache)
|
|
||||||
.mock.calls[0] as [string[], string, string[]];
|
|
||||||
expect(paths).toHaveLength(1);
|
|
||||||
expect(
|
|
||||||
paths[0].startsWith(path.join(runnerTemp, 'setup-java-jdk-resolution'))
|
|
||||||
).toBe(true);
|
|
||||||
expect(paths[0]).not.toContain(bucket());
|
|
||||||
expect(primaryKey).toBe(`${restoreKeys[0]}${bucket()}`);
|
|
||||||
expect(restoreKeys[0]).toMatch(
|
|
||||||
/^setup-java-jdkres-v1-Linux-x64-[0-9a-f]{64}-$/
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('holds the key steady for a week and then rolls it', async () => {
|
|
||||||
createRunnerTemp();
|
|
||||||
const nowSpy = jest.spyOn(Date, 'now');
|
|
||||||
const keyAt = async (ms: number) => {
|
|
||||||
nowSpy.mockReturnValue(ms);
|
|
||||||
await restoreJdkResolution(request);
|
|
||||||
return jest.mocked(cache.restoreCache).mock.calls.at(-1)![1] as string;
|
|
||||||
};
|
|
||||||
|
|
||||||
// A window boundary, so the offsets below are unambiguous.
|
|
||||||
const windowStart = 2900 * WEEK;
|
|
||||||
|
|
||||||
const start = await keyAt(windowStart);
|
|
||||||
const sameWindow = await keyAt(windowStart + 6 * 24 * 60 * 60 * 1000);
|
|
||||||
const nextWindow = await keyAt(windowStart + WEEK);
|
|
||||||
|
|
||||||
expect(sameWindow).toBe(start);
|
|
||||||
expect(nextWindow).not.toBe(start);
|
|
||||||
nowSpy.mockRestore();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('reports a hit on the current bucket as fresh', async () => {
|
|
||||||
createRunnerTemp();
|
|
||||||
const key = `setup-java-jdkres-v1-Linux-x64-${'0'.repeat(64)}-${bucket()}`;
|
|
||||||
restoreWith(JSON.stringify(release), key);
|
|
||||||
|
|
||||||
// The key the module computes is the one it passes to restoreCache, so
|
|
||||||
// echo it back to emulate an exact hit.
|
|
||||||
jest
|
|
||||||
.mocked(cache.restoreCache)
|
|
||||||
.mockImplementation(async (paths: string[], primaryKey: string) => {
|
|
||||||
fs.mkdirSync(paths[0], {recursive: true});
|
|
||||||
fs.writeFileSync(
|
|
||||||
path.join(paths[0], 'release.json'),
|
|
||||||
JSON.stringify(release)
|
|
||||||
);
|
|
||||||
return primaryKey;
|
|
||||||
});
|
|
||||||
|
|
||||||
const restored = await restoreJdkResolution(request);
|
|
||||||
expect(restored?.fresh).toBe(true);
|
|
||||||
expect(restored?.release).toEqual(release);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('reports a hit on an older bucket as stale', async () => {
|
|
||||||
createRunnerTemp();
|
|
||||||
restoreWith(JSON.stringify(release), 'setup-java-jdkres-v1-old');
|
|
||||||
|
|
||||||
const restored = await restoreJdkResolution(request);
|
|
||||||
expect(restored?.fresh).toBe(false);
|
|
||||||
expect(restored?.release).toEqual(release);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns nothing when the entry is missing', async () => {
|
|
||||||
createRunnerTemp();
|
|
||||||
await expect(restoreJdkResolution(request)).resolves.toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns nothing when the cache service is unavailable', async () => {
|
|
||||||
createRunnerTemp();
|
|
||||||
jest.mocked(cache.isFeatureAvailable).mockReturnValue(false);
|
|
||||||
|
|
||||||
await expect(restoreJdkResolution(request)).resolves.toBeUndefined();
|
|
||||||
expect(cache.restoreCache).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns nothing when RUNNER_TEMP is not set', async () => {
|
|
||||||
delete process.env['RUNNER_TEMP'];
|
|
||||||
|
|
||||||
await expect(restoreJdkResolution(request)).resolves.toBeUndefined();
|
|
||||||
expect(cache.restoreCache).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not fail the job when the restore throws', async () => {
|
|
||||||
createRunnerTemp();
|
|
||||||
jest
|
|
||||||
.mocked(cache.restoreCache)
|
|
||||||
.mockRejectedValue(new Error('service unavailable'));
|
|
||||||
|
|
||||||
await expect(restoreJdkResolution(request)).resolves.toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each([
|
|
||||||
['malformed JSON', 'not json'],
|
|
||||||
['a non-object payload', '"nope"'],
|
|
||||||
[
|
|
||||||
'a missing version',
|
|
||||||
JSON.stringify({url: 'https://example.com/a.tar.gz'})
|
|
||||||
],
|
|
||||||
['a missing url', JSON.stringify({version: '21.0.8+9'})],
|
|
||||||
[
|
|
||||||
'a non-HTTPS url',
|
|
||||||
JSON.stringify({
|
|
||||||
version: '21.0.8+9',
|
|
||||||
url: 'http://example.com/a.tar.gz'
|
|
||||||
})
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'a malformed url',
|
|
||||||
JSON.stringify({version: '21.0.8+9', url: 'not-a-url'})
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'a non-HTTPS signature url',
|
|
||||||
JSON.stringify({
|
|
||||||
version: '21.0.8+9',
|
|
||||||
url: 'https://example.com/a.tar.gz',
|
|
||||||
signatureUrl: 'http://example.com/a.sig'
|
|
||||||
})
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'an unsupported checksum algorithm',
|
|
||||||
JSON.stringify({
|
|
||||||
version: '21.0.8+9',
|
|
||||||
url: 'https://example.com/a.tar.gz',
|
|
||||||
checksum: {algorithm: 'md5', value: 'abc'}
|
|
||||||
})
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'a checksum without a value',
|
|
||||||
JSON.stringify({
|
|
||||||
version: '21.0.8+9',
|
|
||||||
url: 'https://example.com/a.tar.gz',
|
|
||||||
checksum: {algorithm: 'sha256'}
|
|
||||||
})
|
|
||||||
]
|
|
||||||
])('rejects an entry with %s', async (_name, contents) => {
|
|
||||||
createRunnerTemp();
|
|
||||||
restoreWith(contents, 'setup-java-jdkres-v1-old');
|
|
||||||
|
|
||||||
await expect(restoreJdkResolution(request)).resolves.toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('keeps the optional fields of a valid entry', async () => {
|
|
||||||
createRunnerTemp();
|
|
||||||
const full = {
|
|
||||||
version: '21.0.8+9',
|
|
||||||
url: 'https://example.com/a.tar.gz',
|
|
||||||
signatureUrl: 'https://example.com/a.sig',
|
|
||||||
checksum: {
|
|
||||||
algorithm: 'sha512',
|
|
||||||
value: 'def456',
|
|
||||||
source: 'https://example.com/a.sha512'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
restoreWith(JSON.stringify(full), 'setup-java-jdkres-v1-old');
|
|
||||||
|
|
||||||
const restored = await restoreJdkResolution(request);
|
|
||||||
expect(restored?.release).toEqual(full);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('ignores unknown fields rather than passing them through', async () => {
|
|
||||||
createRunnerTemp();
|
|
||||||
restoreWith(
|
|
||||||
JSON.stringify({...release, evil: 'payload'}),
|
|
||||||
'setup-java-jdkres-v1-old'
|
|
||||||
);
|
|
||||||
|
|
||||||
const restored = await restoreJdkResolution(request);
|
|
||||||
expect(restored?.release).toEqual(release);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('registerJdkResolution', () => {
|
|
||||||
it('writes the release and records it under the current bucket', () => {
|
|
||||||
createRunnerTemp();
|
|
||||||
registerJdkResolution(request, release);
|
|
||||||
|
|
||||||
const state = JSON.parse(
|
|
||||||
jest.mocked(core.saveState).mock.calls.at(-1)![1] as string
|
|
||||||
);
|
|
||||||
const entry = state.at(-1);
|
|
||||||
expect(entry.key.endsWith(bucket())).toBe(true);
|
|
||||||
expect(
|
|
||||||
JSON.parse(
|
|
||||||
fs.readFileSync(path.join(entry.path, 'release.json'), 'utf8')
|
|
||||||
)
|
|
||||||
).toEqual(release);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does nothing when the cache service is unavailable', () => {
|
|
||||||
createRunnerTemp();
|
|
||||||
jest.mocked(cache.isFeatureAvailable).mockReturnValue(false);
|
|
||||||
|
|
||||||
registerJdkResolution(request, release);
|
|
||||||
expect(core.saveState).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does nothing when RUNNER_TEMP is not set', () => {
|
|
||||||
delete process.env['RUNNER_TEMP'];
|
|
||||||
|
|
||||||
registerJdkResolution(request, release);
|
|
||||||
expect(core.saveState).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('uses different keys for different requests', () => {
|
|
||||||
createRunnerTemp();
|
|
||||||
registerJdkResolution(request, release);
|
|
||||||
registerJdkResolution({...request, distribution: 'zulu'}, release);
|
|
||||||
|
|
||||||
const state = JSON.parse(
|
|
||||||
jest.mocked(core.saveState).mock.calls.at(-1)![1] as string
|
|
||||||
);
|
|
||||||
expect(new Set(state.map((item: {key: string}) => item.key)).size).toBe(
|
|
||||||
state.length
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('saveJdkResolutionCaches', () => {
|
|
||||||
const stateFor = (cachePath: string) =>
|
|
||||||
JSON.stringify([
|
|
||||||
{
|
|
||||||
key: 'setup-java-jdkres-v1-key',
|
|
||||||
path: cachePath,
|
|
||||||
release: JSON.stringify(release)
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
|
|
||||||
it('does nothing without state', async () => {
|
|
||||||
await saveJdkResolutionCaches();
|
|
||||||
expect(cache.saveCache).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('saves a recorded entry', async () => {
|
|
||||||
const root = createRunnerTemp();
|
|
||||||
jest.mocked(core.getState).mockReturnValue(stateFor(root));
|
|
||||||
|
|
||||||
await saveJdkResolutionCaches();
|
|
||||||
expect(cache.saveCache).toHaveBeenCalledWith(
|
|
||||||
[root],
|
|
||||||
'setup-java-jdkres-v1-key'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('saves the payload the key was computed for, not the file on disk', async () => {
|
|
||||||
const root = createRunnerTemp();
|
|
||||||
jest.mocked(core.getState).mockReturnValue(stateFor(root));
|
|
||||||
// A restore performed by a later step replaces the file behind the key.
|
|
||||||
fs.writeFileSync(
|
|
||||||
path.join(root, 'release.json'),
|
|
||||||
JSON.stringify({version: '8.0.1+1', url: 'https://example.com/stale'})
|
|
||||||
);
|
|
||||||
|
|
||||||
await saveJdkResolutionCaches();
|
|
||||||
|
|
||||||
expect(
|
|
||||||
JSON.parse(fs.readFileSync(path.join(root, 'release.json'), 'utf8'))
|
|
||||||
).toEqual(release);
|
|
||||||
expect(cache.saveCache).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not fail the job when the payload cannot be written', async () => {
|
|
||||||
const root = createRunnerTemp();
|
|
||||||
const blocked = path.join(root, 'blocked');
|
|
||||||
fs.writeFileSync(blocked, 'not a directory');
|
|
||||||
jest.mocked(core.getState).mockReturnValue(stateFor(blocked));
|
|
||||||
|
|
||||||
await expect(saveJdkResolutionCaches()).resolves.toBeUndefined();
|
|
||||||
expect(cache.saveCache).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not fail the job when the save throws', async () => {
|
|
||||||
const root = createRunnerTemp();
|
|
||||||
jest.mocked(core.getState).mockReturnValue(stateFor(root));
|
|
||||||
jest
|
|
||||||
.mocked(cache.saveCache)
|
|
||||||
.mockRejectedValue(new Error('already reserved'));
|
|
||||||
|
|
||||||
await expect(saveJdkResolutionCaches()).resolves.toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not fail the job on invalid state', async () => {
|
|
||||||
jest.mocked(core.getState).mockReturnValue('{}');
|
|
||||||
|
|
||||||
await expect(saveJdkResolutionCaches()).resolves.toBeUndefined();
|
|
||||||
expect(cache.saveCache).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
import {describe, expect, it, jest} from '@jest/globals';
|
|
||||||
|
|
||||||
const mockXmlBuilderFactory = jest.fn();
|
|
||||||
const mockParse = jest.fn(() => ({
|
|
||||||
toolchains: {
|
|
||||||
toolchain: [
|
|
||||||
{
|
|
||||||
type: 'foo',
|
|
||||||
provides: {id: 'custom'},
|
|
||||||
configuration: {fooHome: '/opt/foo'}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.unstable_mockModule('fast-xml-parser', () => {
|
|
||||||
mockXmlBuilderFactory();
|
|
||||||
return {
|
|
||||||
XMLParser: jest.fn().mockImplementation(() => ({
|
|
||||||
parse: mockParse
|
|
||||||
}))
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const toolchains = await import('../src/toolchains.js');
|
|
||||||
|
|
||||||
describe('Maven XML loading', () => {
|
|
||||||
it('does not load fast-xml-parser for new toolchains.xml generation', async () => {
|
|
||||||
const xml = await toolchains.generateToolchainDefinition(
|
|
||||||
'',
|
|
||||||
'21',
|
|
||||||
'temurin',
|
|
||||||
'temurin_21',
|
|
||||||
'/opt/java/21'
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(xml).toContain('<id>temurin_21</id>');
|
|
||||||
expect(mockXmlBuilderFactory).not.toHaveBeenCalled();
|
|
||||||
expect(mockParse).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('loads fast-xml-parser for existing toolchains.xml merge generation', async () => {
|
|
||||||
await expect(
|
|
||||||
toolchains.generateToolchainDefinition(
|
|
||||||
'<toolchains><toolchain><type>foo</type></toolchain></toolchains>',
|
|
||||||
'21',
|
|
||||||
'temurin',
|
|
||||||
'temurin_21',
|
|
||||||
'/opt/java/21'
|
|
||||||
)
|
|
||||||
).resolves.toContain('<id>temurin_21</id>');
|
|
||||||
|
|
||||||
expect(mockXmlBuilderFactory).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockParse).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
import {afterEach, beforeEach, describe, expect, it, jest} from '@jest/globals';
|
|
||||||
|
|
||||||
const mockGetInput = jest.fn<(...args: any[]) => any>();
|
|
||||||
const mockInfo = jest.fn<(...args: any[]) => any>();
|
|
||||||
const mockDebug = jest.fn<(...args: any[]) => any>();
|
|
||||||
|
|
||||||
jest.unstable_mockModule('@actions/core', () => ({
|
|
||||||
getInput: mockGetInput,
|
|
||||||
info: mockInfo,
|
|
||||||
debug: mockDebug,
|
|
||||||
warning: jest.fn(),
|
|
||||||
setSecret: jest.fn()
|
|
||||||
}));
|
|
||||||
|
|
||||||
const {configureProblemMatcher} = await import('../src/problem-matcher.js');
|
|
||||||
const {INPUT_PROBLEM_MATCHER} = await import('../src/constants.js');
|
|
||||||
|
|
||||||
describe('configureProblemMatcher', () => {
|
|
||||||
let inputs: Record<string, string>;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
inputs = {};
|
|
||||||
mockGetInput.mockImplementation((name: string) => inputs[name] ?? '');
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
jest.resetAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('registers the Java problem matcher by default', () => {
|
|
||||||
configureProblemMatcher('/matchers/java.json');
|
|
||||||
|
|
||||||
expect(mockInfo).toHaveBeenCalledWith('##[add-matcher]/matchers/java.json');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not register the Java problem matcher when disabled', () => {
|
|
||||||
inputs[INPUT_PROBLEM_MATCHER] = 'false';
|
|
||||||
|
|
||||||
configureProblemMatcher('/matchers/java.json');
|
|
||||||
|
|
||||||
expect(mockInfo).not.toHaveBeenCalled();
|
|
||||||
expect(mockDebug).toHaveBeenCalledWith('Java problem matcher is disabled');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,251 +0,0 @@
|
|||||||
import {jest, describe, it, expect, beforeEach, afterEach} from '@jest/globals';
|
|
||||||
import type {IncomingMessage} from 'http';
|
|
||||||
|
|
||||||
jest.unstable_mockModule('@actions/core', () => ({
|
|
||||||
info: jest.fn()
|
|
||||||
}));
|
|
||||||
|
|
||||||
const core = await import('@actions/core');
|
|
||||||
const httpm = await import('@actions/http-client');
|
|
||||||
const {RetryingHttpClient, isRetryableNetworkError, parseRetryAfter} =
|
|
||||||
await import('../src/retrying-http-client.js');
|
|
||||||
|
|
||||||
function response(
|
|
||||||
statusCode: number,
|
|
||||||
retryAfter?: string
|
|
||||||
): httpm.HttpClientResponse {
|
|
||||||
return {
|
|
||||||
message: {
|
|
||||||
statusCode,
|
|
||||||
headers: retryAfter ? {'retry-after': retryAfter} : {}
|
|
||||||
} as IncomingMessage,
|
|
||||||
readBody: jest.fn(async () => '')
|
|
||||||
} as unknown as httpm.HttpClientResponse;
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('RetryingHttpClient', () => {
|
|
||||||
let request: ReturnType<typeof jest.spyOn>;
|
|
||||||
let sleep: jest.Mock<(delayMs: number) => Promise<void>>;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
request = jest.spyOn(httpm.HttpClient.prototype, 'request');
|
|
||||||
sleep = jest.fn(async () => undefined);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
jest.restoreAllMocks();
|
|
||||||
jest.clearAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('uses exponential backoff with jitter for retryable responses', async () => {
|
|
||||||
request
|
|
||||||
.mockResolvedValueOnce(response(503))
|
|
||||||
.mockResolvedValueOnce(response(502))
|
|
||||||
.mockResolvedValueOnce(response(200));
|
|
||||||
const client = new RetryingHttpClient('test', {
|
|
||||||
sleep,
|
|
||||||
random: () => 0,
|
|
||||||
baseDelayMs: 1000,
|
|
||||||
maxDelayMs: 10000
|
|
||||||
});
|
|
||||||
|
|
||||||
await expect(client.get('https://example.com')).resolves.toBeDefined();
|
|
||||||
|
|
||||||
expect(request).toHaveBeenCalledTimes(3);
|
|
||||||
expect(sleep).toHaveBeenNthCalledWith(1, 500);
|
|
||||||
expect(sleep).toHaveBeenNthCalledWith(2, 1000);
|
|
||||||
expect(core.info).toHaveBeenNthCalledWith(
|
|
||||||
1,
|
|
||||||
'Request attempt 1 of 4 failed (HTTP 503); retrying in 500 ms'
|
|
||||||
);
|
|
||||||
expect(core.info).toHaveBeenNthCalledWith(
|
|
||||||
2,
|
|
||||||
'Request attempt 2 of 4 failed (HTTP 502); retrying in 1000 ms'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('honors Retry-After delta-seconds over the client delay', async () => {
|
|
||||||
request
|
|
||||||
.mockResolvedValueOnce(response(429, '3'))
|
|
||||||
.mockResolvedValueOnce(response(200));
|
|
||||||
const client = new RetryingHttpClient('test', {
|
|
||||||
sleep,
|
|
||||||
random: () => 0
|
|
||||||
});
|
|
||||||
|
|
||||||
await client.get('https://example.com');
|
|
||||||
|
|
||||||
expect(sleep).toHaveBeenCalledWith(3000);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('honors Retry-After HTTP dates over the client delay', async () => {
|
|
||||||
const now = Date.parse('2026-07-29T00:00:00Z');
|
|
||||||
request
|
|
||||||
.mockResolvedValueOnce(response(503, new Date(now + 5000).toUTCString()))
|
|
||||||
.mockResolvedValueOnce(response(200));
|
|
||||||
const client = new RetryingHttpClient('test', {
|
|
||||||
sleep,
|
|
||||||
random: () => 0,
|
|
||||||
now: () => now
|
|
||||||
});
|
|
||||||
|
|
||||||
await client.get('https://example.com');
|
|
||||||
|
|
||||||
expect(sleep).toHaveBeenCalledWith(5000);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('caps Retry-After at the configured maximum delay', async () => {
|
|
||||||
request
|
|
||||||
.mockResolvedValueOnce(response(429, '60'))
|
|
||||||
.mockResolvedValueOnce(response(200));
|
|
||||||
const client = new RetryingHttpClient('test', {
|
|
||||||
sleep,
|
|
||||||
random: () => 0,
|
|
||||||
maxDelayMs: 10000
|
|
||||||
});
|
|
||||||
|
|
||||||
await client.get('https://example.com');
|
|
||||||
|
|
||||||
expect(sleep).toHaveBeenCalledWith(10000);
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each([429, 502, 503, 504, 522])(
|
|
||||||
'retries HTTP %s responses',
|
|
||||||
async statusCode => {
|
|
||||||
request
|
|
||||||
.mockResolvedValueOnce(response(statusCode))
|
|
||||||
.mockResolvedValueOnce(response(200));
|
|
||||||
const client = new RetryingHttpClient('test', {
|
|
||||||
sleep,
|
|
||||||
random: () => 0
|
|
||||||
});
|
|
||||||
|
|
||||||
await client.get('https://example.com');
|
|
||||||
|
|
||||||
expect(request).toHaveBeenCalledTimes(2);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
it.each(['ETIMEDOUT', 'ECONNRESET', 'ENOTFOUND', 'ECONNREFUSED'])(
|
|
||||||
'retries network errors with code %s',
|
|
||||||
async code => {
|
|
||||||
request
|
|
||||||
.mockRejectedValueOnce(Object.assign(new Error(code), {code}))
|
|
||||||
.mockResolvedValueOnce(response(200));
|
|
||||||
const client = new RetryingHttpClient('test', {
|
|
||||||
sleep,
|
|
||||||
random: () => 0
|
|
||||||
});
|
|
||||||
|
|
||||||
await client.get('https://example.com');
|
|
||||||
|
|
||||||
expect(request).toHaveBeenCalledTimes(2);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
it('retries retryable aggregate network errors', async () => {
|
|
||||||
const aggregateError = Object.assign(new Error('connection failed'), {
|
|
||||||
errors: [Object.assign(new Error('timed out'), {code: 'ETIMEDOUT'})]
|
|
||||||
});
|
|
||||||
request
|
|
||||||
.mockRejectedValueOnce(aggregateError)
|
|
||||||
.mockResolvedValueOnce(response(200));
|
|
||||||
const client = new RetryingHttpClient('test', {
|
|
||||||
sleep,
|
|
||||||
random: () => 0
|
|
||||||
});
|
|
||||||
|
|
||||||
await client.get('https://example.com');
|
|
||||||
|
|
||||||
expect(request).toHaveBeenCalledTimes(2);
|
|
||||||
expect(sleep).toHaveBeenCalledWith(500);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not retry non-retryable responses or network errors', async () => {
|
|
||||||
request.mockResolvedValueOnce(response(500));
|
|
||||||
const client = new RetryingHttpClient('test', {sleep});
|
|
||||||
|
|
||||||
await expect(client.get('https://example.com')).resolves.toBeDefined();
|
|
||||||
expect(request).toHaveBeenCalledTimes(1);
|
|
||||||
expect(sleep).not.toHaveBeenCalled();
|
|
||||||
|
|
||||||
request.mockRejectedValueOnce(
|
|
||||||
Object.assign(new Error('certificate failed'), {code: 'CERT_HAS_EXPIRED'})
|
|
||||||
);
|
|
||||||
await expect(client.get('https://example.com')).rejects.toThrow(
|
|
||||||
'certificate failed'
|
|
||||||
);
|
|
||||||
expect(request).toHaveBeenCalledTimes(2);
|
|
||||||
expect(sleep).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('stops after the configured total attempt count', async () => {
|
|
||||||
request
|
|
||||||
.mockResolvedValueOnce(response(503))
|
|
||||||
.mockResolvedValueOnce(response(503));
|
|
||||||
const client = new RetryingHttpClient('test', {
|
|
||||||
maxAttempts: 2,
|
|
||||||
sleep,
|
|
||||||
random: () => 0
|
|
||||||
});
|
|
||||||
|
|
||||||
const finalResponse = await client.get('https://example.com');
|
|
||||||
|
|
||||||
expect(finalResponse.message.statusCode).toBe(503);
|
|
||||||
expect(request).toHaveBeenCalledTimes(2);
|
|
||||||
expect(sleep).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('propagates the final network error after exhausting attempts', async () => {
|
|
||||||
const finalError = Object.assign(new Error('still unavailable'), {
|
|
||||||
code: 'ECONNREFUSED'
|
|
||||||
});
|
|
||||||
request
|
|
||||||
.mockRejectedValueOnce(
|
|
||||||
Object.assign(new Error('unavailable'), {code: 'ECONNREFUSED'})
|
|
||||||
)
|
|
||||||
.mockRejectedValueOnce(finalError);
|
|
||||||
const client = new RetryingHttpClient('test', {
|
|
||||||
maxAttempts: 2,
|
|
||||||
sleep,
|
|
||||||
random: () => 0
|
|
||||||
});
|
|
||||||
|
|
||||||
await expect(client.get('https://example.com')).rejects.toBe(finalError);
|
|
||||||
|
|
||||||
expect(request).toHaveBeenCalledTimes(2);
|
|
||||||
expect(sleep).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not retry write requests', async () => {
|
|
||||||
request.mockResolvedValueOnce(response(503));
|
|
||||||
const client = new RetryingHttpClient('test', {sleep});
|
|
||||||
|
|
||||||
await client.post('https://example.com', '{}');
|
|
||||||
|
|
||||||
expect(request).toHaveBeenCalledTimes(1);
|
|
||||||
expect(sleep).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('retry classification', () => {
|
|
||||||
it('parses valid Retry-After values and ignores invalid or past values', () => {
|
|
||||||
const now = Date.parse('2026-07-29T00:00:00Z');
|
|
||||||
|
|
||||||
expect(parseRetryAfter('7', now)).toBe(7000);
|
|
||||||
expect(parseRetryAfter(new Date(now + 3000).toUTCString(), now)).toBe(3000);
|
|
||||||
expect(parseRetryAfter(new Date(now - 3000).toUTCString(), now)).toBe(
|
|
||||||
undefined
|
|
||||||
);
|
|
||||||
expect(parseRetryAfter('not-a-date', now)).toBe(undefined);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('recognizes direct and nested retryable network error codes', () => {
|
|
||||||
expect(isRetryableNetworkError({code: 'ECONNRESET'})).toBe(true);
|
|
||||||
expect(
|
|
||||||
isRetryableNetworkError({errors: [{code: 'ENOTFOUND'}, {code: 'OTHER'}]})
|
|
||||||
).toBe(true);
|
|
||||||
expect(isRetryableNetworkError({code: 'CERT_HAS_EXPIRED'})).toBe(false);
|
|
||||||
expect(isRetryableNetworkError(new Error('unknown'))).toBe(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
import {jest, describe, it, expect, beforeEach} from '@jest/globals';
|
|
||||||
|
|
||||||
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((value: string) => value),
|
|
||||||
toWin32Path: jest.fn((value: string) => value),
|
|
||||||
toPosixPath: jest.fn((value: string) => value)
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.unstable_mockModule('fs', () => ({
|
|
||||||
default: {
|
|
||||||
readFileSync: jest.fn()
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.unstable_mockModule('../src/util.js', () => ({
|
|
||||||
getBooleanInput: jest.fn(),
|
|
||||||
getVersionFromFileContent: jest.fn(),
|
|
||||||
isJdkCacheEnabled: jest.fn()
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.unstable_mockModule('../src/toolchains.js', () => ({
|
|
||||||
validateToolchainIds: jest.fn(),
|
|
||||||
configureToolchains: jest.fn()
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.unstable_mockModule(
|
|
||||||
'../src/distributions/distribution-factory.js',
|
|
||||||
() => ({
|
|
||||||
getJavaDistribution: jest.fn()
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
jest.unstable_mockModule('../src/auth.js', () => ({
|
|
||||||
configureAuthentication: jest.fn()
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.unstable_mockModule('../src/maven-args.js', () => ({
|
|
||||||
configureMavenArgs: jest.fn()
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.unstable_mockModule('../src/problem-matcher.js', () => ({
|
|
||||||
configureProblemMatcher: jest.fn()
|
|
||||||
}));
|
|
||||||
|
|
||||||
// These modules should never be imported when `cache` input is empty.
|
|
||||||
jest.unstable_mockModule('../src/cache-feature.js', () => {
|
|
||||||
throw new Error('cache-feature module should not be loaded');
|
|
||||||
});
|
|
||||||
jest.unstable_mockModule('../src/cache.js', () => {
|
|
||||||
throw new Error('cache module should not be loaded');
|
|
||||||
});
|
|
||||||
|
|
||||||
const core = await import('@actions/core');
|
|
||||||
const util = await import('../src/util.js');
|
|
||||||
const toolchains = await import('../src/toolchains.js');
|
|
||||||
const factory = await import('../src/distributions/distribution-factory.js');
|
|
||||||
const {run} = await import('../src/setup-java.js');
|
|
||||||
|
|
||||||
describe('setup-java conditional module loading', () => {
|
|
||||||
const inputs = new Map<string, string>();
|
|
||||||
const multilineInputs = new Map<string, string[]>();
|
|
||||||
const booleanInputs = new Map<string, boolean>();
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
jest.resetAllMocks();
|
|
||||||
inputs.clear();
|
|
||||||
multilineInputs.clear();
|
|
||||||
booleanInputs.clear();
|
|
||||||
|
|
||||||
(core.getInput as jest.Mock).mockImplementation((name: unknown) => {
|
|
||||||
return inputs.get(name as string) ?? '';
|
|
||||||
});
|
|
||||||
(core.getMultilineInput as jest.Mock).mockImplementation(
|
|
||||||
(name: unknown) => {
|
|
||||||
return multilineInputs.get(name as string) ?? [];
|
|
||||||
}
|
|
||||||
);
|
|
||||||
(util.getBooleanInput as jest.Mock).mockImplementation(
|
|
||||||
(name: unknown, defaultValue: unknown) => {
|
|
||||||
return booleanInputs.get(name as string) ?? defaultValue;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
(util.isJdkCacheEnabled as jest.Mock).mockReturnValue(false);
|
|
||||||
(toolchains.configureToolchains as jest.Mock).mockResolvedValue(undefined);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not import cache modules when cache input is not provided', async () => {
|
|
||||||
inputs.set('distribution', 'temurin');
|
|
||||||
multilineInputs.set('java-version', ['21']);
|
|
||||||
(factory.getJavaDistribution as jest.Mock).mockResolvedValue({
|
|
||||||
setupJava: jest.fn(async () => ({
|
|
||||||
version: '21.0.4+7',
|
|
||||||
path: '/opt/java/21'
|
|
||||||
}))
|
|
||||||
});
|
|
||||||
|
|
||||||
await run();
|
|
||||||
|
|
||||||
expect(core.setFailed).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,609 +0,0 @@
|
|||||||
import {jest, describe, it, expect, beforeEach} from '@jest/globals';
|
|
||||||
|
|
||||||
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((value: string) => value),
|
|
||||||
toWin32Path: jest.fn((value: string) => value),
|
|
||||||
toPosixPath: jest.fn((value: string) => value)
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.unstable_mockModule('fs', () => ({
|
|
||||||
default: {
|
|
||||||
readFileSync: jest.fn()
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.unstable_mockModule('../src/util.js', () => ({
|
|
||||||
getBooleanInput: jest.fn(),
|
|
||||||
getVersionFromFileContent: jest.fn(),
|
|
||||||
isJdkCacheEnabled: jest.fn()
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.unstable_mockModule('../src/toolchains.js', () => ({
|
|
||||||
validateToolchainIds: jest.fn(),
|
|
||||||
configureToolchains: jest.fn()
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.unstable_mockModule('../src/toolchain-ids.js', () => ({
|
|
||||||
validateToolchainIds: jest.fn()
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.unstable_mockModule('../src/cache.js', () => ({
|
|
||||||
restore: jest.fn()
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.unstable_mockModule('../src/cache-feature.js', () => ({
|
|
||||||
isCacheFeatureAvailable: jest.fn()
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.unstable_mockModule(
|
|
||||||
'../src/distributions/distribution-factory.js',
|
|
||||||
() => ({
|
|
||||||
getJavaDistribution: jest.fn()
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
jest.unstable_mockModule('../src/auth.js', () => ({
|
|
||||||
configureAuthentication: jest.fn()
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.unstable_mockModule('../src/maven-args.js', () => ({
|
|
||||||
configureMavenArgs: jest.fn()
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.unstable_mockModule('../src/problem-matcher.js', () => ({
|
|
||||||
configureProblemMatcher: jest.fn()
|
|
||||||
}));
|
|
||||||
|
|
||||||
const core = await import('@actions/core');
|
|
||||||
const fs = (await import('fs')).default;
|
|
||||||
const util = await import('../src/util.js');
|
|
||||||
const toolchains = await import('../src/toolchains.js');
|
|
||||||
const toolchainIds = await import('../src/toolchain-ids.js');
|
|
||||||
const cache = await import('../src/cache.js');
|
|
||||||
const cacheFeature = await import('../src/cache-feature.js');
|
|
||||||
const factory = await import('../src/distributions/distribution-factory.js');
|
|
||||||
const auth = await import('../src/auth.js');
|
|
||||||
const mavenArgs = await import('../src/maven-args.js');
|
|
||||||
const problemMatcher = await import('../src/problem-matcher.js');
|
|
||||||
const {run} = await import('../src/setup-java.js');
|
|
||||||
|
|
||||||
const inputCallsOnImport = (core.getInput as jest.Mock).mock.calls.length;
|
|
||||||
const multilineInputCallsOnImport = (core.getMultilineInput as jest.Mock).mock
|
|
||||||
.calls.length;
|
|
||||||
|
|
||||||
describe('setup action orchestration', () => {
|
|
||||||
const inputs = new Map<string, string>();
|
|
||||||
const multilineInputs = new Map<string, string[]>();
|
|
||||||
const booleanInputs = new Map<string, boolean>();
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
jest.resetAllMocks();
|
|
||||||
inputs.clear();
|
|
||||||
multilineInputs.clear();
|
|
||||||
booleanInputs.clear();
|
|
||||||
|
|
||||||
(core.getInput as jest.Mock).mockImplementation((name: unknown) => {
|
|
||||||
return inputs.get(name as string) ?? '';
|
|
||||||
});
|
|
||||||
(core.getMultilineInput as jest.Mock).mockImplementation(
|
|
||||||
(name: unknown) => {
|
|
||||||
return multilineInputs.get(name as string) ?? [];
|
|
||||||
}
|
|
||||||
);
|
|
||||||
(util.getBooleanInput as jest.Mock).mockImplementation(
|
|
||||||
(name: unknown, defaultValue: unknown) => {
|
|
||||||
return booleanInputs.get(name as string) ?? defaultValue;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
(util.isJdkCacheEnabled as jest.Mock).mockImplementation(
|
|
||||||
(cache: string) => {
|
|
||||||
const explicit = inputs.get('cache-jdk');
|
|
||||||
return explicit
|
|
||||||
? (booleanInputs.get('cache-jdk') ?? explicit === 'true')
|
|
||||||
: Boolean(cache);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
(cacheFeature.isCacheFeatureAvailable as jest.Mock).mockReturnValue(true);
|
|
||||||
(toolchainIds.validateToolchainIds as jest.Mock).mockImplementation(
|
|
||||||
() => undefined
|
|
||||||
);
|
|
||||||
(toolchains.configureToolchains as jest.Mock).mockResolvedValue(undefined);
|
|
||||||
(auth.configureAuthentication as jest.Mock).mockResolvedValue(undefined);
|
|
||||||
(cache.restore as jest.Mock).mockResolvedValue(undefined);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not execute the action when imported', () => {
|
|
||||||
expect(inputCallsOnImport).toBe(0);
|
|
||||||
expect(multilineInputCallsOnImport).toBe(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('requires java-version or java-version-file', async () => {
|
|
||||||
await run();
|
|
||||||
|
|
||||||
expect(core.setFailed).toHaveBeenCalledWith(
|
|
||||||
'java-version or java-version-file input expected'
|
|
||||||
);
|
|
||||||
expect(factory.getJavaDistribution).not.toHaveBeenCalled();
|
|
||||||
expect(problemMatcher.configureProblemMatcher).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('requires distribution when java-version is provided', async () => {
|
|
||||||
multilineInputs.set('java-version', ['21']);
|
|
||||||
|
|
||||||
await run();
|
|
||||||
|
|
||||||
expect(core.setFailed).toHaveBeenCalledWith(
|
|
||||||
'distribution input is required'
|
|
||||||
);
|
|
||||||
expect(factory.getJavaDistribution).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('requires distribution when it cannot be inferred from the version file', async () => {
|
|
||||||
inputs.set('java-version-file', '.java-version');
|
|
||||||
(fs.readFileSync as jest.Mock).mockReturnValue(Buffer.from('21'));
|
|
||||||
(util.getVersionFromFileContent as jest.Mock).mockReturnValue({
|
|
||||||
version: '21'
|
|
||||||
});
|
|
||||||
|
|
||||||
await run();
|
|
||||||
|
|
||||||
expect(core.setFailed).toHaveBeenCalledWith(
|
|
||||||
'distribution input is required when not specified in the version file'
|
|
||||||
);
|
|
||||||
expect(factory.getJavaDistribution).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fails when the version file has no supported version', async () => {
|
|
||||||
inputs.set('java-version-file', '.java-version');
|
|
||||||
inputs.set('distribution', 'temurin');
|
|
||||||
(fs.readFileSync as jest.Mock).mockReturnValue(Buffer.from('invalid'));
|
|
||||||
(util.getVersionFromFileContent as jest.Mock).mockReturnValue(undefined);
|
|
||||||
|
|
||||||
await run();
|
|
||||||
|
|
||||||
expect(core.setFailed).toHaveBeenCalledWith(
|
|
||||||
'No supported version was found in file .java-version'
|
|
||||||
);
|
|
||||||
expect(factory.getJavaDistribution).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('uses the distribution inferred from a version file', async () => {
|
|
||||||
inputs.set('java-version-file', '.sdkmanrc');
|
|
||||||
inputs.set('architecture', 'x64');
|
|
||||||
inputs.set('java-package', 'jdk');
|
|
||||||
inputs.set('distribution', 'zulu');
|
|
||||||
inputs.set('jdk-file', '/tmp/java.tar.gz');
|
|
||||||
multilineInputs.set('mvn-toolchain-id', ['file-jdk']);
|
|
||||||
booleanInputs.set('check-latest', true);
|
|
||||||
booleanInputs.set('force-download', true);
|
|
||||||
booleanInputs.set('set-default', false);
|
|
||||||
booleanInputs.set('verify-signature', true);
|
|
||||||
inputs.set('verify-signature-public-key', 'public-key');
|
|
||||||
(fs.readFileSync as jest.Mock).mockReturnValue(
|
|
||||||
Buffer.from('java=21.0.5-tem')
|
|
||||||
);
|
|
||||||
(util.getVersionFromFileContent as jest.Mock).mockReturnValue({
|
|
||||||
version: '21.0.5',
|
|
||||||
distribution: 'temurin'
|
|
||||||
});
|
|
||||||
const setupJava = jest.fn(async () => ({
|
|
||||||
version: '21.0.5+11',
|
|
||||||
path: '/opt/java/21'
|
|
||||||
}));
|
|
||||||
(factory.getJavaDistribution as jest.Mock).mockReturnValue({setupJava});
|
|
||||||
|
|
||||||
await run();
|
|
||||||
|
|
||||||
expect(util.getVersionFromFileContent).toHaveBeenCalledWith(
|
|
||||||
'java=21.0.5-tem',
|
|
||||||
'zulu',
|
|
||||||
'.sdkmanrc'
|
|
||||||
);
|
|
||||||
expect(factory.getJavaDistribution).toHaveBeenCalledWith(
|
|
||||||
'temurin',
|
|
||||||
{
|
|
||||||
version: '21.0.5',
|
|
||||||
architecture: 'x64',
|
|
||||||
packageType: 'jdk',
|
|
||||||
checkLatest: true,
|
|
||||||
forceDownload: true,
|
|
||||||
cacheJdk: false,
|
|
||||||
setDefault: false,
|
|
||||||
verifySignature: true,
|
|
||||||
verifySignaturePublicKey: 'public-key'
|
|
||||||
},
|
|
||||||
'/tmp/java.tar.gz'
|
|
||||||
);
|
|
||||||
expect(toolchainIds.validateToolchainIds).toHaveBeenCalledWith(
|
|
||||||
[],
|
|
||||||
'.sdkmanrc',
|
|
||||||
['file-jdk']
|
|
||||||
);
|
|
||||||
expect(toolchains.configureToolchains).toHaveBeenCalledWith(
|
|
||||||
'21.0.5',
|
|
||||||
'temurin',
|
|
||||||
'/opt/java/21',
|
|
||||||
'file-jdk'
|
|
||||||
);
|
|
||||||
expect(core.setFailed).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('installs multiple JDKs in order with matching toolchain IDs', async () => {
|
|
||||||
inputs.set('distribution', 'temurin');
|
|
||||||
inputs.set('architecture', 'x64');
|
|
||||||
inputs.set('java-package', 'jdk');
|
|
||||||
multilineInputs.set('java-version', ['17', '21']);
|
|
||||||
multilineInputs.set('mvn-toolchain-id', ['java-17', 'java-21']);
|
|
||||||
|
|
||||||
const setupJava17 = jest.fn(async () => ({
|
|
||||||
version: '17.0.12+7',
|
|
||||||
path: '/opt/java/17'
|
|
||||||
}));
|
|
||||||
const setupJava21 = jest.fn(async () => ({
|
|
||||||
version: '21.0.4+7',
|
|
||||||
path: '/opt/java/21'
|
|
||||||
}));
|
|
||||||
(factory.getJavaDistribution as jest.Mock)
|
|
||||||
.mockReturnValueOnce({setupJava: setupJava17})
|
|
||||||
.mockReturnValueOnce({setupJava: setupJava21});
|
|
||||||
|
|
||||||
await run();
|
|
||||||
|
|
||||||
expect(factory.getJavaDistribution).toHaveBeenNthCalledWith(
|
|
||||||
1,
|
|
||||||
'temurin',
|
|
||||||
expect.objectContaining({version: '17'}),
|
|
||||||
''
|
|
||||||
);
|
|
||||||
expect(factory.getJavaDistribution).toHaveBeenNthCalledWith(
|
|
||||||
2,
|
|
||||||
'temurin',
|
|
||||||
expect.objectContaining({version: '21'}),
|
|
||||||
''
|
|
||||||
);
|
|
||||||
expect(toolchains.configureToolchains).toHaveBeenNthCalledWith(
|
|
||||||
1,
|
|
||||||
'17',
|
|
||||||
'temurin',
|
|
||||||
'/opt/java/17',
|
|
||||||
'java-17'
|
|
||||||
);
|
|
||||||
expect(toolchains.configureToolchains).toHaveBeenNthCalledWith(
|
|
||||||
2,
|
|
||||||
'21',
|
|
||||||
'temurin',
|
|
||||||
'/opt/java/21',
|
|
||||||
'java-21'
|
|
||||||
);
|
|
||||||
expect(setupJava17.mock.invocationCallOrder[0]).toBeLessThan(
|
|
||||||
setupJava21.mock.invocationCallOrder[0]
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('uses the resolved version for the latest Maven toolchain', async () => {
|
|
||||||
inputs.set('distribution', 'temurin');
|
|
||||||
multilineInputs.set('java-version', ['latest']);
|
|
||||||
const setupJava = jest.fn(async () => ({
|
|
||||||
version: '24.0.2+12',
|
|
||||||
path: '/opt/java/24'
|
|
||||||
}));
|
|
||||||
(factory.getJavaDistribution as jest.Mock).mockReturnValue({setupJava});
|
|
||||||
|
|
||||||
await run();
|
|
||||||
|
|
||||||
expect(toolchains.configureToolchains).toHaveBeenCalledWith(
|
|
||||||
'24.0.2+12',
|
|
||||||
'temurin',
|
|
||||||
'/opt/java/24',
|
|
||||||
undefined
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('starts cache restoration before post-install steps and awaits it before finishing', async () => {
|
|
||||||
inputs.set('distribution', 'temurin');
|
|
||||||
inputs.set('cache', 'maven');
|
|
||||||
inputs.set('cache-dependency-path', '**/pom.xml');
|
|
||||||
multilineInputs.set('java-version', ['21']);
|
|
||||||
multilineInputs.set('cache-path', [
|
|
||||||
'/custom/maven/repository',
|
|
||||||
'!/custom/maven/repository/excluded'
|
|
||||||
]);
|
|
||||||
const cacheRestore = deferred<void>();
|
|
||||||
let resolveSetupJava: (() => void) | undefined;
|
|
||||||
const setupJava = jest.fn(
|
|
||||||
() =>
|
|
||||||
new Promise<{version: string; path: string}>(resolve => {
|
|
||||||
resolveSetupJava = () =>
|
|
||||||
resolve({
|
|
||||||
version: '21.0.4+7',
|
|
||||||
path: '/opt/java/21'
|
|
||||||
});
|
|
||||||
})
|
|
||||||
);
|
|
||||||
(cache.restore as jest.Mock).mockReturnValue(cacheRestore.promise);
|
|
||||||
(factory.getJavaDistribution as jest.Mock).mockReturnValue({setupJava});
|
|
||||||
|
|
||||||
const runPromise = run();
|
|
||||||
try {
|
|
||||||
await tick();
|
|
||||||
|
|
||||||
expect(cacheFeature.isCacheFeatureAvailable).toHaveBeenCalled();
|
|
||||||
expect(cache.restore).toHaveBeenCalledWith('maven', '**/pom.xml', [
|
|
||||||
'/custom/maven/repository',
|
|
||||||
'!/custom/maven/repository/excluded'
|
|
||||||
]);
|
|
||||||
expect(toolchains.configureToolchains).not.toHaveBeenCalled();
|
|
||||||
|
|
||||||
resolveSetupJava?.();
|
|
||||||
await tick();
|
|
||||||
expect(problemMatcher.configureProblemMatcher).toHaveBeenCalledWith(
|
|
||||||
expect.stringMatching(/\.github[/\\]java\.json$/)
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(
|
|
||||||
(problemMatcher.configureProblemMatcher as jest.Mock).mock
|
|
||||||
.invocationCallOrder[0]
|
|
||||||
).toBeLessThan(
|
|
||||||
(auth.configureAuthentication as jest.Mock).mock.invocationCallOrder[0]
|
|
||||||
);
|
|
||||||
expect(
|
|
||||||
(problemMatcher.configureProblemMatcher as jest.Mock).mock
|
|
||||||
.invocationCallOrder[0]
|
|
||||||
).toBeLessThan(
|
|
||||||
(toolchains.configureToolchains as jest.Mock).mock
|
|
||||||
.invocationCallOrder[0]
|
|
||||||
);
|
|
||||||
expect(
|
|
||||||
(auth.configureAuthentication as jest.Mock).mock.invocationCallOrder[0]
|
|
||||||
).toBeLessThan(
|
|
||||||
(mavenArgs.configureMavenArgs as jest.Mock).mock.invocationCallOrder[0]
|
|
||||||
);
|
|
||||||
expect(
|
|
||||||
(toolchains.configureToolchains as jest.Mock).mock
|
|
||||||
.invocationCallOrder[0]
|
|
||||||
).toBeLessThan(
|
|
||||||
(mavenArgs.configureMavenArgs as jest.Mock).mock.invocationCallOrder[0]
|
|
||||||
);
|
|
||||||
|
|
||||||
let completed = false;
|
|
||||||
runPromise.then(() => {
|
|
||||||
completed = true;
|
|
||||||
});
|
|
||||||
await tick();
|
|
||||||
expect(completed).toBe(false);
|
|
||||||
} finally {
|
|
||||||
resolveSetupJava?.();
|
|
||||||
cacheRestore.resolve();
|
|
||||||
await runPromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(core.setFailed).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('overlaps independent Maven settings and toolchains configuration', async () => {
|
|
||||||
inputs.set('distribution', 'temurin');
|
|
||||||
multilineInputs.set('java-version', ['21']);
|
|
||||||
(factory.getJavaDistribution as jest.Mock).mockReturnValue({
|
|
||||||
setupJava: jest.fn(async () => ({
|
|
||||||
version: '21.0.4+7',
|
|
||||||
path: '/opt/java/21'
|
|
||||||
}))
|
|
||||||
});
|
|
||||||
const authentication = deferred<void>();
|
|
||||||
const toolchainConfiguration = deferred<void>();
|
|
||||||
(auth.configureAuthentication as jest.Mock).mockReturnValue(
|
|
||||||
authentication.promise
|
|
||||||
);
|
|
||||||
(toolchains.configureToolchains as jest.Mock).mockReturnValue(
|
|
||||||
toolchainConfiguration.promise
|
|
||||||
);
|
|
||||||
|
|
||||||
const runPromise = run();
|
|
||||||
try {
|
|
||||||
await tick();
|
|
||||||
await tick();
|
|
||||||
|
|
||||||
expect(auth.configureAuthentication).toHaveBeenCalled();
|
|
||||||
expect(toolchains.configureToolchains).toHaveBeenCalledWith(
|
|
||||||
'21',
|
|
||||||
'temurin',
|
|
||||||
'/opt/java/21',
|
|
||||||
undefined
|
|
||||||
);
|
|
||||||
expect(mavenArgs.configureMavenArgs).not.toHaveBeenCalled();
|
|
||||||
|
|
||||||
authentication.resolve();
|
|
||||||
await tick();
|
|
||||||
expect(mavenArgs.configureMavenArgs).not.toHaveBeenCalled();
|
|
||||||
|
|
||||||
toolchainConfiguration.resolve();
|
|
||||||
await runPromise;
|
|
||||||
} finally {
|
|
||||||
authentication.resolve();
|
|
||||||
toolchainConfiguration.resolve();
|
|
||||||
await runPromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(mavenArgs.configureMavenArgs).toHaveBeenCalled();
|
|
||||||
expect(core.setFailed).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('skips cache restoration when the cache feature is unavailable', async () => {
|
|
||||||
inputs.set('distribution', 'temurin');
|
|
||||||
inputs.set('cache', 'maven');
|
|
||||||
multilineInputs.set('java-version', ['21']);
|
|
||||||
(cacheFeature.isCacheFeatureAvailable as jest.Mock).mockReturnValue(false);
|
|
||||||
(factory.getJavaDistribution as jest.Mock).mockReturnValue({
|
|
||||||
setupJava: jest.fn(async () => ({
|
|
||||||
version: '21.0.4+7',
|
|
||||||
path: '/opt/java/21'
|
|
||||||
}))
|
|
||||||
});
|
|
||||||
|
|
||||||
await run();
|
|
||||||
|
|
||||||
expect(cache.restore).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not initialize cache modules when cache input is absent', async () => {
|
|
||||||
inputs.set('distribution', 'temurin');
|
|
||||||
multilineInputs.set('java-version', ['21']);
|
|
||||||
booleanInputs.set('cache-jdk', false);
|
|
||||||
(factory.getJavaDistribution as jest.Mock).mockReturnValue({
|
|
||||||
setupJava: jest.fn(async () => ({
|
|
||||||
version: '21.0.4+7',
|
|
||||||
path: '/opt/java/21'
|
|
||||||
}))
|
|
||||||
});
|
|
||||||
|
|
||||||
await run();
|
|
||||||
|
|
||||||
expect(cacheFeature.isCacheFeatureAvailable).not.toHaveBeenCalled();
|
|
||||||
expect(cache.restore).not.toHaveBeenCalled();
|
|
||||||
expect(factory.getJavaDistribution).toHaveBeenCalledWith(
|
|
||||||
'temurin',
|
|
||||||
expect.objectContaining({cacheJdk: false}),
|
|
||||||
''
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each([
|
|
||||||
['', '', false],
|
|
||||||
['', 'true', true],
|
|
||||||
['', 'false', false],
|
|
||||||
['maven', '', true],
|
|
||||||
['maven', 'true', true],
|
|
||||||
['maven', 'false', false]
|
|
||||||
])(
|
|
||||||
'passes effective JDK caching for cache=%j and cache-jdk=%j',
|
|
||||||
async (cacheInput, cacheJdkInput, expected) => {
|
|
||||||
inputs.set('distribution', 'temurin');
|
|
||||||
inputs.set('cache', cacheInput);
|
|
||||||
inputs.set('cache-jdk', cacheJdkInput);
|
|
||||||
multilineInputs.set('java-version', ['21']);
|
|
||||||
if (cacheJdkInput) {
|
|
||||||
booleanInputs.set('cache-jdk', cacheJdkInput === 'true');
|
|
||||||
}
|
|
||||||
(factory.getJavaDistribution as jest.Mock).mockReturnValue({
|
|
||||||
setupJava: jest.fn(async () => ({
|
|
||||||
version: '21.0.4+7',
|
|
||||||
path: '/opt/java/21'
|
|
||||||
}))
|
|
||||||
});
|
|
||||||
|
|
||||||
await run();
|
|
||||||
|
|
||||||
expect(factory.getJavaDistribution).toHaveBeenCalledWith(
|
|
||||||
'temurin',
|
|
||||||
expect.objectContaining({cacheJdk: expected}),
|
|
||||||
''
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
it('reports unsupported distributions through core.setFailed', async () => {
|
|
||||||
inputs.set('distribution', 'unsupported');
|
|
||||||
multilineInputs.set('java-version', ['21']);
|
|
||||||
(factory.getJavaDistribution as jest.Mock).mockReturnValue(null);
|
|
||||||
|
|
||||||
await run();
|
|
||||||
|
|
||||||
expect(core.setFailed).toHaveBeenCalledWith(
|
|
||||||
'No supported distribution was found for input unsupported'
|
|
||||||
);
|
|
||||||
expect(toolchains.configureToolchains).not.toHaveBeenCalled();
|
|
||||||
expect(problemMatcher.configureProblemMatcher).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('reports collaborator failures and stops post-install configuration', async () => {
|
|
||||||
inputs.set('distribution', 'temurin');
|
|
||||||
multilineInputs.set('java-version', ['21']);
|
|
||||||
(factory.getJavaDistribution as jest.Mock).mockReturnValue({
|
|
||||||
setupJava: jest.fn(async () => {
|
|
||||||
throw new Error('download failed');
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
await run();
|
|
||||||
|
|
||||||
expect(core.setFailed).toHaveBeenCalledWith('download failed');
|
|
||||||
expect(toolchains.configureToolchains).not.toHaveBeenCalled();
|
|
||||||
expect(problemMatcher.configureProblemMatcher).not.toHaveBeenCalled();
|
|
||||||
expect(auth.configureAuthentication).not.toHaveBeenCalled();
|
|
||||||
expect(mavenArgs.configureMavenArgs).not.toHaveBeenCalled();
|
|
||||||
expect(cache.restore).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('reports post-install failures and skips later collaborators', async () => {
|
|
||||||
inputs.set('distribution', 'temurin');
|
|
||||||
inputs.set('cache', 'maven');
|
|
||||||
multilineInputs.set('java-version', ['21']);
|
|
||||||
(factory.getJavaDistribution as jest.Mock).mockReturnValue({
|
|
||||||
setupJava: jest.fn(async () => ({
|
|
||||||
version: '21.0.4+7',
|
|
||||||
path: '/opt/java/21'
|
|
||||||
}))
|
|
||||||
});
|
|
||||||
(auth.configureAuthentication as jest.Mock).mockRejectedValue(
|
|
||||||
new Error('authentication failed')
|
|
||||||
);
|
|
||||||
|
|
||||||
await run();
|
|
||||||
|
|
||||||
expect(problemMatcher.configureProblemMatcher).toHaveBeenCalled();
|
|
||||||
expect(core.setFailed).toHaveBeenCalledWith('authentication failed');
|
|
||||||
expect(mavenArgs.configureMavenArgs).not.toHaveBeenCalled();
|
|
||||||
expect(cache.restore).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('keeps Java setup errors deterministic when cache restore also fails', async () => {
|
|
||||||
inputs.set('distribution', 'temurin');
|
|
||||||
inputs.set('cache', 'maven');
|
|
||||||
multilineInputs.set('java-version', ['21']);
|
|
||||||
(factory.getJavaDistribution as jest.Mock).mockReturnValue({
|
|
||||||
setupJava: jest.fn(async () => {
|
|
||||||
throw new Error('download failed');
|
|
||||||
})
|
|
||||||
});
|
|
||||||
(cache.restore as jest.Mock).mockRejectedValue(
|
|
||||||
new Error('cache restore failed')
|
|
||||||
);
|
|
||||||
|
|
||||||
await run();
|
|
||||||
|
|
||||||
expect(core.setFailed).toHaveBeenCalledWith('download failed');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function deferred<T>() {
|
|
||||||
let resolve!: (value: T | PromiseLike<T>) => void;
|
|
||||||
let reject!: (reason?: unknown) => void;
|
|
||||||
const promise = new Promise<T>((res, rej) => {
|
|
||||||
resolve = res;
|
|
||||||
reject = rej;
|
|
||||||
});
|
|
||||||
return {promise, resolve, reject};
|
|
||||||
}
|
|
||||||
|
|
||||||
async function tick() {
|
|
||||||
await new Promise(resolve => setTimeout(resolve, 0));
|
|
||||||
}
|
|
||||||
+24
-201
@@ -13,7 +13,6 @@ import * as fs from 'fs';
|
|||||||
import os from 'os';
|
import os from 'os';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as io from '@actions/io';
|
import * as io from '@actions/io';
|
||||||
import {XMLParser} from 'fast-xml-parser';
|
|
||||||
|
|
||||||
// Mock @actions/core before importing source modules that depend on it
|
// Mock @actions/core before importing source modules that depend on it
|
||||||
jest.unstable_mockModule('@actions/core', () => ({
|
jest.unstable_mockModule('@actions/core', () => ({
|
||||||
@@ -96,7 +95,7 @@ describe('toolchains tests', () => {
|
|||||||
expect(fs.existsSync(altHome)).toBe(true);
|
expect(fs.existsSync(altHome)).toBe(true);
|
||||||
expect(fs.existsSync(altToolchainsFile)).toBe(true);
|
expect(fs.existsSync(altToolchainsFile)).toBe(true);
|
||||||
expect(fs.readFileSync(altToolchainsFile, 'utf-8')).toEqual(
|
expect(fs.readFileSync(altToolchainsFile, 'utf-8')).toEqual(
|
||||||
await toolchains.generateToolchainDefinition(
|
toolchains.generateToolchainDefinition(
|
||||||
'',
|
'',
|
||||||
jdkInfo.version,
|
jdkInfo.version,
|
||||||
jdkInfo.vendor,
|
jdkInfo.vendor,
|
||||||
@@ -141,7 +140,7 @@ describe('toolchains tests', () => {
|
|||||||
expect(fs.existsSync(m2Dir)).toBe(true);
|
expect(fs.existsSync(m2Dir)).toBe(true);
|
||||||
expect(fs.existsSync(toolchainsFile)).toBe(true);
|
expect(fs.existsSync(toolchainsFile)).toBe(true);
|
||||||
expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
|
expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
|
||||||
await toolchains.generateToolchainDefinition(
|
toolchains.generateToolchainDefinition(
|
||||||
'',
|
'',
|
||||||
jdkInfo.version,
|
jdkInfo.version,
|
||||||
jdkInfo.vendor,
|
jdkInfo.vendor,
|
||||||
@@ -150,7 +149,7 @@ describe('toolchains tests', () => {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
await toolchains.generateToolchainDefinition(
|
toolchains.generateToolchainDefinition(
|
||||||
'',
|
'',
|
||||||
jdkInfo.version,
|
jdkInfo.version,
|
||||||
jdkInfo.vendor,
|
jdkInfo.vendor,
|
||||||
@@ -222,7 +221,7 @@ describe('toolchains tests', () => {
|
|||||||
expect(fs.existsSync(m2Dir)).toBe(true);
|
expect(fs.existsSync(m2Dir)).toBe(true);
|
||||||
expect(fs.existsSync(toolchainsFile)).toBe(true);
|
expect(fs.existsSync(toolchainsFile)).toBe(true);
|
||||||
expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
|
expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
|
||||||
await toolchains.generateToolchainDefinition(
|
toolchains.generateToolchainDefinition(
|
||||||
originalFile,
|
originalFile,
|
||||||
jdkInfo.version,
|
jdkInfo.version,
|
||||||
jdkInfo.vendor,
|
jdkInfo.vendor,
|
||||||
@@ -231,7 +230,7 @@ describe('toolchains tests', () => {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
await toolchains.generateToolchainDefinition(
|
toolchains.generateToolchainDefinition(
|
||||||
originalFile,
|
originalFile,
|
||||||
jdkInfo.version,
|
jdkInfo.version,
|
||||||
jdkInfo.vendor,
|
jdkInfo.vendor,
|
||||||
@@ -307,7 +306,7 @@ describe('toolchains tests', () => {
|
|||||||
expect(fs.existsSync(m2Dir)).toBe(true);
|
expect(fs.existsSync(m2Dir)).toBe(true);
|
||||||
expect(fs.existsSync(toolchainsFile)).toBe(true);
|
expect(fs.existsSync(toolchainsFile)).toBe(true);
|
||||||
expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
|
expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
|
||||||
await toolchains.generateToolchainDefinition(
|
toolchains.generateToolchainDefinition(
|
||||||
originalFile,
|
originalFile,
|
||||||
jdkInfo.version,
|
jdkInfo.version,
|
||||||
jdkInfo.vendor,
|
jdkInfo.vendor,
|
||||||
@@ -316,7 +315,7 @@ describe('toolchains tests', () => {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
await toolchains.generateToolchainDefinition(
|
toolchains.generateToolchainDefinition(
|
||||||
originalFile,
|
originalFile,
|
||||||
jdkInfo.version,
|
jdkInfo.version,
|
||||||
jdkInfo.vendor,
|
jdkInfo.vendor,
|
||||||
@@ -384,7 +383,7 @@ describe('toolchains tests', () => {
|
|||||||
expect(fs.existsSync(m2Dir)).toBe(true);
|
expect(fs.existsSync(m2Dir)).toBe(true);
|
||||||
expect(fs.existsSync(toolchainsFile)).toBe(true);
|
expect(fs.existsSync(toolchainsFile)).toBe(true);
|
||||||
expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
|
expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
|
||||||
await toolchains.generateToolchainDefinition(
|
toolchains.generateToolchainDefinition(
|
||||||
originalFile,
|
originalFile,
|
||||||
jdkInfo.version,
|
jdkInfo.version,
|
||||||
jdkInfo.vendor,
|
jdkInfo.vendor,
|
||||||
@@ -393,7 +392,7 @@ describe('toolchains tests', () => {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
await toolchains.generateToolchainDefinition(
|
toolchains.generateToolchainDefinition(
|
||||||
originalFile,
|
originalFile,
|
||||||
jdkInfo.version,
|
jdkInfo.version,
|
||||||
jdkInfo.vendor,
|
jdkInfo.vendor,
|
||||||
@@ -454,7 +453,7 @@ describe('toolchains tests', () => {
|
|||||||
expect(fs.existsSync(m2Dir)).toBe(true);
|
expect(fs.existsSync(m2Dir)).toBe(true);
|
||||||
expect(fs.existsSync(toolchainsFile)).toBe(true);
|
expect(fs.existsSync(toolchainsFile)).toBe(true);
|
||||||
expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
|
expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
|
||||||
await toolchains.generateToolchainDefinition(
|
toolchains.generateToolchainDefinition(
|
||||||
originalFile,
|
originalFile,
|
||||||
jdkInfo.version,
|
jdkInfo.version,
|
||||||
jdkInfo.vendor,
|
jdkInfo.vendor,
|
||||||
@@ -463,7 +462,7 @@ describe('toolchains tests', () => {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
await toolchains.generateToolchainDefinition(
|
toolchains.generateToolchainDefinition(
|
||||||
originalFile,
|
originalFile,
|
||||||
jdkInfo.version,
|
jdkInfo.version,
|
||||||
jdkInfo.vendor,
|
jdkInfo.vendor,
|
||||||
@@ -546,7 +545,7 @@ describe('toolchains tests', () => {
|
|||||||
expect(fs.existsSync(m2Dir)).toBe(true);
|
expect(fs.existsSync(m2Dir)).toBe(true);
|
||||||
expect(fs.existsSync(toolchainsFile)).toBe(true);
|
expect(fs.existsSync(toolchainsFile)).toBe(true);
|
||||||
expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
|
expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
|
||||||
await toolchains.generateToolchainDefinition(
|
toolchains.generateToolchainDefinition(
|
||||||
originalFile,
|
originalFile,
|
||||||
jdkInfo.version,
|
jdkInfo.version,
|
||||||
jdkInfo.vendor,
|
jdkInfo.vendor,
|
||||||
@@ -555,7 +554,7 @@ describe('toolchains tests', () => {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
await toolchains.generateToolchainDefinition(
|
toolchains.generateToolchainDefinition(
|
||||||
originalFile,
|
originalFile,
|
||||||
jdkInfo.version,
|
jdkInfo.version,
|
||||||
jdkInfo.vendor,
|
jdkInfo.vendor,
|
||||||
@@ -605,7 +604,7 @@ describe('toolchains tests', () => {
|
|||||||
expect(fs.existsSync(m2Dir)).toBe(true);
|
expect(fs.existsSync(m2Dir)).toBe(true);
|
||||||
expect(fs.existsSync(toolchainsFile)).toBe(true);
|
expect(fs.existsSync(toolchainsFile)).toBe(true);
|
||||||
expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
|
expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
|
||||||
await toolchains.generateToolchainDefinition(
|
toolchains.generateToolchainDefinition(
|
||||||
originalFile,
|
originalFile,
|
||||||
jdkInfo.version,
|
jdkInfo.version,
|
||||||
jdkInfo.vendor,
|
jdkInfo.vendor,
|
||||||
@@ -614,7 +613,7 @@ describe('toolchains tests', () => {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
await toolchains.generateToolchainDefinition(
|
toolchains.generateToolchainDefinition(
|
||||||
originalFile,
|
originalFile,
|
||||||
jdkInfo.version,
|
jdkInfo.version,
|
||||||
jdkInfo.vendor,
|
jdkInfo.vendor,
|
||||||
@@ -663,7 +662,7 @@ describe('toolchains tests', () => {
|
|||||||
expect(fs.existsSync(m2Dir)).toBe(true);
|
expect(fs.existsSync(m2Dir)).toBe(true);
|
||||||
expect(fs.existsSync(toolchainsFile)).toBe(true);
|
expect(fs.existsSync(toolchainsFile)).toBe(true);
|
||||||
expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
|
expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
|
||||||
await toolchains.generateToolchainDefinition(
|
toolchains.generateToolchainDefinition(
|
||||||
originalFile,
|
originalFile,
|
||||||
jdkInfo.version,
|
jdkInfo.version,
|
||||||
jdkInfo.vendor,
|
jdkInfo.vendor,
|
||||||
@@ -672,7 +671,7 @@ describe('toolchains tests', () => {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
await toolchains.generateToolchainDefinition(
|
toolchains.generateToolchainDefinition(
|
||||||
originalFile,
|
originalFile,
|
||||||
jdkInfo.version,
|
jdkInfo.version,
|
||||||
jdkInfo.vendor,
|
jdkInfo.vendor,
|
||||||
@@ -746,7 +745,7 @@ describe('toolchains tests', () => {
|
|||||||
expect(fs.existsSync(m2Dir)).toBe(true);
|
expect(fs.existsSync(m2Dir)).toBe(true);
|
||||||
expect(fs.existsSync(toolchainsFile)).toBe(true);
|
expect(fs.existsSync(toolchainsFile)).toBe(true);
|
||||||
expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
|
expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
|
||||||
await toolchains.generateToolchainDefinition(
|
toolchains.generateToolchainDefinition(
|
||||||
originalFile,
|
originalFile,
|
||||||
jdkInfo.version,
|
jdkInfo.version,
|
||||||
jdkInfo.vendor,
|
jdkInfo.vendor,
|
||||||
@@ -755,7 +754,7 @@ describe('toolchains tests', () => {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
await toolchains.generateToolchainDefinition(
|
toolchains.generateToolchainDefinition(
|
||||||
originalFile,
|
originalFile,
|
||||||
jdkInfo.version,
|
jdkInfo.version,
|
||||||
jdkInfo.vendor,
|
jdkInfo.vendor,
|
||||||
@@ -825,7 +824,7 @@ describe('toolchains tests', () => {
|
|||||||
expect(fs.existsSync(m2Dir)).toBe(true);
|
expect(fs.existsSync(m2Dir)).toBe(true);
|
||||||
expect(fs.existsSync(toolchainsFile)).toBe(true);
|
expect(fs.existsSync(toolchainsFile)).toBe(true);
|
||||||
expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
|
expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
|
||||||
await toolchains.generateToolchainDefinition(
|
toolchains.generateToolchainDefinition(
|
||||||
originalFile,
|
originalFile,
|
||||||
jdkInfo.version,
|
jdkInfo.version,
|
||||||
jdkInfo.vendor,
|
jdkInfo.vendor,
|
||||||
@@ -834,7 +833,7 @@ describe('toolchains tests', () => {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
await toolchains.generateToolchainDefinition(
|
toolchains.generateToolchainDefinition(
|
||||||
originalFile,
|
originalFile,
|
||||||
jdkInfo.version,
|
jdkInfo.version,
|
||||||
jdkInfo.vendor,
|
jdkInfo.vendor,
|
||||||
@@ -889,7 +888,7 @@ describe('toolchains tests', () => {
|
|||||||
expect(updated).toContain(`<jdkHome>${jdkInfo.jdkHome}</jdkHome>`);
|
expect(updated).toContain(`<jdkHome>${jdkInfo.jdkHome}</jdkHome>`);
|
||||||
}, 100000);
|
}, 100000);
|
||||||
|
|
||||||
it('generates valid toolchains.xml with minimal configuration', async () => {
|
it('generates valid toolchains.xml with minimal configuration', () => {
|
||||||
const jdkInfo = {
|
const jdkInfo = {
|
||||||
version: 'JAVA_VERSION',
|
version: 'JAVA_VERSION',
|
||||||
vendor: 'JAVA_VENDOR',
|
vendor: 'JAVA_VENDOR',
|
||||||
@@ -915,7 +914,7 @@ describe('toolchains tests', () => {
|
|||||||
</toolchains>`;
|
</toolchains>`;
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
await toolchains.generateToolchainDefinition(
|
toolchains.generateToolchainDefinition(
|
||||||
'',
|
'',
|
||||||
jdkInfo.version,
|
jdkInfo.version,
|
||||||
jdkInfo.vendor,
|
jdkInfo.vendor,
|
||||||
@@ -925,29 +924,6 @@ describe('toolchains tests', () => {
|
|||||||
).toEqual(expectedToolchains);
|
).toEqual(expectedToolchains);
|
||||||
}, 100000);
|
}, 100000);
|
||||||
|
|
||||||
it('escapes new toolchains.xml values while preserving parsed semantics', () => {
|
|
||||||
const jdkInfo = {
|
|
||||||
version: `21&<>"'é`,
|
|
||||||
vendor: `Temurin&<>"'é`,
|
|
||||||
id: `temurin&<>"'é`,
|
|
||||||
jdkHome: `/opt/java&<>"'é`
|
|
||||||
};
|
|
||||||
|
|
||||||
const xml = toolchains.generateNewToolchainDefinition(
|
|
||||||
jdkInfo.version,
|
|
||||||
jdkInfo.vendor,
|
|
||||||
jdkInfo.id,
|
|
||||||
jdkInfo.jdkHome
|
|
||||||
);
|
|
||||||
const parsed = parseXmlObject(xml) as any;
|
|
||||||
|
|
||||||
expect(parsed.toolchains.toolchain[0].type).toBe('jdk');
|
|
||||||
expect(xmlElementText(xml, 'version')).toBe(jdkInfo.version);
|
|
||||||
expect(xmlElementText(xml, 'vendor')).toBe(jdkInfo.vendor);
|
|
||||||
expect(xmlElementText(xml, 'id')).toBe(jdkInfo.id);
|
|
||||||
expect(xmlElementText(xml, 'jdkHome')).toBe(jdkInfo.jdkHome);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('creates toolchains.xml with correct id when none is supplied', async () => {
|
it('creates toolchains.xml with correct id when none is supplied', async () => {
|
||||||
const version = '17';
|
const version = '17';
|
||||||
const distributionName = 'temurin';
|
const distributionName = 'temurin';
|
||||||
@@ -970,7 +946,7 @@ describe('toolchains tests', () => {
|
|||||||
expect(fs.existsSync(m2Dir)).toBe(true);
|
expect(fs.existsSync(m2Dir)).toBe(true);
|
||||||
expect(fs.existsSync(toolchainsFile)).toBe(true);
|
expect(fs.existsSync(toolchainsFile)).toBe(true);
|
||||||
expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
|
expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(
|
||||||
await toolchains.generateToolchainDefinition(
|
toolchains.generateToolchainDefinition(
|
||||||
'',
|
'',
|
||||||
version,
|
version,
|
||||||
distributionName,
|
distributionName,
|
||||||
@@ -980,75 +956,6 @@ describe('toolchains tests', () => {
|
|||||||
);
|
);
|
||||||
}, 100000);
|
}, 100000);
|
||||||
|
|
||||||
it('merges a second JDK into a toolchains.xml produced by the new-file fast path', async () => {
|
|
||||||
const firstJdk = {
|
|
||||||
version: '17',
|
|
||||||
vendor: 'temurin',
|
|
||||||
id: 'temurin_17',
|
|
||||||
jdkHome: '/opt/java/17'
|
|
||||||
};
|
|
||||||
const secondJdk = {
|
|
||||||
version: '21',
|
|
||||||
vendor: 'temurin',
|
|
||||||
id: 'temurin_21',
|
|
||||||
jdkHome: '/opt/java/21'
|
|
||||||
};
|
|
||||||
|
|
||||||
const firstToolchains = await toolchains.generateToolchainDefinition(
|
|
||||||
'',
|
|
||||||
firstJdk.version,
|
|
||||||
firstJdk.vendor,
|
|
||||||
firstJdk.id,
|
|
||||||
firstJdk.jdkHome
|
|
||||||
);
|
|
||||||
const mergedToolchains = await toolchains.generateToolchainDefinition(
|
|
||||||
firstToolchains,
|
|
||||||
secondJdk.version,
|
|
||||||
secondJdk.vendor,
|
|
||||||
secondJdk.id,
|
|
||||||
secondJdk.jdkHome
|
|
||||||
);
|
|
||||||
|
|
||||||
for (const jdk of [firstJdk, secondJdk]) {
|
|
||||||
expect(mergedToolchains).toContain(`<id>${jdk.id}</id>`);
|
|
||||||
expect(mergedToolchains).toContain(`<jdkHome>${jdk.jdkHome}</jdkHome>`);
|
|
||||||
}
|
|
||||||
expect((mergedToolchains.match(/<toolchain>/g) || []).length).toBe(2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('preserves custom attributes and elements when merging existing toolchains.xml', async () => {
|
|
||||||
const originalFile = `<toolchains xmlns="http://maven.apache.org/TOOLCHAINS/1.0.0" customRoot="A & B">
|
|
||||||
<toolchain customAttr="custom & value">
|
|
||||||
<type>foo</type>
|
|
||||||
<provides customProvides="yes">
|
|
||||||
<custom attr="custom " attr">baz & qux</custom>
|
|
||||||
</provides>
|
|
||||||
<configuration>
|
|
||||||
<fooHome>/usr/local/bin/foo</fooHome>
|
|
||||||
</configuration>
|
|
||||||
</toolchain>
|
|
||||||
</toolchains>`;
|
|
||||||
|
|
||||||
const mergedToolchains = await toolchains.generateToolchainDefinition(
|
|
||||||
originalFile,
|
|
||||||
'21&<>"\'',
|
|
||||||
'Temurin&<>"\'',
|
|
||||||
'temurin_21&<>"\'',
|
|
||||||
'/opt/java/21&<>"\''
|
|
||||||
);
|
|
||||||
const parsed = parseXmlObject(mergedToolchains) as any;
|
|
||||||
const merged = parsed.toolchains.toolchain;
|
|
||||||
|
|
||||||
expect(parsed.toolchains['@customRoot']).toBe('A & B');
|
|
||||||
expect(merged).toHaveLength(2);
|
|
||||||
expect(merged[0].provides.id).toBe('temurin_21&<>"\'');
|
|
||||||
expect(merged[0].configuration.jdkHome).toBe('/opt/java/21&<>"\'');
|
|
||||||
expect(merged[1]['@customAttr']).toBe('custom & value');
|
|
||||||
expect(merged[1].provides['@customProvides']).toBe('yes');
|
|
||||||
expect(merged[1].provides.custom['#text']).toBe('baz & qux');
|
|
||||||
expect(merged[1].provides.custom['@attr']).toBe('custom " attr');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('preserves toolchains from previous executions across multiple setup-java runs', async () => {
|
it('preserves toolchains from previous executions across multiple setup-java runs', async () => {
|
||||||
// Regression test for https://github.com/actions/setup-java/issues/1099
|
// 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
|
// Running setup-java several times in the same job (e.g. multiple steps / multiple
|
||||||
@@ -1100,87 +1007,3 @@ describe('toolchains tests', () => {
|
|||||||
expect((contents.match(/<toolchain>/g) || []).length).toBe(runs.length);
|
expect((contents.match(/<toolchain>/g) || []).length).toBe(runs.length);
|
||||||
}, 100000);
|
}, 100000);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('validateToolchainIds', () => {
|
|
||||||
it.each([
|
|
||||||
{
|
|
||||||
name: 'uses generated IDs when no custom IDs are supplied',
|
|
||||||
versions: ['17', '21'],
|
|
||||||
versionFile: '',
|
|
||||||
toolchainIds: []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'accepts one custom ID for a single Java version',
|
|
||||||
versions: ['21'],
|
|
||||||
versionFile: '',
|
|
||||||
toolchainIds: ['custom-21']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'accepts one custom ID per Java version',
|
|
||||||
versions: ['17', '21'],
|
|
||||||
versionFile: '',
|
|
||||||
toolchainIds: ['custom-17', 'custom-21']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'accepts one custom ID with java-version-file',
|
|
||||||
versions: [],
|
|
||||||
versionFile: '.java-version',
|
|
||||||
toolchainIds: ['custom-file-version']
|
|
||||||
}
|
|
||||||
])('$name', ({versions, versionFile, toolchainIds}) => {
|
|
||||||
expect(() =>
|
|
||||||
toolchains.validateToolchainIds(versions, versionFile, toolchainIds)
|
|
||||||
).not.toThrow();
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each([
|
|
||||||
{
|
|
||||||
name: 'rejects fewer IDs than Java versions',
|
|
||||||
versions: ['17', '21'],
|
|
||||||
versionFile: '',
|
|
||||||
toolchainIds: ['custom-17'],
|
|
||||||
expectedMessage:
|
|
||||||
'The number of Maven toolchain IDs (1) must match the number of Java versions (2)'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'rejects extra IDs for a single Java version',
|
|
||||||
versions: ['21'],
|
|
||||||
versionFile: '',
|
|
||||||
toolchainIds: ['custom-21', 'custom-extra'],
|
|
||||||
expectedMessage:
|
|
||||||
'The number of Maven toolchain IDs (2) must match the number of Java versions (1)'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'rejects extra IDs with java-version-file',
|
|
||||||
versions: [],
|
|
||||||
versionFile: '.java-version',
|
|
||||||
toolchainIds: ['custom-file-version', 'custom-extra'],
|
|
||||||
expectedMessage:
|
|
||||||
'The number of Maven toolchain IDs (2) must match the number of Java versions (1)'
|
|
||||||
}
|
|
||||||
])('$name', ({versions, versionFile, toolchainIds, expectedMessage}) => {
|
|
||||||
expect(() =>
|
|
||||||
toolchains.validateToolchainIds(versions, versionFile, toolchainIds)
|
|
||||||
).toThrow(expectedMessage);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function xmlElementText(xml: string, tagName: string): string {
|
|
||||||
const match = new RegExp(`<${tagName}>([\\s\\S]*?)</${tagName}>`).exec(xml);
|
|
||||||
expect(match).not.toBeNull();
|
|
||||||
return (parseXmlObject(`<value>${match?.[1]}</value>`) as {value: string})
|
|
||||||
.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseXmlObject(xml: string): unknown {
|
|
||||||
const parser = new XMLParser({
|
|
||||||
ignoreAttributes: false,
|
|
||||||
attributeNamePrefix: '@',
|
|
||||||
textNodeName: '#text',
|
|
||||||
parseAttributeValue: false,
|
|
||||||
parseTagValue: false,
|
|
||||||
trimValues: true,
|
|
||||||
isArray: tagName => tagName === 'toolchain'
|
|
||||||
});
|
|
||||||
return parser.parse(xml);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,412 +0,0 @@
|
|||||||
import {jest, describe, it, expect, beforeEach, afterEach} from '@jest/globals';
|
|
||||||
import * as fs from 'fs';
|
|
||||||
import * as os from 'os';
|
|
||||||
import * as path from 'path';
|
|
||||||
|
|
||||||
jest.unstable_mockModule('@actions/core', () => ({
|
|
||||||
debug: jest.fn(),
|
|
||||||
info: jest.fn(),
|
|
||||||
warning: jest.fn(),
|
|
||||||
error: jest.fn(),
|
|
||||||
getInput: jest.fn(() => ''),
|
|
||||||
isDebug: jest.fn(() => false),
|
|
||||||
addPath: jest.fn(),
|
|
||||||
exportVariable: jest.fn(),
|
|
||||||
setOutput: jest.fn()
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.unstable_mockModule('@actions/tool-cache', () => ({
|
|
||||||
cacheDir: jest.fn(),
|
|
||||||
extractTar: jest.fn(),
|
|
||||||
extractZip: jest.fn(),
|
|
||||||
extract7z: jest.fn()
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.unstable_mockModule('@actions/exec', () => ({
|
|
||||||
exec: jest.fn()
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.unstable_mockModule('@actions/io', () => ({
|
|
||||||
which: jest.fn(),
|
|
||||||
rmRF: jest.fn(async (target: string) =>
|
|
||||||
fs.rmSync(target, {recursive: true, force: true})
|
|
||||||
),
|
|
||||||
mkdirP: jest.fn(async (target: string) =>
|
|
||||||
fs.mkdirSync(target, {recursive: true})
|
|
||||||
)
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.unstable_mockModule('@actions/http-client', () => ({
|
|
||||||
HttpClient: jest.fn(),
|
|
||||||
HttpClientError: class HttpClientError extends Error {}
|
|
||||||
}));
|
|
||||||
|
|
||||||
const tc = await import('@actions/tool-cache');
|
|
||||||
const exec = await import('@actions/exec');
|
|
||||||
const io = await import('@actions/io');
|
|
||||||
const {cacheJdkDir, extractJdkFile} = await import('../src/util.js');
|
|
||||||
|
|
||||||
const originalToolCache = process.env['RUNNER_TOOL_CACHE'];
|
|
||||||
const originalTemp = process.env['RUNNER_TEMP'];
|
|
||||||
const originalPlatform = process.platform;
|
|
||||||
|
|
||||||
let workDir: string;
|
|
||||||
|
|
||||||
function setPlatform(platform: NodeJS.Platform) {
|
|
||||||
Object.defineProperty(process, 'platform', {
|
|
||||||
value: platform,
|
|
||||||
configurable: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
workDir = fs.mkdtempSync(path.join(os.tmpdir(), 'setup-java-util-'));
|
|
||||||
process.env['RUNNER_TOOL_CACHE'] = path.join(workDir, 'toolcache');
|
|
||||||
process.env['RUNNER_TEMP'] = path.join(workDir, 'temp');
|
|
||||||
fs.mkdirSync(process.env['RUNNER_TEMP'], {recursive: true});
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
jest.clearAllMocks();
|
|
||||||
setPlatform(originalPlatform);
|
|
||||||
while (lockedDirs.length) {
|
|
||||||
fs.chmodSync(lockedDirs.pop()!, 0o755);
|
|
||||||
}
|
|
||||||
fs.rmSync(workDir, {recursive: true, force: true});
|
|
||||||
if (originalToolCache === undefined) {
|
|
||||||
delete process.env['RUNNER_TOOL_CACHE'];
|
|
||||||
} else {
|
|
||||||
process.env['RUNNER_TOOL_CACHE'] = originalToolCache;
|
|
||||||
}
|
|
||||||
if (originalTemp === undefined) {
|
|
||||||
delete process.env['RUNNER_TEMP'];
|
|
||||||
} else {
|
|
||||||
process.env['RUNNER_TEMP'] = originalTemp;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function createJdkDir(name = 'jdk-source'): string {
|
|
||||||
const sourceDir = path.join(workDir, name);
|
|
||||||
fs.mkdirSync(path.join(sourceDir, 'bin'), {recursive: true});
|
|
||||||
fs.writeFileSync(path.join(sourceDir, 'bin', 'java'), 'binary');
|
|
||||||
fs.writeFileSync(path.join(sourceDir, 'release'), 'JAVA_VERSION="17"');
|
|
||||||
|
|
||||||
return sourceDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
// A rename needs write permission on the source's parent directory, so making
|
|
||||||
// that parent read-only is a portable way to force the same failure a
|
|
||||||
// cross-device tool-cache (EXDEV) or a Windows anti-virus handle (EPERM) would.
|
|
||||||
// Root ignores the permission bits, so those tests are skipped there.
|
|
||||||
const canForceRenameFailure =
|
|
||||||
process.platform !== 'win32' &&
|
|
||||||
typeof process.getuid === 'function' &&
|
|
||||||
process.getuid() !== 0;
|
|
||||||
const itUnlessRoot = canForceRenameFailure ? it : it.skip;
|
|
||||||
const lockedDirs: string[] = [];
|
|
||||||
|
|
||||||
function createUnrenameableJdkDir(): string {
|
|
||||||
const parent = path.join(workDir, 'locked');
|
|
||||||
fs.mkdirSync(parent, {recursive: true});
|
|
||||||
const sourceDir = path.join(parent, 'jdk-source');
|
|
||||||
fs.mkdirSync(path.join(sourceDir, 'bin'), {recursive: true});
|
|
||||||
fs.writeFileSync(path.join(sourceDir, 'bin', 'java'), 'binary');
|
|
||||||
fs.chmodSync(parent, 0o555);
|
|
||||||
lockedDirs.push(parent);
|
|
||||||
|
|
||||||
return sourceDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('cacheJdkDir', () => {
|
|
||||||
it('moves the JDK into the tool-cache instead of copying it', async () => {
|
|
||||||
const sourceDir = createJdkDir();
|
|
||||||
|
|
||||||
const javaPath = await cacheJdkDir(
|
|
||||||
sourceDir,
|
|
||||||
'Java_temurin_jdk',
|
|
||||||
'17.0.1',
|
|
||||||
'x64'
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(javaPath).toBe(
|
|
||||||
path.join(
|
|
||||||
process.env['RUNNER_TOOL_CACHE']!,
|
|
||||||
'Java_temurin_jdk',
|
|
||||||
'17.0.1',
|
|
||||||
'x64'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
expect(fs.existsSync(path.join(javaPath, 'bin', 'java'))).toBe(true);
|
|
||||||
expect(fs.existsSync(path.join(javaPath, 'release'))).toBe(true);
|
|
||||||
// the source is moved, not copied, so it no longer exists
|
|
||||||
expect(fs.existsSync(sourceDir)).toBe(false);
|
|
||||||
expect(tc.cacheDir).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('writes the .complete marker expected by the tool-cache', async () => {
|
|
||||||
const javaPath = await cacheJdkDir(
|
|
||||||
createJdkDir(),
|
|
||||||
'Java_temurin_jdk',
|
|
||||||
'17.0.1',
|
|
||||||
'x64'
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(fs.existsSync(`${javaPath}.complete`)).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('replaces an existing tool-cache entry', async () => {
|
|
||||||
const destPath = path.join(
|
|
||||||
process.env['RUNNER_TOOL_CACHE']!,
|
|
||||||
'Java_temurin_jdk',
|
|
||||||
'17.0.1',
|
|
||||||
'x64'
|
|
||||||
);
|
|
||||||
fs.mkdirSync(destPath, {recursive: true});
|
|
||||||
fs.writeFileSync(path.join(destPath, 'stale'), 'stale');
|
|
||||||
|
|
||||||
const javaPath = await cacheJdkDir(
|
|
||||||
createJdkDir(),
|
|
||||||
'Java_temurin_jdk',
|
|
||||||
'17.0.1',
|
|
||||||
'x64'
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(fs.existsSync(path.join(javaPath, 'stale'))).toBe(false);
|
|
||||||
expect(fs.existsSync(path.join(javaPath, 'bin', 'java'))).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('normalizes the version the same way as tc.cacheDir', async () => {
|
|
||||||
const javaPath = await cacheJdkDir(
|
|
||||||
createJdkDir(),
|
|
||||||
'Java_temurin_jdk',
|
|
||||||
'v17.0.1',
|
|
||||||
'x64'
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(path.basename(path.dirname(javaPath))).toBe('17.0.1');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('keeps unparseable versions as-is', async () => {
|
|
||||||
const javaPath = await cacheJdkDir(
|
|
||||||
createJdkDir(),
|
|
||||||
'Java_temurin_jdk',
|
|
||||||
'17.0.1-ea.3',
|
|
||||||
'x64'
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(path.basename(path.dirname(javaPath))).toBe('17.0.1-ea.3');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('falls back to tc.cacheDir when the move fails', async () => {
|
|
||||||
(tc.cacheDir as jest.Mock).mockResolvedValue('/fallback/path' as never);
|
|
||||||
const missingDir = path.join(workDir, 'does-not-exist');
|
|
||||||
|
|
||||||
const javaPath = await cacheJdkDir(
|
|
||||||
missingDir,
|
|
||||||
'Java_temurin_jdk',
|
|
||||||
'17.0.1',
|
|
||||||
'x64'
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(javaPath).toBe('/fallback/path');
|
|
||||||
expect(tc.cacheDir).toHaveBeenCalledWith(
|
|
||||||
missingDir,
|
|
||||||
'Java_temurin_jdk',
|
|
||||||
'17.0.1',
|
|
||||||
'x64'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
itUnlessRoot(
|
|
||||||
'falls back to tc.cacheDir when the rename itself fails',
|
|
||||||
async () => {
|
|
||||||
const sourceDir = createUnrenameableJdkDir();
|
|
||||||
(tc.cacheDir as jest.Mock).mockResolvedValue('/fallback/path' as never);
|
|
||||||
|
|
||||||
await expect(
|
|
||||||
cacheJdkDir(sourceDir, 'Java_temurin_jdk', '17.0.1', 'x64')
|
|
||||||
).resolves.toBe('/fallback/path');
|
|
||||||
// the source must survive so the copy-based fallback can still read it
|
|
||||||
expect(fs.existsSync(path.join(sourceDir, 'bin', 'java'))).toBe(true);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
itUnlessRoot(
|
|
||||||
'does not leave a .complete marker behind when the rename fails',
|
|
||||||
async () => {
|
|
||||||
const destPath = path.join(
|
|
||||||
process.env['RUNNER_TOOL_CACHE']!,
|
|
||||||
'Java_temurin_jdk',
|
|
||||||
'17.0.1',
|
|
||||||
'x64'
|
|
||||||
);
|
|
||||||
fs.mkdirSync(destPath, {recursive: true});
|
|
||||||
fs.writeFileSync(`${destPath}.complete`, '');
|
|
||||||
(tc.cacheDir as jest.Mock).mockResolvedValue('/fallback/path' as never);
|
|
||||||
|
|
||||||
await cacheJdkDir(
|
|
||||||
createUnrenameableJdkDir(),
|
|
||||||
'Java_temurin_jdk',
|
|
||||||
'17.0.1',
|
|
||||||
'x64'
|
|
||||||
);
|
|
||||||
|
|
||||||
// a stale marker without a matching installation would make the
|
|
||||||
// tool-cache resolve a directory that is no longer there
|
|
||||||
expect(fs.existsSync(`${destPath}.complete`)).toBe(false);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
it('falls back to tc.cacheDir for symlinked sources', async () => {
|
|
||||||
const realDir = createJdkDir('real-jdk');
|
|
||||||
const linkDir = path.join(workDir, 'linked-jdk');
|
|
||||||
fs.symlinkSync(realDir, linkDir, 'dir');
|
|
||||||
(tc.cacheDir as jest.Mock).mockResolvedValue('/fallback/path' as never);
|
|
||||||
|
|
||||||
await expect(
|
|
||||||
cacheJdkDir(linkDir, 'Java_temurin_jdk', '17.0.1', 'x64')
|
|
||||||
).resolves.toBe('/fallback/path');
|
|
||||||
// moving the symlink itself would leave a dangling tool-cache entry
|
|
||||||
expect(fs.lstatSync(linkDir).isSymbolicLink()).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('defaults the architecture the same way as tc.cacheDir', async () => {
|
|
||||||
const javaPath = await cacheJdkDir(
|
|
||||||
createJdkDir(),
|
|
||||||
'Java_temurin_jdk',
|
|
||||||
'17.0.1',
|
|
||||||
''
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(javaPath).toBe(
|
|
||||||
path.join(
|
|
||||||
process.env['RUNNER_TOOL_CACHE']!,
|
|
||||||
'Java_temurin_jdk',
|
|
||||||
'17.0.1',
|
|
||||||
os.arch()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('falls back to tc.cacheDir when the tool-cache location is unknown', async () => {
|
|
||||||
delete process.env['RUNNER_TOOL_CACHE'];
|
|
||||||
(tc.cacheDir as jest.Mock).mockResolvedValue('/fallback/path' as never);
|
|
||||||
|
|
||||||
await expect(
|
|
||||||
cacheJdkDir(createJdkDir(), 'Java_temurin_jdk', '17.0.1', 'x64')
|
|
||||||
).resolves.toBe('/fallback/path');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('extractJdkFile', () => {
|
|
||||||
it('uses pigz for tarballs when it is available', async () => {
|
|
||||||
(io.which as jest.Mock).mockResolvedValue('/usr/bin/pigz' as never);
|
|
||||||
(tc.extractTar as jest.Mock).mockResolvedValue('/extracted' as never);
|
|
||||||
|
|
||||||
await expect(extractJdkFile('/tmp/jdk.tar.gz')).resolves.toBe('/extracted');
|
|
||||||
expect(tc.extractTar).toHaveBeenCalledWith(
|
|
||||||
'/tmp/jdk.tar.gz',
|
|
||||||
expect.stringContaining(process.env['RUNNER_TEMP']!),
|
|
||||||
['--use-compress-program', '/usr/bin/pigz -d', '-x']
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('falls back to gzip when pigz is not installed', async () => {
|
|
||||||
(io.which as jest.Mock).mockResolvedValue('' as never);
|
|
||||||
(tc.extractTar as jest.Mock).mockResolvedValue('/extracted' as never);
|
|
||||||
|
|
||||||
await expect(extractJdkFile('/tmp/jdk.tar.gz')).resolves.toBe('/extracted');
|
|
||||||
expect(tc.extractTar).toHaveBeenCalledWith('/tmp/jdk.tar.gz');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('falls back to gzip when pigz extraction fails', async () => {
|
|
||||||
(io.which as jest.Mock).mockResolvedValue('/usr/bin/pigz' as never);
|
|
||||||
(tc.extractTar as jest.Mock)
|
|
||||||
.mockRejectedValueOnce(new Error('pigz exploded') as never)
|
|
||||||
.mockResolvedValue('/extracted' as never);
|
|
||||||
|
|
||||||
await expect(extractJdkFile('/tmp/jdk.tar.gz')).resolves.toBe('/extracted');
|
|
||||||
expect(tc.extractTar).toHaveBeenNthCalledWith(2, '/tmp/jdk.tar.gz');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('cleans up the abandoned folder when pigz extraction fails', async () => {
|
|
||||||
(io.which as jest.Mock).mockResolvedValue('/usr/bin/pigz' as never);
|
|
||||||
let pigzDest: string | undefined;
|
|
||||||
(tc.extractTar as jest.Mock)
|
|
||||||
.mockImplementationOnce((...args: unknown[]) => {
|
|
||||||
pigzDest = args[1] as string;
|
|
||||||
throw new Error('pigz exploded');
|
|
||||||
})
|
|
||||||
.mockResolvedValue('/extracted' as never);
|
|
||||||
|
|
||||||
await extractJdkFile('/tmp/jdk.tar.gz');
|
|
||||||
|
|
||||||
expect(pigzDest).toBeDefined();
|
|
||||||
expect(fs.existsSync(pigzDest!)).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('ignores pigz when its path contains whitespace', async () => {
|
|
||||||
(io.which as jest.Mock).mockResolvedValue(
|
|
||||||
'C:\\Program Files\\pigz.exe' as never
|
|
||||||
);
|
|
||||||
(tc.extractTar as jest.Mock).mockResolvedValue('/extracted' as never);
|
|
||||||
|
|
||||||
await extractJdkFile('/tmp/jdk.tar.gz');
|
|
||||||
|
|
||||||
// tar word-splits --use-compress-program, so a spaced path is unusable
|
|
||||||
expect(tc.extractTar).toHaveBeenCalledWith('/tmp/jdk.tar.gz');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('leaves uncompressed tarballs on the default extraction path', async () => {
|
|
||||||
(tc.extractTar as jest.Mock).mockResolvedValue('/extracted' as never);
|
|
||||||
|
|
||||||
await expect(extractJdkFile('/tmp/jdk.tar')).resolves.toBe('/extracted');
|
|
||||||
expect(tc.extractTar).toHaveBeenCalledWith('/tmp/jdk.tar');
|
|
||||||
expect(io.which).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('uses the bundled tar.exe for zip archives on Windows', async () => {
|
|
||||||
setPlatform('win32');
|
|
||||||
const systemRoot = path.join(workDir, 'Windows');
|
|
||||||
fs.mkdirSync(path.join(systemRoot, 'System32'), {recursive: true});
|
|
||||||
const systemTar = path.join(systemRoot, 'System32', 'tar.exe');
|
|
||||||
fs.writeFileSync(systemTar, '');
|
|
||||||
process.env['SystemRoot'] = systemRoot;
|
|
||||||
|
|
||||||
const javaPath = await extractJdkFile('/tmp/jdk.zip');
|
|
||||||
|
|
||||||
expect(tc.extractZip).not.toHaveBeenCalled();
|
|
||||||
expect(exec.exec).toHaveBeenCalledWith(
|
|
||||||
`"${systemTar}"`,
|
|
||||||
['-xf', '/tmp/jdk.zip', '-C', javaPath],
|
|
||||||
{silent: true}
|
|
||||||
);
|
|
||||||
expect(fs.existsSync(javaPath)).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('falls back to tc.extractZip when tar.exe fails', async () => {
|
|
||||||
setPlatform('win32');
|
|
||||||
const systemRoot = path.join(workDir, 'Windows');
|
|
||||||
fs.mkdirSync(path.join(systemRoot, 'System32'), {recursive: true});
|
|
||||||
fs.writeFileSync(path.join(systemRoot, 'System32', 'tar.exe'), '');
|
|
||||||
process.env['SystemRoot'] = systemRoot;
|
|
||||||
let tarDest: string | undefined;
|
|
||||||
(exec.exec as jest.Mock).mockImplementation((...args: unknown[]) => {
|
|
||||||
tarDest = (args[1] as string[])[3];
|
|
||||||
throw new Error('boom');
|
|
||||||
});
|
|
||||||
(tc.extractZip as jest.Mock).mockResolvedValue('/extracted' as never);
|
|
||||||
|
|
||||||
await expect(extractJdkFile('/tmp/jdk.zip')).resolves.toBe('/extracted');
|
|
||||||
expect(tarDest).toBeDefined();
|
|
||||||
expect(fs.existsSync(tarDest!)).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('uses tc.extractZip on non-Windows platforms', async () => {
|
|
||||||
setPlatform('linux');
|
|
||||||
(tc.extractZip as jest.Mock).mockResolvedValue('/extracted' as never);
|
|
||||||
|
|
||||||
await expect(extractJdkFile('/tmp/jdk.zip')).resolves.toBe('/extracted');
|
|
||||||
expect(exec.exec).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
+54
-97
@@ -13,6 +13,13 @@ import * as path from 'path';
|
|||||||
|
|
||||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
|
// Mock @actions/cache
|
||||||
|
jest.unstable_mockModule('@actions/cache', () => ({
|
||||||
|
isFeatureAvailable: jest.fn(),
|
||||||
|
saveCache: jest.fn(),
|
||||||
|
restoreCache: jest.fn()
|
||||||
|
}));
|
||||||
|
|
||||||
// Mock @actions/core
|
// Mock @actions/core
|
||||||
jest.unstable_mockModule('@actions/core', () => ({
|
jest.unstable_mockModule('@actions/core', () => ({
|
||||||
getInput: jest.fn(),
|
getInput: jest.fn(),
|
||||||
@@ -39,6 +46,7 @@ jest.unstable_mockModule('@actions/core', () => ({
|
|||||||
toPosixPath: jest.fn((p: string) => p)
|
toPosixPath: jest.fn((p: string) => p)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const cache = await import('@actions/cache');
|
||||||
const core = await import('@actions/core');
|
const core = await import('@actions/core');
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -46,107 +54,12 @@ const {
|
|||||||
getNextPageUrlFromLinkHeader,
|
getNextPageUrlFromLinkHeader,
|
||||||
getVersionFromFileContent,
|
getVersionFromFileContent,
|
||||||
isVersionSatisfies,
|
isVersionSatisfies,
|
||||||
|
isCacheFeatureAvailable,
|
||||||
isGhes,
|
isGhes,
|
||||||
validatePaginationUrl,
|
validatePaginationUrl,
|
||||||
getLatestMajorVersion,
|
getLatestMajorVersion
|
||||||
getBooleanInput,
|
|
||||||
isJdkCacheEnabled
|
|
||||||
} = await import('../src/util.js');
|
} = await import('../src/util.js');
|
||||||
|
|
||||||
describe('getBooleanInput', () => {
|
|
||||||
let inputs: Record<string, string>;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
inputs = {};
|
|
||||||
(core.getInput as jest.Mock).mockImplementation(
|
|
||||||
(name: string) => inputs[name] ?? ''
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
jest.resetAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each([
|
|
||||||
['true', true],
|
|
||||||
['TRUE', true],
|
|
||||||
['TrUe', true],
|
|
||||||
[' true ', true],
|
|
||||||
['false', false],
|
|
||||||
['FALSE', false],
|
|
||||||
['FaLsE', false],
|
|
||||||
[' false ', false]
|
|
||||||
])('parses %j as %s', (value: string, expected: boolean) => {
|
|
||||||
inputs['boolean-input'] = value;
|
|
||||||
|
|
||||||
expect(getBooleanInput('boolean-input')).toBe(expected);
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each([
|
|
||||||
[undefined, false],
|
|
||||||
[false, false],
|
|
||||||
[true, true]
|
|
||||||
])(
|
|
||||||
'uses the configured default %s when the input is omitted',
|
|
||||||
(defaultValue: boolean | undefined, expected: boolean) => {
|
|
||||||
expect(getBooleanInput('boolean-input', defaultValue)).toBe(expected);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
it('uses the configured default for a whitespace-only input', () => {
|
|
||||||
inputs['boolean-input'] = ' ';
|
|
||||||
|
|
||||||
expect(getBooleanInput('boolean-input', true)).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each([
|
|
||||||
'check-latest',
|
|
||||||
'force-download',
|
|
||||||
'set-default',
|
|
||||||
'verify-signature',
|
|
||||||
'overwrite-settings',
|
|
||||||
'show-download-progress',
|
|
||||||
'problem-matcher'
|
|
||||||
])('rejects an invalid value for %s', inputName => {
|
|
||||||
inputs[inputName] = 'ture';
|
|
||||||
|
|
||||||
expect(() => getBooleanInput(inputName)).toThrow(
|
|
||||||
`Invalid value 'ture' for boolean input '${inputName}'. Expected 'true' or 'false'.`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('isJdkCacheEnabled', () => {
|
|
||||||
let inputs: Record<string, string>;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
inputs = {};
|
|
||||||
(core.getInput as jest.Mock).mockImplementation(
|
|
||||||
(name: string) => inputs[name] ?? ''
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
jest.resetAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each([
|
|
||||||
['', '', false],
|
|
||||||
['', 'true', true],
|
|
||||||
['', 'false', false],
|
|
||||||
['maven', '', true],
|
|
||||||
['maven', 'true', true],
|
|
||||||
['maven', 'false', false]
|
|
||||||
])(
|
|
||||||
'resolves cache=%j and cache-jdk=%j to %s',
|
|
||||||
(cache, cacheJdk, expected) => {
|
|
||||||
inputs['cache-jdk'] = cacheJdk;
|
|
||||||
|
|
||||||
expect(isJdkCacheEnabled(cache)).toBe(expected);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('isVersionSatisfies', () => {
|
describe('isVersionSatisfies', () => {
|
||||||
it.each([
|
it.each([
|
||||||
['x', '11.0.0', true],
|
['x', '11.0.0', true],
|
||||||
@@ -175,6 +88,50 @@ describe('isVersionSatisfies', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('isCacheFeatureAvailable', () => {
|
||||||
|
it('isCacheFeatureAvailable disabled on GHES', () => {
|
||||||
|
(cache.isFeatureAvailable as jest.Mock<any>).mockImplementation(
|
||||||
|
() => false
|
||||||
|
);
|
||||||
|
const infoMock = core.warning as jest.Mock;
|
||||||
|
const message =
|
||||||
|
'Caching is only supported on GHES version >= 3.5. If you are on a version >= 3.5, please check with your GHES admin if the Actions cache service is enabled or not.';
|
||||||
|
try {
|
||||||
|
process.env['GITHUB_SERVER_URL'] = 'http://example.com';
|
||||||
|
expect(isCacheFeatureAvailable()).toBeFalsy();
|
||||||
|
expect(infoMock).toHaveBeenCalledWith(message);
|
||||||
|
} finally {
|
||||||
|
delete process.env['GITHUB_SERVER_URL'];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('isCacheFeatureAvailable disabled on dotcom', () => {
|
||||||
|
(cache.isFeatureAvailable as jest.Mock<any>).mockImplementation(
|
||||||
|
() => false
|
||||||
|
);
|
||||||
|
const infoMock = core.warning as jest.Mock;
|
||||||
|
const message =
|
||||||
|
'The runner was not able to contact the cache service. Caching will be skipped';
|
||||||
|
try {
|
||||||
|
process.env['GITHUB_SERVER_URL'] = 'http://github.com';
|
||||||
|
expect(isCacheFeatureAvailable()).toBe(false);
|
||||||
|
expect(infoMock).toHaveBeenCalledWith(message);
|
||||||
|
} finally {
|
||||||
|
delete process.env['GITHUB_SERVER_URL'];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('isCacheFeatureAvailable is enabled', () => {
|
||||||
|
(cache.isFeatureAvailable as jest.Mock<any>).mockImplementation(() => true);
|
||||||
|
expect(isCacheFeatureAvailable()).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.resetAllMocks();
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('convertVersionToSemver', () => {
|
describe('convertVersionToSemver', () => {
|
||||||
it.each([
|
it.each([
|
||||||
['12', '12'],
|
['12', '12'],
|
||||||
|
|||||||
+8
-33
@@ -13,11 +13,11 @@ inputs:
|
|||||||
description: 'Java distribution. See the list of supported distributions in README file. This input is required except when java-version-file points to .sdkmanrc with a recognized distribution suffix (e.g., java=21.0.5-tem).'
|
description: 'Java distribution. See the list of supported distributions in README file. This input is required except when java-version-file points to .sdkmanrc with a recognized distribution suffix (e.g., java=21.0.5-tem).'
|
||||||
required: false
|
required: false
|
||||||
java-package:
|
java-package:
|
||||||
description: 'The package type (`jdk`, `jre`, `jdk+fx`, `jre+fx`, `jdk+crac`, `jre+crac`, `jdk+jmods`, `jdk+jcef`, `jre+jcef`, `jdk+ft`, or `jre+ft`). Supported values vary by distribution.'
|
description: 'The package type (jdk, jre, jdk+fx, jre+fx, jdk+crac, jre+crac)'
|
||||||
required: false
|
required: false
|
||||||
default: 'jdk'
|
default: 'jdk'
|
||||||
architecture:
|
architecture:
|
||||||
description: "The architecture of the package (`x86`, `x64`, `armv7`, `aarch64`, `ppc64le`, `ppc64`, or `s390x`). Aliases `ia32`, `amd64`, `arm`, and `arm64` are normalized to `x86`, `x64`, `armv7`, and `aarch64`. Supported values vary by distribution and operating system. Defaults to the action runner's architecture."
|
description: "The architecture of the package (defaults to the action runner's architecture)"
|
||||||
required: false
|
required: false
|
||||||
jdk-file:
|
jdk-file:
|
||||||
description: 'Path to where the compressed JDK is located'
|
description: 'Path to where the compressed JDK is located'
|
||||||
@@ -30,10 +30,6 @@ inputs:
|
|||||||
description: 'Set this option if you want the action to check for the latest available version that satisfies the version spec'
|
description: 'Set this option if you want the action to check for the latest available version that satisfies the version spec'
|
||||||
required: false
|
required: false
|
||||||
default: false
|
default: false
|
||||||
force-download:
|
|
||||||
description: 'Set this option to always download Java and replace any matching version in the tool cache'
|
|
||||||
required: false
|
|
||||||
default: false
|
|
||||||
set-default:
|
set-default:
|
||||||
description: 'Set this option to false if you want to install a JDK but not make it the default. When false, JAVA_HOME and PATH are not updated, but JAVA_HOME_<major>_<arch> is still set.'
|
description: 'Set this option to false if you want to install a JDK but not make it the default. When false, JAVA_HOME and PATH are not updated, but JAVA_HOME_<major>_<arch> is still set.'
|
||||||
required: false
|
required: false
|
||||||
@@ -50,20 +46,16 @@ inputs:
|
|||||||
file. Default is `github`'
|
file. Default is `github`'
|
||||||
required: false
|
required: false
|
||||||
default: 'github'
|
default: 'github'
|
||||||
server-username-env-var:
|
server-username:
|
||||||
description: 'Environment variable name for the username for authentication
|
description: 'Environment variable name for the username for authentication
|
||||||
to the Apache Maven repository. Default is $GITHUB_ACTOR'
|
to the Apache Maven repository. Default is $GITHUB_ACTOR'
|
||||||
required: false
|
required: false
|
||||||
server-username:
|
default: 'GITHUB_ACTOR'
|
||||||
description: 'Deprecated alias for server-username-env-var'
|
server-password:
|
||||||
required: false
|
|
||||||
server-password-env-var:
|
|
||||||
description: 'Environment variable name for password or token for
|
description: 'Environment variable name for password or token for
|
||||||
authentication to the Apache Maven repository. Default is $GITHUB_TOKEN'
|
authentication to the Apache Maven repository. Default is $GITHUB_TOKEN'
|
||||||
required: false
|
required: false
|
||||||
server-password:
|
default: 'GITHUB_TOKEN'
|
||||||
description: 'Deprecated alias for server-password-env-var'
|
|
||||||
required: false
|
|
||||||
settings-path:
|
settings-path:
|
||||||
description: 'Path to where the settings.xml file will be written. Default is ~/.m2.'
|
description: 'Path to where the settings.xml file will be written. Default is ~/.m2.'
|
||||||
required: false
|
required: false
|
||||||
@@ -75,28 +67,15 @@ inputs:
|
|||||||
description: 'GPG private key to import. Default is empty string.'
|
description: 'GPG private key to import. Default is empty string.'
|
||||||
required: false
|
required: false
|
||||||
default: ''
|
default: ''
|
||||||
gpg-passphrase-env-var:
|
|
||||||
description: 'Environment variable name for the GPG private key passphrase. Defaults to GPG_PASSPHRASE when gpg-private-key is set.'
|
|
||||||
required: false
|
|
||||||
gpg-passphrase:
|
gpg-passphrase:
|
||||||
description: 'Deprecated alias for gpg-passphrase-env-var'
|
description: 'Environment variable name for the GPG private key passphrase. Defaults to GPG_PASSPHRASE when gpg-private-key is set; ignored otherwise.'
|
||||||
required: false
|
required: false
|
||||||
cache:
|
cache:
|
||||||
description: 'Name of the build platform to cache dependencies. It can be "maven", "gradle" or "sbt".'
|
description: 'Name of the build platform to cache dependencies. It can be "maven", "gradle" or "sbt".'
|
||||||
required: false
|
required: false
|
||||||
cache-jdk:
|
|
||||||
description: 'Cache downloaded JDK installations between jobs. Defaults to enabled when dependency caching is configured with `cache`; set explicitly to "true" or "false" to override.'
|
|
||||||
required: false
|
|
||||||
cache-dependency-path:
|
cache-dependency-path:
|
||||||
description: '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.'
|
description: '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.'
|
||||||
required: false
|
required: false
|
||||||
cache-path:
|
|
||||||
description: 'The path to cache instead of the default dependency cache path for the selected package manager. This option can be used with the `cache` option and supports a list of paths and exclusion patterns.'
|
|
||||||
required: false
|
|
||||||
cache-read-only:
|
|
||||||
description: 'Restore caches without saving cache changes in the post action.'
|
|
||||||
required: false
|
|
||||||
default: false
|
|
||||||
job-status:
|
job-status:
|
||||||
description: 'Workaround to pass job status to post job step. This variable is not intended for manual setting'
|
description: 'Workaround to pass job status to post job step. This variable is not intended for manual setting'
|
||||||
required: false
|
required: false
|
||||||
@@ -106,7 +85,7 @@ inputs:
|
|||||||
required: false
|
required: false
|
||||||
default: ${{ github.server_url == 'https://github.com' && github.token || '' }}
|
default: ${{ github.server_url == 'https://github.com' && github.token || '' }}
|
||||||
mvn-toolchain-id:
|
mvn-toolchain-id:
|
||||||
description: 'Name of Maven Toolchain ID if the default name of "${mvn-toolchain-vendor}_${java-version}" is not wanted. The toolchain vendor defaults to the "distribution" input. When supplied, the number of IDs must match the number of Java versions. See examples of supported syntax in Advanced Usage file'
|
description: 'Name of Maven Toolchain ID if the default name of "${distribution}_${java-version}" is not wanted. See examples of supported syntax in Advanced Usage file'
|
||||||
required: false
|
required: false
|
||||||
mvn-toolchain-vendor:
|
mvn-toolchain-vendor:
|
||||||
description: 'Name of Maven Toolchain Vendor if the default name of "${distribution}" is not wanted. See examples of supported syntax in Advanced Usage file'
|
description: 'Name of Maven Toolchain Vendor if the default name of "${distribution}" is not wanted. See examples of supported syntax in Advanced Usage file'
|
||||||
@@ -115,10 +94,6 @@ inputs:
|
|||||||
description: 'Whether Maven should print artifact download/transfer progress to the build log. When "false" (default) the action sets "-ntp" (--no-transfer-progress) in MAVEN_ARGS to produce cleaner logs. Set to "true" to keep the progress output. Has no effect on non-Maven builds.'
|
description: 'Whether Maven should print artifact download/transfer progress to the build log. When "false" (default) the action sets "-ntp" (--no-transfer-progress) in MAVEN_ARGS to produce cleaner logs. Set to "true" to keep the progress output. Has no effect on non-Maven builds.'
|
||||||
required: false
|
required: false
|
||||||
default: false
|
default: false
|
||||||
problem-matcher:
|
|
||||||
description: 'Whether to register the Java problem matcher (compiler errors/warnings and uncaught exceptions). Set to "false" to disable annotations.'
|
|
||||||
required: false
|
|
||||||
default: true
|
|
||||||
outputs:
|
outputs:
|
||||||
distribution:
|
distribution:
|
||||||
description: 'Distribution of Java that has been installed'
|
description: 'Distribution of Java that has been installed'
|
||||||
|
|||||||
Vendored
-224
@@ -1,224 +0,0 @@
|
|||||||
export const id = 314;
|
|
||||||
export const ids = [314];
|
|
||||||
export const modules = {
|
|
||||||
|
|
||||||
/***/ 2314:
|
|
||||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
||||||
|
|
||||||
|
|
||||||
// EXPORTS
|
|
||||||
__webpack_require__.d(__webpack_exports__, {
|
|
||||||
saveJdkCaches: () => (/* binding */ saveJdkCaches)
|
|
||||||
});
|
|
||||||
|
|
||||||
// UNUSED EXPORTS: buildJdkCacheKey, getJdkVerificationIdentity, registerJdk, restoreJdk
|
|
||||||
|
|
||||||
// EXTERNAL MODULE: external "crypto"
|
|
||||||
var external_crypto_ = __webpack_require__(6982);
|
|
||||||
// EXTERNAL MODULE: external "fs"
|
|
||||||
var external_fs_ = __webpack_require__(9896);
|
|
||||||
var external_fs_default = /*#__PURE__*/__webpack_require__.n(external_fs_);
|
|
||||||
// EXTERNAL MODULE: external "path"
|
|
||||||
var external_path_ = __webpack_require__(6928);
|
|
||||||
var external_path_default = /*#__PURE__*/__webpack_require__.n(external_path_);
|
|
||||||
// EXTERNAL MODULE: ./node_modules/@actions/cache/lib/cache.js + 291 modules
|
|
||||||
var lib_cache = __webpack_require__(5767);
|
|
||||||
// EXTERNAL MODULE: ./node_modules/@actions/core/lib/core.js + 7 modules
|
|
||||||
var lib_core = __webpack_require__(3838);
|
|
||||||
// EXTERNAL MODULE: ./src/util.ts
|
|
||||||
var util = __webpack_require__(4527);
|
|
||||||
;// CONCATENATED MODULE: ./src/cache-feature.ts
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function cache_feature_isCacheFeatureAvailable() {
|
|
||||||
if (cache.isFeatureAvailable()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (isGhes()) {
|
|
||||||
core.warning('Caching is only supported on GHES version >= 3.5. If you are on a version >= 3.5, please check with your GHES admin if the Actions cache service is enabled or not.');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
core.warning('The runner was not able to contact the cache service. Caching will be skipped');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
;// CONCATENATED MODULE: ./src/jdk-cache.ts
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const STATE_JDK_CACHES = 'jdk-caches';
|
|
||||||
const JDK_CACHE_KEY_VERSION = 1;
|
|
||||||
const restoredCaches = (/* unused pure expression or super */ null && ([]));
|
|
||||||
async function restoreJdk(jdk) {
|
|
||||||
if (!jdk.path || !isCacheFeatureAvailable()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const key = buildJdkCacheKey(jdk);
|
|
||||||
let matchedKey;
|
|
||||||
try {
|
|
||||||
matchedKey = await cache.restoreCache([jdk.path], key);
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
core.warning(`Failed to restore JDK cache: ${error.message}`);
|
|
||||||
}
|
|
||||||
const architecturePath = path.join(jdk.path, jdk.architecture);
|
|
||||||
if (matchedKey &&
|
|
||||||
(!fs.existsSync(architecturePath) ||
|
|
||||||
!fs.existsSync(`${architecturePath}.complete`))) {
|
|
||||||
core.warning(`JDK cache key ${matchedKey} was restored without the expected tool-cache path; downloading the JDK instead.`);
|
|
||||||
matchedKey = undefined;
|
|
||||||
}
|
|
||||||
recordJdkCache({
|
|
||||||
key,
|
|
||||||
path: jdk.path,
|
|
||||||
architecture: jdk.architecture,
|
|
||||||
matchedKey
|
|
||||||
});
|
|
||||||
if (matchedKey) {
|
|
||||||
core.info(`JDK cache restored from key: ${matchedKey}`);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
core.info(`JDK cache is not found for ${jdk.distribution} ${jdk.version}`);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
function registerJdk(jdk) {
|
|
||||||
if (!jdk.path) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
recordJdkCache({
|
|
||||||
key: buildJdkCacheKey(jdk),
|
|
||||||
path: jdk.path,
|
|
||||||
architecture: jdk.architecture,
|
|
||||||
installation: getInstallationIdentity(jdk.path, jdk.architecture)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Cheap fingerprint of the installation stored at a tool-cache path. The
|
|
||||||
* `<architecture>.complete` marker is (re)created by `tc.cacheDir` every time an
|
|
||||||
* installation is written, so its inode and timestamps change whenever the
|
|
||||||
* installation is replaced. This avoids rehashing a multi-hundred-megabyte JDK
|
|
||||||
* directory while still detecting that the bytes behind a key were swapped.
|
|
||||||
*/
|
|
||||||
function getInstallationIdentity(jdkPath, architecture) {
|
|
||||||
const architecturePath = external_path_default().join(jdkPath, architecture);
|
|
||||||
try {
|
|
||||||
const marker = external_fs_default().statSync(`${architecturePath}.complete`);
|
|
||||||
const installation = external_fs_default().statSync(architecturePath);
|
|
||||||
return [
|
|
||||||
marker.ino,
|
|
||||||
marker.mtimeMs,
|
|
||||||
marker.ctimeMs,
|
|
||||||
marker.size,
|
|
||||||
installation.ino,
|
|
||||||
installation.mtimeMs,
|
|
||||||
installation.ctimeMs
|
|
||||||
].join(':');
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function getJdkVerificationIdentity(verifySignature, publicKey) {
|
|
||||||
if (!verifySignature) {
|
|
||||||
return 'unverified';
|
|
||||||
}
|
|
||||||
if (!publicKey) {
|
|
||||||
return 'verified:bundled';
|
|
||||||
}
|
|
||||||
const normalizedKey = publicKey.replace(/\r\n?/g, '\n').trim();
|
|
||||||
const fingerprint = createHash('sha256').update(normalizedKey).digest('hex');
|
|
||||||
return `verified:custom:sha256:${fingerprint}`;
|
|
||||||
}
|
|
||||||
async function saveJdkCaches() {
|
|
||||||
const state = lib_core/* getState */.Gu(STATE_JDK_CACHES);
|
|
||||||
if (!state) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const caches = parseJdkCacheState(state);
|
|
||||||
for (const jdk of caches) {
|
|
||||||
if (jdk.matchedKey === jdk.key) {
|
|
||||||
lib_core/* info */.pq(`Cache hit occurred on the JDK primary key ${jdk.key}, not saving cache.`);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!external_fs_default().existsSync(jdk.path)) {
|
|
||||||
lib_core/* debug */.Yz(`JDK cache path does not exist, not saving: ${jdk.path}`);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!jdk.installation) {
|
|
||||||
lib_core/* debug */.Yz(`No JDK installation was registered for the key ${jdk.key}, not saving cache.`);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (getInstallationIdentity(jdk.path, jdk.architecture) !== jdk.installation) {
|
|
||||||
lib_core/* warning */.$e(`The JDK installation in ${jdk.path} was replaced after it was registered for the key ${jdk.key}; not saving cache.`);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const cacheId = await lib_cache/* saveCache */.Io([jdk.path], jdk.key);
|
|
||||||
if (cacheId !== -1) {
|
|
||||||
lib_core/* info */.pq(`JDK cache saved with the key: ${jdk.key}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
const err = error;
|
|
||||||
if (err.name === lib_cache/* ReserveCacheError */.Zh.name) {
|
|
||||||
lib_core/* info */.pq(err.message);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Saving is best-effort and per entry: one failure must not suppress
|
|
||||||
// the remaining JDK caches.
|
|
||||||
lib_core/* warning */.$e(`Failed to save the JDK cache with the key ${jdk.key}: ${err.message}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function buildJdkCacheKey(jdk) {
|
|
||||||
const runnerOs = process.env['RUNNER_OS'] ?? process.platform;
|
|
||||||
const normalizedArchitecture = jdk.architecture.toLowerCase();
|
|
||||||
const identity = JSON.stringify({
|
|
||||||
keyVersion: JDK_CACHE_KEY_VERSION,
|
|
||||||
runnerOs,
|
|
||||||
distribution: jdk.distribution.toLowerCase(),
|
|
||||||
packageType: jdk.packageType.toLowerCase(),
|
|
||||||
architecture: normalizedArchitecture,
|
|
||||||
version: jdk.version,
|
|
||||||
source: jdk.source,
|
|
||||||
verification: jdk.verification
|
|
||||||
});
|
|
||||||
const digest = createHash('sha256').update(identity).digest('hex');
|
|
||||||
return `setup-java-jdk-v${JDK_CACHE_KEY_VERSION}-${runnerOs}-${normalizedArchitecture}-${digest}`;
|
|
||||||
}
|
|
||||||
function recordJdkCache(jdk) {
|
|
||||||
const existing = restoredCaches.findIndex(item => item.key === jdk.key && item.path === jdk.path);
|
|
||||||
if (existing === -1) {
|
|
||||||
restoredCaches.push(jdk);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
restoredCaches[existing] = { ...restoredCaches[existing], ...jdk };
|
|
||||||
}
|
|
||||||
core.saveState(STATE_JDK_CACHES, JSON.stringify(restoredCaches));
|
|
||||||
}
|
|
||||||
function parseJdkCacheState(state) {
|
|
||||||
const value = JSON.parse(state);
|
|
||||||
if (!Array.isArray(value) ||
|
|
||||||
!value.every(item => typeof item === 'object' &&
|
|
||||||
item !== null &&
|
|
||||||
typeof item.key === 'string' &&
|
|
||||||
typeof item.path === 'string' &&
|
|
||||||
typeof item.architecture === 'string' &&
|
|
||||||
(item.matchedKey === undefined ||
|
|
||||||
typeof item.matchedKey === 'string') &&
|
|
||||||
(item.installation === undefined ||
|
|
||||||
typeof item.installation === 'string'))) {
|
|
||||||
throw new Error('Invalid JDK cache information retrieved from state.');
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/***/ })
|
|
||||||
|
|
||||||
};
|
|
||||||
Vendored
-270
@@ -1,270 +0,0 @@
|
|||||||
export const id = 348;
|
|
||||||
export const ids = [348];
|
|
||||||
export const modules = {
|
|
||||||
|
|
||||||
/***/ 967:
|
|
||||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
||||||
|
|
||||||
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
||||||
/* harmony export */ saveJdkResolutionCaches: () => (/* binding */ saveJdkResolutionCaches)
|
|
||||||
/* harmony export */ });
|
|
||||||
/* unused harmony exports restoreJdkResolution, registerJdkResolution */
|
|
||||||
/* harmony import */ var crypto__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6982);
|
|
||||||
/* harmony import */ var crypto__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(crypto__WEBPACK_IMPORTED_MODULE_0__);
|
|
||||||
/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(9896);
|
|
||||||
/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_1__);
|
|
||||||
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6928);
|
|
||||||
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_2__);
|
|
||||||
/* harmony import */ var _actions_cache__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(5767);
|
|
||||||
/* harmony import */ var _actions_core__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(3838);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const STATE_JDK_RESOLUTIONS = 'jdk-resolutions';
|
|
||||||
const JDK_RESOLUTION_KEY_VERSION = 1;
|
|
||||||
const RESOLUTION_DIRECTORY = 'setup-java-jdk-resolution';
|
|
||||||
const RESOLUTION_FILE_NAME = 'release.json';
|
|
||||||
const pendingResolutions = (/* unused pure expression or super */ null && ([]));
|
|
||||||
/**
|
|
||||||
* Restores a previously resolved release so a distribution can skip its vendor
|
|
||||||
* metadata API.
|
|
||||||
*
|
|
||||||
* The cache path deliberately excludes the freshness window: `@actions/cache`
|
|
||||||
* derives
|
|
||||||
* a cache version by hashing the requested paths, so a bucket-independent path
|
|
||||||
* is what allows the restore keys to fall back to an older bucket.
|
|
||||||
*/
|
|
||||||
async function restoreJdkResolution(request) {
|
|
||||||
// Deliberately not `isCacheFeatureAvailable()`: this is an optional
|
|
||||||
// optimization, and the JDK cache already warns once when the service is
|
|
||||||
// unreachable.
|
|
||||||
if (!cache.isFeatureAvailable()) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
const cachePath = getResolutionCachePath(request);
|
|
||||||
if (!cachePath) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
const keyPrefix = getResolutionKeyPrefix(request);
|
|
||||||
const primaryKey = `${keyPrefix}${getFreshnessBucket()}`;
|
|
||||||
let matchedKey;
|
|
||||||
try {
|
|
||||||
matchedKey = await cache.restoreCache([cachePath], primaryKey, [keyPrefix]);
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
core.debug(`Failed to restore the JDK resolution cache: ${getErrorMessage(error)}`);
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
if (!matchedKey) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
let release;
|
|
||||||
try {
|
|
||||||
const contents = fs.readFileSync(path.join(cachePath, RESOLUTION_FILE_NAME), 'utf8');
|
|
||||||
release = parseResolvedRelease(contents);
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
core.debug(`Ignoring the JDK resolution cache entry ${matchedKey}: ${getErrorMessage(error)}`);
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
return { release, fresh: matchedKey === primaryKey };
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Persists a freshly resolved release for later jobs. The entry is written to
|
|
||||||
* disk immediately and uploaded by the post-job step.
|
|
||||||
*/
|
|
||||||
function registerJdkResolution(request, release) {
|
|
||||||
if (!cache.isFeatureAvailable()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const cachePath = getResolutionCachePath(request);
|
|
||||||
if (!cachePath) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const payload = JSON.stringify(release);
|
|
||||||
try {
|
|
||||||
fs.mkdirSync(cachePath, { recursive: true });
|
|
||||||
fs.writeFileSync(path.join(cachePath, RESOLUTION_FILE_NAME), payload);
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
core.debug(`Failed to record the JDK resolution cache entry: ${getErrorMessage(error)}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const key = `${getResolutionKeyPrefix(request)}${getFreshnessBucket()}`;
|
|
||||||
if (!pendingResolutions.some(item => item.key === key)) {
|
|
||||||
pendingResolutions.push({ key, path: cachePath, release: payload });
|
|
||||||
}
|
|
||||||
core.saveState(STATE_JDK_RESOLUTIONS, JSON.stringify(pendingResolutions));
|
|
||||||
}
|
|
||||||
async function saveJdkResolutionCaches() {
|
|
||||||
const state = _actions_core__WEBPACK_IMPORTED_MODULE_4__/* .getState */ .Gu(STATE_JDK_RESOLUTIONS);
|
|
||||||
if (!state) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let resolutions;
|
|
||||||
try {
|
|
||||||
resolutions = parseJdkResolutionState(state);
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_4__/* .debug */ .Yz(`Invalid JDK resolution cache state, not saving: ${getErrorMessage(error)}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (const resolution of resolutions) {
|
|
||||||
// A restore performed by a later step overwrites this path, so the payload
|
|
||||||
// the key was computed for is written again rather than trusted to still be
|
|
||||||
// on disk.
|
|
||||||
try {
|
|
||||||
fs__WEBPACK_IMPORTED_MODULE_1___default().mkdirSync(resolution.path, { recursive: true });
|
|
||||||
fs__WEBPACK_IMPORTED_MODULE_1___default().writeFileSync(path__WEBPACK_IMPORTED_MODULE_2___default().join(resolution.path, RESOLUTION_FILE_NAME), resolution.release);
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_4__/* .debug */ .Yz(`Failed to write the JDK resolution cache entry for the key ${resolution.key}: ${getErrorMessage(error)}`);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
await _actions_cache__WEBPACK_IMPORTED_MODULE_3__/* .saveCache */ .Io([resolution.path], resolution.key);
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
// A matrix of jobs resolving the same JDK races on the same daily key, so
|
|
||||||
// an already-reserved key is the expected outcome rather than a problem.
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_4__/* .debug */ .Yz(`Failed to save the JDK resolution cache with the key ${resolution.key}: ${getErrorMessage(error)}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function getResolutionCachePath(request) {
|
|
||||||
const runnerTemp = process.env['RUNNER_TEMP'];
|
|
||||||
if (!runnerTemp) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
return path.join(runnerTemp, RESOLUTION_DIRECTORY, getResolutionIdentity(request));
|
|
||||||
}
|
|
||||||
function getResolutionIdentity(request) {
|
|
||||||
const identity = JSON.stringify({
|
|
||||||
keyVersion: JDK_RESOLUTION_KEY_VERSION,
|
|
||||||
runnerOs: getRunnerOs(),
|
|
||||||
distribution: request.distribution.toLowerCase(),
|
|
||||||
packageType: request.packageType.toLowerCase(),
|
|
||||||
architecture: request.architecture.toLowerCase(),
|
|
||||||
versionSpec: request.versionSpec,
|
|
||||||
stable: request.stable
|
|
||||||
});
|
|
||||||
return createHash('sha256').update(identity).digest('hex');
|
|
||||||
}
|
|
||||||
function getResolutionKeyPrefix(request) {
|
|
||||||
const architecture = request.architecture.toLowerCase();
|
|
||||||
const digest = getResolutionIdentity(request);
|
|
||||||
return `setup-java-jdkres-v${JDK_RESOLUTION_KEY_VERSION}-${getRunnerOs()}-${architecture}-${digest}-`;
|
|
||||||
}
|
|
||||||
function getRunnerOs() {
|
|
||||||
return process.env['RUNNER_OS'] ?? process.platform;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Start of the seven-day window the entry was resolved in, which bounds how long
|
|
||||||
* a floating version spec such as `21` can keep resolving to an already known
|
|
||||||
* release.
|
|
||||||
*
|
|
||||||
* Seven days is the longest usable window: GitHub evicts cache entries that have
|
|
||||||
* not been accessed for seven days, so a longer one would mean the previous
|
|
||||||
* entry is already gone when the window rolls over, taking the stale-fallback
|
|
||||||
* path with it. It also comfortably covers the real release cadence, which is
|
|
||||||
* monthly at its fastest and usually quarterly.
|
|
||||||
*/
|
|
||||||
function getFreshnessBucket() {
|
|
||||||
const week = 7 * 24 * 60 * 60 * 1000;
|
|
||||||
return new Date(Math.floor(Date.now() / week) * week)
|
|
||||||
.toISOString()
|
|
||||||
.slice(0, 10);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* The restored payload drives a download, so it is validated as untrusted input
|
|
||||||
* rather than trusted because it came back from the cache service.
|
|
||||||
*/
|
|
||||||
function parseResolvedRelease(contents) {
|
|
||||||
const value = JSON.parse(contents);
|
|
||||||
if (typeof value !== 'object' || value === null) {
|
|
||||||
throw new Error('The cached resolution is not an object.');
|
|
||||||
}
|
|
||||||
const candidate = value;
|
|
||||||
const version = candidate['version'];
|
|
||||||
const url = candidate['url'];
|
|
||||||
const signatureUrl = candidate['signatureUrl'];
|
|
||||||
if (typeof version !== 'string' || !version) {
|
|
||||||
throw new Error('The cached resolution has no version.');
|
|
||||||
}
|
|
||||||
assertHttpsUrl(url, 'url');
|
|
||||||
if (signatureUrl !== undefined) {
|
|
||||||
assertHttpsUrl(signatureUrl, 'signatureUrl');
|
|
||||||
}
|
|
||||||
const release = {
|
|
||||||
version,
|
|
||||||
url: url
|
|
||||||
};
|
|
||||||
if (signatureUrl !== undefined) {
|
|
||||||
release.signatureUrl = signatureUrl;
|
|
||||||
}
|
|
||||||
const checksum = candidate['checksum'];
|
|
||||||
if (checksum !== undefined) {
|
|
||||||
release.checksum = parseChecksum(checksum);
|
|
||||||
}
|
|
||||||
return release;
|
|
||||||
}
|
|
||||||
function parseChecksum(value) {
|
|
||||||
if (typeof value !== 'object' || value === null) {
|
|
||||||
throw new Error('The cached checksum is not an object.');
|
|
||||||
}
|
|
||||||
const candidate = value;
|
|
||||||
const algorithm = candidate['algorithm'];
|
|
||||||
const checksumValue = candidate['value'];
|
|
||||||
const source = candidate['source'];
|
|
||||||
if (algorithm !== 'sha256' && algorithm !== 'sha512') {
|
|
||||||
throw new Error(`Unsupported cached checksum algorithm: ${algorithm}`);
|
|
||||||
}
|
|
||||||
if (typeof checksumValue !== 'string' || !checksumValue) {
|
|
||||||
throw new Error('The cached checksum has no value.');
|
|
||||||
}
|
|
||||||
if (source !== undefined && typeof source !== 'string') {
|
|
||||||
throw new Error('The cached checksum source is not a string.');
|
|
||||||
}
|
|
||||||
const checksum = { algorithm, value: checksumValue };
|
|
||||||
if (source !== undefined) {
|
|
||||||
checksum.source = source;
|
|
||||||
}
|
|
||||||
return checksum;
|
|
||||||
}
|
|
||||||
function assertHttpsUrl(value, field) {
|
|
||||||
if (typeof value !== 'string' || !value) {
|
|
||||||
throw new Error(`The cached resolution has no ${field}.`);
|
|
||||||
}
|
|
||||||
let parsed;
|
|
||||||
try {
|
|
||||||
parsed = new URL(value);
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
throw new Error(`The cached resolution has a malformed ${field}.`);
|
|
||||||
}
|
|
||||||
if (parsed.protocol !== 'https:') {
|
|
||||||
throw new Error(`The cached resolution ${field} does not use HTTPS: ${parsed.protocol}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function parseJdkResolutionState(state) {
|
|
||||||
const value = JSON.parse(state);
|
|
||||||
if (!Array.isArray(value) ||
|
|
||||||
!value.every(item => typeof item === 'object' &&
|
|
||||||
item !== null &&
|
|
||||||
typeof item.key === 'string' &&
|
|
||||||
typeof item.path === 'string' &&
|
|
||||||
typeof item.release === 'string')) {
|
|
||||||
throw new Error('Invalid JDK resolution information retrieved from state.');
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
function getErrorMessage(error) {
|
|
||||||
return error instanceof Error ? error.message : String(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/***/ })
|
|
||||||
|
|
||||||
};
|
|
||||||
Vendored
-356
@@ -1,356 +0,0 @@
|
|||||||
export const id = 377;
|
|
||||||
export const ids = [377];
|
|
||||||
export const modules = {
|
|
||||||
|
|
||||||
/***/ 7377:
|
|
||||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
||||||
|
|
||||||
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
||||||
/* harmony export */ save: () => (/* binding */ save)
|
|
||||||
/* harmony export */ });
|
|
||||||
/* unused harmony export restore */
|
|
||||||
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6928);
|
|
||||||
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_0__);
|
|
||||||
/* harmony import */ var os__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(857);
|
|
||||||
/* harmony import */ var os__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(os__WEBPACK_IMPORTED_MODULE_1__);
|
|
||||||
/* harmony import */ var _actions_cache__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(5767);
|
|
||||||
/* harmony import */ var _actions_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(3838);
|
|
||||||
/* harmony import */ var _actions_glob__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(2377);
|
|
||||||
/**
|
|
||||||
* @fileoverview this file provides methods handling dependency cache
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const STATE_CACHE_PRIMARY_KEY = 'cache-primary-key';
|
|
||||||
const STATE_CACHE_PATHS = 'cache-paths';
|
|
||||||
const CACHE_MATCHED_KEY = 'cache-matched-key';
|
|
||||||
const CACHE_KEY_PREFIX = 'setup-java';
|
|
||||||
const supportedPackageManager = [
|
|
||||||
{
|
|
||||||
id: 'maven',
|
|
||||||
path: [(0,path__WEBPACK_IMPORTED_MODULE_0__.join)(os__WEBPACK_IMPORTED_MODULE_1___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,path__WEBPACK_IMPORTED_MODULE_0__.join)(os__WEBPACK_IMPORTED_MODULE_1___default().homedir(), '.m2', 'wrapper', 'dists')],
|
|
||||||
pattern: ['**/.mvn/wrapper/maven-wrapper.properties']
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'gradle',
|
|
||||||
path: [(0,path__WEBPACK_IMPORTED_MODULE_0__.join)(os__WEBPACK_IMPORTED_MODULE_1___default().homedir(), '.gradle', 'caches')],
|
|
||||||
// https://github.com/actions/cache/blob/0638051e9af2c23d10bb70fa9beffcad6cff9ce3/examples.md#java---gradle
|
|
||||||
pattern: [
|
|
||||||
'**/*.gradle*',
|
|
||||||
'**/gradle-wrapper.properties',
|
|
||||||
'buildSrc/**/Versions.kt',
|
|
||||||
'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,path__WEBPACK_IMPORTED_MODULE_0__.join)(os__WEBPACK_IMPORTED_MODULE_1___default().homedir(), '.gradle', 'wrapper')],
|
|
||||||
pattern: ['**/gradle-wrapper.properties']
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'sbt',
|
|
||||||
path: [
|
|
||||||
(0,path__WEBPACK_IMPORTED_MODULE_0__.join)(os__WEBPACK_IMPORTED_MODULE_1___default().homedir(), '.ivy2', 'cache'),
|
|
||||||
(0,path__WEBPACK_IMPORTED_MODULE_0__.join)(os__WEBPACK_IMPORTED_MODULE_1___default().homedir(), '.sbt'),
|
|
||||||
getCoursierCachePath(),
|
|
||||||
// Some files should not be cached to avoid resolution problems.
|
|
||||||
// In particular the resolution of snapshots (ideological gap between maven/ivy).
|
|
||||||
'!' + (0,path__WEBPACK_IMPORTED_MODULE_0__.join)(os__WEBPACK_IMPORTED_MODULE_1___default().homedir(), '.sbt', '*.lock'),
|
|
||||||
'!' + (0,path__WEBPACK_IMPORTED_MODULE_0__.join)(os__WEBPACK_IMPORTED_MODULE_1___default().homedir(), '**', 'ivydata-*.properties')
|
|
||||||
],
|
|
||||||
pattern: [
|
|
||||||
'**/*.sbt',
|
|
||||||
'**/project/build.properties',
|
|
||||||
'**/project/**.scala',
|
|
||||||
'**/project/**.sbt'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
];
|
|
||||||
function getCoursierCachePath() {
|
|
||||||
if (os__WEBPACK_IMPORTED_MODULE_1___default().type() === 'Linux')
|
|
||||||
return (0,path__WEBPACK_IMPORTED_MODULE_0__.join)(os__WEBPACK_IMPORTED_MODULE_1___default().homedir(), '.cache', 'coursier');
|
|
||||||
if (os__WEBPACK_IMPORTED_MODULE_1___default().type() === 'Darwin')
|
|
||||||
return (0,path__WEBPACK_IMPORTED_MODULE_0__.join)(os__WEBPACK_IMPORTED_MODULE_1___default().homedir(), 'Library', 'Caches', 'Coursier');
|
|
||||||
return (0,path__WEBPACK_IMPORTED_MODULE_0__.join)(os__WEBPACK_IMPORTED_MODULE_1___default().homedir(), 'AppData', 'Local', 'Coursier', 'Cache');
|
|
||||||
}
|
|
||||||
function findPackageManager(id) {
|
|
||||||
const packageManager = supportedPackageManager.find(packageManager => packageManager.id === id);
|
|
||||||
if (packageManager === undefined) {
|
|
||||||
throw new Error(`unknown package manager specified: ${id}`);
|
|
||||||
}
|
|
||||||
return packageManager;
|
|
||||||
}
|
|
||||||
function resolveCachePaths(packageManager, cachePaths) {
|
|
||||||
return cachePaths.length > 0 ? cachePaths : packageManager.path;
|
|
||||||
}
|
|
||||||
function getCachePathsFromState(packageManager) {
|
|
||||||
const cachePathsState = _actions_core__WEBPACK_IMPORTED_MODULE_3__/* .getState */ .Gu(STATE_CACHE_PATHS);
|
|
||||||
if (!cachePathsState) {
|
|
||||||
return packageManager.path;
|
|
||||||
}
|
|
||||||
const cachePaths = JSON.parse(cachePathsState);
|
|
||||||
if (!Array.isArray(cachePaths) ||
|
|
||||||
!cachePaths.every(cachePath => typeof cachePath === 'string')) {
|
|
||||||
throw new Error('Invalid cache paths retrieved from state.');
|
|
||||||
}
|
|
||||||
return cachePaths;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 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 }}"".
|
|
||||||
* @see {@link https://docs.github.com/en/actions/guides/caching-dependencies-to-speed-up-workflows#matching-a-cache-key|spec of cache key}
|
|
||||||
*/
|
|
||||||
async function computeCacheKey(packageManager, cacheDependencyPath) {
|
|
||||||
const pattern = cacheDependencyPath
|
|
||||||
? cacheDependencyPath.trim().split('\n')
|
|
||||||
: packageManager.pattern;
|
|
||||||
const fileHash = await glob.hashFiles(pattern.join('\n'));
|
|
||||||
if (!fileHash) {
|
|
||||||
throw new Error(`No file in ${process.cwd()} matched to [${pattern}], make sure you have checked out the target repository`);
|
|
||||||
}
|
|
||||||
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
|
|
||||||
* @param id ID of the package manager, should be "maven", "gradle", or "sbt"
|
|
||||||
* @param cacheDependencyPath The path to a dependency file
|
|
||||||
* @param cachePaths Paths to cache instead of the package manager defaults
|
|
||||||
*/
|
|
||||||
async function restore(id, cacheDependencyPath, cachePaths = []) {
|
|
||||||
const packageManager = findPackageManager(id);
|
|
||||||
const resolvedCachePaths = resolveCachePaths(packageManager, cachePaths);
|
|
||||||
const [primaryKey, preparedAdditionalCaches] = await Promise.all([
|
|
||||||
computeCacheKey(packageManager, cacheDependencyPath),
|
|
||||||
prepareAdditionalCaches(packageManager.additionalCaches ?? [])
|
|
||||||
]);
|
|
||||||
core.debug(`primary key is ${primaryKey}`);
|
|
||||||
core.saveState(STATE_CACHE_PRIMARY_KEY, primaryKey);
|
|
||||||
core.saveState(STATE_CACHE_PATHS, JSON.stringify(resolvedCachePaths));
|
|
||||||
core.setOutput(STATE_CACHE_PRIMARY_KEY, primaryKey);
|
|
||||||
for (const preparedCache of preparedAdditionalCaches) {
|
|
||||||
core.debug(`${preparedCache.cache.name} primary key is ${preparedCache.primaryKey}`);
|
|
||||||
core.saveState(additionalCachePrimaryKeyState(preparedCache.cache.name), preparedCache.primaryKey);
|
|
||||||
}
|
|
||||||
await Promise.all([
|
|
||||||
restorePrimaryCache(packageManager, resolvedCachePaths, primaryKey),
|
|
||||||
...preparedAdditionalCaches.map(preparedCache => restoreAdditionalCache(preparedCache))
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
async function restorePrimaryCache(packageManager, cachePaths, primaryKey) {
|
|
||||||
// No "restoreKeys" is set, to start with a clear cache after dependency update (see https://github.com/actions/setup-java/issues/269)
|
|
||||||
const matchedKey = await cache.restoreCache(cachePaths, primaryKey);
|
|
||||||
if (matchedKey) {
|
|
||||||
core.saveState(CACHE_MATCHED_KEY, matchedKey);
|
|
||||||
core.setOutput('cache-hit', matchedKey === primaryKey);
|
|
||||||
core.info(`Cache restored from key: ${matchedKey}`);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
core.setOutput('cache-hit', false);
|
|
||||||
core.info(`${packageManager.id} cache is not found`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Compute keys for additional caches (e.g. build-tool wrapper distributions).
|
|
||||||
* Additional caches without a matching configuration file are omitted.
|
|
||||||
*/
|
|
||||||
async function prepareAdditionalCaches(additionalCaches) {
|
|
||||||
const preparedCaches = await Promise.all(additionalCaches.map(async (additionalCache) => {
|
|
||||||
const primaryKey = await computeAdditionalCacheKey(additionalCache);
|
|
||||||
if (!primaryKey) {
|
|
||||||
core.debug(`No file matched [${additionalCache.pattern}] for the ${additionalCache.name} cache, skipping.`);
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
return { cache: additionalCache, primaryKey };
|
|
||||||
}));
|
|
||||||
return preparedCaches.filter((preparedCache) => preparedCache !== undefined);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Restore an additional cache keyed independently of the main dependency cache.
|
|
||||||
*/
|
|
||||||
async function restoreAdditionalCache(preparedCache) {
|
|
||||||
const { cache: additionalCache, primaryKey } = preparedCache;
|
|
||||||
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}`);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
core.info(`${additionalCache.name} cache is not found`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Save the dependency cache
|
|
||||||
* @param id ID of the package manager, should be "maven" or "gradle"
|
|
||||||
*/
|
|
||||||
async function save(id) {
|
|
||||||
const packageManager = findPackageManager(id);
|
|
||||||
const cachePaths = getCachePathsFromState(packageManager);
|
|
||||||
const matchedKey = _actions_core__WEBPACK_IMPORTED_MODULE_3__/* .getState */ .Gu(CACHE_MATCHED_KEY);
|
|
||||||
// Inputs are re-evaluated before the post action, so we want the original key used for restore
|
|
||||||
const primaryKey = _actions_core__WEBPACK_IMPORTED_MODULE_3__/* .getState */ .Gu(STATE_CACHE_PRIMARY_KEY);
|
|
||||||
for (const additionalCache of packageManager.additionalCaches ?? []) {
|
|
||||||
try {
|
|
||||||
await saveAdditionalCache(packageManager, additionalCache);
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
const err = error;
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_3__/* .warning */ .$e(`Failed to save ${additionalCache.name} cache: ${err.message}. Continuing with primary cache save.`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!primaryKey) {
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_3__/* .warning */ .$e('Error retrieving key from state.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (matchedKey === primaryKey) {
|
|
||||||
// no change in target directories
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_3__/* .info */ .pq(`Cache hit occurred on the primary key ${primaryKey}, not saving cache.`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const cacheId = await _actions_cache__WEBPACK_IMPORTED_MODULE_2__/* .saveCache */ .Io(cachePaths, primaryKey);
|
|
||||||
if (cacheId === -1) {
|
|
||||||
// saveCache returns -1 without throwing when the cache was not saved,
|
|
||||||
// e.g. a reserve collision or a read-only token (fork PR). @actions/cache
|
|
||||||
// has already logged the reason at the appropriate severity, so just
|
|
||||||
// trace it instead of misreporting that the cache was saved.
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_3__/* .debug */ .Yz(`Cache was not saved for the key: ${primaryKey}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_3__/* .info */ .pq(`Cache saved with the key: ${primaryKey}`);
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
const err = error;
|
|
||||||
if (err.name === _actions_cache__WEBPACK_IMPORTED_MODULE_2__/* .ReserveCacheError */ .Zh.name) {
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_3__/* .info */ .pq(err.message);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (isProbablyGradleDaemonProblem(packageManager, err)) {
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_3__/* .warning */ .$e('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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 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 = _actions_core__WEBPACK_IMPORTED_MODULE_3__/* .getState */ .Gu(additionalCachePrimaryKeyState(additionalCache.name));
|
|
||||||
const matchedKey = _actions_core__WEBPACK_IMPORTED_MODULE_3__/* .getState */ .Gu(additionalCacheMatchedKeyState(additionalCache.name));
|
|
||||||
if (!primaryKey) {
|
|
||||||
// The feature is not used by this project, nothing to save.
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_3__/* .debug */ .Yz(`No primary key for the ${additionalCache.name} cache, not saving cache.`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (matchedKey === primaryKey) {
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_3__/* .info */ .pq(`Cache hit occurred on the ${additionalCache.name} primary key ${primaryKey}, not saving cache.`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const globber = await _actions_glob__WEBPACK_IMPORTED_MODULE_4__/* .create */ .v(additionalCache.path.join('\n'), {
|
|
||||||
implicitDescendants: false
|
|
||||||
});
|
|
||||||
const cachePaths = await globber.glob();
|
|
||||||
if (cachePaths.length === 0) {
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_3__/* .debug */ .Yz(`${additionalCache.name} cache paths do not exist, not saving cache.`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const cacheId = await _actions_cache__WEBPACK_IMPORTED_MODULE_2__/* .saveCache */ .Io(cachePaths, primaryKey);
|
|
||||||
if (cacheId === -1) {
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_3__/* .debug */ .Yz(`${additionalCache.name} cache was not saved for the key: ${primaryKey}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_3__/* .info */ .pq(`${additionalCache.name} cache saved with the key: ${primaryKey}`);
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
const err = error;
|
|
||||||
if (err.name === _actions_cache__WEBPACK_IMPORTED_MODULE_2__/* .ValidationError */ .yI.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.
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_3__/* .debug */ .Yz(`${additionalCache.name} cache paths do not exist, not saving cache: ${err.message}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (err.name === _actions_cache__WEBPACK_IMPORTED_MODULE_2__/* .ReserveCacheError */ .Zh.name) {
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_3__/* .info */ .pq(err.message);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (isProbablyGradleDaemonProblem(packageManager, err)) {
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_3__/* .warning */ .$e(`Failed to save ${additionalCache.name} 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
|
|
||||||
* @returns true if the given error seems related to the {@link https://github.com/actions/cache/issues/454|running Gradle Daemon issue}.
|
|
||||||
* @see {@link https://github.com/actions/cache/issues/454#issuecomment-840493935|why --no-daemon is necessary}
|
|
||||||
*/
|
|
||||||
function isProbablyGradleDaemonProblem(packageManager, error) {
|
|
||||||
if (packageManager.id !== 'gradle' ||
|
|
||||||
process.env['RUNNER_OS'] !== 'Windows') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const message = error.message || '';
|
|
||||||
return message.startsWith('Tar failed with error: ');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/***/ })
|
|
||||||
|
|
||||||
};
|
|
||||||
Vendored
-62560
File diff suppressed because it is too large
Load Diff
Vendored
+66714
-2674
File diff suppressed because it is too large
Load Diff
Vendored
-160
@@ -1,160 +0,0 @@
|
|||||||
export const id = 126;
|
|
||||||
export const ids = [126];
|
|
||||||
export const modules = {
|
|
||||||
|
|
||||||
/***/ 4126:
|
|
||||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
||||||
|
|
||||||
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
||||||
/* harmony export */ CorrettoDistribution: () => (/* binding */ CorrettoDistribution)
|
|
||||||
/* harmony export */ });
|
|
||||||
/* harmony import */ var _actions_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(3838);
|
|
||||||
/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(9896);
|
|
||||||
/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_1__);
|
|
||||||
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6928);
|
|
||||||
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_2__);
|
|
||||||
/* harmony import */ var _util_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(4527);
|
|
||||||
/* harmony import */ var _base_installer_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(6242);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const CORRETTO_VERSIONS_URL = 'https://corretto.github.io/corretto-downloads/latest_links/indexmap_with_checksum.json';
|
|
||||||
class CorrettoDistribution extends _base_installer_js__WEBPACK_IMPORTED_MODULE_4__/* .JavaBase */ .O {
|
|
||||||
constructor(installerOptions) {
|
|
||||||
super('Corretto', installerOptions);
|
|
||||||
}
|
|
||||||
async downloadTool(javaRelease) {
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_0__/* .info */ .pq(`Downloading Java ${javaRelease.version} (${this.distribution}) from ${javaRelease.url} ...`);
|
|
||||||
let javaArchivePath = await this.downloadAndVerify(javaRelease);
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_0__/* .info */ .pq(`Extracting Java archive...`);
|
|
||||||
const extension = (0,_util_js__WEBPACK_IMPORTED_MODULE_3__/* .getDownloadArchiveExtension */ .ag)();
|
|
||||||
if (process.platform === 'win32') {
|
|
||||||
javaArchivePath = (0,_util_js__WEBPACK_IMPORTED_MODULE_3__/* .renameWinArchive */ .n2)(javaArchivePath);
|
|
||||||
}
|
|
||||||
const extractedJavaPath = await (0,_util_js__WEBPACK_IMPORTED_MODULE_3__/* .extractJdkFile */ .PE)(javaArchivePath, extension);
|
|
||||||
const archiveName = fs__WEBPACK_IMPORTED_MODULE_1___default().readdirSync(extractedJavaPath)[0];
|
|
||||||
const archivePath = path__WEBPACK_IMPORTED_MODULE_2___default().join(extractedJavaPath, archiveName);
|
|
||||||
const version = this.getToolcacheVersionName(javaRelease.version);
|
|
||||||
const javaPath = await (0,_util_js__WEBPACK_IMPORTED_MODULE_3__/* .cacheJdkDir */ .Vj)(archivePath, this.toolcacheFolderName, version, this.architecture);
|
|
||||||
return { version: javaRelease.version, path: javaPath };
|
|
||||||
}
|
|
||||||
async findPackageForDownload(version) {
|
|
||||||
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 matchingVersions = availableVersions
|
|
||||||
.filter(item => item.version == version)
|
|
||||||
.map(item => {
|
|
||||||
return {
|
|
||||||
version: (0,_util_js__WEBPACK_IMPORTED_MODULE_3__/* .convertVersionToSemver */ .ZY)(item.correttoVersion),
|
|
||||||
url: item.downloadLink,
|
|
||||||
checksum: {
|
|
||||||
algorithm: 'sha256',
|
|
||||||
value: item.checksum_sha256,
|
|
||||||
source: CORRETTO_VERSIONS_URL
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
const resolvedVersion = matchingVersions.length > 0 ? matchingVersions[0] : null;
|
|
||||||
if (!resolvedVersion) {
|
|
||||||
const availableVersionStrings = availableVersions.map(item => item.version);
|
|
||||||
throw this.createVersionNotFoundError(version, availableVersionStrings);
|
|
||||||
}
|
|
||||||
return resolvedVersion;
|
|
||||||
}
|
|
||||||
async getAvailableVersions() {
|
|
||||||
const platform = this.getPlatformOption();
|
|
||||||
const arch = this.distributionArchitecture();
|
|
||||||
const imageType = this.packageType;
|
|
||||||
if (_actions_core__WEBPACK_IMPORTED_MODULE_0__/* .isDebug */ ._o()) {
|
|
||||||
console.time('Retrieving available versions for Corretto took'); // eslint-disable-line no-console
|
|
||||||
}
|
|
||||||
const fetchCurrentVersions = await this.http.getJson(CORRETTO_VERSIONS_URL);
|
|
||||||
const fetchedCurrentVersions = fetchCurrentVersions.result;
|
|
||||||
if (!fetchedCurrentVersions) {
|
|
||||||
throw Error(`Could not fetch latest corretto versions from ${CORRETTO_VERSIONS_URL}`);
|
|
||||||
}
|
|
||||||
const eligibleVersions = fetchedCurrentVersions?.[platform]?.[arch]?.[imageType];
|
|
||||||
const availableVersions = this.getAvailableVersionsForPlatform(eligibleVersions);
|
|
||||||
if (_actions_core__WEBPACK_IMPORTED_MODULE_0__/* .isDebug */ ._o()) {
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_0__/* .startGroup */ .Oh('Print information about available versions');
|
|
||||||
console.timeEnd('Retrieving available versions for Corretto took'); // eslint-disable-line no-console
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_0__/* .debug */ .Yz(`Available versions: [${availableVersions.length}]`);
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_0__/* .debug */ .Yz(availableVersions
|
|
||||||
.map(item => `${item.version}: ${item.correttoVersion}`)
|
|
||||||
.join(', '));
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_0__/* .endGroup */ .N4();
|
|
||||||
}
|
|
||||||
return availableVersions;
|
|
||||||
}
|
|
||||||
getAvailableVersionsForPlatform(eligibleVersions) {
|
|
||||||
const availableVersions = [];
|
|
||||||
for (const version in eligibleVersions) {
|
|
||||||
const availableVersion = eligibleVersions[version];
|
|
||||||
for (const fileType in availableVersion) {
|
|
||||||
const skipNonExtractableBinaries = fileType != (0,_util_js__WEBPACK_IMPORTED_MODULE_3__/* .getDownloadArchiveExtension */ .ag)();
|
|
||||||
if (skipNonExtractableBinaries) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const availableVersionDetails = availableVersion[fileType];
|
|
||||||
const correttoVersion = this.getCorrettoVersion(availableVersionDetails.resource);
|
|
||||||
availableVersions.push({
|
|
||||||
checksum: availableVersionDetails.checksum,
|
|
||||||
checksum_sha256: availableVersionDetails.checksum_sha256,
|
|
||||||
fileType,
|
|
||||||
resource: availableVersionDetails.resource,
|
|
||||||
downloadLink: `https://corretto.aws${availableVersionDetails.resource}`,
|
|
||||||
version: version,
|
|
||||||
correttoVersion
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return availableVersions;
|
|
||||||
}
|
|
||||||
getPlatformOption() {
|
|
||||||
// Corretto has its own platform names so we need to map them
|
|
||||||
switch (process.platform) {
|
|
||||||
case 'darwin':
|
|
||||||
return 'macos';
|
|
||||||
case 'win32':
|
|
||||||
return 'windows';
|
|
||||||
default:
|
|
||||||
return process.platform;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
distributionArchitecture() {
|
|
||||||
const architecture = super.distributionArchitecture();
|
|
||||||
return architecture === 'armv7' ? 'arm' : architecture;
|
|
||||||
}
|
|
||||||
getCorrettoVersion(resource) {
|
|
||||||
const regex = /(\d+.+)\//;
|
|
||||||
const match = regex.exec(resource);
|
|
||||||
if (match === null) {
|
|
||||||
throw Error(`Could not parse corretto version from ${resource}`);
|
|
||||||
}
|
|
||||||
return match[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/***/ })
|
|
||||||
|
|
||||||
};
|
|
||||||
Vendored
-155
@@ -1,155 +0,0 @@
|
|||||||
export const id = 151;
|
|
||||||
export const ids = [151];
|
|
||||||
export const modules = {
|
|
||||||
|
|
||||||
/***/ 8151:
|
|
||||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
||||||
|
|
||||||
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
||||||
/* harmony export */ KonaDistribution: () => (/* binding */ KonaDistribution)
|
|
||||||
/* harmony export */ });
|
|
||||||
/* harmony import */ var _actions_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(3838);
|
|
||||||
/* harmony import */ var semver__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2088);
|
|
||||||
/* harmony import */ var semver__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(semver__WEBPACK_IMPORTED_MODULE_1__);
|
|
||||||
/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(9896);
|
|
||||||
/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_2__);
|
|
||||||
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(6928);
|
|
||||||
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_3__);
|
|
||||||
/* harmony import */ var _base_installer_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(6242);
|
|
||||||
/* harmony import */ var _util_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(4527);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const KONA_RELEASES_URL = 'https://tencent.github.io/konajdk/releases/kona-v1.json';
|
|
||||||
class KonaDistribution extends _base_installer_js__WEBPACK_IMPORTED_MODULE_4__/* .JavaBase */ .O {
|
|
||||||
constructor(installerOptions) {
|
|
||||||
super('Kona', installerOptions);
|
|
||||||
}
|
|
||||||
async downloadTool(javaRelease) {
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_0__/* .info */ .pq(`Downloading Kona JDK ${javaRelease.version} (${this.distribution}) from ${javaRelease.url} ...`);
|
|
||||||
const javaArchivePath = await this.downloadAndVerify(javaRelease);
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_0__/* .info */ .pq(`Extracting Java archive...`);
|
|
||||||
const extension = (0,_util_js__WEBPACK_IMPORTED_MODULE_5__/* .getDownloadArchiveExtension */ .ag)();
|
|
||||||
const archivePath = process.platform === 'win32'
|
|
||||||
? (0,_util_js__WEBPACK_IMPORTED_MODULE_5__/* .renameWinArchive */ .n2)(javaArchivePath)
|
|
||||||
: javaArchivePath;
|
|
||||||
const extractedJavaPath = await (0,_util_js__WEBPACK_IMPORTED_MODULE_5__/* .extractJdkFile */ .PE)(archivePath, extension);
|
|
||||||
const archiveName = fs__WEBPACK_IMPORTED_MODULE_2___default().readdirSync(extractedJavaPath)[0];
|
|
||||||
const jdkDirectory = path__WEBPACK_IMPORTED_MODULE_3___default().join(extractedJavaPath, archiveName);
|
|
||||||
const version = this.getToolcacheVersionName(javaRelease.version);
|
|
||||||
const javaPath = await (0,_util_js__WEBPACK_IMPORTED_MODULE_5__/* .cacheJdkDir */ .Vj)(jdkDirectory, this.toolcacheFolderName, version, this.architecture);
|
|
||||||
return { version: javaRelease.version, path: javaPath };
|
|
||||||
}
|
|
||||||
async findPackageForDownload(version) {
|
|
||||||
if (!this.stable) {
|
|
||||||
throw new Error('Kona provides stable releases only');
|
|
||||||
}
|
|
||||||
if (this.packageType !== 'jdk') {
|
|
||||||
throw new Error('Kona provides jdk only');
|
|
||||||
}
|
|
||||||
const availableReleases = await this.getAvailableReleases();
|
|
||||||
const releases = availableReleases
|
|
||||||
.filter(item => {
|
|
||||||
return (0,_util_js__WEBPACK_IMPORTED_MODULE_5__/* .isVersionSatisfies */ .y)(version, item.version);
|
|
||||||
})
|
|
||||||
.map(item => {
|
|
||||||
return {
|
|
||||||
version: item.version,
|
|
||||||
url: item.downloadUrl,
|
|
||||||
checksum: item.checksum
|
|
||||||
? {
|
|
||||||
algorithm: 'sha256',
|
|
||||||
value: item.checksum,
|
|
||||||
source: KONA_RELEASES_URL
|
|
||||||
}
|
|
||||||
: undefined
|
|
||||||
};
|
|
||||||
})
|
|
||||||
.sort((a, b) => -semver__WEBPACK_IMPORTED_MODULE_1___default().compareBuild(a.version, b.version));
|
|
||||||
if (!releases.length) {
|
|
||||||
throw new Error(`No Kona release for the specified version "${version}" on OS "${this.getOs()}" and arch "${this.getArch()}".`);
|
|
||||||
}
|
|
||||||
return releases[0];
|
|
||||||
}
|
|
||||||
async getAvailableReleases() {
|
|
||||||
if (_actions_core__WEBPACK_IMPORTED_MODULE_0__/* .isDebug */ ._o()) {
|
|
||||||
console.time('Retrieving available releases for Kona took'); // eslint-disable-line no-console
|
|
||||||
}
|
|
||||||
const releaseInfo = await this.fetchReleaseInfo();
|
|
||||||
if (!releaseInfo) {
|
|
||||||
throw new Error(`Couldn't fetch Kona release information`);
|
|
||||||
}
|
|
||||||
const availableReleases = this.chooseReleases(this.getOs(), this.getArch(), releaseInfo);
|
|
||||||
if (_actions_core__WEBPACK_IMPORTED_MODULE_0__/* .isDebug */ ._o()) {
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_0__/* .startGroup */ .Oh('Print information about available releases');
|
|
||||||
console.timeEnd('Retrieving available releases for Kona took'); // eslint-disable-line no-console
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_0__/* .debug */ .Yz(availableReleases.map(item => item.version).join(', '));
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_0__/* .endGroup */ .N4();
|
|
||||||
}
|
|
||||||
return availableReleases;
|
|
||||||
}
|
|
||||||
async fetchReleaseInfo() {
|
|
||||||
try {
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_0__/* .debug */ .Yz(`Fetching Kona release info from URL: ${KONA_RELEASES_URL}`);
|
|
||||||
return (await this.http.getJson(KONA_RELEASES_URL))
|
|
||||||
.result;
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_0__/* .debug */ .Yz(`Fetching Kona release info from the URL: ${KONA_RELEASES_URL} failed with the error: ${err.message}`);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
chooseReleases(os, arch, releaseInfo) {
|
|
||||||
const releases = [];
|
|
||||||
for (const majorVersion in releaseInfo) {
|
|
||||||
const versions = releaseInfo[majorVersion];
|
|
||||||
for (const version of versions) {
|
|
||||||
if (!version.latest) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for (const file of version.files) {
|
|
||||||
if (file.os === os && file.arch === arch) {
|
|
||||||
releases.push({
|
|
||||||
version: version.version,
|
|
||||||
jdkVersion: version.jdkVersion,
|
|
||||||
os: os,
|
|
||||||
arch: arch,
|
|
||||||
downloadUrl: version.baseUrl + file.filename,
|
|
||||||
checksum: file.checksum
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return releases;
|
|
||||||
}
|
|
||||||
getOs() {
|
|
||||||
switch (process.platform) {
|
|
||||||
case 'darwin':
|
|
||||||
return 'macos';
|
|
||||||
case 'win32':
|
|
||||||
return 'windows';
|
|
||||||
default:
|
|
||||||
return process.platform;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
getArch() {
|
|
||||||
switch (this.architecture) {
|
|
||||||
case 'arm64':
|
|
||||||
return 'aarch64';
|
|
||||||
case 'x64':
|
|
||||||
return 'x86_64';
|
|
||||||
default:
|
|
||||||
return this.architecture;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/***/ })
|
|
||||||
|
|
||||||
};
|
|
||||||
Vendored
-63
@@ -1,63 +0,0 @@
|
|||||||
export const id = 172;
|
|
||||||
export const ids = [172];
|
|
||||||
export const modules = {
|
|
||||||
|
|
||||||
/***/ 8172:
|
|
||||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
||||||
|
|
||||||
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
||||||
/* harmony export */ configureMavenArgs: () => (/* binding */ configureMavenArgs)
|
|
||||||
/* harmony export */ });
|
|
||||||
/* harmony import */ var _actions_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(3838);
|
|
||||||
/* harmony import */ var _util_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4527);
|
|
||||||
/* harmony import */ var _constants_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(7242);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configures the MAVEN_ARGS environment variable so that Maven suppresses
|
|
||||||
* artifact transfer/download progress output by default, producing cleaner
|
|
||||||
* CI logs.
|
|
||||||
*
|
|
||||||
* Behavior:
|
|
||||||
* - When `show-download-progress` is `false` (the default), `-ntp`
|
|
||||||
* (`--no-transfer-progress`) is appended to any existing MAVEN_ARGS value.
|
|
||||||
* - When `show-download-progress` is `true`, MAVEN_ARGS is left untouched so
|
|
||||||
* the user's own configuration (and Maven's default progress output) is
|
|
||||||
* preserved.
|
|
||||||
*
|
|
||||||
* The change is idempotent: if MAVEN_ARGS already disables transfer progress
|
|
||||||
* (via `-ntp` or `--no-transfer-progress`) nothing is added. Any pre-existing
|
|
||||||
* MAVEN_ARGS value is preserved.
|
|
||||||
*
|
|
||||||
* MAVEN_ARGS is honored by Maven 3.9.0+ and the Maven Wrapper; older Maven
|
|
||||||
* versions ignore it, so this is a no-op there. It has no effect on non-Maven
|
|
||||||
* builds such as Gradle or sbt.
|
|
||||||
*/
|
|
||||||
function configureMavenArgs() {
|
|
||||||
const showDownloadProgress = (0,_util_js__WEBPACK_IMPORTED_MODULE_1__/* .getBooleanInput */ .Vt)(_constants_js__WEBPACK_IMPORTED_MODULE_2__/* .INPUT_SHOW_DOWNLOAD_PROGRESS */ .wX, false);
|
|
||||||
if (showDownloadProgress) {
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_0__/* .debug */ .Yz(`${_constants_js__WEBPACK_IMPORTED_MODULE_2__/* .INPUT_SHOW_DOWNLOAD_PROGRESS */ .wX} is true; leaving ${_constants_js__WEBPACK_IMPORTED_MODULE_2__/* .MAVEN_ARGS_ENV */ .qm} unchanged`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const existingArgs = (process.env[_constants_js__WEBPACK_IMPORTED_MODULE_2__/* .MAVEN_ARGS_ENV */ .qm] ?? '').trim();
|
|
||||||
const alreadyDisabled = existingArgs
|
|
||||||
.split(/\s+/)
|
|
||||||
.some(arg => arg === _constants_js__WEBPACK_IMPORTED_MODULE_2__/* .MAVEN_NO_TRANSFER_PROGRESS_FLAG */ .ti ||
|
|
||||||
arg === _constants_js__WEBPACK_IMPORTED_MODULE_2__/* .MAVEN_NO_TRANSFER_PROGRESS_LONG_FLAG */ .kN);
|
|
||||||
if (alreadyDisabled) {
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_0__/* .debug */ .Yz(`${_constants_js__WEBPACK_IMPORTED_MODULE_2__/* .MAVEN_ARGS_ENV */ .qm} already disables transfer progress; leaving it unchanged`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const updatedArgs = existingArgs
|
|
||||||
? `${existingArgs} ${_constants_js__WEBPACK_IMPORTED_MODULE_2__/* .MAVEN_NO_TRANSFER_PROGRESS_FLAG */ .ti}`
|
|
||||||
: _constants_js__WEBPACK_IMPORTED_MODULE_2__/* .MAVEN_NO_TRANSFER_PROGRESS_FLAG */ .ti;
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_0__/* .exportVariable */ .dN(_constants_js__WEBPACK_IMPORTED_MODULE_2__/* .MAVEN_ARGS_ENV */ .qm, updatedArgs);
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_0__/* .info */ .pq(`Configured ${_constants_js__WEBPACK_IMPORTED_MODULE_2__/* .MAVEN_ARGS_ENV */ .qm} to include ${_constants_js__WEBPACK_IMPORTED_MODULE_2__/* .MAVEN_NO_TRANSFER_PROGRESS_FLAG */ .ti} to suppress Maven transfer progress logs. ` +
|
|
||||||
`Set '${_constants_js__WEBPACK_IMPORTED_MODULE_2__/* .INPUT_SHOW_DOWNLOAD_PROGRESS */ .wX}: true' to keep the download progress output.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/***/ })
|
|
||||||
|
|
||||||
};
|
|
||||||
Vendored
-121
@@ -1,121 +0,0 @@
|
|||||||
export const id = 182;
|
|
||||||
export const ids = [182];
|
|
||||||
export const modules = {
|
|
||||||
|
|
||||||
/***/ 1182:
|
|
||||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
||||||
|
|
||||||
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
||||||
/* harmony export */ OracleDistribution: () => (/* binding */ OracleDistribution)
|
|
||||||
/* harmony export */ });
|
|
||||||
/* harmony import */ var _actions_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(3838);
|
|
||||||
/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(9896);
|
|
||||||
/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_1__);
|
|
||||||
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6928);
|
|
||||||
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_2__);
|
|
||||||
/* harmony import */ var _base_installer_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(6242);
|
|
||||||
/* harmony import */ var _util_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(4527);
|
|
||||||
/* harmony import */ var _actions_http_client__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(4942);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const ORACLE_DL_BASE = 'https://download.oracle.com/java';
|
|
||||||
class OracleDistribution extends _base_installer_js__WEBPACK_IMPORTED_MODULE_3__/* .JavaBase */ .O {
|
|
||||||
constructor(installerOptions) {
|
|
||||||
super('Oracle', installerOptions);
|
|
||||||
}
|
|
||||||
async downloadTool(javaRelease) {
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_0__/* .info */ .pq(`Downloading Java ${javaRelease.version} (${this.distribution}) from ${javaRelease.url} ...`);
|
|
||||||
let javaArchivePath = await this.downloadAndVerify(javaRelease);
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_0__/* .info */ .pq(`Extracting Java archive...`);
|
|
||||||
const extension = (0,_util_js__WEBPACK_IMPORTED_MODULE_4__/* .getDownloadArchiveExtension */ .ag)();
|
|
||||||
if (process.platform === 'win32') {
|
|
||||||
javaArchivePath = (0,_util_js__WEBPACK_IMPORTED_MODULE_4__/* .renameWinArchive */ .n2)(javaArchivePath);
|
|
||||||
}
|
|
||||||
const extractedJavaPath = await (0,_util_js__WEBPACK_IMPORTED_MODULE_4__/* .extractJdkFile */ .PE)(javaArchivePath, extension);
|
|
||||||
const archiveName = fs__WEBPACK_IMPORTED_MODULE_1___default().readdirSync(extractedJavaPath)[0];
|
|
||||||
const archivePath = path__WEBPACK_IMPORTED_MODULE_2___default().join(extractedJavaPath, archiveName);
|
|
||||||
const version = this.getToolcacheVersionName(javaRelease.version);
|
|
||||||
const javaPath = await (0,_util_js__WEBPACK_IMPORTED_MODULE_4__/* .cacheJdkDir */ .Vj)(archivePath, this.toolcacheFolderName, version, this.architecture);
|
|
||||||
return { version: javaRelease.version, path: javaPath };
|
|
||||||
}
|
|
||||||
async findPackageForDownload(range) {
|
|
||||||
const arch = this.distributionArchitecture();
|
|
||||||
if (arch !== 'x64' && arch !== 'aarch64') {
|
|
||||||
throw new Error(`Unsupported architecture: ${this.architecture}`);
|
|
||||||
}
|
|
||||||
if (!this.stable) {
|
|
||||||
throw new Error('Early access versions are not supported');
|
|
||||||
}
|
|
||||||
if (this.packageType !== 'jdk') {
|
|
||||||
throw new Error('Oracle JDK provides only the `jdk` package type');
|
|
||||||
}
|
|
||||||
const platform = this.getPlatform();
|
|
||||||
const extension = (0,_util_js__WEBPACK_IMPORTED_MODULE_4__/* .getDownloadArchiveExtension */ .ag)();
|
|
||||||
// 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 (0,_util_js__WEBPACK_IMPORTED_MODULE_4__/* .getLatestMajorVersion */ .ri)(this.http);
|
|
||||||
range = latestMajor.toString();
|
|
||||||
}
|
|
||||||
const isOnlyMajorProvided = !range.includes('.');
|
|
||||||
const major = isOnlyMajorProvided ? range : range.split('.')[0];
|
|
||||||
const possibleUrls = [];
|
|
||||||
/**
|
|
||||||
* NOTE
|
|
||||||
* If only major version was provided we will check it under /latest first
|
|
||||||
* in order to retrieve the latest possible version if possible,
|
|
||||||
* otherwise we will fall back to /archive where we are guaranteed to
|
|
||||||
* find any version if it exists
|
|
||||||
*/
|
|
||||||
if (isOnlyMajorProvided) {
|
|
||||||
possibleUrls.push(`${ORACLE_DL_BASE}/${major}/latest/jdk-${major}_${platform}-${arch}_bin.${extension}`);
|
|
||||||
}
|
|
||||||
const floatingUrl = isOnlyMajorProvided ? possibleUrls[0] : undefined;
|
|
||||||
possibleUrls.push(`${ORACLE_DL_BASE}/${major}/archive/jdk-${range}_${platform}-${arch}_bin.${extension}`);
|
|
||||||
if (parseInt(major) < 17) {
|
|
||||||
throw new Error('Oracle JDK is only supported for JDK 17 and later');
|
|
||||||
}
|
|
||||||
for (const url of possibleUrls) {
|
|
||||||
const response = await this.http.head(url);
|
|
||||||
if (response.message.statusCode === _actions_http_client__WEBPACK_IMPORTED_MODULE_5__/* .HttpCodes */ .Hv.OK) {
|
|
||||||
return {
|
|
||||||
url,
|
|
||||||
version: range,
|
|
||||||
checksum: await this.fetchChecksum(`${url}.sha256`, 'sha256'),
|
|
||||||
floating: url === floatingUrl
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (response.message.statusCode !== _actions_http_client__WEBPACK_IMPORTED_MODULE_5__/* .HttpCodes */ .Hv.NotFound) {
|
|
||||||
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) {
|
|
||||||
switch (platform) {
|
|
||||||
case 'darwin':
|
|
||||||
return 'macos';
|
|
||||||
case 'win32':
|
|
||||||
return 'windows';
|
|
||||||
case 'linux':
|
|
||||||
return 'linux';
|
|
||||||
default:
|
|
||||||
throw new Error(`Platform '${platform}' is not supported. Supported platforms: 'linux', 'macos', 'windows'`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/***/ })
|
|
||||||
|
|
||||||
};
|
|
||||||
Vendored
-137
@@ -1,137 +0,0 @@
|
|||||||
export const id = 19;
|
|
||||||
export const ids = [19];
|
|
||||||
export const modules = {
|
|
||||||
|
|
||||||
/***/ 1019:
|
|
||||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
||||||
|
|
||||||
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
||||||
/* harmony export */ LocalDistribution: () => (/* binding */ LocalDistribution)
|
|
||||||
/* harmony export */ });
|
|
||||||
/* harmony import */ var _actions_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(3838);
|
|
||||||
/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(9896);
|
|
||||||
/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_1__);
|
|
||||||
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6928);
|
|
||||||
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_2__);
|
|
||||||
/* harmony import */ var _base_installer_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(6242);
|
|
||||||
/* harmony import */ var _util_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(4527);
|
|
||||||
/* harmony import */ var _constants_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(7242);
|
|
||||||
/* harmony import */ var crypto__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(6982);
|
|
||||||
/* harmony import */ var crypto__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(crypto__WEBPACK_IMPORTED_MODULE_5__);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class LocalDistribution extends _base_installer_js__WEBPACK_IMPORTED_MODULE_3__/* .JavaBase */ .O {
|
|
||||||
jdkFile;
|
|
||||||
constructor(installerOptions, jdkFile) {
|
|
||||||
super('jdkfile', installerOptions);
|
|
||||||
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.");
|
|
||||||
}
|
|
||||||
if (this.verifySignature) {
|
|
||||||
throw new Error(`Input 'verify-signature' is not supported for distribution '${this.distribution}'.`);
|
|
||||||
}
|
|
||||||
let foundJava = this.forceDownload ? null : this.findInToolcache();
|
|
||||||
if (foundJava) {
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_0__/* .info */ .pq(`Resolved Java ${foundJava.version} from tool-cache`);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_0__/* .info */ .pq(`Java ${this.version} was not found in tool-cache. Trying to unpack JDK file...`);
|
|
||||||
if (!this.jdkFile) {
|
|
||||||
throw new Error("'jdkFile' is not specified");
|
|
||||||
}
|
|
||||||
const jdkFilePath = path__WEBPACK_IMPORTED_MODULE_2___default().resolve(this.jdkFile);
|
|
||||||
const stats = fs__WEBPACK_IMPORTED_MODULE_1___default().statSync(jdkFilePath);
|
|
||||||
if (!stats.isFile()) {
|
|
||||||
throw new Error(`JDK file was not found in path '${jdkFilePath}'`);
|
|
||||||
}
|
|
||||||
let jdkCache;
|
|
||||||
if (this.cacheJdk) {
|
|
||||||
const [{ getJdkVerificationIdentity }, source] = await Promise.all([
|
|
||||||
Promise.all(/* import() */[__webpack_require__.e(824), __webpack_require__.e(971), __webpack_require__.e(779)]).then(__webpack_require__.bind(__webpack_require__, 5779)),
|
|
||||||
hashFile(jdkFilePath)
|
|
||||||
]);
|
|
||||||
jdkCache = {
|
|
||||||
distribution: this.distribution,
|
|
||||||
packageType: this.packageType,
|
|
||||||
architecture: this.architecture,
|
|
||||||
version: this.version,
|
|
||||||
source,
|
|
||||||
verification: getJdkVerificationIdentity(false),
|
|
||||||
path: this.getJdkCachePath(this.version)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (!this.forceDownload && jdkCache) {
|
|
||||||
const { restoreJdk } = await Promise.all(/* import() */[__webpack_require__.e(824), __webpack_require__.e(971), __webpack_require__.e(779)]).then(__webpack_require__.bind(__webpack_require__, 5779));
|
|
||||||
const restored = await restoreJdk(jdkCache);
|
|
||||||
const restoredPath = restored
|
|
||||||
? this.getRestoredJdkPath(this.version)
|
|
||||||
: undefined;
|
|
||||||
if (restoredPath) {
|
|
||||||
foundJava = {
|
|
||||||
version: this.version,
|
|
||||||
path: restoredPath
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!foundJava) {
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_0__/* .info */ .pq(`Extracting Java from '${jdkFilePath}'`);
|
|
||||||
const extractedJavaPath = await (0,_util_js__WEBPACK_IMPORTED_MODULE_4__/* .extractJdkFile */ .PE)(jdkFilePath);
|
|
||||||
const archiveName = fs__WEBPACK_IMPORTED_MODULE_1___default().readdirSync(extractedJavaPath)[0];
|
|
||||||
const archivePath = path__WEBPACK_IMPORTED_MODULE_2___default().join(extractedJavaPath, archiveName);
|
|
||||||
const javaVersion = this.version;
|
|
||||||
const javaPath = await (0,_util_js__WEBPACK_IMPORTED_MODULE_4__/* .cacheJdkDir */ .Vj)(archivePath, this.toolcacheFolderName, this.getToolcacheVersionName(javaVersion), this.architecture);
|
|
||||||
foundJava = {
|
|
||||||
version: javaVersion,
|
|
||||||
path: javaPath
|
|
||||||
};
|
|
||||||
if (jdkCache) {
|
|
||||||
const { registerJdk } = await Promise.all(/* import() */[__webpack_require__.e(824), __webpack_require__.e(971), __webpack_require__.e(779)]).then(__webpack_require__.bind(__webpack_require__, 5779));
|
|
||||||
registerJdk(jdkCache);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// JDK folder may contain postfix "Contents/Home" on macOS
|
|
||||||
const macOSPostfixPath = path__WEBPACK_IMPORTED_MODULE_2___default().join(foundJava.path, _constants_js__WEBPACK_IMPORTED_MODULE_6__/* .MACOS_JAVA_CONTENT_POSTFIX */ .PG);
|
|
||||||
if (process.platform === 'darwin' && fs__WEBPACK_IMPORTED_MODULE_1___default().existsSync(macOSPostfixPath)) {
|
|
||||||
foundJava.path = macOSPostfixPath;
|
|
||||||
}
|
|
||||||
if (this.setDefault) {
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_0__/* .info */ .pq(`Setting Java ${foundJava.version} as the default`);
|
|
||||||
this.setJavaDefault(foundJava.version, foundJava.path);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_actions_core__WEBPACK_IMPORTED_MODULE_0__/* .info */ .pq(`Installing Java ${foundJava.version} (not setting as default)`);
|
|
||||||
this.setJavaEnvironment(foundJava.version, foundJava.path);
|
|
||||||
}
|
|
||||||
return foundJava;
|
|
||||||
}
|
|
||||||
async findPackageForDownload(version // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
||||||
) {
|
|
||||||
throw new Error('This method should not be implemented in local file provider');
|
|
||||||
}
|
|
||||||
async downloadTool(javaRelease // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
||||||
) {
|
|
||||||
throw new Error('This method should not be implemented in local file provider');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function hashFile(file) {
|
|
||||||
const hash = (0,crypto__WEBPACK_IMPORTED_MODULE_5__.createHash)('sha256');
|
|
||||||
for await (const chunk of (0,fs__WEBPACK_IMPORTED_MODULE_1__.createReadStream)(file)) {
|
|
||||||
hash.update(chunk);
|
|
||||||
}
|
|
||||||
return hash.digest('hex');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/***/ })
|
|
||||||
|
|
||||||
};
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user