diff --git a/.github/ISSUE_TEMPLATE/new_distribution_request.md b/.github/ISSUE_TEMPLATE/new_distribution_request.md new file mode 100644 index 000000000..f5d7c7faf --- /dev/null +++ b/.github/ISSUE_TEMPLATE/new_distribution_request.md @@ -0,0 +1,22 @@ +--- +name: New Java distribution template +about: Suggest a new Java distribution +title: '' +labels: feature request, needs triage +assignees: '' +--- + +**Description:** +Describe your proposal. + +**Justification:** +Justification or a use case for your proposal. + +**Download URL:** +Download URL for the new distribution. + +**License:** +Link to the license for the new distribution. + +**Are you willing to submit a PR?** + \ No newline at end of file diff --git a/.github/PULL_REQUEST_TEMPLATE/new_distribution_pull_request_template.md b/.github/PULL_REQUEST_TEMPLATE/new_distribution_pull_request_template.md new file mode 100644 index 000000000..4e3b44372 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/new_distribution_pull_request_template.md @@ -0,0 +1,16 @@ +**Description:** +Describe your changes. + +**Related issue:** +Add link to the related issue. + +**Download URL:** +Download URL for the new distribution. + +**License:** +Link to the license for the new distribution. + +**Check list:** +- [ ] Mark if documentation changes are required. +- [ ] Mark if tests were added or updated to cover the changes. +- [ ] Mark if new distribution is being added. \ No newline at end of file diff --git a/.github/java.json b/.github/java.json index eda1b0cd4..5e52ab819 100644 --- a/.github/java.json +++ b/.github/java.json @@ -9,6 +9,31 @@ "message": 3 } ] + }, + { + "owner": "javac", + "pattern": [ + { + "regexp": "^([^:]+):(\\d+): (warning|error): (.+?)$", + "file": 1, + "line": 2, + "severity": 3, + "message": 4 + } + ] + }, + { + "owner": "maven-javac", + "pattern": [ + { + "regexp": "^\\[(WARNING|ERROR)\\]\\s+(.+?\\.java):\\[(\\d+),(\\d+)\\]\\s+(.+)$", + "severity": 1, + "file": 2, + "line": 3, + "column": 4, + "message": 5 + } + ] } ] -} \ No newline at end of file +} diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index ef54acadd..dcf4beaaf 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -5,5 +5,6 @@ Describe your changes. Add link to the related issue. **Check list:** +- [ ] Ran `npm run check` locally (format, lint, build, test) and all checks pass. - [ ] Mark if documentation changes are required. - [ ] Mark if tests were added or updated to cover the changes. \ No newline at end of file diff --git a/.github/workflows/basic-validation.yml b/.github/workflows/basic-validation.yml index e93e58009..ea70e0577 100644 --- a/.github/workflows/basic-validation.yml +++ b/.github/workflows/basic-validation.yml @@ -11,6 +11,9 @@ on: paths-ignore: - '**.md' +permissions: + contents: read + jobs: call-basic-validation: name: Basic validation diff --git a/.github/workflows/check-dist.yml b/.github/workflows/check-dist.yml index 90ef986ad..5592249e7 100644 --- a/.github/workflows/check-dist.yml +++ b/.github/workflows/check-dist.yml @@ -11,6 +11,9 @@ on: - '**.md' workflow_dispatch: +permissions: + contents: read + jobs: call-check-dist: name: Check dist/ diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 7a8261238..598f7de5d 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -8,7 +8,13 @@ on: schedule: - cron: '0 3 * * 0' +permissions: {} + jobs: call-codeQL-analysis: + permissions: + actions: read + contents: read + security-events: write name: CodeQL analysis uses: actions/reusable-workflows/.github/workflows/codeql-analysis.yml@main diff --git a/.github/workflows/e2e-cache-dependency-path.yml b/.github/workflows/e2e-cache-dependency-path.yml index 8b40e99f0..1c79c0814 100644 --- a/.github/workflows/e2e-cache-dependency-path.yml +++ b/.github/workflows/e2e-cache-dependency-path.yml @@ -11,6 +11,9 @@ on: paths-ignore: - '**.md' +permissions: + contents: read + defaults: run: shell: bash @@ -24,7 +27,9 @@ jobs: os: [macos-latest, windows-latest, ubuntu-latest] steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 + with: + persist-credentials: false - name: Run setup-java with the cache for gradle uses: ./ id: setup-java @@ -51,7 +56,9 @@ jobs: needs: gradle1-save steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 + with: + persist-credentials: false - name: Run setup-java with the cache for gradle uses: ./ id: setup-java @@ -76,7 +83,9 @@ jobs: needs: gradle1-save steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 + with: + persist-credentials: false - name: Run setup-java with the cache for gradle uses: ./ id: setup-java diff --git a/.github/workflows/e2e-cache.yml b/.github/workflows/e2e-cache.yml index 6df10b578..c76cf50b9 100644 --- a/.github/workflows/e2e-cache.yml +++ b/.github/workflows/e2e-cache.yml @@ -11,6 +11,9 @@ on: paths-ignore: - '**.md' +permissions: + contents: read + defaults: run: shell: bash @@ -24,7 +27,9 @@ jobs: os: [macos-15-intel, windows-latest, ubuntu-latest] steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 + with: + persist-credentials: false - name: Run setup-java with the cache for gradle uses: ./ id: setup-java @@ -50,7 +55,9 @@ jobs: needs: gradle-save steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 + with: + persist-credentials: false - name: Run setup-java with the cache for gradle uses: ./ id: setup-java @@ -73,7 +80,9 @@ jobs: os: [macos-15-intel, windows-latest, ubuntu-latest] steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 + with: + persist-credentials: false - name: Run setup-java with the cache for maven uses: ./ id: setup-java @@ -97,7 +106,9 @@ jobs: needs: maven-save steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 + with: + persist-credentials: false - name: Run setup-java with the cache for maven uses: ./ id: setup-java @@ -124,7 +135,9 @@ jobs: os: [macos-15-intel, windows-latest, ubuntu-22.04] steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 + with: + persist-credentials: false - name: Run setup-java with the cache for sbt uses: ./ id: setup-java @@ -174,7 +187,9 @@ jobs: needs: sbt-save steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 + with: + persist-credentials: false - name: Run setup-java with the cache for sbt uses: ./ id: setup-java diff --git a/.github/workflows/e2e-local-file.yml b/.github/workflows/e2e-local-file.yml index 92fdf7597..0a81182e4 100644 --- a/.github/workflows/e2e-local-file.yml +++ b/.github/workflows/e2e-local-file.yml @@ -11,6 +11,9 @@ on: paths-ignore: - '**.md' +permissions: + contents: read + jobs: setup-java-local-file-adopt: name: Validate installation from local file Adopt @@ -21,7 +24,9 @@ jobs: os: [macos-latest, windows-latest, ubuntu-latest] steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 + with: + persist-credentials: false - name: Download Adopt OpenJDK file run: | if ($IsLinux) { @@ -42,11 +47,13 @@ jobs: id: setup-java with: distribution: 'jdkfile' - jdkFile: ${{ runner.temp }}/${{ env.LocalFilename }} + jdk-file: ${{ runner.temp }}/${{ env.LocalFilename }} java-version: '11.0.0-ea' architecture: x64 - name: Verify Java version - run: bash __tests__/verify-java.sh "11.0.10" "${{ steps.setup-java.outputs.path }}" + 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: @@ -58,7 +65,9 @@ jobs: os: [macos-latest, windows-latest, ubuntu-latest] steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 + with: + persist-credentials: false - name: Download Zulu OpenJDK file run: | if ($IsLinux) { @@ -79,11 +88,13 @@ jobs: id: setup-java with: distribution: 'jdkfile' - jdkFile: ${{ runner.temp }}/${{ env.LocalFilename }} + jdk-file: ${{ runner.temp }}/${{ env.LocalFilename }} java-version: '11.0.0-ea' architecture: x64 - name: Verify Java version - run: bash __tests__/verify-java.sh "11.0" "${{ steps.setup-java.outputs.path }}" + env: + JAVA_PATH: ${{ steps.setup-java.outputs.path }} + run: bash __tests__/verify-java.sh "11.0" "$JAVA_PATH" shell: bash setup-java-local-file-temurin: @@ -95,7 +106,9 @@ jobs: os: [macos-latest, windows-latest, ubuntu-latest] steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 + with: + persist-credentials: false - name: Download Eclipse Temurin file run: | if ($IsLinux) { @@ -116,9 +129,12 @@ jobs: id: setup-java with: distribution: 'jdkfile' + # Intentionally uses the deprecated `jdkFile` alias to keep it covered. jdkFile: ${{ runner.temp }}/${{ env.LocalFilename }} java-version: '11.0.0-ea' architecture: x64 - name: Verify Java version - run: bash __tests__/verify-java.sh "11.0.12" "${{ steps.setup-java.outputs.path }}" + env: + JAVA_PATH: ${{ steps.setup-java.outputs.path }} + run: bash __tests__/verify-java.sh "11.0.12" "$JAVA_PATH" shell: bash diff --git a/.github/workflows/e2e-publishing.yml b/.github/workflows/e2e-publishing.yml index 0c0aaafa9..02a6b2596 100644 --- a/.github/workflows/e2e-publishing.yml +++ b/.github/workflows/e2e-publishing.yml @@ -11,6 +11,9 @@ on: paths-ignore: - '**.md' +permissions: + contents: read + defaults: run: shell: pwsh @@ -25,7 +28,9 @@ jobs: os: [macos-latest, windows-latest, ubuntu-latest] steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 + with: + persist-credentials: false - name: setup-java uses: ./ id: setup-java @@ -60,7 +65,9 @@ jobs: os: [macos-latest, windows-latest, ubuntu-latest] steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 + with: + persist-credentials: false - name: Create fake settings.xml run: | $xmlDirectory = Join-Path $HOME ".m2" @@ -96,7 +103,9 @@ jobs: os: [macos-latest, windows-latest, ubuntu-latest] steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 + with: + persist-credentials: false - name: Create fake settings.xml run: | $xmlDirectory = Join-Path $HOME ".m2" @@ -133,7 +142,9 @@ jobs: os: [macos-latest, windows-latest, ubuntu-latest] steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 + with: + persist-credentials: false - name: setup-java uses: ./ id: setup-java diff --git a/.github/workflows/e2e-versions.yml b/.github/workflows/e2e-versions.yml index 7dc8d8a71..8a7322b69 100644 --- a/.github/workflows/e2e-versions.yml +++ b/.github/workflows/e2e-versions.yml @@ -13,9 +13,13 @@ on: schedule: - cron: '0 */12 * * *' workflow_dispatch: + +permissions: + contents: read + jobs: setup-java-major-versions: - name: ${{ matrix.distribution }} ${{ matrix.version }} (jdk-x64) - ${{ matrix.os }} + name: ${{ matrix.distribution }} ${{ matrix.version }} (jdk-${{ contains(matrix.os, 'macos') && !contains(matrix.os, 'intel') && 'arm64' || 'x64' }}) - ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: fail-fast: false @@ -32,7 +36,8 @@ jobs: 'corretto', 'dragonwell', 'sapmachine', - 'jetbrains' + 'jetbrains', + 'kona' ] # internally 'adopt-hotspot' is the same as 'adopt' version: ['21', '11', '17'] exclude: @@ -50,6 +55,15 @@ jobs: - distribution: microsoft os: macos-latest version: 25 + - distribution: kona + os: windows-latest + version: 25 + - distribution: kona + os: ubuntu-latest + version: 25 + - distribution: kona + os: macos-latest + version: 25 - distribution: oracle os: macos-15-intel version: 17 @@ -73,7 +87,9 @@ jobs: version: '24-ea' steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 + with: + persist-credentials: false - name: setup-java uses: ./ id: setup-java @@ -83,14 +99,17 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Verify Java - run: bash __tests__/verify-java.sh "${{ matrix.version }}" "${{ steps.setup-java.outputs.path }}" + 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-alpine-linux: - name: ${{ matrix.distribution }} ${{ matrix.version }} (jdk-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 }} container: - image: alpine:latest + image: alpine:3.21 strategy: fail-fast: false matrix: @@ -99,7 +118,9 @@ jobs: version: ['21', '17'] steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 + with: + persist-credentials: false - name: Install bash run: apk add --no-cache bash - name: setup-java @@ -109,11 +130,14 @@ jobs: java-version: ${{ matrix.version }} distribution: ${{ matrix.distribution }} - name: Verify Java - run: bash __tests__/verify-java.sh "${{ matrix.version }}" "${{ steps.setup-java.outputs.path }}" + 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-major-minor-versions: - name: ${{ matrix.distribution }} ${{ matrix.version }} (jdk-x64) - ${{ matrix.os }} + name: ${{ matrix.distribution }} ${{ matrix.version }} (jdk-${{ contains(matrix.os, 'macos') && !contains(matrix.os, 'intel') && 'arm64' || 'x64' }}) - ${{ matrix.os }} needs: setup-java-major-versions runs-on: ${{ matrix.os }} strategy: @@ -149,7 +173,9 @@ jobs: version: '17.0.7' steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 + with: + persist-credentials: false - name: setup-java uses: ./ id: setup-java @@ -157,10 +183,12 @@ jobs: java-version: ${{ matrix.version }} distribution: ${{ matrix.distribution }} - name: Verify Java - run: bash __tests__/verify-java.sh "${{ matrix.version }}" "${{ steps.setup-java.outputs.path }}" - shell: bash env: + JAVA_VERSION: ${{ matrix.version }} + JAVA_PATH: ${{ steps.setup-java.outputs.path }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: bash __tests__/verify-java.sh "$JAVA_VERSION" "$JAVA_PATH" + shell: bash setup-java-check-latest: name: ${{ matrix.distribution }} ${{ matrix.version }} - check-latest flag - ${{ matrix.os }} @@ -184,7 +212,9 @@ jobs: os: macos-latest steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 + with: + persist-credentials: false - name: setup-java uses: ./ id: setup-java @@ -195,7 +225,9 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Verify Java - run: bash __tests__/verify-java.sh "11" "${{ steps.setup-java.outputs.path }}" + env: + JAVA_PATH: ${{ steps.setup-java.outputs.path }} + run: bash __tests__/verify-java.sh "11" "$JAVA_PATH" shell: bash setup-java-multiple-jdks: @@ -220,7 +252,9 @@ jobs: os: macos-latest steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 + with: + persist-credentials: false - name: setup-java uses: ./ id: setup-java @@ -245,11 +279,13 @@ jobs: } shell: pwsh - name: Verify Java - run: bash __tests__/verify-java.sh "17" "${{ steps.setup-java.outputs.path }}" + env: + JAVA_PATH: ${{ steps.setup-java.outputs.path }} + run: bash __tests__/verify-java.sh "17" "$JAVA_PATH" shell: bash setup-java-ea-versions-zulu: - name: zulu ${{ matrix.version }} (jdk-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 runs-on: ${{ matrix.os }} strategy: @@ -259,7 +295,9 @@ jobs: version: ['17-ea', '15.0.0-ea.14'] steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 + with: + persist-credentials: false - name: setup-java uses: ./ id: setup-java @@ -267,11 +305,14 @@ jobs: java-version: ${{ matrix.version }} distribution: zulu - name: Verify Java - run: bash __tests__/verify-java.sh "${{ matrix.version }}" "${{ steps.setup-java.outputs.path }}" + 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-temurin: - name: temurin ${{ matrix.version }} (jdk-x64) - ${{ 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 runs-on: ${{ matrix.os }} strategy: @@ -281,7 +322,9 @@ jobs: version: ['17-ea'] steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 + with: + persist-credentials: false - name: setup-java uses: ./ id: setup-java @@ -289,11 +332,70 @@ jobs: java-version: ${{ matrix.version }} distribution: temurin - name: Verify Java - run: bash __tests__/verify-java.sh "${{ matrix.version }}" "${{ steps.setup-java.outputs.path }}" + 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 + uses: ./ + id: setup-java + with: + java-version: ${{ matrix.version }} + distribution: temurin + 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-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-x64) - ${{ matrix.os }} + 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: @@ -303,7 +405,9 @@ jobs: version: ['17-ea', '21-ea'] steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 + with: + persist-credentials: false - name: setup-java uses: ./ id: setup-java @@ -311,7 +415,10 @@ jobs: java-version: ${{ matrix.version }} distribution: sapmachine - name: Verify Java - run: bash __tests__/verify-java.sh "${{ matrix.version }}" "${{ steps.setup-java.outputs.path }}" + 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: @@ -390,7 +497,9 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 + with: + persist-credentials: false - name: setup-java uses: ./ id: setup-java @@ -401,7 +510,10 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Verify Java - run: bash __tests__/verify-java.sh "${{ matrix.version }}" "${{ steps.setup-java.outputs.path }}" + env: + JAVA_VERSION: ${{ matrix.version }} + JAVA_PATH: ${{ steps.setup-java.outputs.path }} + run: bash __tests__/verify-java.sh "$JAVA_VERSION" "$JAVA_PATH" shell: bash # Only Liberica and Zulu provide x86 @@ -418,7 +530,9 @@ jobs: version: ['11'] steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 + with: + persist-credentials: false - name: setup-java uses: ./ id: setup-java @@ -427,7 +541,10 @@ jobs: java-version: ${{ matrix.version }} architecture: 'x86' - name: Verify Java - run: bash __tests__/verify-java.sh "${{ matrix.version }}" "${{ steps.setup-java.outputs.path }}" + 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-version-both-version-inputs-presents: @@ -441,7 +558,9 @@ jobs: java-version-file: ['.java-version', '.tool-versions'] steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 + with: + persist-credentials: false - name: Create .java-version file shell: bash run: echo "17" > .java-version @@ -456,7 +575,9 @@ jobs: java-version: 11 java-version-file: ${{matrix.java-version-file }} - name: Verify Java - run: bash __tests__/verify-java.sh "11" "${{ steps.setup-java.outputs.path }}" + env: + JAVA_PATH: ${{ steps.setup-java.outputs.path }} + run: bash __tests__/verify-java.sh "11" "$JAVA_PATH" shell: bash setup-java-version-from-file-major-notation: @@ -470,7 +591,9 @@ jobs: java-version-file: ['.java-version', '.tool-versions'] steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 + with: + persist-credentials: false - name: Create .java-version file shell: bash run: echo "11" > .java-version @@ -484,7 +607,9 @@ jobs: distribution: ${{ matrix.distribution }} java-version-file: ${{matrix.java-version-file }} - name: Verify Java - run: bash __tests__/verify-java.sh "11" "${{ steps.setup-java.outputs.path }}" + env: + JAVA_PATH: ${{ steps.setup-java.outputs.path }} + run: bash __tests__/verify-java.sh "11" "$JAVA_PATH" shell: bash setup-java-version-from-file-major-minor-patch-notation: @@ -498,7 +623,9 @@ jobs: java-version-file: ['.java-version', '.tool-versions'] steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 + with: + persist-credentials: false - name: Create .java-version file shell: bash run: echo "17.0.10" > .java-version @@ -512,7 +639,9 @@ jobs: distribution: ${{ matrix.distribution }} java-version-file: ${{matrix.java-version-file }} - name: Verify Java - run: bash __tests__/verify-java.sh "17.0.10" "${{ steps.setup-java.outputs.path }}" + env: + JAVA_PATH: ${{ steps.setup-java.outputs.path }} + run: bash __tests__/verify-java.sh "17.0.10" "$JAVA_PATH" shell: bash setup-java-version-from-file-major-minor-patch-with-dist: @@ -526,7 +655,9 @@ jobs: java-version-file: ['.java-version', '.tool-versions', '.sdkmanrc'] steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 + with: + persist-credentials: false - name: Create .java-version file shell: bash run: echo "openjdk64-17.0.10" > .java-version @@ -543,5 +674,81 @@ jobs: distribution: ${{ matrix.distribution }} java-version-file: ${{matrix.java-version-file }} - name: Verify Java - run: bash __tests__/verify-java.sh "17.0.10" "${{ steps.setup-java.outputs.path }}" + env: + JAVA_PATH: ${{ steps.setup-java.outputs.path }} + run: bash __tests__/verify-java.sh "17.0.10" "$JAVA_PATH" + shell: bash + + setup-java-set-default: + name: set-default option - ${{ matrix.os }} + needs: setup-java-major-versions + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [macos-latest, windows-latest, ubuntu-latest] + steps: + - name: Checkout + uses: actions/checkout@v6 + - name: Setup Java 17 as default + uses: ./ + id: setup-java-17 + with: + distribution: 'temurin' + java-version: '17' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Setup Java 21 without setting as default + uses: ./ + id: setup-java-21 + with: + distribution: 'temurin' + java-version: '21' + set-default: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Verify JAVA_HOME still points to Java 17 + run: | + echo "JAVA_HOME=$JAVA_HOME" + echo "Java 17 path=${{ steps.setup-java-17.outputs.path }}" + if [ "$JAVA_HOME" != "${{ steps.setup-java-17.outputs.path }}" ]; then + echo "JAVA_HOME should still point to Java 17" + exit 1 + fi + shell: bash + - name: Verify java -version reports Java 17 + run: | + JAVA_VERSION=$(java -version 2>&1 | head -1) + echo "java -version: $JAVA_VERSION" + if ! echo "$JAVA_VERSION" | grep -q "17"; then + echo "Default java should still be version 17" + exit 1 + fi + shell: bash + - name: Verify JAVA_HOME_21 env var is set + run: | + $envName = "JAVA_HOME_21_${env:RUNNER_ARCH}" + $JavaVersionPath = [Environment]::GetEnvironmentVariable($envName) + if (-not $JavaVersionPath) { + Write-Host "$envName is not set" + exit 1 + } + if (-not (Test-Path "$JavaVersionPath")) { + Write-Host "$envName path does not exist: $JavaVersionPath" + exit 1 + } + Write-Host "$envName=$JavaVersionPath" + shell: pwsh + - name: Verify Java 21 outputs are set + run: | + echo "Java 21 path=${{ steps.setup-java-21.outputs.path }}" + echo "Java 21 version=${{ steps.setup-java-21.outputs.version }}" + if [ -z "${{ steps.setup-java-21.outputs.path }}" ]; then + echo "Java 21 path output should be set" + exit 1 + fi + if [ -z "${{ steps.setup-java-21.outputs.version }}" ]; then + echo "Java 21 version output should be set" + exit 1 + fi shell: bash diff --git a/.github/workflows/licensed.yml b/.github/workflows/licensed.yml index 37f1560c3..b5d009cb5 100644 --- a/.github/workflows/licensed.yml +++ b/.github/workflows/licensed.yml @@ -9,6 +9,9 @@ on: - main workflow_dispatch: +permissions: + contents: read + jobs: call-licensed: name: Licensed diff --git a/.github/workflows/publish-immutable-actions.yml b/.github/workflows/publish-immutable-actions.yml index bfe592049..3888f9a85 100644 --- a/.github/workflows/publish-immutable-actions.yml +++ b/.github/workflows/publish-immutable-actions.yml @@ -5,6 +5,8 @@ on: types: [released] workflow_dispatch: +permissions: {} + jobs: publish: runs-on: ubuntu-latest @@ -15,7 +17,9 @@ jobs: steps: - name: Checking out - uses: actions/checkout@v6 + uses: actions/checkout@v7 + with: + persist-credentials: false - name: Publish id: publish uses: actions/publish-immutable-action@v0.0.4 diff --git a/.github/workflows/update-config-files.yml b/.github/workflows/update-config-files.yml index 87af50042..bacdc74ec 100644 --- a/.github/workflows/update-config-files.yml +++ b/.github/workflows/update-config-files.yml @@ -5,7 +5,12 @@ on: - cron: '0 3 * * 0' workflow_dispatch: +permissions: {} + jobs: call-update-configuration-files: name: Update configuration files + permissions: + contents: write # to push the branch with updated configuration files + pull-requests: write # to open/update the configuration update PR uses: actions/reusable-workflows/.github/workflows/update-config-files.yml@main diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml new file mode 100644 index 000000000..79e470f62 --- /dev/null +++ b/.github/workflows/zizmor.yml @@ -0,0 +1,48 @@ +name: Security analysis with zizmor + +on: + push: + branches: + - main + - releases/* + paths-ignore: + - '**.md' + pull_request: + paths-ignore: + - '**.md' + workflow_dispatch: + +permissions: {} + +jobs: + zizmor: + name: Analyze workflows with zizmor + runs-on: ubuntu-latest + permissions: + contents: read + security-events: write # to upload SARIF results to code scanning + steps: + - name: Checkout repository + uses: actions/checkout@v7 + with: + persist-credentials: false + + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: '3.x' + + - name: Install zizmor + run: pip install zizmor + + - name: Run zizmor + run: zizmor --format sarif .github/workflows/ > zizmor.sarif + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Upload SARIF results to code scanning + if: always() && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) + uses: github/codeql-action/upload-sarif@v4 + with: + sarif_file: zizmor.sarif + category: zizmor diff --git a/.github/zizmor.yml b/.github/zizmor.yml new file mode 100644 index 000000000..38309ec47 --- /dev/null +++ b/.github/zizmor.yml @@ -0,0 +1,11 @@ +# Configuration for zizmor (https://docs.zizmor.sh) +rules: + unpinned-uses: + config: + # First-party GitHub-maintained actions are trusted and referenced by + # major-version tags (the convention used across the actions org). + # Any third-party action must be pinned to a full commit SHA. + policies: + actions/*: ref-pin + github/*: ref-pin + '*': hash-pin diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 000000000..2312dc587 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +npx lint-staged diff --git a/.husky/pre-push b/.husky/pre-push new file mode 100755 index 000000000..192cb67eb --- /dev/null +++ b/.husky/pre-push @@ -0,0 +1 @@ +npm run build && npm test diff --git a/.licenses/npm/@actions/cache.dep.yml b/.licenses/npm/@actions/cache.dep.yml index 25b3a5b13..979068018 100644 --- a/.licenses/npm/@actions/cache.dep.yml +++ b/.licenses/npm/@actions/cache.dep.yml @@ -1,6 +1,6 @@ --- name: "@actions/cache" -version: 5.0.5 +version: 5.1.0 type: npm summary: Actions cache lib homepage: https://github.com/actions/toolkit/tree/main/packages/cache diff --git a/.licenses/npm/debug.dep.yml b/.licenses/npm/debug.dep.yml index b9b723389..b49c69e92 100644 --- a/.licenses/npm/debug.dep.yml +++ b/.licenses/npm/debug.dep.yml @@ -1,6 +1,6 @@ --- name: debug -version: 4.3.4 +version: 4.4.3 type: npm summary: Lightweight debugging utility for Node.js and the browser homepage: diff --git a/.licenses/npm/ms.dep.yml b/.licenses/npm/ms.dep.yml index ac3c8eb15..5a303e4d6 100644 --- a/.licenses/npm/ms.dep.yml +++ b/.licenses/npm/ms.dep.yml @@ -1,6 +1,6 @@ --- name: ms -version: 2.1.2 +version: 2.1.3 type: npm summary: Tiny millisecond conversion utility homepage: @@ -10,7 +10,7 @@ licenses: text: | The MIT License (MIT) - Copyright (c) 2016 Zeit, Inc. + Copyright (c) 2020 Vercel, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/.licenses/npm/undici.dep.yml b/.licenses/npm/undici.dep.yml index 121a6e35a..c46a5c7bf 100644 --- a/.licenses/npm/undici.dep.yml +++ b/.licenses/npm/undici.dep.yml @@ -1,6 +1,6 @@ --- name: undici -version: 6.24.1 +version: 6.27.0 type: npm summary: An HTTP/1.1 client, written from scratch for Node.js homepage: https://undici.nodejs.org diff --git a/README.md b/README.md index 8a7392a9f..78c595801 100644 --- a/README.md +++ b/README.md @@ -25,29 +25,28 @@ This action allows you to work with Java and Scala projects. For more details, see the full release notes on the [releases page](https://github.com/actions/setup-java/releases/tag/v5.0.0) -## V2 vs V1 - -- V2 supports custom distributions and provides support for Azul Zulu OpenJDK, Eclipse Temurin and AdoptOpenJDK out of the box. V1 supports only Azul Zulu OpenJDK. -- V2 requires you to specify distribution along with the version. V1 defaults to Azul Zulu OpenJDK, 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). - ## Usage - `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` and `.tool-versions`. See more details in [about .java-version-file](docs/advanced-usage.md#Java-version-file). + - `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`: _(required)_ Java [distribution](#supported-distributions). + - `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`. Default value: `jdk`. + - `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. - - `jdkFile`: 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. + - `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__` 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. @@ -83,7 +82,7 @@ steps: with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '25' -- run: java HelloWorldApp.java +- run: java --version ``` #### Azul Zulu OpenJDK @@ -94,40 +93,42 @@ steps: with: distribution: 'zulu' # See 'Supported distributions' for available options java-version: '25' -- run: java HelloWorldApp.java +- run: java --version ``` #### Supported version syntax -The `java-version` input supports an exact version or a version range using [SemVer](https://semver.org/) notation: -- major versions: `8`, `11`, `16`, `17`, `21`, `25` +The `java-version` input supports an exact version or a version range using [SemVer](https://semver.org/) notation. The values below are examples, not an exhaustive list: +- major versions, such as: `8`, `11`, `16`, `17`, `21`, `25` - more specific versions: `8.0.282+8`, `8.0.232`, `11.0`, `11.0.4`, `17.0` - early access (EA) versions: `15-ea`, `15.0.0-ea` #### Supported distributions Currently, the following distributions are supported: -| Keyword | Distribution | Official site | License -|-|-|-|-| -| `temurin` | Eclipse Temurin | [Link](https://adoptium.net/) | [Link](https://adoptium.net/about.html) -| `zulu` | Azul Zulu OpenJDK | [Link](https://www.azul.com/downloads/zulu-community/?package=jdk) | [Link](https://www.azul.com/products/zulu-and-zulu-enterprise/zulu-terms-of-use/) | -| `adopt` or `adopt-hotspot` | AdoptOpenJDK Hotspot | [Link](https://adoptopenjdk.net/) | [Link](https://adoptopenjdk.net/about.html) | -| `adopt-openj9` | AdoptOpenJDK OpenJ9 | [Link](https://adoptopenjdk.net/) | [Link](https://adoptopenjdk.net/about.html) | -| `liberica` | Liberica JDK | [Link](https://bell-sw.com/) | [Link](https://bell-sw.com/liberica_eula/) | -| `microsoft` | Microsoft Build of OpenJDK | [Link](https://www.microsoft.com/openjdk) | [Link](https://docs.microsoft.com/java/openjdk/faq) -| `corretto` | Amazon Corretto Build of OpenJDK | [Link](https://aws.amazon.com/corretto/) | [Link](https://aws.amazon.com/corretto/faqs/) -| `semeru` | IBM Semeru Runtime Open Edition | [Link](https://developer.ibm.com/languages/java/semeru-runtimes/downloads/) | [Link](https://openjdk.java.net/legal/gplv2+ce.html) | -| `oracle` | Oracle JDK | [Link](https://www.oracle.com/java/technologies/downloads/) | [Link](https://java.com/freeuselicense) -| `dragonwell` | Alibaba Dragonwell JDK | [Link](https://dragonwell-jdk.io/) | [Link](https://www.aliyun.com/product/dragonwell/) -| `sapmachine` | SAP SapMachine JDK/JRE | [Link](https://sapmachine.io/) | [Link](https://github.com/SAP/SapMachine/blob/sapmachine/LICENSE) -| `graalvm` | Oracle GraalVM | [Link](https://www.graalvm.org/) | [Link](https://www.oracle.com/downloads/licenses/graal-free-license.html) -| `jetbrains` | JetBrains Runtime | [Link](https://github.com/JetBrains/JetBrainsRuntime/) | [Link](https://github.com/JetBrains/JetBrainsRuntime/blob/main/LICENSE) - -**NOTE:** 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. - -**NOTE:** 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/). - -**NOTE:** For Azul Zulu OpenJDK architectures x64 and arm64 are mapped to x86 / arm with proper hw_bitness. - -**NOTE:** 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. +| 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/) | +| `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 | | + +> [!NOTE] +> - 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. +> - 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/). +> - 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. **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. @@ -137,15 +138,19 @@ Currently, the following distributions are supported: 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: - gradle: `**/*.gradle*`, `**/gradle-wrapper.properties`, `buildSrc/**/Versions.kt`, `buildSrc/**/Dependencies.kt`, `gradle/*.versions.toml`, and `**/versions.properties` -- maven: `**/pom.xml` +- 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` 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. 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). +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). + The cache input is optional, and caching is turned off by default. +**Maven Wrapper:** when `cache: 'maven'` is enabled, the action also caches and restores the Maven Wrapper distribution downloaded to `~/.m2/wrapper/dists` (in addition to the local repository), so wrapper-based (`./mvnw`) builds don't re-download the Maven distribution. The wrapper distribution is stored in a **separate** cache entry keyed only on `**/.mvn/wrapper/maven-wrapper.properties`, so it stays cached across the frequent `pom.xml` changes that rotate the main dependency cache key. + #### Caching gradle dependencies ```yaml steps: @@ -162,6 +167,8 @@ steps: ``` Using the `cache: gradle` provides a simple and effective way to cache Gradle dependencies with minimal configuration. +**Gradle Wrapper:** when `cache: 'gradle'` is enabled, the action also caches and restores the Gradle Wrapper distribution downloaded to `~/.gradle/wrapper` (in addition to the Gradle caches), so wrapper-based (`./gradlew`) builds don't re-download the Gradle distribution. The wrapper distribution is stored in a **separate** cache entry keyed only on `**/gradle-wrapper.properties`, so it stays cached across the frequent `*.gradle*` changes that rotate the main dependency cache key. + For projects that require more advanced `Gradle` caching features, such as caching build outputs, support for Gradle configuration cache, encrypted cache storage, fine-grained cache control (including options to enable or disable the cache, set it to read-only or write-only, perform automated cleanup, and define custom cache rules), or optimized performance for complex CI workflows, consider using [`gradle/actions/setup-gradle`](https://github.com/gradle/actions/tree/main/setup-gradle). For setup details and a comprehensive overview of all available features, visit the [setup-gradle documentation](https://github.com/gradle/actions/blob/main/docs/setup-gradle.md). @@ -218,7 +225,7 @@ In the basic examples above, the `check-latest` flag defaults to `false`. When s 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-flight. Check out [Hosted Tool Cache](docs/advanced-usage.md#Hosted-Tool-Cache) for more details about pre-cached Java 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. ```yaml @@ -229,7 +236,7 @@ steps: distribution: 'temurin' java-version: '25' check-latest: true -- run: java HelloWorldApp.java +- run: java --version ``` ### Testing against different Java versions @@ -248,7 +255,7 @@ jobs: with: distribution: '' java-version: ${{ matrix.java }} - - run: java HelloWorldApp.java + - run: java --version ``` ### Install multiple JDKs @@ -282,6 +289,8 @@ In the example above multiple JDKs are installed for the same job. The result af - [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) @@ -293,6 +302,15 @@ In the example above multiple JDKs are installed for the same job. The result af - [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 When using the `setup-java` action in your GitHub Actions workflow, it is recommended to set the following permissions to ensure proper functionality: diff --git a/__tests__/auth.test.ts b/__tests__/auth.test.ts index 06591da7a..eca837a56 100644 --- a/__tests__/auth.test.ts +++ b/__tests__/auth.test.ts @@ -160,6 +160,7 @@ describe('auth tests', () => { const expectedSettings = ` + false ${id} @@ -181,6 +182,7 @@ describe('auth tests', () => { const expectedSettings = ` + false ${id} diff --git a/__tests__/cache.test.ts b/__tests__/cache.test.ts index df7a59bd4..88660ae65 100644 --- a/__tests__/cache.test.ts +++ b/__tests__/cache.test.ts @@ -78,6 +78,10 @@ describe('dependency cache', () => { ReturnType, Parameters >; + let spySetOutput: jest.SpyInstance< + ReturnType, + Parameters + >; beforeEach(() => { spyCacheRestore = jest @@ -86,6 +90,7 @@ describe('dependency cache', () => { Promise.resolve(undefined) ); spyGlobHashFiles = jest.spyOn(glob, 'hashFiles'); + spySetOutput = jest.spyOn(core, 'setOutput').mockImplementation(() => {}); spyWarning.mockImplementation(() => null); }); @@ -96,22 +101,102 @@ describe('dependency cache', () => { }); describe('for maven', () => { - it('throws error if no pom.xml found', async () => { + it('throws error if no pom.xml, maven-wrapper.properties, or extensions.xml found', async () => { await expect(restore('maven', '')).rejects.toThrow( `No file in ${projectRoot( workspace - )} matched to [**/pom.xml], make sure you have checked out the target repository` + )} matched to [**/pom.xml,**/.mvn/wrapper/maven-wrapper.properties,**/.mvn/extensions.xml], make sure you have checked out the target repository` ); }); - it('downloads cache', async () => { + it('downloads cache based on pom.xml', async () => { createFile(join(workspace, 'pom.xml')); await restore('maven', ''); - expect(spyCacheRestore).toHaveBeenCalled(); - expect(spyGlobHashFiles).toHaveBeenCalledWith('**/pom.xml'); + expect(spyCacheRestore).toHaveBeenCalledWith( + [join(os.homedir(), '.m2', 'repository')], + expect.any(String) + ); + expect(spyGlobHashFiles).toHaveBeenCalledWith( + '**/pom.xml\n**/.mvn/wrapper/maven-wrapper.properties\n**/.mvn/extensions.xml' + ); expect(spyWarning).not.toHaveBeenCalled(); expect(spyInfo).toHaveBeenCalledWith('maven cache is not found'); }); + it('sets the cache-primary-key output', async () => { + createFile(join(workspace, 'pom.xml')); + + await restore('maven', ''); + expect(spySetOutput).toHaveBeenCalledWith( + 'cache-primary-key', + expect.stringContaining('setup-java-') + ); + }); + it('downloads cache based on maven-wrapper.properties', async () => { + createDirectory(join(workspace, '.mvn')); + createDirectory(join(workspace, '.mvn', 'wrapper')); + createFile( + join(workspace, '.mvn', 'wrapper', 'maven-wrapper.properties') + ); + + await restore('maven', ''); + expect(spyCacheRestore).toHaveBeenCalledWith( + [join(os.homedir(), '.m2', 'repository')], + expect.any(String) + ); + expect(spyGlobHashFiles).toHaveBeenCalledWith( + '**/pom.xml\n**/.mvn/wrapper/maven-wrapper.properties\n**/.mvn/extensions.xml' + ); + expect(spyWarning).not.toHaveBeenCalled(); + expect(spyInfo).toHaveBeenCalledWith('maven cache is not found'); + }); + it('downloads cache based on extensions.xml', async () => { + createDirectory(join(workspace, '.mvn')); + createFile(join(workspace, '.mvn', 'extensions.xml')); + + await restore('maven', ''); + expect(spyCacheRestore).toHaveBeenCalledWith( + [join(os.homedir(), '.m2', 'repository')], + expect.any(String) + ); + expect(spyGlobHashFiles).toHaveBeenCalledWith( + '**/pom.xml\n**/.mvn/wrapper/maven-wrapper.properties\n**/.mvn/extensions.xml' + ); + expect(spyWarning).not.toHaveBeenCalled(); + expect(spyInfo).toHaveBeenCalledWith('maven cache is not found'); + }); + it('restores the maven wrapper distribution cache independently of the main cache', async () => { + createFile(join(workspace, 'pom.xml')); + createDirectory(join(workspace, '.mvn')); + createDirectory(join(workspace, '.mvn', 'wrapper')); + createFile( + join(workspace, '.mvn', 'wrapper', 'maven-wrapper.properties') + ); + + await restore('maven', ''); + // Main cache no longer includes the wrapper distribution. + expect(spyCacheRestore).toHaveBeenCalledWith( + [join(os.homedir(), '.m2', 'repository')], + expect.any(String) + ); + // Wrapper distribution is restored on its own, keyed only on the + // maven-wrapper.properties hash. + expect(spyCacheRestore).toHaveBeenCalledWith( + [join(os.homedir(), '.m2', 'wrapper', 'dists')], + expect.any(String) + ); + expect(spyGlobHashFiles).toHaveBeenCalledWith( + '**/.mvn/wrapper/maven-wrapper.properties' + ); + }); + it('skips the maven wrapper cache when no maven-wrapper.properties exists', async () => { + createFile(join(workspace, 'pom.xml')); + + await restore('maven', ''); + expect(spyCacheRestore).not.toHaveBeenCalledWith( + [join(os.homedir(), '.m2', 'wrapper', 'dists')], + expect.any(String) + ); + }); }); describe('for gradle', () => { it('throws error if no build.gradle found', async () => { @@ -167,6 +252,30 @@ describe('dependency cache', () => { expect(spyWarning).not.toHaveBeenCalled(); expect(spyInfo).toHaveBeenCalledWith('gradle cache is not found'); }); + it('restores the gradle wrapper distribution cache independently of the main cache', async () => { + createFile(join(workspace, 'build.gradle')); + createDirectory(join(workspace, 'gradle')); + createDirectory(join(workspace, 'gradle', 'wrapper')); + createFile( + join(workspace, 'gradle', 'wrapper', 'gradle-wrapper.properties') + ); + + await restore('gradle', ''); + // Main cache no longer includes the wrapper distribution. + expect(spyCacheRestore).toHaveBeenCalledWith( + [join(os.homedir(), '.gradle', 'caches')], + expect.any(String) + ); + // Wrapper distribution is restored on its own, keyed only on the + // gradle-wrapper.properties hash. + expect(spyCacheRestore).toHaveBeenCalledWith( + [join(os.homedir(), '.gradle', 'wrapper')], + expect.any(String) + ); + expect(spyGlobHashFiles).toHaveBeenCalledWith( + '**/gradle-wrapper.properties' + ); + }); }); describe('for sbt', () => { it('throws error if no build.sbt found', async () => { @@ -291,10 +400,12 @@ describe('dependency cache', () => { await save('maven'); expect(spyCacheSave).toHaveBeenCalled(); expect(spyWarning).not.toHaveBeenCalled(); - expect(spyInfo).toHaveBeenCalled(); - expect(spyInfo).toHaveBeenCalledWith( + expect(spyInfo).not.toHaveBeenCalledWith( expect.stringMatching(/^Cache saved with the key:.*/) ); + expect(spyDebug).toHaveBeenCalledWith( + expect.stringMatching(/^Cache was not saved for the key:.*/) + ); }); it('saves with error from toolkit, should fail workflow', async () => { @@ -336,6 +447,40 @@ describe('dependency cache', () => { expect.stringMatching(/^Cache saved with the key:.*/) ); }); + it('saves the maven wrapper distribution cache under its own key', async () => { + createFile(join(workspace, 'pom.xml')); + createStateForWrapperRestore('maven-wrapper', false); + + await save('maven'); + expect(spyCacheSave).toHaveBeenCalledWith( + [join(os.homedir(), '.m2', 'wrapper', 'dists')], + 'setup-java-maven-wrapper-primary-key' + ); + }); + it('does not save the maven wrapper cache on an exact wrapper hit', async () => { + createFile(join(workspace, 'pom.xml')); + createStateForWrapperRestore('maven-wrapper', true); + + 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')); + createStateForWrapperRestore('maven-wrapper', false); + spyCacheSave.mockImplementation((paths: string[], key: string) => { + if (paths.includes(join(os.homedir(), '.m2', 'wrapper', 'dists'))) { + return Promise.reject( + new cache.ValidationError('Path Validation Error') + ); + } + return Promise.resolve(0); + }); + + await expect(save('maven')).resolves.not.toThrow(); + }); }); describe('for gradle', () => { it('uploads cache even if no build.gradle found', async () => { @@ -388,6 +533,26 @@ describe('dependency cache', () => { expect.stringMatching(/^Cache saved with the key:.*/) ); }); + it('saves the gradle wrapper distribution cache under its own key', async () => { + createFile(join(workspace, 'build.gradle')); + createStateForWrapperRestore('gradle-wrapper', false); + + await save('gradle'); + expect(spyCacheSave).toHaveBeenCalledWith( + [join(os.homedir(), '.gradle', 'wrapper')], + 'setup-java-gradle-wrapper-primary-key' + ); + }); + it('does not save the gradle wrapper cache on an exact wrapper hit', async () => { + createFile(join(workspace, 'build.gradle')); + createStateForWrapperRestore('gradle-wrapper', true); + + await save('gradle'); + expect(spyCacheSave).not.toHaveBeenCalledWith( + [join(os.homedir(), '.gradle', 'wrapper')], + expect.any(String) + ); + }); }); describe('for sbt', () => { it('uploads cache even if no build.sbt found', async () => { @@ -465,6 +630,29 @@ function createStateForSuccessfulRestore() { }); } +/** + * Create states to emulate a restore process where an additional (wrapper) + * cache was restored. When `hit` is true the matched key equals the primary + * key, emulating an exact wrapper cache hit. + */ +function createStateForWrapperRestore(wrapperName: string, hit: boolean) { + const primaryKey = `setup-java-${wrapperName}-primary-key`; + jest.spyOn(core, 'getState').mockImplementation(name => { + 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-${wrapperName}`: + return primaryKey; + case `cache-matched-key-${wrapperName}`: + return hit ? primaryKey : ''; + default: + return ''; + } + }); +} + function createFile(path: string) { core.info(`created a file at ${path}`); fs.writeFileSync(path, ''); diff --git a/__tests__/cleanup-java.test.ts b/__tests__/cleanup-java.test.ts index 4cd2709d8..bb988b3c9 100644 --- a/__tests__/cleanup-java.test.ts +++ b/__tests__/cleanup-java.test.ts @@ -39,7 +39,7 @@ describe('cleanup', () => { jest.restoreAllMocks(); }); - it('does not fail nor warn even when the save process throws a ReserveCacheError', async () => { + it('does not warn/fail even when the save process throws a ReserveCacheError', async () => { spyCacheSave.mockImplementation((paths: string[], key: string) => Promise.reject( new cache.ReserveCacheError( diff --git a/__tests__/data/kona.json b/__tests__/data/kona.json new file mode 100644 index 000000000..7dc24c38d --- /dev/null +++ b/__tests__/data/kona.json @@ -0,0 +1,202 @@ +{ + "8": [ + { + "version": "8.0.20", + "jdkVersion": "8u432", + "latest": true, + "baseUrl": "https://github.com/Tencent/TencentKona-8/releases/download/8.0.20-GA/", + "files": [ + { + "os": "linux", + "arch": "aarch64", + "filename": "TencentKona8.0.20.b1_jdk_linux-aarch64_8u432.tar.gz", + "checksum": "8e6ab38b17f98d7ba727037cb49bbd174f3103a6ddacafb1fb7c0231006a80a7" + }, + { + "os": "linux", + "arch": "x86_64", + "filename": "TencentKona8.0.20.b1_jdk_linux-x86_64_8u432.tar.gz", + "checksum": "384cdb36b38993f4b7292682a5dfd8d5d33ba7bdbca2d95018d1341c792d2823" + }, + { + "os": "macos", + "arch": "aarch64", + "filename": "TencentKona8.0.20.b1_jdk_macosx-aarch64_8u432_notarized.tar.gz", + "checksum": "829c46691a4b519f14fedfcdca32a94d7793d3570c4a51b3a5072cc394619f25" + }, + { + "os": "macos", + "arch": "x86_64", + "filename": "TencentKona8.0.20.b1_jdk_macosx-x86_64_8u432_notarized.tar.gz", + "checksum": "" + }, + { + "os": "windows", + "arch": "x86_64", + "filename": "TencentKona8.0.20.b1_jdk_windows-x86_64_8u432_signed.zip", + "checksum": "339646817254dbcb5c17904807bbfdeafaa8e4bac9f2aae25434870cdeaba296" + } + ] + } + ], + "11": [ + { + "version": "11.0.25", + "jdkVersion": "11.0.25", + "latest": true, + "baseUrl": "https://github.com/Tencent/TencentKona-11/releases/download/kona11.0.25/", + "files": [ + { + "os": "linux", + "arch": "aarch64", + "filename": "TencentKona-11.0.25.b1-jdk_linux-aarch64.tar.gz", + "checksum": "887ca5eeb675dd9b9d22833a8b0c1031ee1a031227d6cf2d8c1920cc585d2b71" + }, + { + "os": "linux", + "arch": "x86_64", + "filename": "TencentKona-11.0.25.b1-jdk_linux-x86_64.tar.gz", + "checksum": "6642d7cccf98f33b3ec55cdbf77979c614f0d3cbbd282e8d0df52233edc52f9a" + }, + { + "os": "macos", + "arch": "aarch64", + "filename": "TencentKona-11.0.25.b1_jdk_macosx-aarch64_notarized.tar.gz", + "checksum": "8f07242d3191a35c3b2fca1122f315518c7312f0155e98ac7ae39ea083f93e21" + }, + { + "os": "macos", + "arch": "x86_64", + "filename": "TencentKona-11.0.25.b1_jdk_macosx-x86_64_notarized.tar.gz", + "checksum": "0832b93d8d8122cb72db85321ddd85c9a6086e0f28327733fc2da3c0ecc9c455" + }, + { + "os": "windows", + "arch": "x86_64", + "filename": "TencentKona-11.0.25.b1_jdk_windows-x86_64_signed.zip", + "checksum": "05c470c5da4b3bc1844117f611ecd241d3ae9e5d01c17ffafffde0f23825aad7" + } + ] + } + ], + "17": [ + { + "version": "17.0.13", + "jdkVersion": "17.0.13", + "latest": true, + "baseUrl": "https://github.com/Tencent/TencentKona-17/releases/download/TencentKona-17.0.13/", + "files": [ + { + "os": "linux", + "arch": "aarch64", + "filename": "TencentKona-17.0.13.b1-jdk_linux-aarch64.tar.gz", + "checksum": "372411dff5b42f6e419f1dd40772d98141a15c3d180ed1af6f2b49bdbbd32d52" + }, + { + "os": "linux", + "arch": "x86_64", + "filename": "TencentKona-17.0.13.b1-jdk_linux-x86_64.tar.gz", + "checksum": "b54bb023d1187737b23ca34d0857d2d40822b14e38d28c7948c8ff6b5927e523" + }, + { + "os": "macos", + "arch": "aarch64", + "filename": "TencentKona-17.0.13.b1_jdk_macosx-aarch64_notarized.tar.gz", + "checksum": "22f5d296c407fc137e6af9ce275e662346ca82f1a5acfc407247efd8cedf5256" + }, + { + "os": "macos", + "arch": "x86_64", + "filename": "TencentKona-17.0.13.b1_jdk_macosx-x86_64_notarized.tar.gz", + "checksum": "87ace41ac9718f2a9512b24bad0f735bc5ac61b8198b4cd5634199f124883b36" + }, + { + "os": "windows", + "arch": "x86_64", + "filename": "TencentKona-17.0.13.b1_jdk_windows-x86_64_signed.zip", + "checksum": "616089018151e8e5daf8e88276063633a2cb28a718a2afce49bb8fc10541e83d" + } + ] + } + ], + "21": [ + { + "version": "21.0.5", + "jdkVersion": "21.0.5", + "latest": true, + "baseUrl": "https://github.com/Tencent/TencentKona-21/releases/download/TencentKona-21.0.5/", + "files": [ + { + "os": "linux", + "arch": "aarch64", + "filename": "TencentKona-21.0.5.b1-jdk_linux-aarch64.tar.gz", + "checksum": "d8ca108147db3f19134d7aa995bac14e1fb3d124b0300a9a7893266a8f028104" + }, + { + "os": "linux", + "arch": "x86_64", + "filename": "TencentKona-21.0.5.b1-jdk_linux-x86_64.tar.gz", + "checksum": "afae039d9666fadcb84940c5350b29cd061019b0cc43700f0bf0342320892adf" + }, + { + "os": "macos", + "arch": "aarch64", + "filename": "TencentKona-21.0.5.b1_jdk_macosx-aarch64_notarized.tar.gz", + "checksum": "7621a218767bfbd3023b176dc6d9dd019677f8efec0d48a4eb2b2ed2b50bd1fb" + }, + { + "os": "macos", + "arch": "x86_64", + "filename": "TencentKona-21.0.5.b1_jdk_macosx-x86_64_notarized.tar.gz", + "checksum": "6c54d46f979ad998b708f664c5aeeeef855660ef527d584a7c2930951cca9999" + }, + { + "os": "windows", + "arch": "x86_64", + "filename": "TencentKona-21.0.5.b1_jdk_windows-x86_64_signed.zip", + "checksum": "ee1ee730fc5e02268d91b9df602b65122dad25b3d3898069331ebc8338005da1" + } + ] + } + ], + "25": [ + { + "version": "25.0.3", + "jdkVersion": "25.0.3", + "latest": true, + "baseUrl": "https://github.com/Tencent/TencentKona-25/releases/download/TencentKona-25.0.3/", + "files": [ + { + "os": "linux", + "arch": "aarch64", + "filename": "TencentKona-25.0.3.b1-jdk_linux-aarch64.tar.gz", + "checksum": "2fb77e3ba9c00045ca497ea22210f18dae4bf7df4c87029f5abadd42a5daf8c7" + }, + { + "os": "linux", + "arch": "x86_64", + "filename": "TencentKona-25.0.3.b1-jdk_linux-x86_64.tar.gz", + "checksum": "47445e6fad020e834055a705bb48fa3cd0727a2c57ad6f1c5206a45f4efb2d67" + }, + { + "os": "macos", + "arch": "aarch64", + "filename": "TencentKona-25.0.3.b1_jdk_macosx-aarch64_notarized.tar.gz", + "checksum": "e29405eff95da412ed7ecc890e6ef5ebbfcd9ab334005b3d32d1700bbe4204d2" + }, + { + "os": "macos", + "arch": "x86_64", + "filename": "TencentKona-25.0.3.b1_jdk_macosx-x86_64_notarized.tar.gz", + "checksum": "d512db5c079db16bd3a9c86d9cb979808994e90e4de29e17d27e5219fe488659" + }, + { + "os": "windows", + "arch": "x86_64", + "filename": "TencentKona-25.0.3.b1_jdk_windows-x86_64_signed.zip", + "checksum": "865bce92ccbbca75115076e618a98baa1d0f30fcccdce954c0a22bee33d6ae83" + } + ] + } + ] +} diff --git a/__tests__/data/microsoft.json b/__tests__/data/microsoft.json index b2f0e68a1..b67b9447d 100644 --- a/__tests__/data/microsoft.json +++ b/__tests__/data/microsoft.json @@ -79,6 +79,49 @@ } ] }, + { + "version": "17.0.18", + "stable": true, + "release_url": "https://aka.ms/download-jdk", + "files": [ + { + "filename": "microsoft-jdk-17.0.18-macos-x64.tar.gz", + "arch": "x64", + "platform": "darwin", + "download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-macos-x64.tar.gz" + }, + { + "filename": "microsoft-jdk-17.0.18-linux-x64.tar.gz", + "arch": "x64", + "platform": "linux", + "download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-linux-x64.tar.gz" + }, + { + "filename": "microsoft-jdk-17.0.18-windows-x64.zip", + "arch": "x64", + "platform": "win32", + "download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-windows-x64.zip" + }, + { + "filename": "microsoft-jdk-17.0.18-macos-aarch64.tar.gz", + "arch": "aarch64", + "platform": "darwin", + "download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-macos-aarch64.tar.gz" + }, + { + "filename": "microsoft-jdk-17.0.18-linux-aarch64.tar.gz", + "arch": "aarch64", + "platform": "linux", + "download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-linux-aarch64.tar.gz" + }, + { + "filename": "microsoft-jdk-17.0.18-windows-aarch64.zip", + "arch": "aarch64", + "platform": "win32", + "download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-windows-aarch64.zip" + } + ] + }, { "version": "17.0.7", "stable": true, diff --git a/__tests__/data/sdkman-java-versions.csv b/__tests__/data/sdkman-java-versions.csv index 5c75a44c9..edbdc265c 100644 --- a/__tests__/data/sdkman-java-versions.csv +++ b/__tests__/data/sdkman-java-versions.csv @@ -2,7 +2,7 @@ 7.0.352-zulu, 7.0.352 8.0.282-trava, 8.0.282 8.0.432-albba, 8.0.432 -8.0.432-amzn, 8.0.432 +8.0.432-amzn, 8 8.0.432-kona, 8.0.432 8.0.432-librca, 8.0.432 8.0.432-sem, 8.0.432 @@ -10,7 +10,7 @@ 8.0.432-zulu, 8.0.432 8.0.432.fx-librca, 8.0.432 8.0.432.fx-zulu, 8.0.432 -8.0.442-amzn, 8.0.442 +8.0.442-amzn, 8 8.0.442-librca, 8.0.442 8.0.442-tem, 8.0.442 8.0.442-zulu, 8.0.442 @@ -19,7 +19,7 @@ 11.0.14.1-jbr, 11.0.14 11.0.15-trava, 11.0.15 11.0.25-albba, 11.0.25 -11.0.25-amzn, 11.0.25 +11.0.25-amzn, 11 11.0.25-kona, 11.0.25 11.0.25-librca, 11.0.25 11.0.25-ms, 11.0.25 @@ -29,7 +29,7 @@ 11.0.25-zulu, 11.0.25 11.0.25.fx-librca, 11.0.25 11.0.25.fx-zulu, 11.0.25 -11.0.26-amzn, 11.0.26 +11.0.26-amzn, 11 11.0.26-librca, 11.0.26 11.0.26-ms, 11.0.26 11.0.26-sapmchn, 11.0.26 @@ -40,7 +40,7 @@ 17.0.12-jbr, 17.0.12 17.0.12-oracle, 17.0.12 17.0.13-albba, 17.0.13 -17.0.13-amzn, 17.0.13 +17.0.13-amzn, 17 17.0.13-kona, 17.0.13 17.0.13-librca, 17.0.13 17.0.13-ms, 17.0.13 @@ -52,7 +52,7 @@ 17.0.13.crac-zulu, 17.0.13 17.0.13.fx-librca, 17.0.13 17.0.13.fx-zulu, 17.0.13 -17.0.14-amzn, 17.0.14 +17.0.14-amzn, 17 17.0.14-librca, 17.0.14 17.0.14-ms, 17.0.14 17.0.14-sapmchn, 17.0.14 @@ -62,7 +62,7 @@ 17.0.9-graalce, 17.0.9 21.0.2-graalce, 21.0.2 21.0.2-open, 21.0.2 -21.0.5-amzn, 21.0.5 +21.0.5-amzn, 21 21.0.5-graal, 21.0.5 21.0.5-jbr, 21.0.5 21.0.5-kona, 21.0.5 @@ -77,7 +77,7 @@ 21.0.5.crac-zulu, 21.0.5 21.0.5.fx-librca, 21.0.5 21.0.5.fx-zulu, 21.0.5 -21.0.6-amzn, 21.0.6 +21.0.6-amzn, 21 21.0.6-graal, 21.0.6 21.0.6-librca, 21.0.6 21.0.6-ms, 21.0.6 @@ -94,7 +94,7 @@ 22.3.5.r17-mandrel, 22.3.5 22.3.5.r17-nik, 22.3.5 23-open, 23 -23.0.1-amzn, 23.0.1 +23.0.1-amzn, 23 23.0.1-graal, 23.0.1 23.0.1-graalce, 23.0.1 23.0.1-librca, 23.0.1 @@ -106,7 +106,7 @@ 23.0.1.crac-zulu, 23.0.1 23.0.1.fx-librca, 23.0.1 23.0.1.fx-zulu, 23.0.1 -23.0.2-amzn, 23.0.2 +23.0.2-amzn, 23 23.0.2-graal, 23.0.2 23.0.2-graalce, 23.0.2 23.0.2-librca, 23.0.2 diff --git a/__tests__/data/temurin.json b/__tests__/data/temurin.json index 7ce00d2c7..cec2c631a 100644 --- a/__tests__/data/temurin.json +++ b/__tests__/data/temurin.json @@ -15,7 +15,8 @@ "link": "https://github.com/adoptium/temurin16-binaries/releases/download/jdk-16.0.2%2B7/OpenJDK16U-jdk_x64_linux_hotspot_16.0.2_7.tar.gz", "metadata_link": "https://github.com/adoptium/temurin16-binaries/releases/download/jdk-16.0.2%2B7/OpenJDK16U-jdk_x64_linux_hotspot_16.0.2_7.tar.gz.json", "name": "OpenJDK16U-jdk_x64_linux_hotspot_16.0.2_7.tar.gz", - "size": 205463525 + "size": 205463525, + "signature_link": "https://github.com/adoptium/temurin16-binaries/releases/download/jdk-16.0.2%2B7/OpenJDK16U-jdk_x64_linux_hotspot_16.0.2_7.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-16.0.2+7_adopt", @@ -44,7 +45,8 @@ "link": "https://github.com/adoptium/temurin16-binaries/releases/download/jdk-16.0.2%2B7/OpenJDK16U-jdk_x64_mac_hotspot_16.0.2_7.tar.gz", "metadata_link": "https://github.com/adoptium/temurin16-binaries/releases/download/jdk-16.0.2%2B7/OpenJDK16U-jdk_x64_mac_hotspot_16.0.2_7.tar.gz.json", "name": "OpenJDK16U-jdk_x64_mac_hotspot_16.0.2_7.tar.gz", - "size": 206621395 + "size": 206621395, + "signature_link": "https://github.com/adoptium/temurin16-binaries/releases/download/jdk-16.0.2%2B7/OpenJDK16U-jdk_x64_mac_hotspot_16.0.2_7.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-16.0.2+7_adopt", @@ -73,7 +75,8 @@ "link": "https://github.com/adoptium/temurin16-binaries/releases/download/jdk-16.0.2%2B7/OpenJDK16U-jdk_x64_windows_hotspot_16.0.2_7.zip", "metadata_link": "https://github.com/adoptium/temurin16-binaries/releases/download/jdk-16.0.2%2B7/OpenJDK16U-jdk_x64_windows_hotspot_16.0.2_7.zip.json", "name": "OpenJDK16U-jdk_x64_windows_hotspot_16.0.2_7.zip", - "size": 203448494 + "size": 203448494, + "signature_link": "https://github.com/adoptium/temurin16-binaries/releases/download/jdk-16.0.2%2B7/OpenJDK16U-jdk_x64_windows_hotspot_16.0.2_7.zip.sig" }, "project": "jdk", "scm_ref": "jdk-16.0.2+7_adopt", @@ -113,7 +116,8 @@ "link": "https://github.com/adoptium/temurin8-binaries/releases/download/jdk8u302-b08/OpenJDK8U-jdk_x64_linux_hotspot_8u302b08.tar.gz", "metadata_link": "https://github.com/adoptium/temurin8-binaries/releases/download/jdk8u302-b08/OpenJDK8U-jdk_x64_linux_hotspot_8u302b08.tar.gz.json", "name": "OpenJDK8U-jdk_x64_linux_hotspot_8u302b08.tar.gz", - "size": 102954777 + "size": 102954777, + "signature_link": "https://github.com/adoptium/temurin8-binaries/releases/download/jdk8u302-b08/OpenJDK8U-jdk_x64_linux_hotspot_8u302b08.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk8u302-b08", @@ -142,7 +146,8 @@ "link": "https://github.com/adoptium/temurin8-binaries/releases/download/jdk8u302-b08/OpenJDK8U-jdk_x64_mac_hotspot_8u302b08.tar.gz", "metadata_link": "https://github.com/adoptium/temurin8-binaries/releases/download/jdk8u302-b08/OpenJDK8U-jdk_x64_mac_hotspot_8u302b08.tar.gz.json", "name": "OpenJDK8U-jdk_x64_mac_hotspot_8u302b08.tar.gz", - "size": 107303398 + "size": 107303398, + "signature_link": "https://github.com/adoptium/temurin8-binaries/releases/download/jdk8u302-b08/OpenJDK8U-jdk_x64_mac_hotspot_8u302b08.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk8u302-b08", @@ -171,7 +176,8 @@ "link": "https://github.com/adoptium/temurin8-binaries/releases/download/jdk8u302-b08/OpenJDK8U-jdk_x64_windows_hotspot_8u302b08.zip", "metadata_link": "https://github.com/adoptium/temurin8-binaries/releases/download/jdk8u302-b08/OpenJDK8U-jdk_x64_windows_hotspot_8u302b08.zip.json", "name": "OpenJDK8U-jdk_x64_windows_hotspot_8u302b08.zip", - "size": 104297671 + "size": 104297671, + "signature_link": "https://github.com/adoptium/temurin8-binaries/releases/download/jdk8u302-b08/OpenJDK8U-jdk_x64_windows_hotspot_8u302b08.zip.sig" }, "project": "jdk", "scm_ref": "jdk8u302-b08", @@ -211,7 +217,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-31-00-07.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-31-00-07.tar.gz.json", "name": "OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-31-00-07.tar.gz", - "size": 188909250 + "size": 188909250, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-31-00-07.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+33_adopt-16-ge39bf269d60", @@ -240,7 +247,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-31-00-07.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-31-00-07.tar.gz.json", "name": "OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-31-00-07.tar.gz", - "size": 192952713 + "size": 192952713, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-31-00-07.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+33_adopt-219-ge39bf269d60", @@ -260,7 +268,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-31-00-07.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-31-00-07.tar.gz.json", "name": "OpenJDK17-jdk_arm_linux_hotspot_2021-07-31-00-07.tar.gz", - "size": 188816971 + "size": 188816971, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-31-00-07.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+33_adopt-16-ge39bf269d60", @@ -280,7 +289,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-31-00-07.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-31-00-07.tar.gz.json", "name": "OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-31-00-07.tar.gz", - "size": 182299353 + "size": 182299353, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-31-00-07.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+33_adopt-219-ge39bf269d60", @@ -300,7 +310,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-31-00-07.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-31-00-07.tar.gz.json", "name": "OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-31-00-07.tar.gz", - "size": 187674392 + "size": 187674392, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-31-00-07.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+33_adopt-46-gea8d2c72e83", @@ -320,7 +331,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-31-00-07.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-31-00-07.tar.gz.json", "name": "OpenJDK17-jdk_s390x_linux_hotspot_2021-07-31-00-07.tar.gz", - "size": 179501342 + "size": 179501342, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-31-00-07.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+33_adopt-21-ge39bf269d60", @@ -340,7 +352,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-29-23-34.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-29-23-34.tar.gz.json", "name": "OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-29-23-34.tar.gz", - "size": 192126971 + "size": 192126971, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-29-23-34.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+33_adopt-219-ge39bf269d60", @@ -360,7 +373,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-31-00-07.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-31-00-07.tar.gz.json", "name": "OpenJDK17-jdk_x64_linux_hotspot_2021-07-31-00-07.tar.gz", - "size": 192015878 + "size": 192015878, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-31-00-07.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+33_adopt-21-ge39bf269d60", @@ -389,7 +403,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-31-00-07.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-31-00-07.tar.gz.json", "name": "OpenJDK17-jdk_x64_mac_hotspot_2021-07-31-00-07.tar.gz", - "size": 192422068 + "size": 192422068, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-31-00-07.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+33_adopt-219-ge39bf269d60", @@ -418,7 +433,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-31-00-07.zip", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-31-00-07.zip.json", "name": "OpenJDK17-jdk_x64_windows_hotspot_2021-07-31-00-07.zip", - "size": 188694175 + "size": 188694175, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-31-00-07.zip.sig" }, "project": "jdk", "scm_ref": "jdk-17+33_adopt-219-ge39bf269d60", @@ -447,7 +463,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-31-00-07.zip", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-31-00-07.zip.json", "name": "OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-31-00-07.zip", - "size": 184618115 + "size": 184618115, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-31-00-07.zip.sig" }, "project": "jdk", "scm_ref": "jdk-17+33_adopt-219-ge39bf269d60", @@ -489,7 +506,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-27-23-34.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-27-23-34.tar.gz.json", "name": "OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-27-23-34.tar.gz", - "size": 192125161 + "size": 192125161, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-31-00-07-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-27-23-34.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+32_adopt-242-gce1857dd7a1", @@ -531,7 +549,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-23-03-09.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-23-03-09.tar.gz.json", "name": "OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-23-03-09.tar.gz", - "size": 188911467 + "size": 188911467, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-23-03-09.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+32_adopt-42-g4596b4e9d4e", @@ -560,7 +579,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-23-03-09.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-23-03-09.tar.gz.json", "name": "OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-23-03-09.tar.gz", - "size": 192950510 + "size": 192950510, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-23-03-09.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+32_adopt-217-g4596b4e9d4e", @@ -580,7 +600,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-23-03-09.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-23-03-09.tar.gz.json", "name": "OpenJDK17-jdk_arm_linux_hotspot_2021-07-23-03-09.tar.gz", - "size": 188815685 + "size": 188815685, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-23-03-09.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+32_adopt-36-g4596b4e9d4e", @@ -600,7 +621,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-23-03-09.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-23-03-09.tar.gz.json", "name": "OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-23-03-09.tar.gz", - "size": 182307654 + "size": 182307654, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-23-03-09.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+32_adopt-217-g4596b4e9d4e", @@ -620,7 +642,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-23-03-09.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-23-03-09.tar.gz.json", "name": "OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-23-03-09.tar.gz", - "size": 187698851 + "size": 187698851, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-23-03-09.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+32_adopt-36-g4596b4e9d4e", @@ -640,7 +663,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-23-03-09.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-23-03-09.tar.gz.json", "name": "OpenJDK17-jdk_s390x_linux_hotspot_2021-07-23-03-09.tar.gz", - "size": 179501218 + "size": 179501218, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-23-03-09.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+32_adopt-40-g4596b4e9d4e", @@ -660,7 +684,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-22-23-30.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-22-23-30.tar.gz.json", "name": "OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-22-23-30.tar.gz", - "size": 192124471 + "size": 192124471, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-22-23-30.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+32_adopt-217-g4596b4e9d4e", @@ -680,7 +705,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-23-03-09.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-23-03-09.tar.gz.json", "name": "OpenJDK17-jdk_x64_linux_hotspot_2021-07-23-03-09.tar.gz", - "size": 192015026 + "size": 192015026, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-23-03-09.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+32_adopt-40-g4596b4e9d4e", @@ -709,7 +735,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-23-03-09.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-23-03-09.tar.gz.json", "name": "OpenJDK17-jdk_x64_mac_hotspot_2021-07-23-03-09.tar.gz", - "size": 193003513 + "size": 193003513, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-23-03-09.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+32_adopt-217-g4596b4e9d4e", @@ -738,7 +765,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-23-03-09.zip", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-23-03-09.zip.json", "name": "OpenJDK17-jdk_x64_windows_hotspot_2021-07-23-03-09.zip", - "size": 188694996 + "size": 188694996, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-23-03-09.zip.sig" }, "project": "jdk", "scm_ref": "jdk-17+32_adopt-217-g4596b4e9d4e", @@ -767,7 +795,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-23-03-09.zip", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-23-03-09.zip.json", "name": "OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-23-03-09.zip", - "size": 184626937 + "size": 184626937, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-23-03-09-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-23-03-09.zip.sig" }, "project": "jdk", "scm_ref": "jdk-17+32_adopt-217-g4596b4e9d4e", @@ -809,7 +838,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-21-03-09.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-21-03-09.tar.gz.json", "name": "OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-21-03-09.tar.gz", - "size": 188891565 + "size": 188891565, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-21-03-09.tar.gz.sig" }, "project": "jdk", "scm_ref": "a342f28aaec", @@ -829,7 +859,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-21-03-09.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-21-03-09.tar.gz.json", "name": "OpenJDK17-jdk_arm_linux_hotspot_2021-07-21-03-09.tar.gz", - "size": 188790907 + "size": 188790907, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-21-03-09.tar.gz.sig" }, "project": "jdk", "scm_ref": "a342f28aaec", @@ -849,7 +880,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-21-03-09.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-21-03-09.tar.gz.json", "name": "OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-21-03-09.tar.gz", - "size": 182276594 + "size": 182276594, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-21-03-09.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+31_adopt-191-ga342f28aaec", @@ -869,7 +901,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-21-03-09.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-21-03-09.tar.gz.json", "name": "OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-21-03-09.tar.gz", - "size": 187678422 + "size": 187678422, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-21-03-09.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+31_adopt-26-ga342f28aaec", @@ -889,7 +922,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-21-03-09.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-21-03-09.tar.gz.json", "name": "OpenJDK17-jdk_s390x_linux_hotspot_2021-07-21-03-09.tar.gz", - "size": 179475721 + "size": 179475721, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-21-03-09.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+31_adopt-26-ga342f28aaec", @@ -909,7 +943,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-20-23-34.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-20-23-34.tar.gz.json", "name": "OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-20-23-34.tar.gz", - "size": 192104689 + "size": 192104689, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-20-23-34.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+31_adopt-191-ga342f28aaec", @@ -929,7 +964,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-21-03-09.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-21-03-09.tar.gz.json", "name": "OpenJDK17-jdk_x64_linux_hotspot_2021-07-21-03-09.tar.gz", - "size": 191982821 + "size": 191982821, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-21-03-09.tar.gz.sig" }, "project": "jdk", "scm_ref": "a342f28aaec", @@ -958,7 +994,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-21-03-09.zip", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-21-03-09.zip.json", "name": "OpenJDK17-jdk_x64_windows_hotspot_2021-07-21-03-09.zip", - "size": 188685330 + "size": 188685330, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-21-03-09.zip.sig" }, "project": "jdk", "scm_ref": "jdk-17+31_adopt-191-ga342f28aaec", @@ -987,7 +1024,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-21-03-09.zip", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-21-03-09.zip.json", "name": "OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-21-03-09.zip", - "size": 184607457 + "size": 184607457, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-21-03-09-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-21-03-09.zip.sig" }, "project": "jdk", "scm_ref": "jdk-17+31_adopt-191-ga342f28aaec", @@ -1029,7 +1067,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-16-10-58.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-16-10-58.tar.gz.json", "name": "OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-16-10-58.tar.gz", - "size": 188896773 + "size": 188896773, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-16-10-58.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+31_adopt-14-g20418a26958", @@ -1058,7 +1097,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-16-10-58.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-16-10-58.tar.gz.json", "name": "OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-16-10-58.tar.gz", - "size": 192948484 + "size": 192948484, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-16-10-58.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+31_adopt-179-g20418a26958", @@ -1078,7 +1118,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-16-10-58.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-16-10-58.tar.gz.json", "name": "OpenJDK17-jdk_arm_linux_hotspot_2021-07-16-10-58.tar.gz", - "size": 188791964 + "size": 188791964, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-16-10-58.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+31_adopt-14-g20418a26958", @@ -1098,7 +1139,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-16-10-58.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-16-10-58.tar.gz.json", "name": "OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-16-10-58.tar.gz", - "size": 182281944 + "size": 182281944, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-16-10-58.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+31_adopt-179-g20418a26958", @@ -1118,7 +1160,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-16-10-58.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-16-10-58.tar.gz.json", "name": "OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-16-10-58.tar.gz", - "size": 187650365 + "size": 187650365, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-16-10-58.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+31_adopt-23-g20418a26958", @@ -1138,7 +1181,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-16-10-58.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-16-10-58.tar.gz.json", "name": "OpenJDK17-jdk_s390x_linux_hotspot_2021-07-16-10-58.tar.gz", - "size": 179483622 + "size": 179483622, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-16-10-58.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+31_adopt-55-g20418a26958", @@ -1158,7 +1202,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-15-23-34.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-15-23-34.tar.gz.json", "name": "OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-15-23-34.tar.gz", - "size": 192108731 + "size": 192108731, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-15-23-34.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+31_adopt-179-g20418a26958", @@ -1178,7 +1223,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-16-10-58.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-16-10-58.tar.gz.json", "name": "OpenJDK17-jdk_x64_linux_hotspot_2021-07-16-10-58.tar.gz", - "size": 191985123 + "size": 191985123, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-16-10-58.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+31_adopt-14-g20418a26958", @@ -1207,7 +1253,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-16-10-58.zip", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-16-10-58.zip.json", "name": "OpenJDK17-jdk_x64_windows_hotspot_2021-07-16-10-58.zip", - "size": 188688539 + "size": 188688539, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-16-10-58.zip.sig" }, "project": "jdk", "scm_ref": "jdk-17+31_adopt-179-g20418a26958", @@ -1236,7 +1283,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-16-10-58.zip", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-16-10-58.zip.json", "name": "OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-16-10-58.zip", - "size": 184612045 + "size": 184612045, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-16-10-58-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-16-10-58.zip.sig" }, "project": "jdk", "scm_ref": "jdk-17+31_adopt-179-g20418a26958", @@ -1278,7 +1326,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-14-11-30.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-14-11-30.tar.gz.json", "name": "OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-14-11-30.tar.gz", - "size": 188899456 + "size": 188899456, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-14-11-30.tar.gz.sig" }, "project": "jdk", "scm_ref": "ce22197617d", @@ -1307,7 +1356,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-14-11-30.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-14-11-30.tar.gz.json", "name": "OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-14-11-30.tar.gz", - "size": 192953428 + "size": 192953428, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-14-11-30.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+30_adopt-200-gce22197617d", @@ -1327,7 +1377,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-14-11-30.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-14-11-30.tar.gz.json", "name": "OpenJDK17-jdk_arm_linux_hotspot_2021-07-14-11-30.tar.gz", - "size": 188792852 + "size": 188792852, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-14-11-30.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+30_adopt-66-gce22197617d", @@ -1347,7 +1398,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-14-11-30.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-14-11-30.tar.gz.json", "name": "OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-14-11-30.tar.gz", - "size": 187678600 + "size": 187678600, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-14-11-30.tar.gz.sig" }, "project": "jdk", "scm_ref": "ce22197617d", @@ -1367,7 +1419,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-14-11-30.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-14-11-30.tar.gz.json", "name": "OpenJDK17-jdk_s390x_linux_hotspot_2021-07-14-11-30.tar.gz", - "size": 179480996 + "size": 179480996, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-14-11-30.tar.gz.sig" }, "project": "jdk", "scm_ref": "ce22197617d", @@ -1387,7 +1440,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-13-23-34.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-13-23-34.tar.gz.json", "name": "OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-13-23-34.tar.gz", - "size": 192105446 + "size": 192105446, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-13-23-34.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+30_adopt-200-gce22197617d", @@ -1407,7 +1461,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-14-11-30.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-14-11-30.tar.gz.json", "name": "OpenJDK17-jdk_x64_linux_hotspot_2021-07-14-11-30.tar.gz", - "size": 191986856 + "size": 191986856, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-14-11-30.tar.gz.sig" }, "project": "jdk", "scm_ref": "ce22197617d", @@ -1436,7 +1491,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-14-11-30.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-14-11-30.tar.gz.json", "name": "OpenJDK17-jdk_x64_mac_hotspot_2021-07-14-11-30.tar.gz", - "size": 192995067 + "size": 192995067, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-14-11-30.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+30_adopt-200-gce22197617d", @@ -1465,7 +1521,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-14-11-30.zip", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-14-11-30.zip.json", "name": "OpenJDK17-jdk_x64_windows_hotspot_2021-07-14-11-30.zip", - "size": 188686556 + "size": 188686556, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-14-11-30.zip.sig" }, "project": "jdk", "scm_ref": "jdk-17+30_adopt-200-gce22197617d", @@ -1494,7 +1551,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-14-11-30.zip", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-14-11-30.zip.json", "name": "OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-14-11-30.zip", - "size": 184620492 + "size": 184620492, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-14-11-30-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-14-11-30.zip.sig" }, "project": "jdk", "scm_ref": "jdk-17+30_adopt-200-gce22197617d", @@ -1536,7 +1594,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-09-12-54.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-09-12-54.tar.gz.json", "name": "OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-09-12-54.tar.gz", - "size": 188896299 + "size": 188896299, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-09-12-54.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+30_adopt-164-g3e7e5bc2003", @@ -1565,7 +1624,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-09-12-54.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-09-12-54.tar.gz.json", "name": "OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-09-12-54.tar.gz", - "size": 192941671 + "size": 192941671, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-09-12-54.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+30_adopt-164-g3e7e5bc2003", @@ -1585,7 +1645,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-09-12-54.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-09-12-54.tar.gz.json", "name": "OpenJDK17-jdk_arm_linux_hotspot_2021-07-09-12-54.tar.gz", - "size": 188838708 + "size": 188838708, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-09-12-54.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+30_adopt-161-g3e7e5bc2003", @@ -1605,7 +1666,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-09-12-54.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-09-12-54.tar.gz.json", "name": "OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-09-12-54.tar.gz", - "size": 182274073 + "size": 182274073, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-09-12-54.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+30_adopt-40-g3e7e5bc2003", @@ -1625,7 +1687,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-09-12-54.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-09-12-54.tar.gz.json", "name": "OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-09-12-54.tar.gz", - "size": 187666608 + "size": 187666608, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-09-12-54.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+30_adopt-40-g3e7e5bc2003", @@ -1645,7 +1708,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-09-12-54.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-09-12-54.tar.gz.json", "name": "OpenJDK17-jdk_s390x_linux_hotspot_2021-07-09-12-54.tar.gz", - "size": 179472325 + "size": 179472325, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-09-12-54.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+30_adopt-30-g3e7e5bc2003", @@ -1665,7 +1729,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-08-23-35.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-08-23-35.tar.gz.json", "name": "OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-08-23-35.tar.gz", - "size": 192098387 + "size": 192098387, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-08-23-35.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+30_adopt-164-g3e7e5bc2003", @@ -1685,7 +1750,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-09-12-54.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-09-12-54.tar.gz.json", "name": "OpenJDK17-jdk_x64_linux_hotspot_2021-07-09-12-54.tar.gz", - "size": 191983708 + "size": 191983708, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-09-12-54.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+30_adopt-164-g3e7e5bc2003", @@ -1714,7 +1780,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-09-12-54.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-09-12-54.tar.gz.json", "name": "OpenJDK17-jdk_x64_mac_hotspot_2021-07-09-12-54.tar.gz", - "size": 193004476 + "size": 193004476, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-09-12-54.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+30_adopt-164-g3e7e5bc2003", @@ -1743,7 +1810,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-09-12-54.zip", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-09-12-54.zip.json", "name": "OpenJDK17-jdk_x64_windows_hotspot_2021-07-09-12-54.zip", - "size": 188681640 + "size": 188681640, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-09-12-54.zip.sig" }, "project": "jdk", "scm_ref": "jdk-17+30_adopt-164-g3e7e5bc2003", @@ -1772,7 +1840,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-09-12-54.zip", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-09-12-54.zip.json", "name": "OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-09-12-54.zip", - "size": 184605514 + "size": 184605514, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-09-12-54-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-09-12-54.zip.sig" }, "project": "jdk", "scm_ref": "jdk-17+30_adopt-164-g3e7e5bc2003", @@ -1823,7 +1892,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-07-11-35.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-07-11-35.tar.gz.json", "name": "OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-07-11-35.tar.gz", - "size": 192962903 + "size": 192962903, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-07-11-35.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+29_adopt-172-g06428c22b61", @@ -1843,7 +1913,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-07-11-35.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-07-11-35.tar.gz.json", "name": "OpenJDK17-jdk_arm_linux_hotspot_2021-07-07-11-35.tar.gz", - "size": 188800217 + "size": 188800217, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-07-11-35.tar.gz.sig" }, "project": "jdk", "scm_ref": "06428c22b61", @@ -1863,7 +1934,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-07-11-35.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-07-11-35.tar.gz.json", "name": "OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-07-11-35.tar.gz", - "size": 187663978 + "size": 187663978, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-07-11-35.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+29_adopt-78-g06428c22b61", @@ -1883,7 +1955,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-07-11-35.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-07-11-35.tar.gz.json", "name": "OpenJDK17-jdk_s390x_linux_hotspot_2021-07-07-11-35.tar.gz", - "size": 179496669 + "size": 179496669, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-07-11-35.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+29_adopt-78-g06428c22b61", @@ -1903,7 +1976,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-06-23-34.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-06-23-34.tar.gz.json", "name": "OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-06-23-34.tar.gz", - "size": 192113242 + "size": 192113242, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-06-23-34.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+29_adopt-172-g06428c22b61", @@ -1923,7 +1997,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-07-11-35.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-07-11-35.tar.gz.json", "name": "OpenJDK17-jdk_x64_linux_hotspot_2021-07-07-11-35.tar.gz", - "size": 192021951 + "size": 192021951, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-07-11-35.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+29_adopt-172-g06428c22b61", @@ -1952,7 +2027,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-07-11-35.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-07-11-35.tar.gz.json", "name": "OpenJDK17-jdk_x64_mac_hotspot_2021-07-07-11-35.tar.gz", - "size": 193018554 + "size": 193018554, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-07-11-35.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+29_adopt-172-g06428c22b61", @@ -1981,7 +2057,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-07-11-35.zip", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-07-11-35.zip.json", "name": "OpenJDK17-jdk_x64_windows_hotspot_2021-07-07-11-35.zip", - "size": 188702463 + "size": 188702463, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-07-11-35-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-07-11-35.zip.sig" }, "project": "jdk", "scm_ref": "jdk-17+29_adopt-172-g06428c22b61", @@ -2023,7 +2100,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-02-12-00.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-02-12-00.tar.gz.json", "name": "OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-02-12-00.tar.gz", - "size": 188953178 + "size": 188953178, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-07-02-12-00.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+29_adopt-138-g6d3debb5c12", @@ -2052,7 +2130,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-02-12-00.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-02-12-00.tar.gz.json", "name": "OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-02-12-00.tar.gz", - "size": 192957934 + "size": 192957934, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-07-02-12-00.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+29_adopt-138-g6d3debb5c12", @@ -2072,7 +2151,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-02-12-00.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-02-12-00.tar.gz.json", "name": "OpenJDK17-jdk_arm_linux_hotspot_2021-07-02-12-00.tar.gz", - "size": 188797466 + "size": 188797466, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-07-02-12-00.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+29_adopt-43-g6d3debb5c12", @@ -2092,7 +2172,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-02-12-00.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-02-12-00.tar.gz.json", "name": "OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-02-12-00.tar.gz", - "size": 182292580 + "size": 182292580, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-07-02-12-00.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+29_adopt-138-g6d3debb5c12", @@ -2112,7 +2193,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-02-12-00.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-02-12-00.tar.gz.json", "name": "OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-02-12-00.tar.gz", - "size": 187684930 + "size": 187684930, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-07-02-12-00.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+29_adopt-64-g6d3debb5c12", @@ -2132,7 +2214,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-02-12-00.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-02-12-00.tar.gz.json", "name": "OpenJDK17-jdk_s390x_linux_hotspot_2021-07-02-12-00.tar.gz", - "size": 179484390 + "size": 179484390, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-07-02-12-00.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+29_adopt-54-g6d3debb5c12", @@ -2152,7 +2235,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-01-23-30.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-01-23-30.tar.gz.json", "name": "OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-01-23-30.tar.gz", - "size": 192114561 + "size": 192114561, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-07-01-23-30.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+29_adopt-138-g6d3debb5c12", @@ -2172,7 +2256,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-02-12-00.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-02-12-00.tar.gz.json", "name": "OpenJDK17-jdk_x64_linux_hotspot_2021-07-02-12-00.tar.gz", - "size": 192014644 + "size": 192014644, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-07-02-12-00.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+29_adopt-138-g6d3debb5c12", @@ -2201,7 +2286,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-02-12-00.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-02-12-00.tar.gz.json", "name": "OpenJDK17-jdk_x64_mac_hotspot_2021-07-02-12-00.tar.gz", - "size": 192425033 + "size": 192425033, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-07-02-12-00.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+29_adopt-138-g6d3debb5c12", @@ -2230,7 +2316,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-02-12-00.zip", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-02-12-00.zip.json", "name": "OpenJDK17-jdk_x64_windows_hotspot_2021-07-02-12-00.zip", - "size": 188697393 + "size": 188697393, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-07-02-12-00.zip.sig" }, "project": "jdk", "scm_ref": "jdk-17+29_adopt-138-g6d3debb5c12", @@ -2259,7 +2346,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-02-12-00.zip", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-02-12-00.zip.json", "name": "OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-02-12-00.zip", - "size": 184618232 + "size": 184618232, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-07-02-12-00-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-07-02-12-00.zip.sig" }, "project": "jdk", "scm_ref": "jdk-17+29_adopt-138-g6d3debb5c12", @@ -2301,7 +2389,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-06-30-09-16.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-06-30-09-16.tar.gz.json", "name": "OpenJDK17-jdk_aarch64_linux_hotspot_2021-06-30-09-16.tar.gz", - "size": 188940191 + "size": 188940191, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_aarch64_linux_hotspot_2021-06-30-09-16.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+28_adopt-130-g0fe0d0825e7", @@ -2330,7 +2419,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-06-30-09-16.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-06-30-09-16.tar.gz.json", "name": "OpenJDK17-jdk_aarch64_mac_hotspot_2021-06-30-09-16.tar.gz", - "size": 192953718 + "size": 192953718, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_aarch64_mac_hotspot_2021-06-30-09-16.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+28_adopt-130-g0fe0d0825e7", @@ -2350,7 +2440,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-06-30-09-16.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-06-30-09-16.tar.gz.json", "name": "OpenJDK17-jdk_arm_linux_hotspot_2021-06-30-09-16.tar.gz", - "size": 188795343 + "size": 188795343, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_arm_linux_hotspot_2021-06-30-09-16.tar.gz.sig" }, "project": "jdk", "scm_ref": "0fe0d0825e7", @@ -2370,7 +2461,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-06-30-09-16.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-06-30-09-16.tar.gz.json", "name": "OpenJDK17-jdk_ppc64_aix_hotspot_2021-06-30-09-16.tar.gz", - "size": 182285782 + "size": 182285782, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_ppc64_aix_hotspot_2021-06-30-09-16.tar.gz.sig" }, "project": "jdk", "scm_ref": "0fe0d0825e7", @@ -2390,7 +2482,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-06-30-09-16.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-06-30-09-16.tar.gz.json", "name": "OpenJDK17-jdk_ppc64le_linux_hotspot_2021-06-30-09-16.tar.gz", - "size": 187652430 + "size": 187652430, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_ppc64le_linux_hotspot_2021-06-30-09-16.tar.gz.sig" }, "project": "jdk", "scm_ref": "0fe0d0825e7", @@ -2410,7 +2503,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-06-30-09-16.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-06-30-09-16.tar.gz.json", "name": "OpenJDK17-jdk_s390x_linux_hotspot_2021-06-30-09-16.tar.gz", - "size": 179489547 + "size": 179489547, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_s390x_linux_hotspot_2021-06-30-09-16.tar.gz.sig" }, "project": "jdk", "scm_ref": "0fe0d0825e7", @@ -2430,7 +2524,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-06-29-23-33.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-06-29-23-33.tar.gz.json", "name": "OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-06-29-23-33.tar.gz", - "size": 192109453 + "size": 192109453, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_x64_alpine-linux_hotspot_2021-06-29-23-33.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+28_adopt-130-g0fe0d0825e7", @@ -2450,7 +2545,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-06-30-09-16.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-06-30-09-16.tar.gz.json", "name": "OpenJDK17-jdk_x64_linux_hotspot_2021-06-30-09-16.tar.gz", - "size": 192013559 + "size": 192013559, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_x64_linux_hotspot_2021-06-30-09-16.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+28_adopt-130-g0fe0d0825e7", @@ -2479,7 +2575,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-06-30-09-16.tar.gz", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-06-30-09-16.tar.gz.json", "name": "OpenJDK17-jdk_x64_mac_hotspot_2021-06-30-09-16.tar.gz", - "size": 192419518 + "size": 192419518, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_x64_mac_hotspot_2021-06-30-09-16.tar.gz.sig" }, "project": "jdk", "scm_ref": "jdk-17+28_adopt-130-g0fe0d0825e7", @@ -2508,7 +2605,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-06-30-09-16.zip", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-06-30-09-16.zip.json", "name": "OpenJDK17-jdk_x64_windows_hotspot_2021-06-30-09-16.zip", - "size": 188672489 + "size": 188672489, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_x64_windows_hotspot_2021-06-30-09-16.zip.sig" }, "project": "jdk", "scm_ref": "jdk-17+28_adopt-130-g0fe0d0825e7", @@ -2537,7 +2635,8 @@ "link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-06-30-09-16.zip", "metadata_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-06-30-09-16.zip.json", "name": "OpenJDK17-jdk_x86-32_windows_hotspot_2021-06-30-09-16.zip", - "size": 184626094 + "size": 184626094, + "signature_link": "https://github.com/adoptium/temurin17-binaries/releases/download/jdk17-2021-06-30-09-16-beta/OpenJDK17-jdk_x86-32_windows_hotspot_2021-06-30-09-16.zip.sig" }, "project": "jdk", "scm_ref": "jdk-17+28_adopt-132-g23fbf51b850", diff --git a/__tests__/data/zulu-linux.json b/__tests__/data/zulu-linux.json index 1f2fa2716..c74487e2c 100644 --- a/__tests__/data/zulu-linux.json +++ b/__tests__/data/zulu-linux.json @@ -1,254 +1,686 @@ -[ +[ { - "id": 10996, - "url": "https://cdn.azul.com/zulu/bin/zulu1.8.0_05-8.1.0.10-linux.tar.gz", + "package_uuid": "test-uuid-10996", "name": "zulu1.8.0_05-8.1.0.10-linux.tar.gz", - "zulu_version": [8, 1, 0, 10], - "jdk_version": [8, 0, 5, 13] - }, - { - "id": 10997, - "url": "https://cdn.azul.com/zulu/bin/zulu1.8.0_11-8.2.0.1-linux.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu1.8.0_05-8.1.0.10-linux.tar.gz", + "java_version": [ + 8, + 0, + 5 + ], + "openjdk_build_number": 13, + "distro_version": [ + 8, + 1, + 0, + 10 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10997", "name": "zulu1.8.0_11-8.2.0.1-linux.tar.gz", - "zulu_version": [8, 2, 0, 1], - "jdk_version": [8, 0, 11, 12] - }, - { - "id": 10346, - "url": "https://cdn.azul.com/zulu/bin/zulu8.21.0.1-jdk8.0.131-linux_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu1.8.0_11-8.2.0.1-linux.tar.gz", + "java_version": [ + 8, + 0, + 11 + ], + "openjdk_build_number": 12, + "distro_version": [ + 8, + 2, + 0, + 1 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10346", "name": "zulu8.21.0.1-jdk8.0.131-linux_x64.tar.gz", - "zulu_version": [8, 21, 0, 1], - "jdk_version": [8, 0, 131, 11] - }, - { - "id": 10362, - "url": "https://cdn.azul.com/zulu/bin/zulu8.23.0.3-jdk8.0.144-linux_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu8.21.0.1-jdk8.0.131-linux_x64.tar.gz", + "java_version": [ + 8, + 0, + 131 + ], + "openjdk_build_number": 11, + "distro_version": [ + 8, + 21, + 0, + 1 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10362", "name": "zulu8.23.0.3-jdk8.0.144-linux_x64.tar.gz", - "zulu_version": [8, 23, 0, 3], - "jdk_version": [8, 0, 144, 1] - }, - { - "id": 10399, - "url": "https://cdn.azul.com/zulu/bin/zulu8.25.0.1-jdk8.0.152-linux_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu8.23.0.3-jdk8.0.144-linux_x64.tar.gz", + "java_version": [ + 8, + 0, + 144 + ], + "openjdk_build_number": 1, + "distro_version": [ + 8, + 23, + 0, + 3 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10399", "name": "zulu8.25.0.1-jdk8.0.152-linux_x64.tar.gz", - "zulu_version": [8, 25, 0, 1], - "jdk_version": [8, 0, 152, 16] - }, - { - "id": 11355, - "url": "https://cdn.azul.com/zulu/bin/zulu8.46.0.19-ca-jdk8.0.252-linux_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu8.25.0.1-jdk8.0.152-linux_x64.tar.gz", + "java_version": [ + 8, + 0, + 152 + ], + "openjdk_build_number": 16, + "distro_version": [ + 8, + 25, + 0, + 1 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-11355", "name": "zulu8.46.0.19-ca-jdk8.0.252-linux_x64.tar.gz", - "zulu_version": [8, 46, 0, 19], - "jdk_version": [8, 0, 252, 14] - }, - { - "id": 11481, - "url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.47-ca-jdk8.0.262-linux_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu8.46.0.19-ca-jdk8.0.252-linux_x64.tar.gz", + "java_version": [ + 8, + 0, + 252 + ], + "openjdk_build_number": 14, + "distro_version": [ + 8, + 46, + 0, + 19 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-11481", "name": "zulu8.48.0.47-ca-jdk8.0.262-linux_x64.tar.gz", - "zulu_version": [8, 48, 0, 47], - "jdk_version": [8, 0, 262, 17] - }, - { - "id": 11622, - "url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.51-ca-jdk8.0.262-linux_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.47-ca-jdk8.0.262-linux_x64.tar.gz", + "java_version": [ + 8, + 0, + 262 + ], + "openjdk_build_number": 17, + "distro_version": [ + 8, + 48, + 0, + 47 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-11622", "name": "zulu8.48.0.51-ca-jdk8.0.262-linux_x64.tar.gz", - "zulu_version": [8, 48, 0, 51], - "jdk_version": [8, 0, 262, 19] - }, - { - "id": 11535, - "url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.49-ca-jdk8.0.262-linux_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.51-ca-jdk8.0.262-linux_x64.tar.gz", + "java_version": [ + 8, + 0, + 262 + ], + "openjdk_build_number": 19, + "distro_version": [ + 8, + 48, + 0, + 51 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-11535", "name": "zulu8.48.0.49-ca-jdk8.0.262-linux_x64.tar.gz", - "zulu_version": [8, 48, 0, 49], - "jdk_version": [8, 0, 262, 18] - }, - { - "id": 12424, - "url": "https://cdn.azul.com/zulu/bin/zulu8.52.0.23-ca-jdk8.0.282-linux_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.49-ca-jdk8.0.262-linux_x64.tar.gz", + "java_version": [ + 8, + 0, + 262 + ], + "openjdk_build_number": 18, + "distro_version": [ + 8, + 48, + 0, + 49 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-12424", "name": "zulu8.52.0.23-ca-jdk8.0.282-linux_x64.tar.gz", - "zulu_version": [8, 52, 0, 23], - "jdk_version": [8, 0, 282, 8] - }, - { - "id": 10383, - "url": "https://cdn.azul.com/zulu/bin/zulu9.0.0.15-jdk9.0.0-linux_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu8.52.0.23-ca-jdk8.0.282-linux_x64.tar.gz", + "java_version": [ + 8, + 0, + 282 + ], + "openjdk_build_number": 8, + "distro_version": [ + 8, + 52, + 0, + 23 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10383", "name": "zulu9.0.0.15-jdk9.0.0-linux_x64.tar.gz", - "zulu_version": [9, 0, 0, 15], - "jdk_version": [9, 0, 0, 0] - }, - { - "id": 10413, - "url": "https://cdn.azul.com/zulu/bin/zulu9.0.1.3-jdk9.0.1-linux_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu9.0.0.15-jdk9.0.0-linux_x64.tar.gz", + "java_version": [ + 9, + 0, + 0 + ], + "openjdk_build_number": 0, + "distro_version": [ + 9, + 0, + 0, + 15 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10413", "name": "zulu9.0.1.3-jdk9.0.1-linux_x64.tar.gz", - "zulu_version": [9, 0, 1, 3], - "jdk_version": [9, 0, 1, 0] - }, - { - "id": 10503, - "url": "https://cdn.azul.com/zulu/bin/zulu10.2+3-jdk10.0.1-linux_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu9.0.1.3-jdk9.0.1-linux_x64.tar.gz", + "java_version": [ + 9, + 0, + 1 + ], + "openjdk_build_number": 0, + "distro_version": [ + 9, + 0, + 1, + 3 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10503", "name": "zulu10.2+3-jdk10.0.1-linux_x64.tar.gz", - "zulu_version": [10, 2, 3, 0], - "jdk_version": [10, 0, 1, 9] - }, - { - "id": 10541, - "url": "https://cdn.azul.com/zulu/bin/zulu10.3+5-jdk10.0.2-linux_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu10.2+3-jdk10.0.1-linux_x64.tar.gz", + "java_version": [ + 10, + 0, + 1 + ], + "openjdk_build_number": 9, + "distro_version": [ + 10, + 2, + 3, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10541", "name": "zulu10.3+5-jdk10.0.2-linux_x64.tar.gz", - "zulu_version": [10, 3, 5, 0], - "jdk_version": [10, 0, 2, 13] - }, - { - "id": 10576, - "url": "https://cdn.azul.com/zulu/bin/zulu11.2.3-jdk11.0.1-linux_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu10.3+5-jdk10.0.2-linux_x64.tar.gz", + "java_version": [ + 10, + 0, + 2 + ], + "openjdk_build_number": 13, + "distro_version": [ + 10, + 3, + 5, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10576", "name": "zulu11.2.3-jdk11.0.1-linux_x64.tar.gz", - "zulu_version": [11, 2, 3, 0], - "jdk_version": [11, 0, 1, 13] - }, - { - "id": 10604, - "url": "https://cdn.azul.com/zulu/bin/zulu11.29.3-ca-jdk11.0.2-linux_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu11.2.3-jdk11.0.1-linux_x64.tar.gz", + "java_version": [ + 11, + 0, + 1 + ], + "openjdk_build_number": 13, + "distro_version": [ + 11, + 2, + 3, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10604", "name": "zulu11.29.3-ca-jdk11.0.2-linux_x64.tar.gz", - "zulu_version": [11, 29, 3, 0], - "jdk_version": [11, 0, 2, 7] - }, - { - "id": 10687, - "url": "https://cdn.azul.com/zulu/bin/zulu11.31.11-ca-jdk11.0.3-linux_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu11.29.3-ca-jdk11.0.2-linux_x64.tar.gz", + "java_version": [ + 11, + 0, + 2 + ], + "openjdk_build_number": 7, + "distro_version": [ + 11, + 29, + 3, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10687", "name": "zulu11.31.11-ca-jdk11.0.3-linux_x64.tar.gz", - "zulu_version": [11, 31, 11, 0], - "jdk_version": [11, 0, 3, 7] - }, - { - "id": 10856, - "url": "https://cdn.azul.com/zulu/bin/zulu11.35.13-ca-jdk11.0.5-linux_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu11.31.11-ca-jdk11.0.3-linux_x64.tar.gz", + "java_version": [ + 11, + 0, + 3 + ], + "openjdk_build_number": 7, + "distro_version": [ + 11, + 31, + 11, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10856", "name": "zulu11.35.13-ca-jdk11.0.5-linux_x64.tar.gz", - "zulu_version": [11, 35, 13, 0], - "jdk_version": [11, 0, 5, 10] - }, - { - "id": 10933, - "url": "https://cdn.azul.com/zulu/bin/zulu11.35.15-ca-jdk11.0.5-linux_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu11.35.13-ca-jdk11.0.5-linux_x64.tar.gz", + "java_version": [ + 11, + 0, + 5 + ], + "openjdk_build_number": 10, + "distro_version": [ + 11, + 35, + 13, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10933", "name": "zulu11.35.15-ca-jdk11.0.5-linux_x64.tar.gz", - "zulu_version": [11, 35, 15, 0], - "jdk_version": [11, 0, 5, 10] - }, - { - "id": 10933, - "url": "https://cdn.azul.com/zulu/bin/zulu11.35.11-ca-jdk11.0.5-linux_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu11.35.15-ca-jdk11.0.5-linux_x64.tar.gz", + "java_version": [ + 11, + 0, + 5 + ], + "openjdk_build_number": 10, + "distro_version": [ + 11, + 35, + 15, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10933", "name": "zulu11.35.15-ca-jdk11.0.5-linux_x64.tar.gz", - "zulu_version": [11, 35, 11, 0], - "jdk_version": [11, 0, 5, 10] - }, - { - "id": 12397, - "url": "https://cdn.azul.com/zulu/bin/zulu11.45.27-ca-jdk11.0.10-linux_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu11.35.11-ca-jdk11.0.5-linux_x64.tar.gz", + "java_version": [ + 11, + 0, + 5 + ], + "openjdk_build_number": 10, + "distro_version": [ + 11, + 35, + 11, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-12397", "name": "zulu11.45.27-ca-jdk11.0.10-linux_x64.tar.gz", - "zulu_version": [11, 45, 27, 0], - "jdk_version": [11, 0, 10, 9] - }, - { - "id": 10667, - "url": "https://cdn.azul.com/zulu/bin/zulu12.1.3-ca-jdk12.0.0-linux_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu11.45.27-ca-jdk11.0.10-linux_x64.tar.gz", + "java_version": [ + 11, + 0, + 10 + ], + "openjdk_build_number": 9, + "distro_version": [ + 11, + 45, + 27, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10667", "name": "zulu12.1.3-ca-jdk12.0.0-linux_x64.tar.gz", - "zulu_version": [12, 1, 3, 0], - "jdk_version": [12, 0, 0, 33] - }, - { - "id": 10710, - "url": "https://cdn.azul.com/zulu/bin/zulu12.2.3-ca-jdk12.0.1-linux_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu12.1.3-ca-jdk12.0.0-linux_x64.tar.gz", + "java_version": [ + 12, + 0, + 0 + ], + "openjdk_build_number": 33, + "distro_version": [ + 12, + 1, + 3, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10710", "name": "zulu12.2.3-ca-jdk12.0.1-linux_x64.tar.gz", - "zulu_version": [12, 2, 3, 0], - "jdk_version": [12, 0, 1, 12] - }, - { - "id": 10780, - "url": "https://cdn.azul.com/zulu/bin/zulu12.3.11-ca-jdk12.0.2-linux_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu12.2.3-ca-jdk12.0.1-linux_x64.tar.gz", + "java_version": [ + 12, + 0, + 1 + ], + "openjdk_build_number": 12, + "distro_version": [ + 12, + 2, + 3, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10780", "name": "zulu12.3.11-ca-jdk12.0.2-linux_x64.tar.gz", - "zulu_version": [12, 3, 11, 0], - "jdk_version": [12, 0, 2, 3] - }, - { - "id": 10846, - "url": "https://cdn.azul.com/zulu/bin/zulu13.27.9-ca-jdk13.0.0-linux_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu12.3.11-ca-jdk12.0.2-linux_x64.tar.gz", + "java_version": [ + 12, + 0, + 2 + ], + "openjdk_build_number": 3, + "distro_version": [ + 12, + 3, + 11, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10846", "name": "zulu13.27.9-ca-jdk13.0.0-linux_x64.tar.gz", - "zulu_version": [13, 27, 9, 0], - "jdk_version": [13, 0, 0, 33] - }, - { - "id": 10888, - "url": "https://cdn.azul.com/zulu/bin/zulu13.28.11-ca-jdk13.0.1-linux_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu13.27.9-ca-jdk13.0.0-linux_x64.tar.gz", + "java_version": [ + 13, + 0, + 0 + ], + "openjdk_build_number": 33, + "distro_version": [ + 13, + 27, + 9, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10888", "name": "zulu13.28.11-ca-jdk13.0.1-linux_x64.tar.gz", - "zulu_version": [13, 28, 11, 0], - "jdk_version": [13, 0, 1, 10] - }, - { - "id": 11073, - "url": "https://cdn.azul.com/zulu/bin/zulu13.29.9-ca-jdk13.0.2-linux_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu13.28.11-ca-jdk13.0.1-linux_x64.tar.gz", + "java_version": [ + 13, + 0, + 1 + ], + "openjdk_build_number": 10, + "distro_version": [ + 13, + 28, + 11, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-11073", "name": "zulu13.29.9-ca-jdk13.0.2-linux_x64.tar.gz", - "zulu_version": [13, 29, 9, 0], - "jdk_version": [13, 0, 2, 6] - }, - { - "id": 12408, - "url": "https://cdn.azul.com/zulu/bin/zulu13.37.21-ca-jdk13.0.6-linux_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu13.29.9-ca-jdk13.0.2-linux_x64.tar.gz", + "java_version": [ + 13, + 0, + 2 + ], + "openjdk_build_number": 6, + "distro_version": [ + 13, + 29, + 9, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-12408", "name": "zulu13.37.21-ca-jdk13.0.6-linux_x64.tar.gz", - "zulu_version": [13, 37, 21, 0], - "jdk_version": [13, 0, 6, 5] - }, - { - "id": 11236, - "url": "https://cdn.azul.com/zulu/bin/zulu14.27.1-ca-jdk14.0.0-linux_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu13.37.21-ca-jdk13.0.6-linux_x64.tar.gz", + "java_version": [ + 13, + 0, + 6 + ], + "openjdk_build_number": 5, + "distro_version": [ + 13, + 37, + 21, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-11236", "name": "zulu14.27.1-ca-jdk14.0.0-linux_x64.tar.gz", - "zulu_version": [14, 27, 1, 0], - "jdk_version": [14, 0, 0, 36] - }, - { - "id": 11349, - "url": "https://cdn.azul.com/zulu/bin/zulu14.28.21-ca-jdk14.0.1-linux_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu14.27.1-ca-jdk14.0.0-linux_x64.tar.gz", + "java_version": [ + 14, + 0, + 0 + ], + "openjdk_build_number": 36, + "distro_version": [ + 14, + 27, + 1, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-11349", "name": "zulu14.28.21-ca-jdk14.0.1-linux_x64.tar.gz", - "zulu_version": [14, 28, 21, 0], - "jdk_version": [14, 0, 1, 8] - }, - { - "id": 11513, - "url": "https://cdn.azul.com/zulu/bin/zulu14.29.23-ca-jdk14.0.2-linux_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu14.28.21-ca-jdk14.0.1-linux_x64.tar.gz", + "java_version": [ + 14, + 0, + 1 + ], + "openjdk_build_number": 8, + "distro_version": [ + 14, + 28, + 21, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-11513", "name": "zulu14.29.23-ca-jdk14.0.2-linux_x64.tar.gz", - "zulu_version": [14, 29, 23, 0], - "jdk_version": [14, 0, 2, 12] - }, - { - "id": 11780, - "url": "https://cdn.azul.com/zulu/bin/zulu15.27.17-ca-jdk15.0.0-linux_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu14.29.23-ca-jdk14.0.2-linux_x64.tar.gz", + "java_version": [ + 14, + 0, + 2 + ], + "openjdk_build_number": 12, + "distro_version": [ + 14, + 29, + 23, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-11780", "name": "zulu15.27.17-ca-jdk15.0.0-linux_x64.tar.gz", - "zulu_version": [15, 27, 17, 0], - "jdk_version": [15, 0, 0, 36] - }, - { - "id": 11924, - "url": "https://cdn.azul.com/zulu/bin/zulu15.28.13-ca-jdk15.0.1-linux_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu15.27.17-ca-jdk15.0.0-linux_x64.tar.gz", + "java_version": [ + 15, + 0, + 0 + ], + "openjdk_build_number": 36, + "distro_version": [ + 15, + 27, + 17, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-11924", "name": "zulu15.28.13-ca-jdk15.0.1-linux_x64.tar.gz", - "zulu_version": [15, 28, 13, 0], - "jdk_version": [15, 0, 1, 8] - }, - { - "id": 12101, - "url": "https://cdn.azul.com/zulu/bin/zulu15.28.51-ca-jdk15.0.1-linux_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu15.28.13-ca-jdk15.0.1-linux_x64.tar.gz", + "java_version": [ + 15, + 0, + 1 + ], + "openjdk_build_number": 8, + "distro_version": [ + 15, + 28, + 13, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-12101", "name": "zulu15.28.51-ca-jdk15.0.1-linux_x64.tar.gz", - "zulu_version": [15, 28, 51, 0], - "jdk_version": [15, 0, 1, 9] - }, - { - "id": 12445, - "url": "https://cdn.azul.com/zulu/bin/zulu15.29.15-ca-jdk15.0.2-linux_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu15.28.51-ca-jdk15.0.1-linux_x64.tar.gz", + "java_version": [ + 15, + 0, + 1 + ], + "openjdk_build_number": 9, + "distro_version": [ + 15, + 28, + 51, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-12445", "name": "zulu15.29.15-ca-jdk15.0.2-linux_x64.tar.gz", - "zulu_version": [15, 29, 15, 0], - "jdk_version": [15, 0, 2, 7] - }, - { - "id": 12447, - "url": "https://cdn.azul.com/zulu/bin/zulu21.32.17-ca-jdk21.0.2-linux_aarch64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu15.29.15-ca-jdk15.0.2-linux_x64.tar.gz", + "java_version": [ + 15, + 0, + 2 + ], + "openjdk_build_number": 7, + "distro_version": [ + 15, + 29, + 15, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-12447", "name": "zulu21.32.17-ca-jdk21.0.2-linux_aarch64.tar.gz", - "zulu_version": [21, 32, 17, 0], - "jdk_version": [21, 0, 2, 6] + "download_url": "https://cdn.azul.com/zulu/bin/zulu21.32.17-ca-jdk21.0.2-linux_aarch64.tar.gz", + "java_version": [ + 21, + 0, + 2 + ], + "openjdk_build_number": 6, + "distro_version": [ + 21, + 32, + 17, + 0 + ], + "latest": false, + "availability_type": "ca" } -] \ No newline at end of file +] diff --git a/__tests__/data/zulu-releases-default.json b/__tests__/data/zulu-releases-default.json index f23a87d43..16ed97772 100644 --- a/__tests__/data/zulu-releases-default.json +++ b/__tests__/data/zulu-releases-default.json @@ -1,247 +1,667 @@ [ { - "id": 10996, - "url": "https://cdn.azul.com/zulu/bin/zulu1.8.0_05-8.1.0.10-macosx.tar.gz", + "package_uuid": "test-uuid-10996", "name": "zulu1.8.0_05-8.1.0.10-macosx.tar.gz", - "zulu_version": [8, 1, 0, 10], - "jdk_version": [8, 0, 5, 13] - }, - { - "id": 10997, - "url": "https://cdn.azul.com/zulu/bin/zulu1.8.0_11-8.2.0.1-macosx.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu1.8.0_05-8.1.0.10-macosx.tar.gz", + "java_version": [ + 8, + 0, + 5 + ], + "openjdk_build_number": 13, + "distro_version": [ + 8, + 1, + 0, + 10 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10997", "name": "zulu1.8.0_11-8.2.0.1-macosx.tar.gz", - "zulu_version": [8, 2, 0, 1], - "jdk_version": [8, 0, 11, 12] - }, - { - "id": 10346, - "url": "https://cdn.azul.com/zulu/bin/zulu8.21.0.1-jdk8.0.131-macosx_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu1.8.0_11-8.2.0.1-macosx.tar.gz", + "java_version": [ + 8, + 0, + 11 + ], + "openjdk_build_number": 12, + "distro_version": [ + 8, + 2, + 0, + 1 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10346", "name": "zulu8.21.0.1-jdk8.0.131-macosx_x64.tar.gz", - "zulu_version": [8, 21, 0, 1], - "jdk_version": [8, 0, 131, 11] - }, - { - "id": 10362, - "url": "https://cdn.azul.com/zulu/bin/zulu8.23.0.3-jdk8.0.144-macosx_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu8.21.0.1-jdk8.0.131-macosx_x64.tar.gz", + "java_version": [ + 8, + 0, + 131 + ], + "openjdk_build_number": 11, + "distro_version": [ + 8, + 21, + 0, + 1 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10362", "name": "zulu8.23.0.3-jdk8.0.144-macosx_x64.tar.gz", - "zulu_version": [8, 23, 0, 3], - "jdk_version": [8, 0, 144, 1] - }, - { - "id": 10399, - "url": "https://cdn.azul.com/zulu/bin/zulu8.25.0.1-jdk8.0.152-macosx_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu8.23.0.3-jdk8.0.144-macosx_x64.tar.gz", + "java_version": [ + 8, + 0, + 144 + ], + "openjdk_build_number": 1, + "distro_version": [ + 8, + 23, + 0, + 3 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10399", "name": "zulu8.25.0.1-jdk8.0.152-macosx_x64.tar.gz", - "zulu_version": [8, 25, 0, 1], - "jdk_version": [8, 0, 152, 16] - }, - { - "id": 11355, - "url": "https://cdn.azul.com/zulu/bin/zulu8.46.0.19-ca-jdk8.0.252-macosx_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu8.25.0.1-jdk8.0.152-macosx_x64.tar.gz", + "java_version": [ + 8, + 0, + 152 + ], + "openjdk_build_number": 16, + "distro_version": [ + 8, + 25, + 0, + 1 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-11355", "name": "zulu8.46.0.19-ca-jdk8.0.252-macosx_x64.tar.gz", - "zulu_version": [8, 46, 0, 19], - "jdk_version": [8, 0, 252, 14] - }, - { - "id": 11481, - "url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.47-ca-jdk8.0.262-macosx_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu8.46.0.19-ca-jdk8.0.252-macosx_x64.tar.gz", + "java_version": [ + 8, + 0, + 252 + ], + "openjdk_build_number": 14, + "distro_version": [ + 8, + 46, + 0, + 19 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-11481", "name": "zulu8.48.0.47-ca-jdk8.0.262-macosx_x64.tar.gz", - "zulu_version": [8, 48, 0, 47], - "jdk_version": [8, 0, 262, 17] - }, - { - "id": 11622, - "url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.51-ca-jdk8.0.262-macosx_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.47-ca-jdk8.0.262-macosx_x64.tar.gz", + "java_version": [ + 8, + 0, + 262 + ], + "openjdk_build_number": 17, + "distro_version": [ + 8, + 48, + 0, + 47 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-11622", "name": "zulu8.48.0.51-ca-jdk8.0.262-macosx_x64.tar.gz", - "zulu_version": [8, 48, 0, 51], - "jdk_version": [8, 0, 262, 19] - }, - { - "id": 11535, - "url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.49-ca-jdk8.0.262-macosx_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.51-ca-jdk8.0.262-macosx_x64.tar.gz", + "java_version": [ + 8, + 0, + 262 + ], + "openjdk_build_number": 19, + "distro_version": [ + 8, + 48, + 0, + 51 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-11535", "name": "zulu8.48.0.49-ca-jdk8.0.262-macosx_x64.tar.gz", - "zulu_version": [8, 48, 0, 49], - "jdk_version": [8, 0, 262, 18] - }, - { - "id": 12424, - "url": "https://cdn.azul.com/zulu/bin/zulu8.52.0.23-ca-jdk8.0.282-macosx_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.49-ca-jdk8.0.262-macosx_x64.tar.gz", + "java_version": [ + 8, + 0, + 262 + ], + "openjdk_build_number": 18, + "distro_version": [ + 8, + 48, + 0, + 49 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-12424", "name": "zulu8.52.0.23-ca-jdk8.0.282-macosx_x64.tar.gz", - "zulu_version": [8, 52, 0, 23], - "jdk_version": [8, 0, 282, 8] - }, - { - "id": 10383, - "url": "https://cdn.azul.com/zulu/bin/zulu9.0.0.15-jdk9.0.0-macosx_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu8.52.0.23-ca-jdk8.0.282-macosx_x64.tar.gz", + "java_version": [ + 8, + 0, + 282 + ], + "openjdk_build_number": 8, + "distro_version": [ + 8, + 52, + 0, + 23 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10383", "name": "zulu9.0.0.15-jdk9.0.0-macosx_x64.tar.gz", - "zulu_version": [9, 0, 0, 15], - "jdk_version": [9, 0, 0, 0] - }, - { - "id": 10413, - "url": "https://cdn.azul.com/zulu/bin/zulu9.0.1.3-jdk9.0.1-macosx_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu9.0.0.15-jdk9.0.0-macosx_x64.tar.gz", + "java_version": [ + 9, + 0, + 0 + ], + "openjdk_build_number": 0, + "distro_version": [ + 9, + 0, + 0, + 15 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10413", "name": "zulu9.0.1.3-jdk9.0.1-macosx_x64.tar.gz", - "zulu_version": [9, 0, 1, 3], - "jdk_version": [9, 0, 1, 0] - }, - { - "id": 10503, - "url": "https://cdn.azul.com/zulu/bin/zulu10.2+3-jdk10.0.1-macosx_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu9.0.1.3-jdk9.0.1-macosx_x64.tar.gz", + "java_version": [ + 9, + 0, + 1 + ], + "openjdk_build_number": 0, + "distro_version": [ + 9, + 0, + 1, + 3 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10503", "name": "zulu10.2+3-jdk10.0.1-macosx_x64.tar.gz", - "zulu_version": [10, 2, 3, 0], - "jdk_version": [10, 0, 1, 9] - }, - { - "id": 10541, - "url": "https://cdn.azul.com/zulu/bin/zulu10.3+5-jdk10.0.2-macosx_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu10.2+3-jdk10.0.1-macosx_x64.tar.gz", + "java_version": [ + 10, + 0, + 1 + ], + "openjdk_build_number": 9, + "distro_version": [ + 10, + 2, + 3, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10541", "name": "zulu10.3+5-jdk10.0.2-macosx_x64.tar.gz", - "zulu_version": [10, 3, 5, 0], - "jdk_version": [10, 0, 2, 13] - }, - { - "id": 10576, - "url": "https://cdn.azul.com/zulu/bin/zulu11.2.3-jdk11.0.1-macosx_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu10.3+5-jdk10.0.2-macosx_x64.tar.gz", + "java_version": [ + 10, + 0, + 2 + ], + "openjdk_build_number": 13, + "distro_version": [ + 10, + 3, + 5, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10576", "name": "zulu11.2.3-jdk11.0.1-macosx_x64.tar.gz", - "zulu_version": [11, 2, 3, 0], - "jdk_version": [11, 0, 1, 13] - }, - { - "id": 10604, - "url": "https://cdn.azul.com/zulu/bin/zulu11.29.3-ca-jdk11.0.2-macosx_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu11.2.3-jdk11.0.1-macosx_x64.tar.gz", + "java_version": [ + 11, + 0, + 1 + ], + "openjdk_build_number": 13, + "distro_version": [ + 11, + 2, + 3, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10604", "name": "zulu11.29.3-ca-jdk11.0.2-macosx_x64.tar.gz", - "zulu_version": [11, 29, 3, 0], - "jdk_version": [11, 0, 2, 7] - }, - { - "id": 10687, - "url": "https://cdn.azul.com/zulu/bin/zulu11.31.11-ca-jdk11.0.3-macosx_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu11.29.3-ca-jdk11.0.2-macosx_x64.tar.gz", + "java_version": [ + 11, + 0, + 2 + ], + "openjdk_build_number": 7, + "distro_version": [ + 11, + 29, + 3, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10687", "name": "zulu11.31.11-ca-jdk11.0.3-macosx_x64.tar.gz", - "zulu_version": [11, 31, 11, 0], - "jdk_version": [11, 0, 3, 7] - }, - { - "id": 10856, - "url": "https://cdn.azul.com/zulu/bin/zulu11.35.13-ca-jdk11.0.5-macosx_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu11.31.11-ca-jdk11.0.3-macosx_x64.tar.gz", + "java_version": [ + 11, + 0, + 3 + ], + "openjdk_build_number": 7, + "distro_version": [ + 11, + 31, + 11, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10856", "name": "zulu11.35.13-ca-jdk11.0.5-macosx_x64.tar.gz", - "zulu_version": [11, 35, 13, 0], - "jdk_version": [11, 0, 5, 10] - }, - { - "id": 10933, - "url": "https://cdn.azul.com/zulu/bin/zulu11.35.15-ca-jdk11.0.5-macosx_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu11.35.13-ca-jdk11.0.5-macosx_x64.tar.gz", + "java_version": [ + 11, + 0, + 5 + ], + "openjdk_build_number": 10, + "distro_version": [ + 11, + 35, + 13, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10933", "name": "zulu11.35.15-ca-jdk11.0.5-macosx_x64.tar.gz", - "zulu_version": [11, 35, 15, 0], - "jdk_version": [11, 0, 5, 10] - }, - { - "id": 10933, - "url": "https://cdn.azul.com/zulu/bin/zulu11.35.11-ca-jdk11.0.5-macosx_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu11.35.15-ca-jdk11.0.5-macosx_x64.tar.gz", + "java_version": [ + 11, + 0, + 5 + ], + "openjdk_build_number": 10, + "distro_version": [ + 11, + 35, + 15, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10933", "name": "zulu11.35.15-ca-jdk11.0.5-macosx_x64.tar.gz", - "zulu_version": [11, 35, 11, 0], - "jdk_version": [11, 0, 5, 10] - }, - { - "id": 12397, - "url": "https://cdn.azul.com/zulu/bin/zulu11.45.27-ca-jdk11.0.10-macosx_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu11.35.11-ca-jdk11.0.5-macosx_x64.tar.gz", + "java_version": [ + 11, + 0, + 5 + ], + "openjdk_build_number": 10, + "distro_version": [ + 11, + 35, + 11, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-12397", "name": "zulu11.45.27-ca-jdk11.0.10-macosx_x64.tar.gz", - "zulu_version": [11, 45, 27, 0], - "jdk_version": [11, 0, 10, 9] - }, - { - "id": 10667, - "url": "https://cdn.azul.com/zulu/bin/zulu12.1.3-ca-jdk12.0.0-macosx_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu11.45.27-ca-jdk11.0.10-macosx_x64.tar.gz", + "java_version": [ + 11, + 0, + 10 + ], + "openjdk_build_number": 9, + "distro_version": [ + 11, + 45, + 27, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10667", "name": "zulu12.1.3-ca-jdk12.0.0-macosx_x64.tar.gz", - "zulu_version": [12, 1, 3, 0], - "jdk_version": [12, 0, 0, 33] - }, - { - "id": 10710, - "url": "https://cdn.azul.com/zulu/bin/zulu12.2.3-ca-jdk12.0.1-macosx_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu12.1.3-ca-jdk12.0.0-macosx_x64.tar.gz", + "java_version": [ + 12, + 0, + 0 + ], + "openjdk_build_number": 33, + "distro_version": [ + 12, + 1, + 3, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10710", "name": "zulu12.2.3-ca-jdk12.0.1-macosx_x64.tar.gz", - "zulu_version": [12, 2, 3, 0], - "jdk_version": [12, 0, 1, 12] - }, - { - "id": 10780, - "url": "https://cdn.azul.com/zulu/bin/zulu12.3.11-ca-jdk12.0.2-macosx_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu12.2.3-ca-jdk12.0.1-macosx_x64.tar.gz", + "java_version": [ + 12, + 0, + 1 + ], + "openjdk_build_number": 12, + "distro_version": [ + 12, + 2, + 3, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10780", "name": "zulu12.3.11-ca-jdk12.0.2-macosx_x64.tar.gz", - "zulu_version": [12, 3, 11, 0], - "jdk_version": [12, 0, 2, 3] - }, - { - "id": 10846, - "url": "https://cdn.azul.com/zulu/bin/zulu13.27.9-ca-jdk13.0.0-macosx_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu12.3.11-ca-jdk12.0.2-macosx_x64.tar.gz", + "java_version": [ + 12, + 0, + 2 + ], + "openjdk_build_number": 3, + "distro_version": [ + 12, + 3, + 11, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10846", "name": "zulu13.27.9-ca-jdk13.0.0-macosx_x64.tar.gz", - "zulu_version": [13, 27, 9, 0], - "jdk_version": [13, 0, 0, 33] - }, - { - "id": 10888, - "url": "https://cdn.azul.com/zulu/bin/zulu13.28.11-ca-jdk13.0.1-macosx_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu13.27.9-ca-jdk13.0.0-macosx_x64.tar.gz", + "java_version": [ + 13, + 0, + 0 + ], + "openjdk_build_number": 33, + "distro_version": [ + 13, + 27, + 9, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10888", "name": "zulu13.28.11-ca-jdk13.0.1-macosx_x64.tar.gz", - "zulu_version": [13, 28, 11, 0], - "jdk_version": [13, 0, 1, 10] - }, - { - "id": 11073, - "url": "https://cdn.azul.com/zulu/bin/zulu13.29.9-ca-jdk13.0.2-macosx_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu13.28.11-ca-jdk13.0.1-macosx_x64.tar.gz", + "java_version": [ + 13, + 0, + 1 + ], + "openjdk_build_number": 10, + "distro_version": [ + 13, + 28, + 11, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-11073", "name": "zulu13.29.9-ca-jdk13.0.2-macosx_x64.tar.gz", - "zulu_version": [13, 29, 9, 0], - "jdk_version": [13, 0, 2, 6] - }, - { - "id": 12408, - "url": "https://cdn.azul.com/zulu/bin/zulu13.37.21-ca-jdk13.0.6-macosx_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu13.29.9-ca-jdk13.0.2-macosx_x64.tar.gz", + "java_version": [ + 13, + 0, + 2 + ], + "openjdk_build_number": 6, + "distro_version": [ + 13, + 29, + 9, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-12408", "name": "zulu13.37.21-ca-jdk13.0.6-macosx_x64.tar.gz", - "zulu_version": [13, 37, 21, 0], - "jdk_version": [13, 0, 6, 5] - }, - { - "id": 11236, - "url": "https://cdn.azul.com/zulu/bin/zulu14.27.1-ca-jdk14.0.0-macosx_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu13.37.21-ca-jdk13.0.6-macosx_x64.tar.gz", + "java_version": [ + 13, + 0, + 6 + ], + "openjdk_build_number": 5, + "distro_version": [ + 13, + 37, + 21, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-11236", "name": "zulu14.27.1-ca-jdk14.0.0-macosx_x64.tar.gz", - "zulu_version": [14, 27, 1, 0], - "jdk_version": [14, 0, 0, 36] - }, - { - "id": 11349, - "url": "https://cdn.azul.com/zulu/bin/zulu14.28.21-ca-jdk14.0.1-macosx_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu14.27.1-ca-jdk14.0.0-macosx_x64.tar.gz", + "java_version": [ + 14, + 0, + 0 + ], + "openjdk_build_number": 36, + "distro_version": [ + 14, + 27, + 1, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-11349", "name": "zulu14.28.21-ca-jdk14.0.1-macosx_x64.tar.gz", - "zulu_version": [14, 28, 21, 0], - "jdk_version": [14, 0, 1, 8] - }, - { - "id": 11513, - "url": "https://cdn.azul.com/zulu/bin/zulu14.29.23-ca-jdk14.0.2-macosx_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu14.28.21-ca-jdk14.0.1-macosx_x64.tar.gz", + "java_version": [ + 14, + 0, + 1 + ], + "openjdk_build_number": 8, + "distro_version": [ + 14, + 28, + 21, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-11513", "name": "zulu14.29.23-ca-jdk14.0.2-macosx_x64.tar.gz", - "zulu_version": [14, 29, 23, 0], - "jdk_version": [14, 0, 2, 12] - }, - { - "id": 11780, - "url": "https://cdn.azul.com/zulu/bin/zulu15.27.17-ca-jdk15.0.0-macosx_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu14.29.23-ca-jdk14.0.2-macosx_x64.tar.gz", + "java_version": [ + 14, + 0, + 2 + ], + "openjdk_build_number": 12, + "distro_version": [ + 14, + 29, + 23, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-11780", "name": "zulu15.27.17-ca-jdk15.0.0-macosx_x64.tar.gz", - "zulu_version": [15, 27, 17, 0], - "jdk_version": [15, 0, 0, 36] - }, - { - "id": 11924, - "url": "https://cdn.azul.com/zulu/bin/zulu15.28.13-ca-jdk15.0.1-macosx_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu15.27.17-ca-jdk15.0.0-macosx_x64.tar.gz", + "java_version": [ + 15, + 0, + 0 + ], + "openjdk_build_number": 36, + "distro_version": [ + 15, + 27, + 17, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-11924", "name": "zulu15.28.13-ca-jdk15.0.1-macosx_x64.tar.gz", - "zulu_version": [15, 28, 13, 0], - "jdk_version": [15, 0, 1, 8] - }, - { - "id": 12101, - "url": "https://cdn.azul.com/zulu/bin/zulu15.28.51-ca-jdk15.0.1-macosx_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu15.28.13-ca-jdk15.0.1-macosx_x64.tar.gz", + "java_version": [ + 15, + 0, + 1 + ], + "openjdk_build_number": 8, + "distro_version": [ + 15, + 28, + 13, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-12101", "name": "zulu15.28.51-ca-jdk15.0.1-macosx_x64.tar.gz", - "zulu_version": [15, 28, 51, 0], - "jdk_version": [15, 0, 1, 9] - }, - { - "id": 12445, - "url": "https://cdn.azul.com/zulu/bin/zulu15.29.15-ca-jdk15.0.2-macosx_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu15.28.51-ca-jdk15.0.1-macosx_x64.tar.gz", + "java_version": [ + 15, + 0, + 1 + ], + "openjdk_build_number": 9, + "distro_version": [ + 15, + 28, + 51, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-12445", "name": "zulu15.29.15-ca-jdk15.0.2-macosx_x64.tar.gz", - "zulu_version": [15, 29, 15, 0], - "jdk_version": [15, 0, 2, 7] + "download_url": "https://cdn.azul.com/zulu/bin/zulu15.29.15-ca-jdk15.0.2-macosx_x64.tar.gz", + "java_version": [ + 15, + 0, + 2 + ], + "openjdk_build_number": 7, + "distro_version": [ + 15, + 29, + 15, + 0 + ], + "latest": false, + "availability_type": "ca" } ] diff --git a/__tests__/data/zulu-windows.json b/__tests__/data/zulu-windows.json index e4ce99538..dcfb9462f 100644 --- a/__tests__/data/zulu-windows.json +++ b/__tests__/data/zulu-windows.json @@ -1,254 +1,686 @@ -[ +[ { - "id": 10996, - "url": "https://cdn.azul.com/zulu/bin/zulu1.8.0_05-8.1.0.10-windows.tar.gz", + "package_uuid": "test-uuid-10996", "name": "zulu1.8.0_05-8.1.0.10-windows.tar.gz", - "zulu_version": [8, 1, 0, 10], - "jdk_version": [8, 0, 5, 13] - }, - { - "id": 10997, - "url": "https://cdn.azul.com/zulu/bin/zulu1.8.0_11-8.2.0.1-windows.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu1.8.0_05-8.1.0.10-windows.tar.gz", + "java_version": [ + 8, + 0, + 5 + ], + "openjdk_build_number": 13, + "distro_version": [ + 8, + 1, + 0, + 10 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10997", "name": "zulu1.8.0_11-8.2.0.1-windows.tar.gz", - "zulu_version": [8, 2, 0, 1], - "jdk_version": [8, 0, 11, 12] - }, - { - "id": 10346, - "url": "https://cdn.azul.com/zulu/bin/zulu8.21.0.1-jdk8.0.131-windows_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu1.8.0_11-8.2.0.1-windows.tar.gz", + "java_version": [ + 8, + 0, + 11 + ], + "openjdk_build_number": 12, + "distro_version": [ + 8, + 2, + 0, + 1 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10346", "name": "zulu8.21.0.1-jdk8.0.131-windows_x64.tar.gz", - "zulu_version": [8, 21, 0, 1], - "jdk_version": [8, 0, 131, 11] - }, - { - "id": 10362, - "url": "https://cdn.azul.com/zulu/bin/zulu8.23.0.3-jdk8.0.144-windows_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu8.21.0.1-jdk8.0.131-windows_x64.tar.gz", + "java_version": [ + 8, + 0, + 131 + ], + "openjdk_build_number": 11, + "distro_version": [ + 8, + 21, + 0, + 1 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10362", "name": "zulu8.23.0.3-jdk8.0.144-windows_x64.tar.gz", - "zulu_version": [8, 23, 0, 3], - "jdk_version": [8, 0, 144, 1] - }, - { - "id": 10399, - "url": "https://cdn.azul.com/zulu/bin/zulu8.25.0.1-jdk8.0.152-windows_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu8.23.0.3-jdk8.0.144-windows_x64.tar.gz", + "java_version": [ + 8, + 0, + 144 + ], + "openjdk_build_number": 1, + "distro_version": [ + 8, + 23, + 0, + 3 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10399", "name": "zulu8.25.0.1-jdk8.0.152-windows_x64.tar.gz", - "zulu_version": [8, 25, 0, 1], - "jdk_version": [8, 0, 152, 16] - }, - { - "id": 11355, - "url": "https://cdn.azul.com/zulu/bin/zulu8.46.0.19-ca-jdk8.0.252-windows_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu8.25.0.1-jdk8.0.152-windows_x64.tar.gz", + "java_version": [ + 8, + 0, + 152 + ], + "openjdk_build_number": 16, + "distro_version": [ + 8, + 25, + 0, + 1 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-11355", "name": "zulu8.46.0.19-ca-jdk8.0.252-windows_x64.tar.gz", - "zulu_version": [8, 46, 0, 19], - "jdk_version": [8, 0, 252, 14] - }, - { - "id": 11481, - "url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.47-ca-jdk8.0.262-windows_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu8.46.0.19-ca-jdk8.0.252-windows_x64.tar.gz", + "java_version": [ + 8, + 0, + 252 + ], + "openjdk_build_number": 14, + "distro_version": [ + 8, + 46, + 0, + 19 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-11481", "name": "zulu8.48.0.47-ca-jdk8.0.262-windows_x64.tar.gz", - "zulu_version": [8, 48, 0, 47], - "jdk_version": [8, 0, 262, 17] - }, - { - "id": 11622, - "url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.51-ca-jdk8.0.262-windows_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.47-ca-jdk8.0.262-windows_x64.tar.gz", + "java_version": [ + 8, + 0, + 262 + ], + "openjdk_build_number": 17, + "distro_version": [ + 8, + 48, + 0, + 47 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-11622", "name": "zulu8.48.0.51-ca-jdk8.0.262-windows_x64.tar.gz", - "zulu_version": [8, 48, 0, 51], - "jdk_version": [8, 0, 262, 19] - }, - { - "id": 11535, - "url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.49-ca-jdk8.0.262-windows_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.51-ca-jdk8.0.262-windows_x64.tar.gz", + "java_version": [ + 8, + 0, + 262 + ], + "openjdk_build_number": 19, + "distro_version": [ + 8, + 48, + 0, + 51 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-11535", "name": "zulu8.48.0.49-ca-jdk8.0.262-windows_x64.tar.gz", - "zulu_version": [8, 48, 0, 49], - "jdk_version": [8, 0, 262, 18] - }, - { - "id": 12424, - "url": "https://cdn.azul.com/zulu/bin/zulu8.52.0.23-ca-jdk8.0.282-windows_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.49-ca-jdk8.0.262-windows_x64.tar.gz", + "java_version": [ + 8, + 0, + 262 + ], + "openjdk_build_number": 18, + "distro_version": [ + 8, + 48, + 0, + 49 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-12424", "name": "zulu8.52.0.23-ca-jdk8.0.282-windows_x64.tar.gz", - "zulu_version": [8, 52, 0, 23], - "jdk_version": [8, 0, 282, 8] - }, - { - "id": 10383, - "url": "https://cdn.azul.com/zulu/bin/zulu9.0.0.15-jdk9.0.0-windows_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu8.52.0.23-ca-jdk8.0.282-windows_x64.tar.gz", + "java_version": [ + 8, + 0, + 282 + ], + "openjdk_build_number": 8, + "distro_version": [ + 8, + 52, + 0, + 23 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10383", "name": "zulu9.0.0.15-jdk9.0.0-windows_x64.tar.gz", - "zulu_version": [9, 0, 0, 15], - "jdk_version": [9, 0, 0, 0] - }, - { - "id": 10413, - "url": "https://cdn.azul.com/zulu/bin/zulu9.0.1.3-jdk9.0.1-windows_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu9.0.0.15-jdk9.0.0-windows_x64.tar.gz", + "java_version": [ + 9, + 0, + 0 + ], + "openjdk_build_number": 0, + "distro_version": [ + 9, + 0, + 0, + 15 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10413", "name": "zulu9.0.1.3-jdk9.0.1-windows_x64.tar.gz", - "zulu_version": [9, 0, 1, 3], - "jdk_version": [9, 0, 1, 0] - }, - { - "id": 10503, - "url": "https://cdn.azul.com/zulu/bin/zulu10.2+3-jdk10.0.1-windows_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu9.0.1.3-jdk9.0.1-windows_x64.tar.gz", + "java_version": [ + 9, + 0, + 1 + ], + "openjdk_build_number": 0, + "distro_version": [ + 9, + 0, + 1, + 3 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10503", "name": "zulu10.2+3-jdk10.0.1-windows_x64.tar.gz", - "zulu_version": [10, 2, 3, 0], - "jdk_version": [10, 0, 1, 9] - }, - { - "id": 10541, - "url": "https://cdn.azul.com/zulu/bin/zulu10.3+5-jdk10.0.2-windows_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu10.2+3-jdk10.0.1-windows_x64.tar.gz", + "java_version": [ + 10, + 0, + 1 + ], + "openjdk_build_number": 9, + "distro_version": [ + 10, + 2, + 3, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10541", "name": "zulu10.3+5-jdk10.0.2-windows_x64.tar.gz", - "zulu_version": [10, 3, 5, 0], - "jdk_version": [10, 0, 2, 13] - }, - { - "id": 10576, - "url": "https://cdn.azul.com/zulu/bin/zulu11.2.3-jdk11.0.1-windows_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu10.3+5-jdk10.0.2-windows_x64.tar.gz", + "java_version": [ + 10, + 0, + 2 + ], + "openjdk_build_number": 13, + "distro_version": [ + 10, + 3, + 5, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10576", "name": "zulu11.2.3-jdk11.0.1-windows_x64.tar.gz", - "zulu_version": [11, 2, 3, 0], - "jdk_version": [11, 0, 1, 13] - }, - { - "id": 10604, - "url": "https://cdn.azul.com/zulu/bin/zulu11.29.3-ca-jdk11.0.2-windows_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu11.2.3-jdk11.0.1-windows_x64.tar.gz", + "java_version": [ + 11, + 0, + 1 + ], + "openjdk_build_number": 13, + "distro_version": [ + 11, + 2, + 3, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10604", "name": "zulu11.29.3-ca-jdk11.0.2-windows_x64.tar.gz", - "zulu_version": [11, 29, 3, 0], - "jdk_version": [11, 0, 2, 7] - }, - { - "id": 10687, - "url": "https://cdn.azul.com/zulu/bin/zulu11.31.11-ca-jdk11.0.3-windows_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu11.29.3-ca-jdk11.0.2-windows_x64.tar.gz", + "java_version": [ + 11, + 0, + 2 + ], + "openjdk_build_number": 7, + "distro_version": [ + 11, + 29, + 3, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10687", "name": "zulu11.31.11-ca-jdk11.0.3-windows_x64.tar.gz", - "zulu_version": [11, 31, 11, 0], - "jdk_version": [11, 0, 3, 7] - }, - { - "id": 10856, - "url": "https://cdn.azul.com/zulu/bin/zulu11.35.13-ca-jdk11.0.5-windows_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu11.31.11-ca-jdk11.0.3-windows_x64.tar.gz", + "java_version": [ + 11, + 0, + 3 + ], + "openjdk_build_number": 7, + "distro_version": [ + 11, + 31, + 11, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10856", "name": "zulu11.35.13-ca-jdk11.0.5-windows_x64.tar.gz", - "zulu_version": [11, 35, 13, 0], - "jdk_version": [11, 0, 5, 10] - }, - { - "id": 10933, - "url": "https://cdn.azul.com/zulu/bin/zulu11.35.15-ca-jdk11.0.5-windows_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu11.35.13-ca-jdk11.0.5-windows_x64.tar.gz", + "java_version": [ + 11, + 0, + 5 + ], + "openjdk_build_number": 10, + "distro_version": [ + 11, + 35, + 13, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10933", "name": "zulu11.35.15-ca-jdk11.0.5-windows_x64.tar.gz", - "zulu_version": [11, 35, 15, 0], - "jdk_version": [11, 0, 5, 10] - }, - { - "id": 10933, - "url": "https://cdn.azul.com/zulu/bin/zulu11.35.11-ca-jdk11.0.5-windows_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu11.35.15-ca-jdk11.0.5-windows_x64.tar.gz", + "java_version": [ + 11, + 0, + 5 + ], + "openjdk_build_number": 10, + "distro_version": [ + 11, + 35, + 15, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10933", "name": "zulu11.35.15-ca-jdk11.0.5-windows_x64.tar.gz", - "zulu_version": [11, 35, 11, 0], - "jdk_version": [11, 0, 5, 10] - }, - { - "id": 12397, - "url": "https://cdn.azul.com/zulu/bin/zulu11.45.27-ca-jdk11.0.10-windows_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu11.35.11-ca-jdk11.0.5-windows_x64.tar.gz", + "java_version": [ + 11, + 0, + 5 + ], + "openjdk_build_number": 10, + "distro_version": [ + 11, + 35, + 11, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-12397", "name": "zulu11.45.27-ca-jdk11.0.10-windows_x64.tar.gz", - "zulu_version": [11, 45, 27, 0], - "jdk_version": [11, 0, 10, 9] - }, - { - "id": 10667, - "url": "https://cdn.azul.com/zulu/bin/zulu12.1.3-ca-jdk12.0.0-windows_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu11.45.27-ca-jdk11.0.10-windows_x64.tar.gz", + "java_version": [ + 11, + 0, + 10 + ], + "openjdk_build_number": 9, + "distro_version": [ + 11, + 45, + 27, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10667", "name": "zulu12.1.3-ca-jdk12.0.0-windows_x64.tar.gz", - "zulu_version": [12, 1, 3, 0], - "jdk_version": [12, 0, 0, 33] - }, - { - "id": 10710, - "url": "https://cdn.azul.com/zulu/bin/zulu12.2.3-ca-jdk12.0.1-windows_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu12.1.3-ca-jdk12.0.0-windows_x64.tar.gz", + "java_version": [ + 12, + 0, + 0 + ], + "openjdk_build_number": 33, + "distro_version": [ + 12, + 1, + 3, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10710", "name": "zulu12.2.3-ca-jdk12.0.1-windows_x64.tar.gz", - "zulu_version": [12, 2, 3, 0], - "jdk_version": [12, 0, 1, 12] - }, - { - "id": 10780, - "url": "https://cdn.azul.com/zulu/bin/zulu12.3.11-ca-jdk12.0.2-windows_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu12.2.3-ca-jdk12.0.1-windows_x64.tar.gz", + "java_version": [ + 12, + 0, + 1 + ], + "openjdk_build_number": 12, + "distro_version": [ + 12, + 2, + 3, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10780", "name": "zulu12.3.11-ca-jdk12.0.2-windows_x64.tar.gz", - "zulu_version": [12, 3, 11, 0], - "jdk_version": [12, 0, 2, 3] - }, - { - "id": 10846, - "url": "https://cdn.azul.com/zulu/bin/zulu13.27.9-ca-jdk13.0.0-windows_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu12.3.11-ca-jdk12.0.2-windows_x64.tar.gz", + "java_version": [ + 12, + 0, + 2 + ], + "openjdk_build_number": 3, + "distro_version": [ + 12, + 3, + 11, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10846", "name": "zulu13.27.9-ca-jdk13.0.0-windows_x64.tar.gz", - "zulu_version": [13, 27, 9, 0], - "jdk_version": [13, 0, 0, 33] - }, - { - "id": 10888, - "url": "https://cdn.azul.com/zulu/bin/zulu13.28.11-ca-jdk13.0.1-windows_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu13.27.9-ca-jdk13.0.0-windows_x64.tar.gz", + "java_version": [ + 13, + 0, + 0 + ], + "openjdk_build_number": 33, + "distro_version": [ + 13, + 27, + 9, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-10888", "name": "zulu13.28.11-ca-jdk13.0.1-windows_x64.tar.gz", - "zulu_version": [13, 28, 11, 0], - "jdk_version": [13, 0, 1, 10] - }, - { - "id": 11073, - "url": "https://cdn.azul.com/zulu/bin/zulu13.29.9-ca-jdk13.0.2-windows_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu13.28.11-ca-jdk13.0.1-windows_x64.tar.gz", + "java_version": [ + 13, + 0, + 1 + ], + "openjdk_build_number": 10, + "distro_version": [ + 13, + 28, + 11, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-11073", "name": "zulu13.29.9-ca-jdk13.0.2-windows_x64.tar.gz", - "zulu_version": [13, 29, 9, 0], - "jdk_version": [13, 0, 2, 6] - }, - { - "id": 12408, - "url": "https://cdn.azul.com/zulu/bin/zulu13.37.21-ca-jdk13.0.6-windows_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu13.29.9-ca-jdk13.0.2-windows_x64.tar.gz", + "java_version": [ + 13, + 0, + 2 + ], + "openjdk_build_number": 6, + "distro_version": [ + 13, + 29, + 9, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-12408", "name": "zulu13.37.21-ca-jdk13.0.6-windows_x64.tar.gz", - "zulu_version": [13, 37, 21, 0], - "jdk_version": [13, 0, 6, 5] - }, - { - "id": 11236, - "url": "https://cdn.azul.com/zulu/bin/zulu14.27.1-ca-jdk14.0.0-windows_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu13.37.21-ca-jdk13.0.6-windows_x64.tar.gz", + "java_version": [ + 13, + 0, + 6 + ], + "openjdk_build_number": 5, + "distro_version": [ + 13, + 37, + 21, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-11236", "name": "zulu14.27.1-ca-jdk14.0.0-windows_x64.tar.gz", - "zulu_version": [14, 27, 1, 0], - "jdk_version": [14, 0, 0, 36] - }, - { - "id": 11349, - "url": "https://cdn.azul.com/zulu/bin/zulu14.28.21-ca-jdk14.0.1-windows_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu14.27.1-ca-jdk14.0.0-windows_x64.tar.gz", + "java_version": [ + 14, + 0, + 0 + ], + "openjdk_build_number": 36, + "distro_version": [ + 14, + 27, + 1, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-11349", "name": "zulu14.28.21-ca-jdk14.0.1-windows_x64.tar.gz", - "zulu_version": [14, 28, 21, 0], - "jdk_version": [14, 0, 1, 8] - }, - { - "id": 11513, - "url": "https://cdn.azul.com/zulu/bin/zulu14.29.23-ca-jdk14.0.2-windows_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu14.28.21-ca-jdk14.0.1-windows_x64.tar.gz", + "java_version": [ + 14, + 0, + 1 + ], + "openjdk_build_number": 8, + "distro_version": [ + 14, + 28, + 21, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-11513", "name": "zulu14.29.23-ca-jdk14.0.2-windows_x64.tar.gz", - "zulu_version": [14, 29, 23, 0], - "jdk_version": [14, 0, 2, 12] - }, - { - "id": 11780, - "url": "https://cdn.azul.com/zulu/bin/zulu15.27.17-ca-jdk15.0.0-windows_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu14.29.23-ca-jdk14.0.2-windows_x64.tar.gz", + "java_version": [ + 14, + 0, + 2 + ], + "openjdk_build_number": 12, + "distro_version": [ + 14, + 29, + 23, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-11780", "name": "zulu15.27.17-ca-jdk15.0.0-windows_x64.tar.gz", - "zulu_version": [15, 27, 17, 0], - "jdk_version": [15, 0, 0, 36] - }, - { - "id": 11924, - "url": "https://cdn.azul.com/zulu/bin/zulu15.28.13-ca-jdk15.0.1-windows_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu15.27.17-ca-jdk15.0.0-windows_x64.tar.gz", + "java_version": [ + 15, + 0, + 0 + ], + "openjdk_build_number": 36, + "distro_version": [ + 15, + 27, + 17, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-11924", "name": "zulu15.28.13-ca-jdk15.0.1-windows_x64.tar.gz", - "zulu_version": [15, 28, 13, 0], - "jdk_version": [15, 0, 1, 8] - }, - { - "id": 12101, - "url": "https://cdn.azul.com/zulu/bin/zulu15.28.51-ca-jdk15.0.1-windows_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu15.28.13-ca-jdk15.0.1-windows_x64.tar.gz", + "java_version": [ + 15, + 0, + 1 + ], + "openjdk_build_number": 8, + "distro_version": [ + 15, + 28, + 13, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-12101", "name": "zulu15.28.51-ca-jdk15.0.1-windows_x64.tar.gz", - "zulu_version": [15, 28, 51, 0], - "jdk_version": [15, 0, 1, 9] - }, - { - "id": 12445, - "url": "https://cdn.azul.com/zulu/bin/zulu15.29.15-ca-jdk15.0.2-windows_x64.tar.gz", + "download_url": "https://cdn.azul.com/zulu/bin/zulu15.28.51-ca-jdk15.0.1-windows_x64.tar.gz", + "java_version": [ + 15, + 0, + 1 + ], + "openjdk_build_number": 9, + "distro_version": [ + 15, + 28, + 51, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-12445", "name": "zulu15.29.15-ca-jdk15.0.2-windows_x64.tar.gz", - "zulu_version": [15, 29, 15, 0], - "jdk_version": [15, 0, 2, 7] - }, - { - "id": 12446, - "url": "https://cdn.azul.com/zulu/bin/zulu17.48.15-ca-jdk17.0.10-windows_aarch64.zip", - "name": "zulu17.48.15-ca-jdk17.0.10-win_aarhc4.zip", - "zulu_version": [17, 48, 15, 0], - "jdk_version": [17, 0, 10, 7] + "download_url": "https://cdn.azul.com/zulu/bin/zulu15.29.15-ca-jdk15.0.2-windows_x64.tar.gz", + "java_version": [ + 15, + 0, + 2 + ], + "openjdk_build_number": 7, + "distro_version": [ + 15, + 29, + 15, + 0 + ], + "latest": false, + "availability_type": "ca" + }, + { + "package_uuid": "test-uuid-12446", + "name": "zulu17.48.15-ca-jdk17.0.10-win_aarch64.zip", + "download_url": "https://cdn.azul.com/zulu/bin/zulu17.48.15-ca-jdk17.0.10-windows_aarch64.zip", + "java_version": [ + 17, + 0, + 10 + ], + "openjdk_build_number": 7, + "distro_version": [ + 17, + 48, + 15, + 0 + ], + "latest": false, + "availability_type": "ca" } -] \ No newline at end of file +] diff --git a/__tests__/distributors/base-installer.test.ts b/__tests__/distributors/base-installer.test.ts index 2a0b13ab1..1ee703cd2 100644 --- a/__tests__/distributors/base-installer.test.ts +++ b/__tests__/distributors/base-installer.test.ts @@ -464,6 +464,24 @@ describe('setupJava', () => { } ); + it('should fail when verify-signature is enabled for unsupported distributions', async () => { + mockJavaBase = new EmptyJavaBase({ + version: '11', + architecture: 'x86', + packageType: 'jdk', + checkLatest: false, + verifySignature: true + }); + + await expect(mockJavaBase.setupJava()).rejects.toThrow( + "Input 'verify-signature' is not supported for distribution 'Empty'." + ); + expect(spyTcFindAllVersions).not.toHaveBeenCalled(); + expect(spyCoreAddPath).not.toHaveBeenCalled(); + expect(spyCoreExportVariable).not.toHaveBeenCalled(); + expect(spyCoreSetOutput).not.toHaveBeenCalled(); + }); + it.each([ [ { @@ -545,6 +563,110 @@ describe('setupJava', () => { expect(spyCoreExportVariable).not.toHaveBeenCalled(); expect(spyCoreSetOutput).not.toHaveBeenCalled(); }); + + it('should not set JAVA_HOME and PATH when setDefault is false', async () => { + mockJavaBase = new EmptyJavaBase({ + version: '11', + architecture: 'x86', + packageType: 'jdk', + checkLatest: false, + setDefault: false + }); + await expect(mockJavaBase.setupJava()).resolves.toEqual({ + version: installedJavaVersion, + path: javaPath + }); + expect(spyCoreExportVariable).not.toHaveBeenCalledWith( + 'JAVA_HOME', + expect.anything() + ); + expect(spyCoreAddPath).not.toHaveBeenCalled(); + expect(spyCoreExportVariable).toHaveBeenCalledWith( + 'JAVA_HOME_11_X86', + javaPath + ); + expect(spyCoreSetOutput).toHaveBeenCalledWith( + 'version', + installedJavaVersion + ); + expect(spyCoreSetOutput).toHaveBeenCalledWith('path', javaPath); + expect(spyCoreSetOutput).toHaveBeenCalledWith('distribution', 'Empty'); + expect(spyCoreInfo).toHaveBeenCalledWith( + `Installing Java ${installedJavaVersion} (not setting as default)` + ); + }); + + it('should set JAVA_HOME and PATH when setDefault is true', async () => { + mockJavaBase = new EmptyJavaBase({ + version: '11', + architecture: 'x86', + packageType: 'jdk', + checkLatest: false, + setDefault: true + }); + await expect(mockJavaBase.setupJava()).resolves.toEqual({ + version: installedJavaVersion, + path: javaPath + }); + expect(spyCoreExportVariable).toHaveBeenCalledWith('JAVA_HOME', javaPath); + expect(spyCoreAddPath).toHaveBeenCalledWith(path.join(javaPath, 'bin')); + expect(spyCoreExportVariable).toHaveBeenCalledWith( + 'JAVA_HOME_11_X86', + javaPath + ); + expect(spyCoreInfo).toHaveBeenCalledWith( + `Setting Java ${installedJavaVersion} as the default` + ); + }); + + it('should default to setting as default when setDefault is not specified', async () => { + mockJavaBase = new EmptyJavaBase({ + version: '11', + architecture: 'x86', + packageType: 'jdk', + checkLatest: false + }); + await expect(mockJavaBase.setupJava()).resolves.toEqual({ + version: installedJavaVersion, + path: javaPath + }); + expect(spyCoreExportVariable).toHaveBeenCalledWith('JAVA_HOME', javaPath); + expect(spyCoreAddPath).toHaveBeenCalledWith(path.join(javaPath, 'bin')); + expect(spyCoreInfo).toHaveBeenCalledWith( + `Setting Java ${installedJavaVersion} as the default` + ); + }); + + it('should download and not set default when setDefault is false', async () => { + mockJavaBase = new EmptyJavaBase({ + version: '11', + architecture: 'x64', + packageType: 'jdk', + checkLatest: false, + setDefault: false + }); + await expect(mockJavaBase.setupJava()).resolves.toEqual({ + version: '11.0.9', + path: path.join('toolcache', 'Java_Empty_jdk', '11.0.9', 'x64') + }); + expect(spyCoreExportVariable).not.toHaveBeenCalledWith( + 'JAVA_HOME', + expect.anything() + ); + expect(spyCoreAddPath).not.toHaveBeenCalled(); + expect(spyCoreExportVariable).toHaveBeenCalledWith( + 'JAVA_HOME_11_X64', + path.join('toolcache', 'Java_Empty_jdk', '11.0.9', 'x64') + ); + expect(spyCoreSetOutput).toHaveBeenCalledWith('version', '11.0.9'); + expect(spyCoreSetOutput).toHaveBeenCalledWith( + 'path', + path.join('toolcache', 'Java_Empty_jdk', '11.0.9', 'x64') + ); + expect(spyCoreInfo).toHaveBeenCalledWith( + 'Installing Java 11.0.9 (not setting as default)' + ); + }); }); describe('normalizeVersion', () => { diff --git a/__tests__/distributors/dragonwell-installer.test.ts b/__tests__/distributors/dragonwell-installer.test.ts index a10f75a9c..dffadde48 100644 --- a/__tests__/distributors/dragonwell-installer.test.ts +++ b/__tests__/distributors/dragonwell-installer.test.ts @@ -225,7 +225,7 @@ describe('getAvailableVersions', () => { ['11', 'macos', 'aarch64'], ['17', 'linux', 'riscv'] ])( - 'should throw when required version of JDK can not be found in the JSON', + 'should throw when required version of JDK cannot be found in the JSON', async (jdkVersion: string, platform: string, arch: string) => { const distribution = new DragonwellDistribution({ version: jdkVersion, diff --git a/__tests__/distributors/graalvm-installer.test.ts b/__tests__/distributors/graalvm-installer.test.ts index 23f90b884..beefbd13f 100644 --- a/__tests__/distributors/graalvm-installer.test.ts +++ b/__tests__/distributors/graalvm-installer.test.ts @@ -3,7 +3,11 @@ import * as tc from '@actions/tool-cache'; import * as http from '@actions/http-client'; import fs from 'fs'; import path from 'path'; -import {GraalVMDistribution} from '../../src/distributions/graalvm/installer'; +import { + GraalVMCommunityDistribution, + GraalVMDistribution +} from '../../src/distributions/graalvm/installer'; +import {getJavaDistribution} from '../../src/distributions/distribution-factory'; import {JavaInstallerOptions} from '../../src/distributions/base-models'; import * as util from '../../src/util'; @@ -41,6 +45,7 @@ beforeAll(() => { describe('GraalVMDistribution', () => { let distribution: GraalVMDistribution; + let communityDistribution: GraalVMCommunityDistribution; let mockHttpClient: jest.Mocked; let spyCoreError: jest.SpyInstance; @@ -55,9 +60,11 @@ describe('GraalVMDistribution', () => { jest.clearAllMocks(); distribution = new GraalVMDistribution(defaultOptions); + communityDistribution = new GraalVMCommunityDistribution(defaultOptions); mockHttpClient = new http.HttpClient() as jest.Mocked; (distribution as any).http = mockHttpClient; + (communityDistribution as any).http = mockHttpClient; (util.getDownloadArchiveExtension as jest.Mock).mockReturnValue('tar.gz'); @@ -242,6 +249,23 @@ describe('GraalVMDistribution', () => { path: '/cached/java/path' }); }); + + it('should use a dedicated toolcache folder for GraalVM Community', async () => { + const result = await (communityDistribution as any).downloadTool( + javaRelease + ); + + expect(tc.cacheDir).toHaveBeenCalledWith( + path.join('/tmp/extracted', 'graalvm-jdk-17.0.5'), + 'Java_GraalVM_Community_jdk', + '17.0.5', + 'x64' + ); + expect(result).toEqual({ + version: '17.0.5', + path: '/cached/java/path' + }); + }); }); describe('findPackageForDownload', () => { @@ -948,5 +972,121 @@ describe('GraalVMDistribution', () => { configurable: true }); }); + + describe('GraalVMCommunityDistribution', () => { + beforeEach(() => { + jest + .spyOn(communityDistribution, 'getPlatform') + .mockReturnValue('linux'); + }); + + it('should resolve an exact GraalVM Community version from GitHub releases', 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' + } + ] + } + ], + statusCode: 200, + headers: {} + }); + + const result = await ( + communityDistribution as any + ).findPackageForDownload('21.0.2'); + + expect(result).toEqual({ + 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' + }); + }); + + it('should resolve the latest GraalVM Community release for a major version', async () => { + mockHttpClient.getJson.mockResolvedValue({ + result: [ + { + draft: false, + prerelease: false, + assets: [ + { + name: 'graalvm-community-jdk-21.0.1_linux-x64_bin.tar.gz', + browser_download_url: + 'https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-21.0.1/graalvm-community-jdk-21.0.1_linux-x64_bin.tar.gz' + } + ] + }, + { + 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' + } + ] + } + ], + statusCode: 200, + headers: {} + }); + + const result = await ( + communityDistribution as any + ).findPackageForDownload('21'); + + expect(result).toEqual({ + 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' + }); + }); + + it('should reject GraalVM Community early access requests', async () => { + (communityDistribution as any).stable = false; + + await expect( + (communityDistribution as any).findPackageForDownload('23') + ).rejects.toThrow( + 'GraalVM Community does not provide early access builds' + ); + }); + + it('should surface an error when the releases listing is not an array', async () => { + mockHttpClient.getJson.mockResolvedValue({ + result: {message: 'API rate limit exceeded'}, + statusCode: 403, + headers: {} + }); + + await expect( + (communityDistribution as any).findPackageForDownload('21') + ).rejects.toThrow( + /Unexpected response while listing GraalVM Community releases.*HTTP status code: 403/s + ); + }); + }); + }); +}); + +describe('distribution factory', () => { + const defaultOptions: JavaInstallerOptions = { + version: '17', + architecture: 'x64', + packageType: 'jdk', + checkLatest: false + }; + + it('should map graalvm-community to the community installer', () => { + const community = getJavaDistribution('graalvm-community', defaultOptions); + + expect(community).toBeInstanceOf(GraalVMCommunityDistribution); }); }); diff --git a/__tests__/distributors/jetbrains-installer.test.ts b/__tests__/distributors/jetbrains-installer.test.ts index bf1dc15da..2d32e7e63 100644 --- a/__tests__/distributors/jetbrains-installer.test.ts +++ b/__tests__/distributors/jetbrains-installer.test.ts @@ -87,10 +87,26 @@ describe('findPackageForDownload', () => { const url = resolvedVersion.url; const options = {method: 'HEAD'}; - https.request(url, options, res => { - // JetBrains uses 403 for inexistent packages - expect(res.statusCode).not.toBe(403); - res.resume(); + await new Promise((resolve, reject) => { + const request = https.request(url, options, res => { + let assertionError: unknown; + + try { + // JetBrains uses 403 for non-existent packages + expect(res.statusCode).not.toBe(403); + } catch (error) { + assertionError = error; + } + + res.resume(); + res.once('error', reject); + res.once('end', () => + assertionError ? reject(assertionError as Error) : resolve() + ); + }); + + request.on('error', reject); + request.end(); }); } ); diff --git a/__tests__/distributors/kona-installer.test.ts b/__tests__/distributors/kona-installer.test.ts new file mode 100644 index 000000000..2aaaca79d --- /dev/null +++ b/__tests__/distributors/kona-installer.test.ts @@ -0,0 +1,256 @@ +import {KonaDistribution} from '../../src/distributions/kona/installer'; + +import manifestData from '../data/kona.json'; + +function mockDistr( + version: string, + os: string, + arch: string, + packageType: string +): KonaDistribution { + const distribution = new KonaDistribution({ + version: version, + architecture: arch, + packageType: packageType, + checkLatest: false + }); + + distribution['getOs'] = () => os; + distribution['fetchReleaseInfo'] = async () => manifestData; + + return distribution; +} + +describe('Check getAvailableReleases', () => { + it.each([ + ['8', 'linux', 'aarch64', 'linux-aarch64'], + ['8.0.20', 'macos', 'x86_64', 'macosx-x86_64'], + ['11', 'linux', 'x86_64', 'linux-x86_64'], + ['11.0.25', 'macos', 'aarch64', 'macosx-aarch64'], + ['17.0.13', 'windows', 'x86_64', 'windows-x86_64'], + ['21.0.5', 'linux', 'x86_64', 'linux-x86_64'], + ['25', 'linux', 'aarch64', 'linux-aarch64'], + ['25.0.3', 'macos', 'x86_64', 'macosx-x86_64'] + ])( + 'should get releases with the specified version "%s", OS "%s" and arch "%s"', + async ( + version: string, + os: string, + arch: string, + expectedPattern: string + ) => { + const distribution = mockDistr(version, os, arch, 'jdk'); + + const releases = await distribution['getAvailableReleases'](); + expect(releases).not.toBeNull(); + expect(releases.length).toBe(5); + releases.forEach(release => + expect(release.downloadUrl).toContain(expectedPattern) + ); + } + ); +}); + +describe('Check findPackageForDownload', () => { + it.each([ + [ + '8', + 'linux', + 'aarch64', + 'https://github.com/Tencent/TencentKona-8/releases/download/8.0.20-GA/TencentKona8.0.20.b1_jdk_linux-aarch64_8u432.tar.gz' + ], + [ + '8.0.20', + 'linux', + 'x86_64', + 'https://github.com/Tencent/TencentKona-8/releases/download/8.0.20-GA/TencentKona8.0.20.b1_jdk_linux-x86_64_8u432.tar.gz' + ], + [ + '8.0.20', + 'macos', + 'aarch64', + 'https://github.com/Tencent/TencentKona-8/releases/download/8.0.20-GA/TencentKona8.0.20.b1_jdk_macosx-aarch64_8u432_notarized.tar.gz' + ], + [ + '8.0.20', + 'macos', + 'x86_64', + 'https://github.com/Tencent/TencentKona-8/releases/download/8.0.20-GA/TencentKona8.0.20.b1_jdk_macosx-x86_64_8u432_notarized.tar.gz' + ], + [ + '8.0.20', + 'windows', + 'x86_64', + 'https://github.com/Tencent/TencentKona-8/releases/download/8.0.20-GA/TencentKona8.0.20.b1_jdk_windows-x86_64_8u432_signed.zip' + ], + + [ + '11', + 'linux', + 'aarch64', + 'https://github.com/Tencent/TencentKona-11/releases/download/kona11.0.25/TencentKona-11.0.25.b1-jdk_linux-aarch64.tar.gz' + ], + [ + '11.0.25', + 'linux', + 'x86_64', + 'https://github.com/Tencent/TencentKona-11/releases/download/kona11.0.25/TencentKona-11.0.25.b1-jdk_linux-x86_64.tar.gz' + ], + [ + '11.0.25', + 'macos', + 'aarch64', + 'https://github.com/Tencent/TencentKona-11/releases/download/kona11.0.25/TencentKona-11.0.25.b1_jdk_macosx-aarch64_notarized.tar.gz' + ], + [ + '11.0.25', + 'macos', + 'x86_64', + 'https://github.com/Tencent/TencentKona-11/releases/download/kona11.0.25/TencentKona-11.0.25.b1_jdk_macosx-x86_64_notarized.tar.gz' + ], + [ + '11.0.25', + 'windows', + 'x86_64', + 'https://github.com/Tencent/TencentKona-11/releases/download/kona11.0.25/TencentKona-11.0.25.b1_jdk_windows-x86_64_signed.zip' + ], + + [ + '17', + 'linux', + 'aarch64', + 'https://github.com/Tencent/TencentKona-17/releases/download/TencentKona-17.0.13/TencentKona-17.0.13.b1-jdk_linux-aarch64.tar.gz' + ], + [ + '17.0.13', + 'linux', + 'x86_64', + 'https://github.com/Tencent/TencentKona-17/releases/download/TencentKona-17.0.13/TencentKona-17.0.13.b1-jdk_linux-x86_64.tar.gz' + ], + [ + '17.0.13', + 'macos', + 'aarch64', + 'https://github.com/Tencent/TencentKona-17/releases/download/TencentKona-17.0.13/TencentKona-17.0.13.b1_jdk_macosx-aarch64_notarized.tar.gz' + ], + [ + '17.0.13', + 'macos', + 'x86_64', + 'https://github.com/Tencent/TencentKona-17/releases/download/TencentKona-17.0.13/TencentKona-17.0.13.b1_jdk_macosx-x86_64_notarized.tar.gz' + ], + [ + '17.0.13', + 'windows', + 'x86_64', + 'https://github.com/Tencent/TencentKona-17/releases/download/TencentKona-17.0.13/TencentKona-17.0.13.b1_jdk_windows-x86_64_signed.zip' + ], + + [ + '21', + 'linux', + 'aarch64', + 'https://github.com/Tencent/TencentKona-21/releases/download/TencentKona-21.0.5/TencentKona-21.0.5.b1-jdk_linux-aarch64.tar.gz' + ], + [ + '21.0.5', + 'linux', + 'x86_64', + 'https://github.com/Tencent/TencentKona-21/releases/download/TencentKona-21.0.5/TencentKona-21.0.5.b1-jdk_linux-x86_64.tar.gz' + ], + [ + '21.0.5', + 'macos', + 'aarch64', + 'https://github.com/Tencent/TencentKona-21/releases/download/TencentKona-21.0.5/TencentKona-21.0.5.b1_jdk_macosx-aarch64_notarized.tar.gz' + ], + [ + '21.0.5', + 'macos', + 'x86_64', + 'https://github.com/Tencent/TencentKona-21/releases/download/TencentKona-21.0.5/TencentKona-21.0.5.b1_jdk_macosx-x86_64_notarized.tar.gz' + ], + [ + '21.0.5', + 'windows', + 'x86_64', + 'https://github.com/Tencent/TencentKona-21/releases/download/TencentKona-21.0.5/TencentKona-21.0.5.b1_jdk_windows-x86_64_signed.zip' + ], + + [ + '25', + 'linux', + 'aarch64', + 'https://github.com/Tencent/TencentKona-25/releases/download/TencentKona-25.0.3/TencentKona-25.0.3.b1-jdk_linux-aarch64.tar.gz' + ], + [ + '25.0.3', + 'linux', + 'x86_64', + 'https://github.com/Tencent/TencentKona-25/releases/download/TencentKona-25.0.3/TencentKona-25.0.3.b1-jdk_linux-x86_64.tar.gz' + ], + [ + '25.0.3', + 'macos', + 'aarch64', + 'https://github.com/Tencent/TencentKona-25/releases/download/TencentKona-25.0.3/TencentKona-25.0.3.b1_jdk_macosx-aarch64_notarized.tar.gz' + ], + [ + '25.0.3', + 'macos', + 'x86_64', + 'https://github.com/Tencent/TencentKona-25/releases/download/TencentKona-25.0.3/TencentKona-25.0.3.b1_jdk_macosx-x86_64_notarized.tar.gz' + ], + [ + '25.0.3', + 'windows', + 'x86_64', + 'https://github.com/Tencent/TencentKona-25/releases/download/TencentKona-25.0.3/TencentKona-25.0.3.b1_jdk_windows-x86_64_signed.zip' + ] + ])( + 'should return the download URL with the specified version "%s", OS "%s" and arch "%s"', + async (version: string, os: string, arch: string, expectedUrl: string) => { + const distribution = mockDistr(version, os, arch, 'jdk'); + + const availableRelease = + await distribution['findPackageForDownload'](version); + expect(availableRelease).not.toBeNull(); + expect(availableRelease.url).toBe(expectedUrl); + } + ); +}); + +describe('No release is found', () => { + it.each([ + ['8', 'linux', 'x86'], + ['8.0.0', 'linux', 'x86_64'], + ['11', 'linux', 'ppc64'], + ['17', 'solaris', 'x86_64'], + ['17', 'windows', 'aarch64'], + ['22', 'macos', 'x86_64'] + ])( + `should throw an error due to no release with the specified version "%s", os "%s" and arch "%s"`, + async (version: string, os: string, arch: string) => { + const distribution = mockDistr(version, os, arch, 'jdk'); + + await expect( + distribution['findPackageForDownload'](version) + ).rejects.toThrow( + `No Kona release for the specified version "${version}" on OS "${os}" and arch "${arch}".` + ); + } + ); +}); + +describe('The package type must be jdk', () => { + it('should throw an error due to the specified package type is not jdk', async () => { + const version = '8.0.20'; + const os = 'linux'; + const arch = 'x86_64'; + const distribution = mockDistr(version, os, arch, 'jre'); + + await expect( + distribution['findPackageForDownload'](version) + ).rejects.toThrow('Kona provides jdk only'); + }); +}); diff --git a/__tests__/distributors/local-installer.test.ts b/__tests__/distributors/local-installer.test.ts index 201d1d254..5486ba81a 100644 --- a/__tests__/distributors/local-installer.test.ts +++ b/__tests__/distributors/local-installer.test.ts @@ -219,7 +219,7 @@ describe('setupJava', () => { ); }); - it('java is resolved from toolcache including Contents/Home on MacOS', async () => { + it('java is resolved from toolcache including Contents/Home on macOS', async () => { const inputs = { version: actualJavaVersion, architecture: 'x86', @@ -262,7 +262,7 @@ describe('setupJava', () => { }); }); - it('java is unpacked from jdkfile including Contents/Home on MacOS', async () => { + it('java is unpacked from jdkfile including Contents/Home on macOS', async () => { const inputs = { version: '11.0.289', architecture: 'x86', diff --git a/__tests__/distributors/microsoft-installer.test.ts b/__tests__/distributors/microsoft-installer.test.ts index a971dc7fb..d2527f6f7 100644 --- a/__tests__/distributors/microsoft-installer.test.ts +++ b/__tests__/distributors/microsoft-installer.test.ts @@ -1,8 +1,15 @@ -import {MicrosoftDistributions} from '../../src/distributions/microsoft/installer'; +import { + MicrosoftDistributions, + MICROSOFT_PUBLIC_KEY +} from '../../src/distributions/microsoft/installer'; import os from 'os'; import data from '../data/microsoft.json'; import * as httpm from '@actions/http-client'; import * as core from '@actions/core'; +import * as tc from '@actions/tool-cache'; +import * as gpg from '../../src/gpg'; +import * as util from '../../src/util'; +import fs from 'fs'; describe('findPackageForDownload', () => { let distribution: MicrosoftDistributions; @@ -45,15 +52,20 @@ describe('findPackageForDownload', () => { 'https://aka.ms/download-jdk/microsoft-jdk-21.0.0-{{OS_TYPE}}-x64.{{ARCHIVE_TYPE}}' ], [ - '17.0.1', - '17.0.1+12.1', - 'https://aka.ms/download-jdk/microsoft-jdk-17.0.1.12.1-{{OS_TYPE}}-x64.{{ARCHIVE_TYPE}}' + '17.x', + '17.0.18', + 'https://aka.ms/download-jdk/microsoft-jdk-17.0.18-{{OS_TYPE}}-x64.{{ARCHIVE_TYPE}}' ], [ - '17.x', + '17.0.7', '17.0.7', 'https://aka.ms/download-jdk/microsoft-jdk-17.0.7-{{OS_TYPE}}-x64.{{ARCHIVE_TYPE}}' ], + [ + '17.0.1', + '17.0.1+12.1', + 'https://aka.ms/download-jdk/microsoft-jdk-17.0.1.12.1-{{OS_TYPE}}-x64.{{ARCHIVE_TYPE}}' + ], [ '16.0.x', '16.0.2+7.1', @@ -97,6 +109,7 @@ describe('findPackageForDownload', () => { .replace('{{OS_TYPE}}', os) .replace('{{ARCHIVE_TYPE}}', archive); expect(result.url).toBe(url); + expect(result.signatureUrl).toBe(`${url}.sig`); }); it.each([ @@ -119,7 +132,7 @@ describe('findPackageForDownload', () => { }); const result = await distro['findPackageForDownload'](version); - const expectedUrl = `https://aka.ms/download-jdk/microsoft-jdk-17.0.7-macos-${distroArch}.tar.gz`; + const expectedUrl = `https://aka.ms/download-jdk/microsoft-jdk-17.0.18-macos-${distroArch}.tar.gz`; expect(result.url).toBe(expectedUrl); } @@ -145,7 +158,7 @@ describe('findPackageForDownload', () => { }); const result = await distro['findPackageForDownload'](version); - const expectedUrl = `https://aka.ms/download-jdk/microsoft-jdk-17.0.7-linux-${distroArch}.tar.gz`; + const expectedUrl = `https://aka.ms/download-jdk/microsoft-jdk-17.0.18-linux-${distroArch}.tar.gz`; expect(result.url).toBe(expectedUrl); } @@ -171,7 +184,7 @@ describe('findPackageForDownload', () => { }); const result = await distro['findPackageForDownload'](version); - const expectedUrl = `https://aka.ms/download-jdk/microsoft-jdk-17.0.7-windows-${distroArch}.zip`; + const expectedUrl = `https://aka.ms/download-jdk/microsoft-jdk-17.0.18-windows-${distroArch}.zip`; expect(result.url).toBe(expectedUrl); } @@ -182,4 +195,153 @@ describe('findPackageForDownload', () => { /No matching version found for SemVer */ ); }); + + it('uses manifest-provided signature URL when available', async () => { + spyGetManifestFromRepo.mockReturnValue({ + result: [ + { + version: '17.0.10', + stable: true, + release_url: 'https://example.test', + files: [ + { + filename: 'microsoft-jdk-17.0.10-linux-x64.tar.gz', + arch: 'x64', + platform: 'linux', + download_url: 'https://example.test/jdk.tar.gz', + signature_url: 'https://example.test/jdk.tar.gz.custom.sig' + } + ] + } + ], + statusCode: 200, + headers: {} + }); + jest.spyOn(os, 'platform').mockReturnValue('linux'); + + const result = await distribution['findPackageForDownload']('17.0.10'); + + expect(result.signatureUrl).toBe( + 'https://example.test/jdk.tar.gz.custom.sig' + ); + }); +}); + +describe('downloadTool', () => { + let spyDownloadTool: jest.SpyInstance; + let spyExtractJdkFile: jest.SpyInstance; + let spyCacheDir: jest.SpyInstance; + let spyVerifySignature: jest.SpyInstance; + let distribution: MicrosoftDistributions; + + beforeEach(() => { + jest + .spyOn(os, 'platform') + .mockReturnValue(process.platform as ReturnType); + + distribution = new MicrosoftDistributions({ + version: '17', + architecture: 'x64', + packageType: 'jdk', + checkLatest: false + }); + + spyDownloadTool = jest.spyOn(tc, 'downloadTool'); + spyDownloadTool.mockImplementation(async () => { + return '/tmp/jdk.tar.gz'; + }); + + spyExtractJdkFile = jest.spyOn(util, 'extractJdkFile'); + spyExtractJdkFile.mockImplementation(async () => { + return '/tmp/unpacked'; + }); + + jest.spyOn(fs, 'readdirSync').mockReturnValue(['jdk'] as any); + spyCacheDir = jest.spyOn(tc, 'cacheDir'); + spyCacheDir.mockImplementation(async () => { + return '/tmp/cached'; + }); + + jest + .spyOn(util, 'renameWinArchive') + .mockImplementation((archivePath: string) => `${archivePath}.zip`); + + spyVerifySignature = jest.spyOn(gpg, 'verifyPackageSignature'); + spyVerifySignature.mockImplementation(async () => {}); + }); + + afterEach(() => { + jest.restoreAllMocks(); + }); + + it('verifies signature when enabled', async () => { + const signedDistribution = new MicrosoftDistributions({ + version: '17', + architecture: 'x64', + packageType: 'jdk', + checkLatest: false, + verifySignature: true + }); + + await signedDistribution['downloadTool']({ + version: '17.0.14+7', + url: 'https://example.com/jdk.tar.gz', + signatureUrl: 'https://example.com/jdk.tar.gz.sig' + }); + + expect(spyVerifySignature).toHaveBeenCalledWith( + '/tmp/jdk.tar.gz', + 'https://example.com/jdk.tar.gz.sig', + MICROSOFT_PUBLIC_KEY + ); + }); + + it('uses custom public key when verifySignaturePublicKey is provided', async () => { + const customKey = + '-----BEGIN PGP PUBLIC KEY BLOCK-----\ncustom\n-----END PGP PUBLIC KEY BLOCK-----'; + const signedDistribution = new MicrosoftDistributions({ + version: '17', + architecture: 'x64', + packageType: 'jdk', + checkLatest: false, + verifySignature: true, + verifySignaturePublicKey: customKey + }); + + await signedDistribution['downloadTool']({ + version: '17.0.14+7', + url: 'https://example.com/jdk.tar.gz', + signatureUrl: 'https://example.com/jdk.tar.gz.sig' + }); + + expect(spyVerifySignature).toHaveBeenCalledWith( + '/tmp/jdk.tar.gz', + 'https://example.com/jdk.tar.gz.sig', + customKey + ); + }); + + it('fails when signature is missing and verification is enabled', async () => { + const signedDistribution = new MicrosoftDistributions({ + version: '17', + architecture: 'x64', + packageType: 'jdk', + checkLatest: false, + verifySignature: true + }); + + await expect( + signedDistribution['downloadTool']({ + version: '17.0.14+7', + url: 'https://example.com/jdk.tar.gz' + }) + ).rejects.toThrow( + "Input 'verify-signature' is enabled, but no signature URL was found for Microsoft Build of OpenJDK version 17.0.14+7." + ); + expect(spyVerifySignature).not.toHaveBeenCalled(); + }); + + it('supports signature verification', () => { + expect(distribution['supportsSignatureVerification']()).toBe(true); + }); }); diff --git a/__tests__/distributors/sapmachine-installer.test.ts b/__tests__/distributors/sapmachine-installer.test.ts index f49189a70..8f1e2b27d 100644 --- a/__tests__/distributors/sapmachine-installer.test.ts +++ b/__tests__/distributors/sapmachine-installer.test.ts @@ -254,7 +254,7 @@ describe('getAvailableVersions', () => { ['21.0.3+8-ea', 'linux', 'x64', '21.0.3+8'], ['17', 'linux-muse', 'aarch64'] ])( - 'should throw when required version of JDK can not be found in the JSON', + 'should throw when required version of JDK cannot be found in the JSON', async ( version: string, platform: string, diff --git a/__tests__/distributors/temurin-installer.test.ts b/__tests__/distributors/temurin-installer.test.ts index 161a2d087..ddf707eb5 100644 --- a/__tests__/distributors/temurin-installer.test.ts +++ b/__tests__/distributors/temurin-installer.test.ts @@ -1,10 +1,15 @@ import {HttpClient} from '@actions/http-client'; +import * as tc from '@actions/tool-cache'; +import fs from 'fs'; import os from 'os'; import { TemurinDistribution, - TemurinImplementation + TemurinImplementation, + ADOPTIUM_PUBLIC_KEY } from '../../src/distributions/temurin/installer'; import {JavaInstallerOptions} from '../../src/distributions/base-models'; +import * as util from '../../src/util'; +import * as gpg from '../../src/gpg'; import manifestData from '../data/temurin.json'; import * as core from '@actions/core'; @@ -231,6 +236,7 @@ describe('findPackageForDownload', () => { distribution['getAvailableVersions'] = async () => manifestData as any; const resolvedVersion = await distribution['findPackageForDownload'](input); expect(resolvedVersion.version).toBe(expected); + expect(resolvedVersion.signatureUrl).toBeDefined(); }); it('version is found but binaries list is empty', async () => { @@ -281,3 +287,109 @@ describe('findPackageForDownload', () => { ); }); }); + +describe('downloadTool', () => { + let spyDownloadTool: jest.SpyInstance; + let spyVerifySignature: jest.SpyInstance; + let spyExtractJdkFile: jest.SpyInstance; + let spyCacheDir: jest.SpyInstance; + let spyReadDirSync: jest.SpyInstance; + let spyRenameWinArchive: jest.SpyInstance; + + beforeEach(() => { + spyDownloadTool = jest.spyOn(tc, 'downloadTool'); + spyDownloadTool.mockResolvedValue('/tmp/jdk.tar.gz'); + spyVerifySignature = jest.spyOn(gpg, 'verifyPackageSignature'); + spyVerifySignature.mockResolvedValue(undefined); + spyExtractJdkFile = jest.spyOn(util, 'extractJdkFile'); + spyExtractJdkFile.mockResolvedValue('/tmp/extracted'); + spyCacheDir = jest.spyOn(tc, 'cacheDir'); + spyCacheDir.mockResolvedValue('/tmp/toolcache'); + spyReadDirSync = jest.spyOn(fs, 'readdirSync'); + spyReadDirSync.mockReturnValue(['jdk-17'] as any); + spyRenameWinArchive = jest.spyOn(util, 'renameWinArchive'); + spyRenameWinArchive.mockReturnValue('/tmp/jdk.tar.gz.zip'); + }); + + afterEach(() => { + jest.resetAllMocks(); + jest.clearAllMocks(); + jest.restoreAllMocks(); + }); + + it('verifies signature when enabled', async () => { + const distribution = new TemurinDistribution( + { + version: '17', + architecture: 'x64', + packageType: 'jdk', + checkLatest: false, + verifySignature: true + }, + TemurinImplementation.Hotspot + ); + + await distribution['downloadTool']({ + version: '17.0.14+7', + url: 'https://example.com/jdk.tar.gz', + signatureUrl: 'https://example.com/jdk.tar.gz.sig' + }); + + expect(spyVerifySignature).toHaveBeenCalledWith( + '/tmp/jdk.tar.gz', + 'https://example.com/jdk.tar.gz.sig', + ADOPTIUM_PUBLIC_KEY + ); + }); + + it('fails when signature is missing and verification is enabled', async () => { + const distribution = new TemurinDistribution( + { + version: '17', + architecture: 'x64', + packageType: 'jdk', + checkLatest: false, + verifySignature: true + }, + TemurinImplementation.Hotspot + ); + + await expect( + distribution['downloadTool']({ + version: '17.0.14+7', + url: 'https://example.com/jdk.tar.gz' + }) + ).rejects.toThrow( + "Input 'verify-signature' is enabled, but no signature URL was found" + ); + expect(spyVerifySignature).not.toHaveBeenCalled(); + }); + + it('uses custom public key when verifySignaturePublicKey is provided', async () => { + const customKey = + '-----BEGIN PGP PUBLIC KEY BLOCK-----\ncustom\n-----END PGP PUBLIC KEY BLOCK-----'; + const distribution = new TemurinDistribution( + { + version: '17', + architecture: 'x64', + packageType: 'jdk', + checkLatest: false, + verifySignature: true, + verifySignaturePublicKey: customKey + }, + TemurinImplementation.Hotspot + ); + + await distribution['downloadTool']({ + version: '17.0.14+7', + url: 'https://example.com/jdk.tar.gz', + signatureUrl: 'https://example.com/jdk.tar.gz.sig' + }); + + expect(spyVerifySignature).toHaveBeenCalledWith( + '/tmp/jdk.tar.gz', + 'https://example.com/jdk.tar.gz.sig', + customKey + ); + }); +}); diff --git a/__tests__/distributors/zulu-installer.test.ts b/__tests__/distributors/zulu-installer.test.ts index 0a46983b2..25f11be08 100644 --- a/__tests__/distributors/zulu-installer.test.ts +++ b/__tests__/distributors/zulu-installer.test.ts @@ -17,7 +17,7 @@ describe('getAvailableVersions', () => { spyHttpClient.mockReturnValue({ statusCode: 200, headers: {}, - result: manifestData as IZuluVersions[] + result: [] as IZuluVersions[] }); spyUtilGetDownloadArchiveExtension = jest.spyOn( @@ -45,7 +45,7 @@ describe('getAvailableVersions', () => { packageType: 'jdk', checkLatest: false }, - '?os=macos&ext=tar.gz&bundle_type=jdk&javafx=false&arch=x86&hw_bitness=32&release_status=ga' + '?os=macos&archive_type=tar.gz&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=i686&release_status=ga&availability_types=ca&page=1&page_size=100' ], [ { @@ -54,7 +54,7 @@ describe('getAvailableVersions', () => { packageType: 'jdk', checkLatest: false }, - '?os=macos&ext=tar.gz&bundle_type=jdk&javafx=false&arch=x86&hw_bitness=32&release_status=ea' + '?os=macos&archive_type=tar.gz&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=i686&release_status=ea&availability_types=ca&page=1&page_size=100' ], [ { @@ -63,7 +63,7 @@ describe('getAvailableVersions', () => { packageType: 'jdk', checkLatest: false }, - '?os=macos&ext=tar.gz&bundle_type=jdk&javafx=false&arch=x86&hw_bitness=64&release_status=ga' + '?os=macos&archive_type=tar.gz&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=x64&release_status=ga&availability_types=ca&page=1&page_size=100' ], [ { @@ -72,7 +72,7 @@ describe('getAvailableVersions', () => { packageType: 'jre', checkLatest: false }, - '?os=macos&ext=tar.gz&bundle_type=jre&javafx=false&arch=x86&hw_bitness=64&release_status=ga' + '?os=macos&archive_type=tar.gz&java_package_type=jre&javafx_bundled=false&crac_supported=false&arch=x64&release_status=ga&availability_types=ca&page=1&page_size=100' ], [ { @@ -81,7 +81,7 @@ describe('getAvailableVersions', () => { packageType: 'jdk+fx', checkLatest: false }, - '?os=macos&ext=tar.gz&bundle_type=jdk&javafx=true&arch=x86&hw_bitness=64&release_status=ga&features=fx' + '?os=macos&archive_type=tar.gz&java_package_type=jdk&javafx_bundled=true&crac_supported=false&arch=x64&release_status=ga&availability_types=ca&page=1&page_size=100' ], [ { @@ -90,7 +90,16 @@ describe('getAvailableVersions', () => { packageType: 'jre+fx', checkLatest: false }, - '?os=macos&ext=tar.gz&bundle_type=jre&javafx=true&arch=x86&hw_bitness=64&release_status=ga&features=fx' + '?os=macos&archive_type=tar.gz&java_package_type=jre&javafx_bundled=true&crac_supported=false&arch=x64&release_status=ga&availability_types=ca&page=1&page_size=100' + ], + [ + { + version: '8', + architecture: 'x64', + packageType: 'jdk+crac', + checkLatest: false + }, + '?os=macos&archive_type=tar.gz&java_package_type=jdk&javafx_bundled=false&crac_supported=true&arch=x64&release_status=ga&availability_types=ca&page=1&page_size=100' ], [ { @@ -99,7 +108,7 @@ describe('getAvailableVersions', () => { packageType: 'jdk', checkLatest: false }, - '?os=macos&ext=tar.gz&bundle_type=jdk&javafx=false&arch=arm&hw_bitness=64&release_status=ga' + '?os=macos&archive_type=tar.gz&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=aarch64&release_status=ga&availability_types=ca&page=1&page_size=100' ], [ { @@ -108,12 +117,12 @@ describe('getAvailableVersions', () => { packageType: 'jdk', checkLatest: false }, - '?os=macos&ext=tar.gz&bundle_type=jdk&javafx=false&arch=arm&hw_bitness=&release_status=ga' + '?os=macos&archive_type=tar.gz&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=arm&release_status=ga&availability_types=ca&page=1&page_size=100' ] ])('build correct url for %s -> %s', async (input, parsedUrl) => { const distribution = new ZuluDistribution(input); distribution['getPlatformOption'] = () => 'macos'; - const buildUrl = `https://api.azul.com/zulu/download/community/v1.0/bundles/${parsedUrl}`; + const buildUrl = `https://api.azul.com/metadata/v1/zulu/packages/${parsedUrl}`; await distribution['getAvailableVersions'](); @@ -121,16 +130,12 @@ describe('getAvailableVersions', () => { expect(spyHttpClient.mock.calls[0][0]).toBe(buildUrl); }); - type DistroArch = { - bitness: string; - arch: string; - }; it.each([ - ['amd64', {bitness: '64', arch: 'x86'}], - ['arm64', {bitness: '64', arch: 'arm'}] + ['amd64', 'x64'], + ['arm64', 'aarch64'] ])( 'defaults to os.arch(): %s mapped to distro arch: %s', - async (osArch: string, distroArch: DistroArch) => { + async (osArch: string, distroArch: string) => { jest .spyOn(os, 'arch') .mockReturnValue(osArch as ReturnType); @@ -142,7 +147,7 @@ describe('getAvailableVersions', () => { checkLatest: false }); distribution['getPlatformOption'] = () => 'macos'; - const buildUrl = `https://api.azul.com/zulu/download/community/v1.0/bundles/?os=macos&ext=tar.gz&bundle_type=jdk&javafx=false&arch=${distroArch.arch}&hw_bitness=${distroArch.bitness}&release_status=ga`; + const buildUrl = `https://api.azul.com/metadata/v1/zulu/packages/?os=macos&archive_type=tar.gz&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=${distroArch}&release_status=ga&availability_types=ca&page=1&page_size=100`; await distribution['getAvailableVersions'](); @@ -152,6 +157,18 @@ describe('getAvailableVersions', () => { ); it('load available versions', async () => { + spyHttpClient + .mockReturnValueOnce({ + statusCode: 200, + headers: {}, + result: manifestData as IZuluVersions[] + }) + .mockReturnValueOnce({ + statusCode: 200, + headers: {}, + result: [] as IZuluVersions[] + }); + const distribution = new ZuluDistribution({ version: '11', architecture: 'x86', @@ -165,10 +182,11 @@ describe('getAvailableVersions', () => { describe('getArchitectureOptions', () => { it.each([ - [{architecture: 'x64'}, {arch: 'x86', hw_bitness: '64', abi: ''}], - [{architecture: 'x86'}, {arch: 'x86', hw_bitness: '32', abi: ''}], - [{architecture: 'x32'}, {arch: 'x32', hw_bitness: '', abi: ''}], - [{architecture: 'arm'}, {arch: 'arm', hw_bitness: '', abi: ''}] + [{architecture: 'x64'}, 'x64'], + [{architecture: 'x86'}, 'i686'], + [{architecture: 'aarch64'}, 'aarch64'], + [{architecture: 'arm64'}, 'aarch64'], + [{architecture: 'arm'}, 'arm'] ])('%s -> %s', (input, expected) => { const distribution = new ZuluDistribution({ version: '11', @@ -176,7 +194,7 @@ describe('getArchitectureOptions', () => { packageType: 'jdk', checkLatest: false }); - expect(distribution['getArchitectureOptions']()).toEqual(expected); + expect(distribution['getArchitectureOptions']()).toBe(expected); }); }); diff --git a/__tests__/distributors/zulu-linux-installer.test.ts b/__tests__/distributors/zulu-linux-installer.test.ts index b3ca6fa17..6caed3f47 100644 --- a/__tests__/distributors/zulu-linux-installer.test.ts +++ b/__tests__/distributors/zulu-linux-installer.test.ts @@ -18,7 +18,7 @@ describe('getAvailableVersions', () => { spyHttpClient.mockReturnValue({ statusCode: 200, headers: {}, - result: manifestData as IZuluVersions[] + result: [] as IZuluVersions[] }); spyUtilGetDownloadArchiveExtension = jest.spyOn( @@ -46,7 +46,7 @@ describe('getAvailableVersions', () => { packageType: 'jdk', checkLatest: false }, - '?os=linux&ext=zip&bundle_type=jdk&javafx=false&arch=x86&hw_bitness=32&release_status=ga' + '?os=linux_glibc&archive_type=zip&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=i686&release_status=ga&availability_types=ca&page=1&page_size=100' ], [ { @@ -55,7 +55,7 @@ describe('getAvailableVersions', () => { packageType: 'jdk', checkLatest: false }, - '?os=linux&ext=zip&bundle_type=jdk&javafx=false&arch=x86&hw_bitness=32&release_status=ea' + '?os=linux_glibc&archive_type=zip&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=i686&release_status=ea&availability_types=ca&page=1&page_size=100' ], [ { @@ -64,7 +64,7 @@ describe('getAvailableVersions', () => { packageType: 'jdk', checkLatest: false }, - '?os=linux&ext=zip&bundle_type=jdk&javafx=false&arch=x86&hw_bitness=64&release_status=ga' + '?os=linux_glibc&archive_type=zip&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=x64&release_status=ga&availability_types=ca&page=1&page_size=100' ], [ { @@ -73,7 +73,7 @@ describe('getAvailableVersions', () => { packageType: 'jre', checkLatest: false }, - '?os=linux&ext=zip&bundle_type=jre&javafx=false&arch=x86&hw_bitness=64&release_status=ga' + '?os=linux_glibc&archive_type=zip&java_package_type=jre&javafx_bundled=false&crac_supported=false&arch=x64&release_status=ga&availability_types=ca&page=1&page_size=100' ], [ { @@ -82,7 +82,7 @@ describe('getAvailableVersions', () => { packageType: 'jdk+fx', checkLatest: false }, - '?os=linux&ext=zip&bundle_type=jdk&javafx=true&arch=x86&hw_bitness=64&release_status=ga&features=fx' + '?os=linux_glibc&archive_type=zip&java_package_type=jdk&javafx_bundled=true&crac_supported=false&arch=x64&release_status=ga&availability_types=ca&page=1&page_size=100' ], [ { @@ -91,7 +91,16 @@ describe('getAvailableVersions', () => { packageType: 'jre+fx', checkLatest: false }, - '?os=linux&ext=zip&bundle_type=jre&javafx=true&arch=x86&hw_bitness=64&release_status=ga&features=fx' + '?os=linux_glibc&archive_type=zip&java_package_type=jre&javafx_bundled=true&crac_supported=false&arch=x64&release_status=ga&availability_types=ca&page=1&page_size=100' + ], + [ + { + version: '8', + architecture: 'x64', + packageType: 'jdk+crac', + checkLatest: false + }, + '?os=linux_glibc&archive_type=zip&java_package_type=jdk&javafx_bundled=false&crac_supported=true&arch=x64&release_status=ga&availability_types=ca&page=1&page_size=100' ], [ { @@ -100,7 +109,7 @@ describe('getAvailableVersions', () => { packageType: 'jdk', checkLatest: false }, - '?os=linux&ext=zip&bundle_type=jdk&javafx=false&arch=arm&hw_bitness=64&release_status=ga' + '?os=linux_glibc&archive_type=zip&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=aarch64&release_status=ga&availability_types=ca&page=1&page_size=100' ], [ { @@ -109,12 +118,12 @@ describe('getAvailableVersions', () => { packageType: 'jdk', checkLatest: false }, - '?os=linux&ext=zip&bundle_type=jdk&javafx=false&arch=arm&hw_bitness=&release_status=ga' + '?os=linux_glibc&archive_type=zip&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=arm&release_status=ga&availability_types=ca&page=1&page_size=100' ] ])('build correct url for %s -> %s', async (input, parsedUrl) => { const distribution = new ZuluDistribution(input); - distribution['getPlatformOption'] = () => 'linux'; - const buildUrl = `https://api.azul.com/zulu/download/community/v1.0/bundles/${parsedUrl}`; + distribution['getPlatformOption'] = () => 'linux_glibc'; + const buildUrl = `https://api.azul.com/metadata/v1/zulu/packages/${parsedUrl}`; await distribution['getAvailableVersions'](); @@ -122,16 +131,12 @@ describe('getAvailableVersions', () => { expect(spyHttpClient.mock.calls[0][0]).toBe(buildUrl); }); - type DistroArch = { - bitness: string; - arch: string; - }; it.each([ - ['amd64', {bitness: '64', arch: 'x86'}], - ['arm64', {bitness: '64', arch: 'arm'}] + ['amd64', 'x64'], + ['arm64', 'aarch64'] ])( 'defaults to os.arch(): %s mapped to distro arch: %s', - async (osArch: string, distroArch: DistroArch) => { + async (osArch: string, distroArch: string) => { jest .spyOn(os, 'arch') .mockReturnValue(osArch as ReturnType); @@ -142,10 +147,10 @@ describe('getAvailableVersions', () => { packageType: 'jdk', checkLatest: false }); - distribution['getPlatformOption'] = () => 'linux'; + distribution['getPlatformOption'] = () => 'linux_glibc'; // Override extension for linux default arch case to match util behavior spyUtilGetDownloadArchiveExtension.mockReturnValue('tar.gz'); - const buildUrl = `https://api.azul.com/zulu/download/community/v1.0/bundles/?os=linux&ext=tar.gz&bundle_type=jdk&javafx=false&arch=${distroArch.arch}&hw_bitness=${distroArch.bitness}&release_status=ga`; + const buildUrl = `https://api.azul.com/metadata/v1/zulu/packages/?os=linux_glibc&archive_type=tar.gz&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=${distroArch}&release_status=ga&availability_types=ca&page=1&page_size=100`; await distribution['getAvailableVersions'](); @@ -155,6 +160,18 @@ describe('getAvailableVersions', () => { ); it('load available versions', async () => { + spyHttpClient + .mockReturnValueOnce({ + statusCode: 200, + headers: {}, + result: manifestData as IZuluVersions[] + }) + .mockReturnValueOnce({ + statusCode: 200, + headers: {}, + result: [] as IZuluVersions[] + }); + const distribution = new ZuluDistribution({ version: '11', architecture: 'x86', @@ -168,10 +185,11 @@ describe('getAvailableVersions', () => { describe('getArchitectureOptions', () => { it.each([ - [{architecture: 'x64'}, {arch: 'x86', hw_bitness: '64', abi: ''}], - [{architecture: 'x86'}, {arch: 'x86', hw_bitness: '32', abi: ''}], - [{architecture: 'x32'}, {arch: 'x32', hw_bitness: '', abi: ''}], - [{architecture: 'arm'}, {arch: 'arm', hw_bitness: '', abi: ''}] + [{architecture: 'x64'}, 'x64'], + [{architecture: 'x86'}, 'i686'], + [{architecture: 'aarch64'}, 'aarch64'], + [{architecture: 'arm64'}, 'aarch64'], + [{architecture: 'arm'}, 'arm'] ])('%s -> %s', (input, expected) => { const distribution = new ZuluDistribution({ version: '11', @@ -179,7 +197,7 @@ describe('getArchitectureOptions', () => { packageType: 'jdk', checkLatest: false }); - expect(distribution['getArchitectureOptions']()).toEqual(expected); + expect(distribution['getArchitectureOptions']()).toBe(expected); }); }); diff --git a/__tests__/distributors/zulu-windows-installer.test.ts b/__tests__/distributors/zulu-windows-installer.test.ts index 37435e8db..0d3fdb933 100644 --- a/__tests__/distributors/zulu-windows-installer.test.ts +++ b/__tests__/distributors/zulu-windows-installer.test.ts @@ -18,7 +18,7 @@ describe('getAvailableVersions', () => { spyHttpClient.mockReturnValue({ statusCode: 200, headers: {}, - result: manifestData as IZuluVersions[] + result: [] as IZuluVersions[] }); spyUtilGetDownloadArchiveExtension = jest.spyOn( @@ -46,7 +46,7 @@ describe('getAvailableVersions', () => { packageType: 'jdk', checkLatest: false }, - '?os=windows&ext=zip&bundle_type=jdk&javafx=false&arch=x86&hw_bitness=32&release_status=ga' + '?os=windows&archive_type=zip&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=i686&release_status=ga&availability_types=ca&page=1&page_size=100' ], [ { @@ -55,7 +55,7 @@ describe('getAvailableVersions', () => { packageType: 'jdk', checkLatest: false }, - '?os=windows&ext=zip&bundle_type=jdk&javafx=false&arch=x86&hw_bitness=32&release_status=ea' + '?os=windows&archive_type=zip&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=i686&release_status=ea&availability_types=ca&page=1&page_size=100' ], [ { @@ -64,7 +64,7 @@ describe('getAvailableVersions', () => { packageType: 'jdk', checkLatest: false }, - '?os=windows&ext=zip&bundle_type=jdk&javafx=false&arch=x86&hw_bitness=64&release_status=ga' + '?os=windows&archive_type=zip&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=x64&release_status=ga&availability_types=ca&page=1&page_size=100' ], [ { @@ -73,7 +73,7 @@ describe('getAvailableVersions', () => { packageType: 'jre', checkLatest: false }, - '?os=windows&ext=zip&bundle_type=jre&javafx=false&arch=x86&hw_bitness=64&release_status=ga' + '?os=windows&archive_type=zip&java_package_type=jre&javafx_bundled=false&crac_supported=false&arch=x64&release_status=ga&availability_types=ca&page=1&page_size=100' ], [ { @@ -82,7 +82,7 @@ describe('getAvailableVersions', () => { packageType: 'jdk+fx', checkLatest: false }, - '?os=windows&ext=zip&bundle_type=jdk&javafx=true&arch=x86&hw_bitness=64&release_status=ga&features=fx' + '?os=windows&archive_type=zip&java_package_type=jdk&javafx_bundled=true&crac_supported=false&arch=x64&release_status=ga&availability_types=ca&page=1&page_size=100' ], [ { @@ -91,7 +91,16 @@ describe('getAvailableVersions', () => { packageType: 'jre+fx', checkLatest: false }, - '?os=windows&ext=zip&bundle_type=jre&javafx=true&arch=x86&hw_bitness=64&release_status=ga&features=fx' + '?os=windows&archive_type=zip&java_package_type=jre&javafx_bundled=true&crac_supported=false&arch=x64&release_status=ga&availability_types=ca&page=1&page_size=100' + ], + [ + { + version: '8', + architecture: 'x64', + packageType: 'jdk+crac', + checkLatest: false + }, + '?os=windows&archive_type=zip&java_package_type=jdk&javafx_bundled=false&crac_supported=true&arch=x64&release_status=ga&availability_types=ca&page=1&page_size=100' ], [ { @@ -100,7 +109,7 @@ describe('getAvailableVersions', () => { packageType: 'jdk', checkLatest: false }, - '?os=windows&ext=zip&bundle_type=jdk&javafx=false&arch=arm&hw_bitness=64&release_status=ga' + '?os=windows&archive_type=zip&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=aarch64&release_status=ga&availability_types=ca&page=1&page_size=100' ], [ { @@ -109,12 +118,12 @@ describe('getAvailableVersions', () => { packageType: 'jdk', checkLatest: false }, - '?os=windows&ext=zip&bundle_type=jdk&javafx=false&arch=arm&hw_bitness=&release_status=ga' + '?os=windows&archive_type=zip&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=arm&release_status=ga&availability_types=ca&page=1&page_size=100' ] ])('build correct url for %s -> %s', async (input, parsedUrl) => { const distribution = new ZuluDistribution(input); distribution['getPlatformOption'] = () => 'windows'; - const buildUrl = `https://api.azul.com/zulu/download/community/v1.0/bundles/${parsedUrl}`; + const buildUrl = `https://api.azul.com/metadata/v1/zulu/packages/${parsedUrl}`; await distribution['getAvailableVersions'](); @@ -122,16 +131,12 @@ describe('getAvailableVersions', () => { expect(spyHttpClient.mock.calls[0][0]).toBe(buildUrl); }); - type DistroArch = { - bitness: string; - arch: string; - }; it.each([ - ['amd64', {bitness: '64', arch: 'x86'}], - ['arm64', {bitness: '64', arch: 'arm'}] + ['amd64', 'x64'], + ['arm64', 'aarch64'] ])( 'defaults to os.arch(): %s mapped to distro arch: %s', - async (osArch: string, distroArch: DistroArch) => { + async (osArch: string, distroArch: string) => { jest .spyOn(os, 'arch') .mockReturnValue(osArch as ReturnType); @@ -143,7 +148,7 @@ describe('getAvailableVersions', () => { checkLatest: false }); distribution['getPlatformOption'] = () => 'windows'; - const buildUrl = `https://api.azul.com/zulu/download/community/v1.0/bundles/?os=windows&ext=zip&bundle_type=jdk&javafx=false&arch=${distroArch.arch}&hw_bitness=${distroArch.bitness}&release_status=ga`; + const buildUrl = `https://api.azul.com/metadata/v1/zulu/packages/?os=windows&archive_type=zip&java_package_type=jdk&javafx_bundled=false&crac_supported=false&arch=${distroArch}&release_status=ga&availability_types=ca&page=1&page_size=100`; await distribution['getAvailableVersions'](); @@ -153,6 +158,18 @@ describe('getAvailableVersions', () => { ); it('load available versions', async () => { + spyHttpClient + .mockReturnValueOnce({ + statusCode: 200, + headers: {}, + result: manifestData as IZuluVersions[] + }) + .mockReturnValueOnce({ + statusCode: 200, + headers: {}, + result: [] as IZuluVersions[] + }); + const distribution = new ZuluDistribution({ version: '11', architecture: 'x86', @@ -166,10 +183,11 @@ describe('getAvailableVersions', () => { describe('getArchitectureOptions', () => { it.each([ - [{architecture: 'x64'}, {arch: 'x86', hw_bitness: '64', abi: ''}], - [{architecture: 'x86'}, {arch: 'x86', hw_bitness: '32', abi: ''}], - [{architecture: 'x32'}, {arch: 'x32', hw_bitness: '', abi: ''}], - [{architecture: 'arm'}, {arch: 'arm', hw_bitness: '', abi: ''}] + [{architecture: 'x64'}, 'x64'], + [{architecture: 'x86'}, 'i686'], + [{architecture: 'aarch64'}, 'aarch64'], + [{architecture: 'arm64'}, 'aarch64'], + [{architecture: 'arm'}, 'arm'] ])('%s -> %s', (input, expected) => { const distribution = new ZuluDistribution({ version: '11', @@ -177,7 +195,7 @@ describe('getArchitectureOptions', () => { packageType: 'jdk', checkLatest: false }); - expect(distribution['getArchitectureOptions']()).toEqual(expected); + expect(distribution['getArchitectureOptions']()).toBe(expected); }); }); diff --git a/__tests__/gpg.test.ts b/__tests__/gpg.test.ts index 1c981b3f5..bfc5be741 100644 --- a/__tests__/gpg.test.ts +++ b/__tests__/gpg.test.ts @@ -1,6 +1,7 @@ import * as path from 'path'; import * as io from '@actions/io'; import * as exec from '@actions/exec'; +import * as tc from '@actions/tool-cache'; import * as gpg from '../src/gpg'; jest.mock('@actions/exec', () => { @@ -9,6 +10,12 @@ jest.mock('@actions/exec', () => { }; }); +jest.mock('@actions/tool-cache', () => { + return { + downloadTool: jest.fn() + }; +}); + const tempDir = path.join(__dirname, 'runner', 'temp'); process.env['RUNNER_TEMP'] = tempDir; @@ -25,6 +32,35 @@ describe('gpg tests', () => { } }); + describe('toGpgPath', () => { + const originalPlatform = process.platform; + + afterEach(() => { + Object.defineProperty(process, 'platform', {value: originalPlatform}); + }); + + it('returns path unchanged on non-Windows platforms', () => { + Object.defineProperty(process, 'platform', {value: 'linux'}); + expect(gpg.toGpgPath('/tmp/some/path')).toBe('/tmp/some/path'); + expect(gpg.toGpgPath('D:\\a\\_temp\\file')).toBe('D:\\a\\_temp\\file'); + }); + + it('converts Windows backslashes and drive letter to POSIX path on Windows', () => { + Object.defineProperty(process, 'platform', {value: 'win32'}); + expect(gpg.toGpgPath('D:\\a\\_temp\\gpg-home')).toBe( + '/d/a/_temp/gpg-home' + ); + expect( + gpg.toGpgPath('C:\\Users\\runner\\AppData\\Local\\Temp\\key.asc') + ).toBe('/c/Users/runner/AppData/Local/Temp/key.asc'); + }); + + it('handles uppercase and lowercase drive letters on Windows', () => { + Object.defineProperty(process, 'platform', {value: 'win32'}); + expect(gpg.toGpgPath('d:\\a\\_temp\\file')).toBe('/d/a/_temp/file'); + }); + }); + describe('importKey', () => { it('attempts to import private key and returns null key id on failure', async () => { const privateKey = 'KEY CONTENTS'; @@ -51,5 +87,47 @@ describe('gpg tests', () => { expect.anything() ); }); + + describe('verifyPackageSignature', () => { + it('imports bundled key and verifies package', async () => { + const publicKeyContent = + '-----BEGIN PGP PUBLIC KEY BLOCK-----\ntest\n-----END PGP PUBLIC KEY BLOCK-----'; + (tc.downloadTool as jest.Mock).mockResolvedValue('/tmp/jdk.tar.gz.sig'); + await gpg.verifyPackageSignature( + '/tmp/jdk.tar.gz', + 'https://example.com/jdk.tar.gz.sig', + publicKeyContent + ); + + expect(tc.downloadTool).toHaveBeenCalledWith( + 'https://example.com/jdk.tar.gz.sig' + ); + expect(exec.exec).toHaveBeenNthCalledWith( + 1, + 'gpg', + [ + '--homedir', + expect.any(String), + '--batch', + '--import', + expect.stringContaining('public-key.asc') + ], + expect.objectContaining({silent: true}) + ); + expect(exec.exec).toHaveBeenNthCalledWith( + 2, + 'gpg', + [ + '--homedir', + expect.any(String), + '--batch', + '--verify', + '/tmp/jdk.tar.gz.sig', + '/tmp/jdk.tar.gz' + ], + expect.objectContaining({silent: true}) + ); + }); + }); }); }); diff --git a/__tests__/maven-args.test.ts b/__tests__/maven-args.test.ts new file mode 100644 index 000000000..8a45a0ea9 --- /dev/null +++ b/__tests__/maven-args.test.ts @@ -0,0 +1,104 @@ +import * as core from '@actions/core'; + +import {configureMavenArgs} from '../src/maven-args'; +import { + INPUT_SHOW_DOWNLOAD_PROGRESS, + MAVEN_ARGS_ENV, + MAVEN_NO_TRANSFER_PROGRESS_FLAG +} from '../src/constants'; + +describe('configureMavenArgs', () => { + let inputs: Record; + let spyGetInput: jest.SpyInstance; + let spyExportVariable: jest.SpyInstance; + let spyInfo: jest.SpyInstance; + let spyDebug: jest.SpyInstance; + const originalMavenArgs = process.env[MAVEN_ARGS_ENV]; + + beforeEach(() => { + inputs = {}; + + spyGetInput = jest.spyOn(core, 'getInput'); + spyGetInput.mockImplementation((name: string) => inputs[name] ?? ''); + + spyExportVariable = jest.spyOn(core, 'exportVariable'); + spyExportVariable.mockImplementation((name: string, value: string) => { + process.env[name] = value; + }); + + spyInfo = jest.spyOn(core, 'info'); + spyInfo.mockImplementation(() => undefined); + + spyDebug = jest.spyOn(core, 'debug'); + spyDebug.mockImplementation(() => undefined); + + delete process.env[MAVEN_ARGS_ENV]; + }); + + afterEach(() => { + jest.restoreAllMocks(); + if (originalMavenArgs === undefined) { + delete process.env[MAVEN_ARGS_ENV]; + } else { + process.env[MAVEN_ARGS_ENV] = originalMavenArgs; + } + }); + + it('sets MAVEN_ARGS with -ntp by default', () => { + configureMavenArgs(); + + expect(spyExportVariable).toHaveBeenCalledWith( + MAVEN_ARGS_ENV, + MAVEN_NO_TRANSFER_PROGRESS_FLAG + ); + expect(process.env[MAVEN_ARGS_ENV]).toBe(MAVEN_NO_TRANSFER_PROGRESS_FLAG); + }); + + it('does not modify MAVEN_ARGS when show-download-progress is true', () => { + inputs[INPUT_SHOW_DOWNLOAD_PROGRESS] = 'true'; + + configureMavenArgs(); + + expect(spyExportVariable).not.toHaveBeenCalled(); + expect(process.env[MAVEN_ARGS_ENV]).toBeUndefined(); + }); + + it('preserves an existing MAVEN_ARGS value and appends -ntp', () => { + process.env[MAVEN_ARGS_ENV] = '-B -Dstyle.color=always'; + + configureMavenArgs(); + + expect(spyExportVariable).toHaveBeenCalledWith( + MAVEN_ARGS_ENV, + `-B -Dstyle.color=always ${MAVEN_NO_TRANSFER_PROGRESS_FLAG}` + ); + }); + + it('does not duplicate the flag when -ntp is already present', () => { + process.env[MAVEN_ARGS_ENV] = '-B -ntp'; + + configureMavenArgs(); + + expect(spyExportVariable).not.toHaveBeenCalled(); + expect(process.env[MAVEN_ARGS_ENV]).toBe('-B -ntp'); + }); + + it('does not duplicate the flag when --no-transfer-progress is already present', () => { + process.env[MAVEN_ARGS_ENV] = '--no-transfer-progress -B'; + + configureMavenArgs(); + + expect(spyExportVariable).not.toHaveBeenCalled(); + expect(process.env[MAVEN_ARGS_ENV]).toBe('--no-transfer-progress -B'); + }); + + it('keeps the existing MAVEN_ARGS when show-download-progress is true', () => { + inputs[INPUT_SHOW_DOWNLOAD_PROGRESS] = 'true'; + process.env[MAVEN_ARGS_ENV] = '-B'; + + configureMavenArgs(); + + expect(spyExportVariable).not.toHaveBeenCalled(); + expect(process.env[MAVEN_ARGS_ENV]).toBe('-B'); + }); +}); diff --git a/__tests__/toolchains.test.ts b/__tests__/toolchains.test.ts index 483077dc1..01b2ca595 100644 --- a/__tests__/toolchains.test.ts +++ b/__tests__/toolchains.test.ts @@ -46,8 +46,7 @@ describe('toolchains tests', () => { await toolchains.createToolchainsSettings({ jdkInfo, - settingsDirectory: altHome, - overwriteSettings: true + settingsDirectory: altHome }); expect(fs.existsSync(m2Dir)).toBe(false); @@ -95,8 +94,7 @@ describe('toolchains tests', () => { await toolchains.createToolchainsSettings({ jdkInfo, - settingsDirectory: m2Dir, - overwriteSettings: true + settingsDirectory: m2Dir }); expect(fs.existsSync(m2Dir)).toBe(true); @@ -143,7 +141,544 @@ describe('toolchains tests', () => { `; const result = ` - + + + jdk + + 17 + Eclipse Temurin + temurin_17 + + + /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64 + + + + jdk + + 1.6 + Sun + sun_1.6 + + + /opt/jdk/sun/1.6 + + +`; + + fs.mkdirSync(m2Dir, {recursive: true}); + fs.writeFileSync(toolchainsFile, originalFile); + expect(fs.existsSync(m2Dir)).toBe(true); + expect(fs.existsSync(toolchainsFile)).toBe(true); + + await toolchains.createToolchainsSettings({ + jdkInfo, + settingsDirectory: m2Dir + }); + + expect(fs.existsSync(m2Dir)).toBe(true); + expect(fs.existsSync(toolchainsFile)).toBe(true); + expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual( + toolchains.generateToolchainDefinition( + originalFile, + jdkInfo.version, + jdkInfo.vendor, + jdkInfo.id, + jdkInfo.jdkHome + ) + ); + expect( + toolchains.generateToolchainDefinition( + originalFile, + jdkInfo.version, + jdkInfo.vendor, + jdkInfo.id, + jdkInfo.jdkHome + ) + ).toEqual(result); + }, 100000); + + it('does not discard custom elements in existing toolchain definitions', async () => { + const jdkInfo = { + version: '17', + vendor: 'Eclipse Temurin', + id: 'temurin_17', + jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64' + }; + + const originalFile = ` + + jdk + + 1.6 + Sun + sun_1.6 + foo + + + /opt/jdk/sun/1.6 + /usr/local/bin/bash + + + `; + const result = ` + + + jdk + + 17 + Eclipse Temurin + temurin_17 + + + /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64 + + + + jdk + + 1.6 + Sun + sun_1.6 + foo + + + /opt/jdk/sun/1.6 + /usr/local/bin/bash + + +`; + + fs.mkdirSync(m2Dir, {recursive: true}); + fs.writeFileSync(toolchainsFile, originalFile); + expect(fs.existsSync(m2Dir)).toBe(true); + expect(fs.existsSync(toolchainsFile)).toBe(true); + + await toolchains.createToolchainsSettings({ + jdkInfo, + settingsDirectory: m2Dir + }); + + expect(fs.existsSync(m2Dir)).toBe(true); + expect(fs.existsSync(toolchainsFile)).toBe(true); + expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual( + toolchains.generateToolchainDefinition( + originalFile, + jdkInfo.version, + jdkInfo.vendor, + jdkInfo.id, + jdkInfo.jdkHome + ) + ); + expect( + toolchains.generateToolchainDefinition( + originalFile, + jdkInfo.version, + jdkInfo.vendor, + jdkInfo.id, + jdkInfo.jdkHome + ) + ).toEqual(result); + }, 100000); + + it('does not discard existing, custom toolchain definitions', async () => { + const jdkInfo = { + version: '17', + vendor: 'Eclipse Temurin', + id: 'temurin_17', + jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64' + }; + + const originalFile = ` + + foo + + baz + + + /usr/local/bin/foo + + + `; + const result = ` + + + jdk + + 17 + Eclipse Temurin + temurin_17 + + + /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64 + + + + foo + + baz + + + /usr/local/bin/foo + + +`; + + fs.mkdirSync(m2Dir, {recursive: true}); + fs.writeFileSync(toolchainsFile, originalFile); + expect(fs.existsSync(m2Dir)).toBe(true); + expect(fs.existsSync(toolchainsFile)).toBe(true); + + await toolchains.createToolchainsSettings({ + jdkInfo, + settingsDirectory: m2Dir + }); + + expect(fs.existsSync(m2Dir)).toBe(true); + expect(fs.existsSync(toolchainsFile)).toBe(true); + expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual( + toolchains.generateToolchainDefinition( + originalFile, + jdkInfo.version, + jdkInfo.vendor, + jdkInfo.id, + jdkInfo.jdkHome + ) + ); + expect( + toolchains.generateToolchainDefinition( + originalFile, + jdkInfo.version, + jdkInfo.vendor, + jdkInfo.id, + jdkInfo.jdkHome + ) + ).toEqual(result); + }, 100000); + + it('does not duplicate existing toolchain definitions', async () => { + const jdkInfo = { + version: '17', + vendor: 'Eclipse Temurin', + id: 'temurin_17', + jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64' + }; + + const originalFile = ` + + jdk + + 17 + Eclipse Temurin + temurin_17 + + + /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64 + + + `; + const result = ` + + + jdk + + 17 + Eclipse Temurin + temurin_17 + + + /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64 + + +`; + + fs.mkdirSync(m2Dir, {recursive: true}); + fs.writeFileSync(toolchainsFile, originalFile); + expect(fs.existsSync(m2Dir)).toBe(true); + expect(fs.existsSync(toolchainsFile)).toBe(true); + + await toolchains.createToolchainsSettings({ + jdkInfo, + settingsDirectory: m2Dir + }); + + expect(fs.existsSync(m2Dir)).toBe(true); + expect(fs.existsSync(toolchainsFile)).toBe(true); + expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual( + toolchains.generateToolchainDefinition( + originalFile, + jdkInfo.version, + jdkInfo.vendor, + jdkInfo.id, + jdkInfo.jdkHome + ) + ); + expect( + toolchains.generateToolchainDefinition( + originalFile, + jdkInfo.version, + jdkInfo.vendor, + jdkInfo.id, + jdkInfo.jdkHome + ) + ).toEqual(result); + }, 100000); + + it('does not duplicate existing toolchain definitions if multiple exist', async () => { + const jdkInfo = { + version: '17', + vendor: 'Eclipse Temurin', + id: 'temurin_17', + jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64' + }; + + const originalFile = ` + + jdk + + 1.6 + Sun + sun_1.6 + + + /opt/jdk/sun/1.6 + + + + jdk + + 17 + Eclipse Temurin + temurin_17 + + + /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64 + + + `; + const result = ` + + + jdk + + 17 + Eclipse Temurin + temurin_17 + + + /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64 + + + + jdk + + 1.6 + Sun + sun_1.6 + + + /opt/jdk/sun/1.6 + + +`; + + fs.mkdirSync(m2Dir, {recursive: true}); + fs.writeFileSync(toolchainsFile, originalFile); + expect(fs.existsSync(m2Dir)).toBe(true); + expect(fs.existsSync(toolchainsFile)).toBe(true); + + await toolchains.createToolchainsSettings({ + jdkInfo, + settingsDirectory: m2Dir + }); + + expect(fs.existsSync(m2Dir)).toBe(true); + expect(fs.existsSync(toolchainsFile)).toBe(true); + expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual( + toolchains.generateToolchainDefinition( + originalFile, + jdkInfo.version, + jdkInfo.vendor, + jdkInfo.id, + jdkInfo.jdkHome + ) + ); + expect( + toolchains.generateToolchainDefinition( + originalFile, + jdkInfo.version, + jdkInfo.vendor, + jdkInfo.id, + jdkInfo.jdkHome + ) + ).toEqual(result); + }, 100000); + + it('handles an empty list of existing toolchains correctly', async () => { + const jdkInfo = { + version: '17', + vendor: 'Eclipse Temurin', + id: 'temurin_17', + jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64' + }; + + const originalFile = ` + `; + const result = ` + + + jdk + + 17 + Eclipse Temurin + temurin_17 + + + /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64 + + +`; + + fs.mkdirSync(m2Dir, {recursive: true}); + fs.writeFileSync(toolchainsFile, originalFile); + expect(fs.existsSync(m2Dir)).toBe(true); + expect(fs.existsSync(toolchainsFile)).toBe(true); + + await toolchains.createToolchainsSettings({ + jdkInfo, + settingsDirectory: m2Dir + }); + + expect(fs.existsSync(m2Dir)).toBe(true); + expect(fs.existsSync(toolchainsFile)).toBe(true); + expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual( + toolchains.generateToolchainDefinition( + originalFile, + jdkInfo.version, + jdkInfo.vendor, + jdkInfo.id, + jdkInfo.jdkHome + ) + ); + expect( + toolchains.generateToolchainDefinition( + originalFile, + jdkInfo.version, + jdkInfo.vendor, + jdkInfo.id, + jdkInfo.jdkHome + ) + ).toEqual(result); + }, 100000); + + it('handles an empty existing toolchains.xml correctly', async () => { + const jdkInfo = { + version: '17', + vendor: 'Eclipse Temurin', + id: 'temurin_17', + jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64' + }; + + const originalFile = ``; + const result = ` + + + jdk + + 17 + Eclipse Temurin + temurin_17 + + + /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64 + + +`; + + fs.mkdirSync(m2Dir, {recursive: true}); + fs.writeFileSync(toolchainsFile, originalFile); + expect(fs.existsSync(m2Dir)).toBe(true); + expect(fs.existsSync(toolchainsFile)).toBe(true); + + await toolchains.createToolchainsSettings({ + jdkInfo, + settingsDirectory: m2Dir + }); + + expect(fs.existsSync(m2Dir)).toBe(true); + expect(fs.existsSync(toolchainsFile)).toBe(true); + expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual( + toolchains.generateToolchainDefinition( + originalFile, + jdkInfo.version, + jdkInfo.vendor, + jdkInfo.id, + jdkInfo.jdkHome + ) + ); + expect( + toolchains.generateToolchainDefinition( + originalFile, + jdkInfo.version, + jdkInfo.vendor, + jdkInfo.id, + jdkInfo.jdkHome + ) + ).toEqual(result); + }, 100000); + + it('preserves custom root attributes on existing toolchains.xml', async () => { + const jdkInfo = { + version: '17', + vendor: 'Eclipse Temurin', + id: 'temurin_17', + jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64' + }; + + const originalFile = ` + + jdk + + 1.6 + Sun + sun_1.6 + + + /opt/jdk/sun/1.6 + + + `; + const result = ` + + + jdk + + 17 + Eclipse Temurin + temurin_17 + + + /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64 + + jdk @@ -155,6 +690,64 @@ describe('toolchains tests', () => { /opt/jdk/sun/1.6 +`; + + fs.mkdirSync(m2Dir, {recursive: true}); + fs.writeFileSync(toolchainsFile, originalFile); + expect(fs.existsSync(m2Dir)).toBe(true); + expect(fs.existsSync(toolchainsFile)).toBe(true); + + await toolchains.createToolchainsSettings({ + jdkInfo, + settingsDirectory: m2Dir + }); + + expect(fs.existsSync(m2Dir)).toBe(true); + expect(fs.existsSync(toolchainsFile)).toBe(true); + expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual( + toolchains.generateToolchainDefinition( + originalFile, + jdkInfo.version, + jdkInfo.vendor, + jdkInfo.id, + jdkInfo.jdkHome + ) + ); + expect( + toolchains.generateToolchainDefinition( + originalFile, + jdkInfo.version, + jdkInfo.vendor, + jdkInfo.id, + jdkInfo.jdkHome + ) + ).toEqual(result); + }, 100000); + + it('keeps partially-formed jdk toolchains without an id instead of crashing', async () => { + const jdkInfo = { + version: '17', + vendor: 'Eclipse Temurin', + id: 'temurin_17', + jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64' + }; + + const originalFile = ` + + jdk + + 1.6 + Sun + + + /opt/jdk/sun/1.6 + + + `; + const result = ` + jdk @@ -166,6 +759,16 @@ describe('toolchains tests', () => { /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64 + + jdk + + 1.6 + Sun + + + /opt/jdk/sun/1.6 + + `; fs.mkdirSync(m2Dir, {recursive: true}); @@ -175,8 +778,7 @@ describe('toolchains tests', () => { await toolchains.createToolchainsSettings({ jdkInfo, - settingsDirectory: m2Dir, - overwriteSettings: true + settingsDirectory: m2Dir }); expect(fs.existsSync(m2Dir)).toBe(true); @@ -201,7 +803,7 @@ describe('toolchains tests', () => { ).toEqual(result); }, 100000); - it('does not overwrite existing toolchains.xml files', async () => { + it('extends existing toolchains.xml files instead of overwriting them', async () => { const jdkInfo = { version: '17', vendor: 'Eclipse Temurin', @@ -230,13 +832,20 @@ describe('toolchains tests', () => { await toolchains.createToolchainsSettings({ jdkInfo, - settingsDirectory: m2Dir, - overwriteSettings: false + settingsDirectory: m2Dir }); expect(fs.existsSync(m2Dir)).toBe(true); expect(fs.existsSync(toolchainsFile)).toBe(true); - expect(fs.readFileSync(toolchainsFile, 'utf-8')).toEqual(originalFile); + + const updated = fs.readFileSync(toolchainsFile, 'utf-8'); + // The pre-existing (Sun 1.6) toolchain must be preserved ... + expect(updated).toContain('sun_1.6'); + expect(updated).toContain('/opt/jdk/sun/1.6'); + // ... and the newly installed JDK must be included in the merged result. + expect(updated).toContain('temurin_17'); + expect(updated).toContain('Eclipse Temurin'); + expect(updated).toContain(`${jdkInfo.jdkHome}`); }, 100000); it('generates valid toolchains.xml with minimal configuration', () => { @@ -301,4 +910,55 @@ describe('toolchains tests', () => { ) ); }, 100000); + + it('preserves toolchains from previous executions across multiple setup-java runs', async () => { + // Regression test for https://github.com/actions/setup-java/issues/1099 + // Running setup-java several times in the same job (e.g. multiple steps / multiple + // java-version entries) must accumulate every JDK in toolchains.xml rather + // than replacing previously registered entries. + jest.spyOn(core, 'getInput').mockImplementation((name: string) => { + if (name === 'settings-path') return m2Dir; + return ''; + }); + + const runs = [ + { + version: '8', + distributionName: 'temurin', + id: 'temurin_8', + jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/8.0.1-12/x64' + }, + { + version: '11', + distributionName: 'temurin', + id: 'temurin_11', + jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/11.0.1-12/x64' + }, + { + version: '17', + distributionName: 'temurin', + id: 'temurin_17', + jdkHome: '/opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/17.0.1-12/x64' + } + ]; + + for (const run of runs) { + await toolchains.configureToolchains( + run.version, + run.distributionName, + run.jdkHome, + undefined + ); + } + + expect(fs.existsSync(toolchainsFile)).toBe(true); + const contents = fs.readFileSync(toolchainsFile, 'utf-8'); + + for (const run of runs) { + expect(contents).toContain(`${run.id}`); + expect(contents).toContain(`${run.jdkHome}`); + } + // Exactly one entry per run – no duplicates, none dropped. + expect((contents.match(//g) || []).length).toBe(runs.length); + }, 100000); }); diff --git a/__tests__/util.test.ts b/__tests__/util.test.ts index f41d2c918..7a3515b60 100644 --- a/__tests__/util.test.ts +++ b/__tests__/util.test.ts @@ -29,7 +29,11 @@ describe('isVersionSatisfies', () => { ['2.5.1+3', '2.5.1+3', true], ['2.5.1+3', '2.5.1+2', false], ['15.0.0+14', '15.0.0+14.1.202003190635', false], - ['15.0.0+14.1.202003190635', '15.0.0+14.1.202003190635', true] + ['15.0.0+14.1.202003190635', '15.0.0+14.1.202003190635', true], + // 4-segment versions (e.g. JetBrains Runtime '17.0.8.1+1080.1') are not + // valid semver — they should be rejected, not throw. + ['25.0.3+480.61', '17.0.8.1+1080.1', false], + ['17', '17.0.8.1+1080.1', false] ])( '%s, %s -> %s', (inputRange: string, inputVersion: string, expected: boolean) => { @@ -162,15 +166,60 @@ describe('validatePaginationUrl', () => { describe('getVersionFromFileContent', () => { describe('.sdkmanrc', () => { it.each([ - ['java=11.0.20.1-tem', '11.0.20'], - ['java = 11.0.20.1-tem', '11.0.20'], - ['java=11.0.20.1-tem # a comment in sdkmanrc', '11.0.20'], - ['java=11.0.20.1-tem\n#java=21.0.20.1-tem\n', '11.0.20'], // choose first match - ['java=11.0.20.1-tem\njava=21.0.20.1-tem\n', '11.0.20'], // choose first match - ['#java=11.0.20.1-tem\njava=21.0.20.1-tem\n', '21.0.20'] // first one is 'commented' in .sdkmanrc - ])('parsing %s should return %s', (content: string, expected: string) => { - const actual = getVersionFromFileContent(content, 'openjdk', '.sdkmanrc'); - expect(actual).toBe(expected); + ['java=11.0.20.1-tem', '11.0.20', 'temurin'], + ['java = 11.0.20.1-tem', '11.0.20', 'temurin'], + ['java=11.0.20.1-tem # a comment in sdkmanrc', '11.0.20', 'temurin'], + ['java=11.0.20.1-tem\n#java=21.0.20.1-tem\n', '11.0.20', 'temurin'], // choose first match + ['java=11.0.20.1-tem\njava=21.0.20.1-tem\n', '11.0.20', 'temurin'], // choose first match + ['#java=11.0.20.1-tem\njava=21.0.20.1-tem\n', '21.0.20', 'temurin'], // first one is 'commented' in .sdkmanrc + ['java=21.0.5-zulu', '21.0.5', 'zulu'], + ['java=17.0.13-albba', '17.0.13', 'dragonwell'], + ['java=17.0.13-amzn', '17', 'corretto'], + ['java=21.0.5-graal', '21.0.5', 'graalvm'], + ['java=17.0.9-graalce', '17.0.9', 'graalvm'], + ['java=11.0.25-librca', '11.0.25', 'liberica'], + ['java=11.0.25-ms', '11.0.25', 'microsoft'], + ['java=21.0.5-oracle', '21.0.5', 'oracle'], + ['java=11.0.25-sapmchn', '11.0.25', 'sapmachine'], + ['java=21.0.5-jbr', '21.0.5', 'jetbrains'], + ['java=11.0.25-sem', '11.0.25', 'semeru'], + ['java=17.0.13-dragonwell', '17.0.13', 'dragonwell'], + ['java=21.0.5-kona', '21.0.5', 'kona'] + ])( + 'parsing %s should return version %s and distribution %s', + (content: string, expectedVersion: string, expectedDist: string) => { + const actual = getVersionFromFileContent( + content, + 'openjdk', + '.sdkmanrc' + ); + expect(actual?.version).toBe(expectedVersion); + expect(actual?.distribution).toBe(expectedDist); + } + ); + + it('should warn and return undefined distribution for unknown identifier', () => { + const warnSpy = jest.spyOn(core, 'warning'); + const actual = getVersionFromFileContent( + 'java=21.0.5-unknown', + 'temurin', + '.sdkmanrc' + ); + expect(actual?.version).toBe('21.0.5'); + expect(actual?.distribution).toBeUndefined(); + expect(warnSpy).toHaveBeenCalledWith( + expect.stringContaining('Unknown SDKMAN distribution identifier') + ); + }); + + it('should return version without distribution when no suffix provided', () => { + const actual = getVersionFromFileContent( + 'java=11.0.20', + 'temurin', + '.sdkmanrc' + ); + expect(actual?.version).toBe('11.0.20'); + expect(actual?.distribution).toBeUndefined(); }); describe('known versions', () => { @@ -189,11 +238,77 @@ describe('getVersionFromFileContent', () => { 'openjdk', '.sdkmanrc' ); - expect(actual).toBe(expected); + expect(actual?.version).toBe(expected); } ); }); }); + + describe('.tool-versions', () => { + it.each([ + ['java temurin-17.0.3+7', '17.0.3+7', 'temurin'], + ['java temurin-jre-17.0.3+7', '17.0.3+7', 'temurin'], + ['java adoptopenjdk-11.0.16+8', '11.0.16+8', 'temurin'], + ['java adoptopenjdk-openj9-11.0.16+8', '11.0.16+8', 'temurin'], + ['java zulu-11.56.19', '11.56.19', 'zulu'], + ['java corretto-17.0.13.11.1', '17', 'corretto'], // corretto -> major only + ['java liberica-11.0.15+10', '11.0.15+10', 'liberica'], + ['java microsoft-11.0.13.8.1', '11.0.13', 'microsoft'], + ['java semeru-openj9-11.0.25+9', '11.0.25+9', 'semeru'], + ['java ibm-openj9-11.0.25+9', '11.0.25+9', 'semeru'], + ['java dragonwell-17.0.13.0.13+11', '17.0.13', 'dragonwell'], + ['java graalvm-22.3.0+java17', '22.3.0+java17', 'graalvm'], + ['java graalvm-community-22.3.0', '22.3.0', 'graalvm-community'], + ['java oracle-graalvm-21.0.5', '21.0.5', 'graalvm'], + ['java oracle-21.0.5', '21.0.5', 'oracle'], + ['java sapmachine-21.0.5', '21.0.5', 'sapmachine'], + ['java kona-17.0.13', '17.0.13', 'kona'], + ['java jetbrains-21.0.5', '21.0.5', 'jetbrains'] + ])( + 'parsing %s should return version %s and distribution %s', + (content: string, expectedVersion: string, expectedDist: string) => { + const actual = getVersionFromFileContent( + content, + 'openjdk', + '.tool-versions' + ); + expect(actual?.version).toBe(expectedVersion); + expect(actual?.distribution).toBe(expectedDist); + } + ); + + it.each([ + ['java 17.0.7', '17.0.7'], + ['java 17', '17'], + ['java 1.8', '8'], + ['java 21-ea', '21-ea'] + ])( + 'parsing prefix-less %s should return version %s and no distribution', + (content: string, expectedVersion: string) => { + const actual = getVersionFromFileContent( + content, + 'temurin', + '.tool-versions' + ); + expect(actual?.version).toBe(expectedVersion); + expect(actual?.distribution).toBeUndefined(); + } + ); + + it('should warn and return undefined distribution for unsupported vendor', () => { + const warnSpy = jest.spyOn(core, 'warning'); + const actual = getVersionFromFileContent( + 'java openjdk-17.0.7', + 'temurin', + '.tool-versions' + ); + expect(actual?.version).toBe('17.0.7'); + expect(actual?.distribution).toBeUndefined(); + expect(warnSpy).toHaveBeenCalledWith( + expect.stringContaining('Unknown asdf distribution identifier') + ); + }); + }); }); describe('isGhes', () => { diff --git a/action.yml b/action.yml index 21a4269d7..5237f1a8f 100644 --- a/action.yml +++ b/action.yml @@ -5,25 +5,42 @@ author: 'GitHub' inputs: java-version: description: 'The Java version to set up. Takes a whole or semver Java version. See examples of supported syntax in README file' + required: false java-version-file: - description: 'The path to the `.java-version` file. See examples of supported syntax in README file' + description: 'The path to a file containing the Java version to set up (.java-version, .tool-versions, .sdkmanrc). Used when java-version is not set. See examples of supported syntax in README file' + required: false distribution: - description: 'Java distribution. See the list of supported distributions in README file' - required: true + 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 java-package: - description: 'The package type (jdk, jre, jdk+fx, jre+fx)' + description: 'The package type (jdk, jre, jdk+fx, jre+fx, jdk+crac, jre+crac)' required: false default: 'jdk' architecture: description: "The architecture of the package (defaults to the action runner's architecture)" required: false - jdkFile: + jdk-file: description: 'Path to where the compressed JDK is located' required: false + jdkFile: + description: 'Deprecated alias for `jdk-file`. Path to where the compressed JDK is located. Use `jdk-file` instead; this alias may be removed in a future release.' + required: false + deprecationMessage: 'The `jdkFile` input is deprecated. Use `jdk-file` instead.' check-latest: description: 'Set this option if you want the action to check for the latest available version that satisfies the version spec' required: false default: false + 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__ is still set.' + required: false + default: true + verify-signature: + description: 'Verify downloaded Java package signatures when supported by the selected distribution' + required: false + default: false + verify-signature-public-key: + description: 'ASCII-armored GPG public key used to verify the downloaded package signature. Overrides the default bundled key for the selected distribution.' + required: false server-id: description: 'ID of the distributionManagement repository in the pom.xml file. Default is `github`' @@ -49,9 +66,9 @@ inputs: gpg-private-key: description: 'GPG private key to import. Default is empty string.' required: false + default: '' gpg-passphrase: - description: 'Environment variable name for the GPG private key passphrase. Default is - $GPG_PASSPHRASE.' + description: 'Environment variable name for the GPG private key passphrase. Defaults to GPG_PASSPHRASE when gpg-private-key is set; ignored otherwise.' required: false cache: description: 'Name of the build platform to cache dependencies. It can be "maven", "gradle" or "sbt".' @@ -61,9 +78,11 @@ inputs: required: false job-status: description: 'Workaround to pass job status to post job step. This variable is not intended for manual setting' + required: false default: ${{ job.status }} token: description: The token used to authenticate when fetching version manifests hosted on github.com, such as for the Microsoft Build of OpenJDK. When running this action on github.com, the default value is sufficient. When running on GHES, you can pass a personal access token for github.com if you are experiencing rate limiting. + required: false default: ${{ github.server_url == 'https://github.com' && github.token || '' }} mvn-toolchain-id: 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' @@ -71,6 +90,10 @@ inputs: 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' required: false + show-download-progress: + 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 + default: false outputs: distribution: description: 'Distribution of Java that has been installed' @@ -80,6 +103,8 @@ outputs: description: 'Path to where the java environment has been installed (same as $JAVA_HOME)' cache-hit: description: 'A boolean value to indicate an exact match was found for the primary key' + cache-primary-key: + description: 'The primary cache key computed by the action for the configured build tool. Empty when caching is not enabled or when caching is skipped (e.g. cache service unavailable). Useful for composing with actions/cache or actions/cache/restore across jobs.' runs: using: 'node24' main: 'dist/setup/index.js' diff --git a/dist/cleanup/index.js b/dist/cleanup/index.js index b1a86753f..111c1a00c 100644 --- a/dist/cleanup/index.js +++ b/dist/cleanup/index.js @@ -49,7 +49,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge }); }; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.FinalizeCacheError = exports.ReserveCacheError = exports.ValidationError = void 0; +exports.FinalizeCacheError = exports.CacheWriteDeniedError = exports.CACHE_WRITE_DENIED_PREFIX = exports.ReserveCacheError = exports.ValidationError = void 0; exports.isFeatureAvailable = isFeatureAvailable; exports.restoreCache = restoreCache; exports.saveCache = saveCache; @@ -77,6 +77,26 @@ class ReserveCacheError extends Error { } } exports.ReserveCacheError = ReserveCacheError; +/** + * Stable prefix used by the cache receiver to signal that the token has + * no writable scopes (read-only cache policy). Consumers can match on + * this prefix to distinguish policy denials from ordinary contention. + */ +exports.CACHE_WRITE_DENIED_PREFIX = 'cache write denied:'; +/** + * Extends ReserveCacheError for source-compatibility: existing + * `instanceof ReserveCacheError` checks and `typedError.name === + * ReserveCacheError.name` paths keep working, while consumers that want to + * distinguish a policy denial can check for CacheWriteDeniedError.name. + */ +class CacheWriteDeniedError extends ReserveCacheError { + constructor(message) { + super(message); + this.name = 'CacheWriteDeniedError'; + Object.setPrototypeOf(this, CacheWriteDeniedError.prototype); + } +} +exports.CacheWriteDeniedError = CacheWriteDeniedError; class FinalizeCacheError extends Error { constructor(message) { super(message); @@ -387,7 +407,11 @@ function saveCacheV1(paths_1, key_1, options_1) { throw new Error((_d = (_c = reserveCacheResponse === null || reserveCacheResponse === void 0 ? void 0 : reserveCacheResponse.error) === null || _c === void 0 ? void 0 : _c.message) !== null && _d !== void 0 ? _d : `Cache size of ~${Math.round(archiveFileSize / (1024 * 1024))} MB (${archiveFileSize} B) is over the data cap limit, not saving cache.`); } else { - throw new ReserveCacheError(`Unable to reserve cache with key ${key}, another job may be creating this cache. More details: ${(_e = reserveCacheResponse === null || reserveCacheResponse === void 0 ? void 0 : reserveCacheResponse.error) === null || _e === void 0 ? void 0 : _e.message}`); + const detailMessage = (_e = reserveCacheResponse === null || reserveCacheResponse === void 0 ? void 0 : reserveCacheResponse.error) === null || _e === void 0 ? void 0 : _e.message; + if (detailMessage === null || detailMessage === void 0 ? void 0 : detailMessage.startsWith(exports.CACHE_WRITE_DENIED_PREFIX)) { + throw new CacheWriteDeniedError(`Unable to reserve cache with key ${key}. More details: ${detailMessage}`); + } + throw new ReserveCacheError(`Unable to reserve cache with key ${key}, another job may be creating this cache. More details: ${detailMessage}`); } core.debug(`Saving Cache (ID: ${cacheId})`); yield cacheHttpClient.saveCache(cacheId, archivePath, '', options); @@ -397,6 +421,9 @@ function saveCacheV1(paths_1, key_1, options_1) { if (typedError.name === ValidationError.name) { throw error; } + else if (typedError.name === CacheWriteDeniedError.name) { + core.warning(`Failed to save: ${typedError.message}`); + } else if (typedError.name === ReserveCacheError.name) { core.info(`Failed to save: ${typedError.message}`); } @@ -435,6 +462,7 @@ function saveCacheV1(paths_1, key_1, options_1) { */ function saveCacheV2(paths_1, key_1, options_1) { return __awaiter(this, arguments, void 0, function* (paths, key, options, enableCrossOsArchive = false) { + var _a; // Override UploadOptions to force the use of Azure // ...options goes first because we want to override the default values // set in UploadOptions with these specific figures @@ -470,7 +498,11 @@ function saveCacheV2(paths_1, key_1, options_1) { try { const response = yield twirpClient.CreateCacheEntry(request); if (!response.ok) { - if (response.message) { + // Skip the redundant inner warning when the receiver signalled a + // policy denial: the outer catch arm below will log a single + // customer-facing warning. + if (response.message && + !response.message.startsWith(exports.CACHE_WRITE_DENIED_PREFIX)) { core.warning(`Cache reservation failed: ${response.message}`); } throw new Error(response.message || 'Response was not ok'); @@ -479,6 +511,10 @@ function saveCacheV2(paths_1, key_1, options_1) { } catch (error) { core.debug(`Failed to reserve cache: ${error}`); + const errorMessage = (_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : ''; + if (errorMessage.startsWith(exports.CACHE_WRITE_DENIED_PREFIX)) { + throw new CacheWriteDeniedError(`Unable to reserve cache with key ${key}. More details: ${errorMessage}`); + } throw new ReserveCacheError(`Unable to reserve cache with key ${key}, another job may be creating this cache.`); } core.debug(`Attempting to upload cache located at: ${archivePath}`); @@ -503,6 +539,9 @@ function saveCacheV2(paths_1, key_1, options_1) { if (typedError.name === ValidationError.name) { throw error; } + else if (typedError.name === CacheWriteDeniedError.name) { + core.warning(`Failed to save: ${typedError.message}`); + } else if (typedError.name === ReserveCacheError.name) { core.info(`Failed to save: ${typedError.message}`); } @@ -18118,14 +18157,17 @@ function useColors() { return false; } + let m; + // Is webkit? http://stackoverflow.com/a/16459606/376773 // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 + // eslint-disable-next-line no-return-assign return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) || // Is firebug? http://stackoverflow.com/a/398120/376773 (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) || // Is firefox >= v31? // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages - (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) || + (typeof navigator !== 'undefined' && navigator.userAgent && (m = navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)) && parseInt(m[1], 10) >= 31) || // Double check webkit in userAgent just in case we are in a worker (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)); } @@ -18209,7 +18251,7 @@ function save(namespaces) { function load() { let r; try { - r = exports.storage.getItem('debug'); + r = exports.storage.getItem('debug') || exports.storage.getItem('DEBUG') ; } catch (error) { // Swallow // XXX (@Qix-) should we be logging these? @@ -18435,24 +18477,62 @@ function setup(env) { createDebug.names = []; createDebug.skips = []; - let i; - const split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/); - const len = split.length; + const split = (typeof namespaces === 'string' ? namespaces : '') + .trim() + .replace(/\s+/g, ',') + .split(',') + .filter(Boolean); - for (i = 0; i < len; i++) { - if (!split[i]) { - // ignore empty strings - continue; + for (const ns of split) { + if (ns[0] === '-') { + createDebug.skips.push(ns.slice(1)); + } else { + createDebug.names.push(ns); } + } + } - namespaces = split[i].replace(/\*/g, '.*?'); - - if (namespaces[0] === '-') { - createDebug.skips.push(new RegExp('^' + namespaces.slice(1) + '$')); + /** + * Checks if the given string matches a namespace template, honoring + * asterisks as wildcards. + * + * @param {String} search + * @param {String} template + * @return {Boolean} + */ + function matchesTemplate(search, template) { + let searchIndex = 0; + let templateIndex = 0; + let starIndex = -1; + let matchIndex = 0; + + while (searchIndex < search.length) { + if (templateIndex < template.length && (template[templateIndex] === search[searchIndex] || template[templateIndex] === '*')) { + // Match character or proceed with wildcard + if (template[templateIndex] === '*') { + starIndex = templateIndex; + matchIndex = searchIndex; + templateIndex++; // Skip the '*' + } else { + searchIndex++; + templateIndex++; + } + } else if (starIndex !== -1) { // eslint-disable-line no-negated-condition + // Backtrack to the last '*' and try to match more characters + templateIndex = starIndex + 1; + matchIndex++; + searchIndex = matchIndex; } else { - createDebug.names.push(new RegExp('^' + namespaces + '$')); + return false; // No match } } + + // Handle trailing '*' in template + while (templateIndex < template.length && template[templateIndex] === '*') { + templateIndex++; + } + + return templateIndex === template.length; } /** @@ -18463,8 +18543,8 @@ function setup(env) { */ function disable() { const namespaces = [ - ...createDebug.names.map(toNamespace), - ...createDebug.skips.map(toNamespace).map(namespace => '-' + namespace) + ...createDebug.names, + ...createDebug.skips.map(namespace => '-' + namespace) ].join(','); createDebug.enable(''); return namespaces; @@ -18478,21 +18558,14 @@ function setup(env) { * @api public */ function enabled(name) { - if (name[name.length - 1] === '*') { - return true; - } - - let i; - let len; - - for (i = 0, len = createDebug.skips.length; i < len; i++) { - if (createDebug.skips[i].test(name)) { + for (const skip of createDebug.skips) { + if (matchesTemplate(name, skip)) { return false; } } - for (i = 0, len = createDebug.names.length; i < len; i++) { - if (createDebug.names[i].test(name)) { + for (const ns of createDebug.names) { + if (matchesTemplate(name, ns)) { return true; } } @@ -18500,19 +18573,6 @@ function setup(env) { return false; } - /** - * Convert regexp to namespace - * - * @param {RegExp} regxep - * @return {String} namespace - * @api private - */ - function toNamespace(regexp) { - return regexp.toString() - .substring(2, regexp.toString().length - 2) - .replace(/\.\*\?$/, '*'); - } - /** * Coerce `val`. * @@ -18754,11 +18814,11 @@ function getDate() { } /** - * Invokes `util.format()` with the specified arguments and writes to stderr. + * Invokes `util.formatWithOptions()` with the specified arguments and writes to stderr. */ function log(...args) { - return process.stderr.write(util.format(...args) + '\n'); + return process.stderr.write(util.formatWithOptions(exports.inspectOpts, ...args) + '\n'); } /** @@ -20338,7 +20398,7 @@ var y = d * 365.25; * @api public */ -module.exports = function(val, options) { +module.exports = function (val, options) { options = options || {}; var type = typeof val; if (type === 'string' && val.length > 0) { @@ -28277,8 +28337,6 @@ function defaultFactory (origin, opts) { class Agent extends DispatcherBase { constructor ({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) { - super() - if (typeof factory !== 'function') { throw new InvalidArgumentError('factory must be a function.') } @@ -28291,6 +28349,8 @@ class Agent extends DispatcherBase { throw new InvalidArgumentError('maxRedirections must be a positive number') } + super(options) + if (connect && typeof connect !== 'function') { connect = { ...connect } } @@ -28664,6 +28724,9 @@ const EMPTY_BUF = Buffer.alloc(0) const FastBuffer = Buffer[Symbol.species] const addListener = util.addListener const removeAllListeners = util.removeAllListeners +const kIdleSocketValidation = Symbol('kIdleSocketValidation') +const kIdleSocketValidationTimeout = Symbol('kIdleSocketValidationTimeout') +const kSocketUsed = Symbol('kSocketUsed') let extractBody @@ -28886,29 +28949,71 @@ class Parser { const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr - if (ret === constants.ERROR.PAUSED_UPGRADE) { - this.onUpgrade(data.slice(offset)) - } else if (ret === constants.ERROR.PAUSED) { - this.paused = true - socket.unshift(data.slice(offset)) - } else if (ret !== constants.ERROR.OK) { - const ptr = llhttp.llhttp_get_error_reason(this.ptr) - let message = '' - /* istanbul ignore else: difficult to make a test case for */ - if (ptr) { - const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0) - message = - 'Response does not match the HTTP/1.1 protocol (' + - Buffer.from(llhttp.memory.buffer, ptr, len).toString() + - ')' - } - throw new HTTPParserError(message, constants.ERROR[ret], data.slice(offset)) + if (ret !== constants.ERROR.OK) { + const body = data.subarray(offset) + + if (ret === constants.ERROR.PAUSED_UPGRADE) { + this.onUpgrade(body) + } else if (ret === constants.ERROR.PAUSED) { + this.paused = true + socket.unshift(body) + } else { + throw this.createError(ret, body) + } } } catch (err) { util.destroy(socket, err) } } + finish () { + assert(currentParser === null) + assert(this.ptr != null) + assert(!this.paused) + + const { llhttp } = this + + let ret + + try { + currentParser = this + ret = llhttp.llhttp_finish(this.ptr) + } finally { + currentParser = null + } + + if (ret === constants.ERROR.OK) { + return null + } + + if (ret === constants.ERROR.PAUSED || ret === constants.ERROR.PAUSED_UPGRADE) { + this.paused = true + return null + } + + return this.createError(ret, EMPTY_BUF) + } + + createError (ret, data) { + const { llhttp, contentLength, bytesRead } = this + + if (contentLength && bytesRead !== parseInt(contentLength, 10)) { + return new ResponseContentLengthMismatchError() + } + + const ptr = llhttp.llhttp_get_error_reason(this.ptr) + let message = '' + if (ptr) { + const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0) + message = + 'Response does not match the HTTP/1.1 protocol (' + + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + + ')' + } + + return new HTTPParserError(message, constants.ERROR[ret], data) + } + destroy () { assert(this.ptr != null) assert(currentParser == null) @@ -28936,6 +29041,11 @@ class Parser { return -1 } + if (client[kRunning] === 0) { + util.destroy(socket, new SocketError('bad response', util.getSocketInfo(socket))) + return -1 + } + const request = client[kQueue][client[kRunningIdx]] if (!request) { return -1 @@ -29039,6 +29149,11 @@ class Parser { return -1 } + if (client[kRunning] === 0) { + util.destroy(socket, new SocketError('bad response', util.getSocketInfo(socket))) + return -1 + } + const request = client[kQueue][client[kRunningIdx]] /* istanbul ignore next: difficult to make a test case for */ @@ -29212,6 +29327,7 @@ class Parser { request.onComplete(headers) client[kQueue][client[kRunningIdx]++] = null + socket[kSocketUsed] = true if (socket[kWriting]) { assert(client[kRunning] === 0) @@ -29270,6 +29386,9 @@ async function connectH1 (client, socket) { socket[kWriting] = false socket[kReset] = false socket[kBlocking] = false + socket[kIdleSocketValidation] = 0 + socket[kIdleSocketValidationTimeout] = null + socket[kSocketUsed] = false socket[kParser] = new Parser(client, socket, llhttpInstance) addListener(socket, 'error', function (err) { @@ -29280,8 +29399,11 @@ async function connectH1 (client, socket) { // On Mac OS, we get an ECONNRESET even if there is a full body to be forwarded // to the user. if (err.code === 'ECONNRESET' && parser.statusCode && !parser.shouldKeepAlive) { - // We treat all incoming data so for as a valid response. - parser.onMessageComplete() + const parserErr = parser.finish() + if (parserErr) { + this[kError] = parserErr + this[kClient][kOnError](parserErr) + } return } @@ -29300,8 +29422,10 @@ async function connectH1 (client, socket) { const parser = this[kParser] if (parser.statusCode && !parser.shouldKeepAlive) { - // We treat all incoming data so far as a valid response. - parser.onMessageComplete() + const parserErr = parser.finish() + if (parserErr) { + util.destroy(this, parserErr) + } return } @@ -29311,10 +29435,11 @@ async function connectH1 (client, socket) { const client = this[kClient] const parser = this[kParser] + clearIdleSocketValidation(this) + if (parser) { if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) { - // We treat all incoming data so far as a valid response. - parser.onMessageComplete() + this[kError] = parser.finish() || this[kError] } this[kParser].destroy() @@ -29377,7 +29502,7 @@ async function connectH1 (client, socket) { return socket.destroyed }, busy (request) { - if (socket[kWriting] || socket[kReset] || socket[kBlocking]) { + if (socket[kWriting] || socket[kReset] || socket[kBlocking] || socket[kIdleSocketValidation] === 1) { return true } @@ -29415,6 +29540,31 @@ async function connectH1 (client, socket) { } } +function clearIdleSocketValidation (socket) { + if (socket[kIdleSocketValidationTimeout]) { + clearTimeout(socket[kIdleSocketValidationTimeout]) + socket[kIdleSocketValidationTimeout] = null + } + + socket[kIdleSocketValidation] = 0 +} + +function scheduleIdleSocketValidation (client, socket) { + socket[kIdleSocketValidation] = 1 + socket[kIdleSocketValidationTimeout] = setTimeout(() => { + socket[kIdleSocketValidationTimeout] = null + socket[kIdleSocketValidation] = 2 + + if (client[kSocket] === socket && !socket.destroyed) { + client[kResume]() + } + }, 0) + socket[kIdleSocketValidationTimeout].unref?.() +} + +/** + * @param {import('./client.js')} client + */ function resumeH1 (client) { const socket = client[kSocket] @@ -29429,6 +29579,32 @@ function resumeH1 (client) { socket[kNoRef] = false } + if (client[kRunning] === 0 && client[kPending] > 0 && socket[kSocketUsed]) { + if (socket[kIdleSocketValidation] === 0) { + scheduleIdleSocketValidation(client, socket) + socket[kParser].readMore() + if (socket.destroyed) { + return + } + return + } + + if (socket[kIdleSocketValidation] === 1) { + socket[kParser].readMore() + if (socket.destroyed) { + return + } + return + } + } + + if (client[kRunning] === 0) { + socket[kParser].readMore() + if (socket.destroyed) { + return + } + } + if (client[kSize] === 0) { if (socket[kParser].timeoutType !== TIMEOUT_KEEP_ALIVE) { socket[kParser].setTimeout(client[kKeepAliveTimeoutValue], TIMEOUT_KEEP_ALIVE) @@ -29522,6 +29698,7 @@ function writeH1 (client, request) { } const socket = client[kSocket] + clearIdleSocketValidation(socket) const abort = (err) => { if (request.aborted || request.completed) { @@ -30843,9 +31020,10 @@ class Client extends DispatcherBase { autoSelectFamilyAttemptTimeout, // h2 maxConcurrentStreams, - allowH2 + allowH2, + webSocket } = {}) { - super() + super({ webSocket }) if (keepAlive !== undefined) { throw new InvalidArgumentError('unsupported keepAlive, use pipelining=0 instead') @@ -31378,15 +31556,24 @@ const { kDestroy, kClose, kClosed, kDestroyed, kDispatch, kInterceptors } = __nc const kOnDestroyed = Symbol('onDestroyed') const kOnClosed = Symbol('onClosed') const kInterceptedDispatch = Symbol('Intercepted Dispatch') +const kWebSocketOptions = Symbol('webSocketOptions') class DispatcherBase extends Dispatcher { - constructor () { + constructor (opts) { super() this[kDestroyed] = false this[kOnDestroyed] = null this[kClosed] = false this[kOnClosed] = [] + this[kWebSocketOptions] = opts?.webSocket ?? {} + } + + get webSocketOptions () { + return { + maxFragments: this[kWebSocketOptions].maxFragments ?? 131072, + maxPayloadSize: this[kWebSocketOptions].maxPayloadSize ?? 128 * 1024 * 1024 + } } get destroyed () { @@ -31950,8 +32137,8 @@ const kRemoveClient = Symbol('remove client') const kStats = Symbol('stats') class PoolBase extends DispatcherBase { - constructor () { - super() + constructor (opts) { + super(opts) this[kQueue] = new FixedQueue() this[kClients] = [] @@ -32211,8 +32398,6 @@ class Pool extends PoolBase { allowH2, ...options } = {}) { - super() - if (connections != null && (!Number.isFinite(connections) || connections < 0)) { throw new InvalidArgumentError('invalid connections') } @@ -32237,6 +32422,8 @@ class Pool extends PoolBase { }) } + super(options) + this[kInterceptors] = options.interceptors?.Pool && Array.isArray(options.interceptors.Pool) ? options.interceptors.Pool : [] @@ -37321,32 +37508,25 @@ function parseUnparsedAttributes (unparsedAttributes, cookieAttributeList = {}) // If the attribute-name case-insensitively matches the string // "SameSite", the user agent MUST process the cookie-av as follows: - // 1. Let enforcement be "Default". - let enforcement = 'Default' - const attributeValueLowercase = attributeValue.toLowerCase() - // 2. If cookie-av's attribute-value is a case-insensitive match for - // "None", set enforcement to "None". - if (attributeValueLowercase.includes('none')) { - enforcement = 'None' - } - - // 3. If cookie-av's attribute-value is a case-insensitive match for - // "Strict", set enforcement to "Strict". - if (attributeValueLowercase.includes('strict')) { - enforcement = 'Strict' - } - // 4. If cookie-av's attribute-value is a case-insensitive match for - // "Lax", set enforcement to "Lax". - if (attributeValueLowercase.includes('lax')) { - enforcement = 'Lax' + // 1. If cookie-av's attribute-value is a case-insensitive match for + // "None", append an attribute to the cookie-attribute-list with an + // attribute-name of "SameSite" and an attribute-value of "None". + if (attributeValueLowercase === 'none') { + cookieAttributeList.sameSite = 'None' + } else if (attributeValueLowercase === 'strict') { + // 2. If cookie-av's attribute-value is a case-insensitive match for + // "Strict", append an attribute to the cookie-attribute-list with + // an attribute-name of "SameSite" and an attribute-value of + // "Strict". + cookieAttributeList.sameSite = 'Strict' + } else if (attributeValueLowercase === 'lax') { + // 3. If cookie-av's attribute-value is a case-insensitive match for + // "Lax", append an attribute to the cookie-attribute-list with an + // attribute-name of "SameSite" and an attribute-value of "Lax". + cookieAttributeList.sameSite = 'Lax' } - - // 5. Append an attribute to the cookie-attribute-list with an - // attribute-name of "SameSite" and an attribute-value of - // enforcement. - cookieAttributeList.sameSite = enforcement } else { cookieAttributeList.unparsed ??= [] @@ -50052,40 +50232,35 @@ const tail = Buffer.from([0x00, 0x00, 0xff, 0xff]) const kBuffer = Symbol('kBuffer') const kLength = Symbol('kLength') -// Default maximum decompressed message size: 4 MB -const kDefaultMaxDecompressedSize = 4 * 1024 * 1024 - class PerMessageDeflate { /** @type {import('node:zlib').InflateRaw} */ #inflate #options = {} - /** @type {boolean} */ - #aborted = false - - /** @type {Function|null} */ - #currentCallback = null + #maxPayloadSize = 0 /** * @param {Map} extensions */ - constructor (extensions) { + constructor (extensions, options) { this.#options.serverNoContextTakeover = extensions.has('server_no_context_takeover') this.#options.serverMaxWindowBits = extensions.get('server_max_window_bits') + + this.#maxPayloadSize = options.maxPayloadSize } + /** + * Decompress a compressed payload. + * @param {Buffer} chunk Compressed data + * @param {boolean} fin Final fragment flag + * @param {Function} callback Callback function + */ decompress (chunk, fin, callback) { // An endpoint uses the following algorithm to decompress a message. // 1. Append 4 octets of 0x00 0x00 0xff 0xff to the tail end of the // payload of the message. // 2. Decompress the resulting data using DEFLATE. - - if (this.#aborted) { - callback(new MessageSizeExceededError()) - return - } - if (!this.#inflate) { let windowBits = Z_DEFAULT_WINDOWBITS @@ -50108,23 +50283,12 @@ class PerMessageDeflate { this.#inflate[kLength] = 0 this.#inflate.on('data', (data) => { - if (this.#aborted) { - return - } - this.#inflate[kLength] += data.length - if (this.#inflate[kLength] > kDefaultMaxDecompressedSize) { - this.#aborted = true + if (this.#maxPayloadSize > 0 && this.#inflate[kLength] > this.#maxPayloadSize) { + callback(new MessageSizeExceededError()) this.#inflate.removeAllListeners() - this.#inflate.destroy() this.#inflate = null - - if (this.#currentCallback) { - const cb = this.#currentCallback - this.#currentCallback = null - cb(new MessageSizeExceededError()) - } return } @@ -50137,14 +50301,13 @@ class PerMessageDeflate { }) } - this.#currentCallback = callback this.#inflate.write(chunk) if (fin) { this.#inflate.write(tail) } this.#inflate.flush(() => { - if (this.#aborted || !this.#inflate) { + if (!this.#inflate) { return } @@ -50152,7 +50315,6 @@ class PerMessageDeflate { this.#inflate[kBuffer].length = 0 this.#inflate[kLength] = 0 - this.#currentCallback = null callback(null, full) }) @@ -50188,6 +50350,12 @@ const { const { WebsocketFrameSend } = __nccwpck_require__(3264) const { closeWebSocketConnection } = __nccwpck_require__(86897) const { PerMessageDeflate } = __nccwpck_require__(19469) +const { MessageSizeExceededError } = __nccwpck_require__(68707) + +function failWebsocketConnectionWithCode (ws, code, reason) { + closeWebSocketConnection(ws, code, reason, Buffer.byteLength(reason)) + failWebsocketConnection(ws, reason) +} // This code was influenced by ws released under the MIT license. // Copyright (c) 2011 Einar Otto Stangvik @@ -50196,6 +50364,7 @@ const { PerMessageDeflate } = __nccwpck_require__(19469) class ByteParser extends Writable { #buffers = [] + #fragmentsBytes = 0 #byteOffset = 0 #loop = false @@ -50207,18 +50376,27 @@ class ByteParser extends Writable { /** @type {Map} */ #extensions + /** @type {number} */ + #maxFragments + + /** @type {number} */ + #maxPayloadSize + /** * @param {import('./websocket').WebSocket} ws * @param {Map|null} extensions + * @param {{ maxFragments?: number, maxPayloadSize?: number }} [options] */ - constructor (ws, extensions) { + constructor (ws, extensions, options = {}) { super() this.ws = ws this.#extensions = extensions == null ? new Map() : extensions + this.#maxFragments = options.maxFragments ?? 0 + this.#maxPayloadSize = options.maxPayloadSize ?? 0 if (this.#extensions.has('permessage-deflate')) { - this.#extensions.set('permessage-deflate', new PerMessageDeflate(extensions)) + this.#extensions.set('permessage-deflate', new PerMessageDeflate(extensions, options)) } } @@ -50234,6 +50412,19 @@ class ByteParser extends Writable { this.run(callback) } + #validatePayloadLength () { + if ( + this.#maxPayloadSize > 0 && + !isControlFrame(this.#info.opcode) && + this.#info.payloadLength + this.#fragmentsBytes > this.#maxPayloadSize + ) { + failWebsocketConnectionWithCode(this.ws, 1009, 'Payload size exceeds maximum allowed size') + return false + } + + return true + } + /** * Runs whenever a new chunk is received. * Callback is called whenever there are no more chunks buffering, @@ -50322,6 +50513,10 @@ class ByteParser extends Writable { if (payloadLength <= 125) { this.#info.payloadLength = payloadLength this.#state = parserStates.READ_DATA + + if (!this.#validatePayloadLength()) { + return + } } else if (payloadLength === 126) { this.#state = parserStates.PAYLOADLENGTH_16 } else if (payloadLength === 127) { @@ -50346,6 +50541,10 @@ class ByteParser extends Writable { this.#info.payloadLength = buffer.readUInt16BE(0) this.#state = parserStates.READ_DATA + + if (!this.#validatePayloadLength()) { + return + } } else if (this.#state === parserStates.PAYLOADLENGTH_64) { if (this.#byteOffset < 8) { return callback() @@ -50368,6 +50567,10 @@ class ByteParser extends Writable { this.#info.payloadLength = lower this.#state = parserStates.READ_DATA + + if (!this.#validatePayloadLength()) { + return + } } else if (this.#state === parserStates.READ_DATA) { if (this.#byteOffset < this.#info.payloadLength) { return callback() @@ -50380,42 +50583,58 @@ class ByteParser extends Writable { this.#state = parserStates.INFO } else { if (!this.#info.compressed) { - this.#fragments.push(body) + if (!this.writeFragments(body)) { + return + } + + if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { + failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message) + return + } // If the frame is not fragmented, a message has been received. // If the frame is fragmented, it will terminate with a fin bit set // and an opcode of 0 (continuation), therefore we handle that when // parsing continuation frames, not here. if (!this.#info.fragmented && this.#info.fin) { - const fullMessage = Buffer.concat(this.#fragments) - websocketMessageReceived(this.ws, this.#info.binaryType, fullMessage) - this.#fragments.length = 0 + websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments()) } this.#state = parserStates.INFO } else { - this.#extensions.get('permessage-deflate').decompress(body, this.#info.fin, (error, data) => { - if (error) { - failWebsocketConnection(this.ws, error.message) - return - } + this.#extensions.get('permessage-deflate').decompress( + body, + this.#info.fin, + (error, data) => { + if (error) { + const code = error instanceof MessageSizeExceededError ? 1009 : 1007 + failWebsocketConnectionWithCode(this.ws, code, error.message) + return + } - this.#fragments.push(data) + if (!this.writeFragments(data)) { + return + } + + if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { + failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message) + return + } + + if (!this.#info.fin) { + this.#state = parserStates.INFO + this.#loop = true + this.run(callback) + return + } + + websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments()) - if (!this.#info.fin) { - this.#state = parserStates.INFO this.#loop = true + this.#state = parserStates.INFO this.run(callback) - return } - - websocketMessageReceived(this.ws, this.#info.binaryType, Buffer.concat(this.#fragments)) - - this.#loop = true - this.#state = parserStates.INFO - this.#fragments.length = 0 - this.run(callback) - }) + ) this.#loop = false break @@ -50467,6 +50686,35 @@ class ByteParser extends Writable { return buffer } + writeFragments (fragment) { + if ( + this.#maxFragments > 0 && + this.#fragments.length === this.#maxFragments + ) { + failWebsocketConnectionWithCode(this.ws, 1008, 'Too many message fragments') + return false + } + + this.#fragmentsBytes += fragment.length + this.#fragments.push(fragment) + return true + } + + consumeFragments () { + const fragments = this.#fragments + + if (fragments.length === 1) { + this.#fragmentsBytes = 0 + return fragments.shift() + } + + const output = Buffer.concat(fragments, this.#fragmentsBytes) + this.#fragments = [] + this.#fragmentsBytes = 0 + + return output + } + parseCloseBody (data) { assert(data.length !== 1) @@ -51502,7 +51750,14 @@ class WebSocket extends EventTarget { // once this happens, the connection is open this[kResponse] = response - const parser = new ByteParser(this, parsedExtensions) + const webSocketOptions = this[kController]?.dispatcher?.webSocketOptions + const maxFragments = webSocketOptions?.maxFragments + const maxPayloadSize = webSocketOptions?.maxPayloadSize + + const parser = new ByteParser(this, parsedExtensions, { + maxFragments, + maxPayloadSize + }) parser.on('drain', onParserDrain) parser.on('error', onParserError.bind(this)) @@ -51715,14 +51970,26 @@ const supportedPackageManager = [ id: 'maven', path: [(0, path_1.join)(os_1.default.homedir(), '.m2', 'repository')], // https://github.com/actions/cache/blob/0638051e9af2c23d10bb70fa9beffcad6cff9ce3/examples.md#java---maven - pattern: ['**/pom.xml'] + 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_1.join)(os_1.default.homedir(), '.m2', 'wrapper', 'dists')], + pattern: ['**/.mvn/wrapper/maven-wrapper.properties'] + } + ] }, { id: 'gradle', - path: [ - (0, path_1.join)(os_1.default.homedir(), '.gradle', 'caches'), - (0, path_1.join)(os_1.default.homedir(), '.gradle', 'wrapper') - ], + path: [(0, path_1.join)(os_1.default.homedir(), '.gradle', 'caches')], // https://github.com/actions/cache/blob/0638051e9af2c23d10bb70fa9beffcad6cff9ce3/examples.md#java---gradle pattern: [ '**/*.gradle*', @@ -51731,6 +51998,17 @@ const supportedPackageManager = [ 'buildSrc/**/Dependencies.kt', 'gradle/*.versions.toml', '**/versions.properties' + ], + // The Gradle wrapper distribution only depends on the wrapper properties, + // which change very rarely, so it is cached separately from the Gradle + // caches. This keeps it available across the frequent *.gradle* changes + // that rotate the main cache key. See issue #269. + additionalCaches: [ + { + name: 'gradle-wrapper', + path: [(0, path_1.join)(os_1.default.homedir(), '.gradle', 'wrapper')], + pattern: ['**/gradle-wrapper.properties'] + } ] }, { @@ -51766,6 +52044,19 @@ function findPackageManager(id) { } return packageManager; } +/** + * State keys used to carry an additional cache's restore-time information over + * to the post (save) action, scoped by the additional cache name. + */ +function additionalCachePrimaryKeyState(name) { + return `${STATE_CACHE_PRIMARY_KEY}-${name}`; +} +function additionalCacheMatchedKeyState(name) { + return `${CACHE_MATCHED_KEY}-${name}`; +} +function buildCacheKey(id, fileHash) { + return `${CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${process.arch}-${id}-${fileHash}`; +} /** * A function that generates a cache key to use. * Format of the generated key will be "${{ platform }}-${{ id }}-${{ fileHash }}"". @@ -51780,7 +52071,21 @@ function computeCacheKey(packageManager, cacheDependencyPath) { if (!fileHash) { throw new Error(`No file in ${process.cwd()} matched to [${pattern}], make sure you have checked out the target repository`); } - return `${CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${process.arch}-${packageManager.id}-${fileHash}`; + return buildCacheKey(packageManager.id, fileHash); + }); +} +/** + * Computes the cache key for an additional cache. Unlike {@link computeCacheKey} + * this returns undefined (instead of throwing) when no file matches the pattern, + * because additional caches are optional features that many projects do not use. + */ +function computeAdditionalCacheKey(additionalCache) { + return __awaiter(this, void 0, void 0, function* () { + const fileHash = yield glob.hashFiles(additionalCache.pattern.join('\n')); + if (!fileHash) { + return undefined; + } + return buildCacheKey(additionalCache.name, fileHash); }); } /** @@ -51789,11 +52094,13 @@ function computeCacheKey(packageManager, cacheDependencyPath) { * @param cacheDependencyPath The path to a dependency file */ function restore(id, cacheDependencyPath) { + var _a; return __awaiter(this, void 0, void 0, function* () { const packageManager = findPackageManager(id); const primaryKey = yield computeCacheKey(packageManager, cacheDependencyPath); core.debug(`primary key is ${primaryKey}`); core.saveState(STATE_CACHE_PRIMARY_KEY, primaryKey); + core.setOutput(STATE_CACHE_PRIMARY_KEY, 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 = yield cache.restoreCache(packageManager.path, primaryKey); if (matchedKey) { @@ -51805,19 +52112,48 @@ function restore(id, cacheDependencyPath) { core.setOutput('cache-hit', false); core.info(`${packageManager.id} cache is not found`); } + for (const additionalCache of (_a = packageManager.additionalCaches) !== null && _a !== void 0 ? _a : []) { + yield restoreAdditionalCache(additionalCache); + } }); } exports.restore = restore; +/** + * Restore an additional cache (e.g. a build-tool wrapper distribution) that is + * keyed independently of the main dependency cache so that it survives changes + * to volatile dependency files. Skips silently when the project does not use + * the corresponding feature. + */ +function restoreAdditionalCache(additionalCache) { + return __awaiter(this, void 0, void 0, function* () { + const primaryKey = yield computeAdditionalCacheKey(additionalCache); + if (!primaryKey) { + core.debug(`No file matched [${additionalCache.pattern}] for the ${additionalCache.name} cache, skipping.`); + return; + } + core.debug(`${additionalCache.name} primary key is ${primaryKey}`); + core.saveState(additionalCachePrimaryKeyState(additionalCache.name), primaryKey); + const matchedKey = yield cache.restoreCache(additionalCache.path, primaryKey); + if (matchedKey) { + core.saveState(additionalCacheMatchedKeyState(additionalCache.name), matchedKey); + core.info(`${additionalCache.name} cache restored from key: ${matchedKey}`); + } + }); +} /** * Save the dependency cache * @param id ID of the package manager, should be "maven" or "gradle" */ function save(id) { + var _a; return __awaiter(this, void 0, void 0, function* () { const packageManager = findPackageManager(id); const matchedKey = core.getState(CACHE_MATCHED_KEY); // Inputs are re-evaluated before the post action, so we want the original key used for restore const primaryKey = core.getState(STATE_CACHE_PRIMARY_KEY); + for (const additionalCache of (_a = packageManager.additionalCaches) !== null && _a !== void 0 ? _a : []) { + yield saveAdditionalCache(packageManager, additionalCache); + } if (!primaryKey) { core.warning('Error retrieving key from state.'); return; @@ -51828,7 +52164,15 @@ function save(id) { return; } try { - yield cache.saveCache(packageManager.path, primaryKey); + const cacheId = yield cache.saveCache(packageManager.path, 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. + core.debug(`Cache was not saved for the key: ${primaryKey}`); + return; + } core.info(`Cache saved with the key: ${primaryKey}`); } catch (error) { @@ -51846,6 +52190,52 @@ function save(id) { }); } exports.save = save; +/** + * 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. + */ +function saveAdditionalCache(packageManager, additionalCache) { + return __awaiter(this, void 0, void 0, function* () { + const primaryKey = core.getState(additionalCachePrimaryKeyState(additionalCache.name)); + const matchedKey = core.getState(additionalCacheMatchedKeyState(additionalCache.name)); + if (!primaryKey) { + // The feature is not used by this project, nothing to save. + core.debug(`No primary key for the ${additionalCache.name} cache, not saving cache.`); + return; + } + else if (matchedKey === primaryKey) { + core.info(`Cache hit occurred on the ${additionalCache.name} primary key ${primaryKey}, not saving cache.`); + return; + } + try { + const cacheId = yield cache.saveCache(additionalCache.path, primaryKey); + if (cacheId === -1) { + core.debug(`${additionalCache.name} cache was not saved for the key: ${primaryKey}`); + return; + } + core.info(`${additionalCache.name} cache saved with the key: ${primaryKey}`); + } + catch (error) { + const err = error; + if (err.name === cache.ValidationError.name) { + // The cache paths did not resolve, e.g. the wrapper distribution was + // never downloaded because a system build tool was used or the download + // failed. Optional wrapper caches must not fail the post step, so skip. + core.debug(`${additionalCache.name} cache paths do not exist, not saving cache: ${err.message}`); + return; + } + if (err.name === cache.ReserveCacheError.name) { + core.info(err.message); + } + else { + if (isProbablyGradleDaemonProblem(packageManager, err)) { + core.warning('Failed to save Gradle cache on Windows. If tar.exe reported "Permission denied", try to run Gradle with `--no-daemon` option. Refer to https://github.com/actions/cache/issues/454 for details.'); + } + throw error; + } + } + }); +} /** * @param packageManager the specified package manager by user * @param error the error thrown by the saveCache @@ -51975,15 +52365,19 @@ else { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.DISTRIBUTIONS_ONLY_MAJOR_VERSION = exports.INPUT_MVN_TOOLCHAIN_VENDOR = exports.INPUT_MVN_TOOLCHAIN_ID = exports.MVN_TOOLCHAINS_FILE = exports.MVN_SETTINGS_FILE = exports.M2_DIR = exports.STATE_GPG_PRIVATE_KEY_FINGERPRINT = exports.INPUT_JOB_STATUS = exports.INPUT_CACHE_DEPENDENCY_PATH = exports.INPUT_CACHE = exports.INPUT_DEFAULT_GPG_PASSPHRASE = exports.INPUT_DEFAULT_GPG_PRIVATE_KEY = exports.INPUT_GPG_PASSPHRASE = exports.INPUT_GPG_PRIVATE_KEY = exports.INPUT_OVERWRITE_SETTINGS = exports.INPUT_SETTINGS_PATH = exports.INPUT_SERVER_PASSWORD = exports.INPUT_SERVER_USERNAME = exports.INPUT_SERVER_ID = exports.INPUT_CHECK_LATEST = exports.INPUT_JDK_FILE = exports.INPUT_DISTRIBUTION = exports.INPUT_JAVA_PACKAGE = exports.INPUT_ARCHITECTURE = exports.INPUT_JAVA_VERSION_FILE = exports.INPUT_JAVA_VERSION = exports.MACOS_JAVA_CONTENT_POSTFIX = void 0; +exports.DISTRIBUTIONS_ONLY_MAJOR_VERSION = exports.MAVEN_NO_TRANSFER_PROGRESS_LONG_FLAG = exports.MAVEN_NO_TRANSFER_PROGRESS_FLAG = exports.MAVEN_ARGS_ENV = exports.INPUT_SHOW_DOWNLOAD_PROGRESS = exports.INPUT_MVN_TOOLCHAIN_VENDOR = exports.INPUT_MVN_TOOLCHAIN_ID = exports.MVN_TOOLCHAINS_FILE = exports.MVN_SETTINGS_FILE = exports.M2_DIR = exports.STATE_GPG_PRIVATE_KEY_FINGERPRINT = exports.INPUT_JOB_STATUS = exports.INPUT_CACHE_DEPENDENCY_PATH = exports.INPUT_CACHE = exports.INPUT_DEFAULT_GPG_PASSPHRASE = exports.INPUT_DEFAULT_GPG_PRIVATE_KEY = exports.INPUT_GPG_PASSPHRASE = exports.INPUT_GPG_PRIVATE_KEY = exports.INPUT_OVERWRITE_SETTINGS = exports.INPUT_SETTINGS_PATH = exports.INPUT_SERVER_PASSWORD = exports.INPUT_SERVER_USERNAME = exports.INPUT_SERVER_ID = exports.INPUT_VERIFY_SIGNATURE_PUBLIC_KEY = exports.INPUT_VERIFY_SIGNATURE = exports.INPUT_SET_DEFAULT = exports.INPUT_CHECK_LATEST = exports.INPUT_JDK_FILE_DEPRECATED = exports.INPUT_JDK_FILE = exports.INPUT_DISTRIBUTION = exports.INPUT_JAVA_PACKAGE = exports.INPUT_ARCHITECTURE = exports.INPUT_JAVA_VERSION_FILE = exports.INPUT_JAVA_VERSION = exports.MACOS_JAVA_CONTENT_POSTFIX = void 0; exports.MACOS_JAVA_CONTENT_POSTFIX = 'Contents/Home'; exports.INPUT_JAVA_VERSION = 'java-version'; exports.INPUT_JAVA_VERSION_FILE = 'java-version-file'; exports.INPUT_ARCHITECTURE = 'architecture'; exports.INPUT_JAVA_PACKAGE = 'java-package'; exports.INPUT_DISTRIBUTION = 'distribution'; -exports.INPUT_JDK_FILE = 'jdkFile'; +exports.INPUT_JDK_FILE = 'jdk-file'; +exports.INPUT_JDK_FILE_DEPRECATED = 'jdkFile'; exports.INPUT_CHECK_LATEST = 'check-latest'; +exports.INPUT_SET_DEFAULT = 'set-default'; +exports.INPUT_VERIFY_SIGNATURE = 'verify-signature'; +exports.INPUT_VERIFY_SIGNATURE_PUBLIC_KEY = 'verify-signature-public-key'; exports.INPUT_SERVER_ID = 'server-id'; exports.INPUT_SERVER_USERNAME = 'server-username'; exports.INPUT_SERVER_PASSWORD = 'server-password'; @@ -52002,6 +52396,10 @@ exports.MVN_SETTINGS_FILE = 'settings.xml'; exports.MVN_TOOLCHAINS_FILE = 'toolchains.xml'; exports.INPUT_MVN_TOOLCHAIN_ID = 'mvn-toolchain-id'; exports.INPUT_MVN_TOOLCHAIN_VENDOR = 'mvn-toolchain-vendor'; +exports.INPUT_SHOW_DOWNLOAD_PROGRESS = 'show-download-progress'; +exports.MAVEN_ARGS_ENV = 'MAVEN_ARGS'; +exports.MAVEN_NO_TRANSFER_PROGRESS_FLAG = '-ntp'; +exports.MAVEN_NO_TRANSFER_PROGRESS_LONG_FLAG = '--no-transfer-progress'; exports.DISTRIBUTIONS_ONLY_MAJOR_VERSION = ['corretto']; @@ -52045,14 +52443,27 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge }); }; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.deleteKey = exports.importKey = exports.PRIVATE_KEY_FILE = void 0; +exports.verifyPackageSignature = exports.deleteKey = exports.importKey = exports.toGpgPath = exports.PRIVATE_KEY_FILE = void 0; const fs = __importStar(__nccwpck_require__(79896)); const path = __importStar(__nccwpck_require__(16928)); const io = __importStar(__nccwpck_require__(94994)); const exec = __importStar(__nccwpck_require__(95236)); +const tc = __importStar(__nccwpck_require__(33472)); const util = __importStar(__nccwpck_require__(54527)); exports.PRIVATE_KEY_FILE = path.join(util.getTempDir(), 'private-key.asc'); const PRIVATE_KEY_FINGERPRINT_REGEX = /\w{40}/; +// Convert a Windows path (D:\a\_temp\...) to a POSIX path (/d/a/_temp/...). +// The Git-bundled GPG on Windows (MSYS2-based) uses POSIX path conventions +// internally. Passing Windows paths with backslashes can cause fatal GPG errors +// (exit code 2), so all paths passed to GPG must be in POSIX format on Windows. +function toGpgPath(p) { + if (process.platform !== 'win32') + return p; + return p + .replace(/\\/g, '/') + .replace(/^([A-Za-z]):\//, (_, drive) => `/${drive.toLowerCase()}/`); +} +exports.toGpgPath = toGpgPath; function importKey(privateKey) { return __awaiter(this, void 0, void 0, function* () { fs.writeFileSync(exports.PRIVATE_KEY_FILE, privateKey, { @@ -52089,6 +52500,49 @@ function deleteKey(keyFingerprint) { }); } exports.deleteKey = deleteKey; +function verifyPackageSignature(archivePath, signatureUrl, publicKeyContent) { + return __awaiter(this, void 0, void 0, function* () { + const signaturePath = yield tc.downloadTool(signatureUrl); + let gpgHome; + try { + gpgHome = fs.mkdtempSync(path.join(util.getTempDir(), 'verify-signature-gpg-home-')); + } + catch (error) { + try { + yield io.rmRF(signaturePath); + } + catch (_a) { + // ignore cleanup failures + } + throw new Error(`Failed to create temporary GPG home directory for signature verification: ${error.message}`); + } + try { + const publicKeyFile = path.join(gpgHome, 'public-key.asc'); + fs.writeFileSync(publicKeyFile, publicKeyContent, { encoding: 'utf-8' }); + const options = { silent: true }; + yield exec.exec('gpg', [ + '--homedir', + toGpgPath(gpgHome), + '--batch', + '--import', + toGpgPath(publicKeyFile) + ], options); + yield exec.exec('gpg', [ + '--homedir', + toGpgPath(gpgHome), + '--batch', + '--verify', + toGpgPath(signaturePath), + toGpgPath(archivePath) + ], options); + } + finally { + yield io.rmRF(signaturePath); + yield io.rmRF(gpgHome); + } + }); +} +exports.verifyPackageSignature = verifyPackageSignature; /***/ }), @@ -52187,6 +52641,13 @@ function getDownloadArchiveExtension() { exports.getDownloadArchiveExtension = getDownloadArchiveExtension; function isVersionSatisfies(range, version) { var _a; + // Some distributions (e.g. JetBrains Runtime) publish 4-segment versions + // like '17.0.8.1+1080.1' that semver rejects. If the candidate version + // isn't valid semver, it can't match — bail out rather than letting + // compareBuild / satisfies throw. + if (!semver.valid(version)) { + return false; + } if (semver.valid(range)) { // if full version with build digit is provided as a range (such as '1.2.3+4') // we should check for exact equal via compareBuild @@ -52236,25 +52697,45 @@ function isCacheFeatureAvailable() { } exports.isCacheFeatureAvailable = isCacheFeatureAvailable; function getVersionFromFileContent(content, distributionName, versionFile) { - var _a, _b, _c, _d, _e; + var _a, _b, _c, _d; let javaVersionRegExp; + let extractedDistribution; function getFileName(versionFile) { return path_1.default.basename(versionFile); } const versionFileName = getFileName(versionFile); if (versionFileName == '.tool-versions') { + // Capture an optional asdf-java vendor prefix (e.g. `temurin-`, `corretto-`) + // in the `distribution` group so it can be mapped to a setup-java distribution. javaVersionRegExp = - /^java\s+(?:\S*-)?(?\d+(?:\.\d+)*([+_.-](?:openj9[-._]?\d[\w.-]*|java\d+|jre[-_\w]*|OpenJDK\d+[\w_.-]*|[a-z0-9]+))*)/im; + /^java\s+(?:(?\S*)-)?(?\d+(?:\.\d+)*([+_.-](?:openj9[-._]?\d[\w.-]*|java\d+|jre[-_\w]*|OpenJDK\d+[\w_.-]*|[a-z0-9]+))*)/im; } else if (versionFileName == '.sdkmanrc') { - javaVersionRegExp = /^java\s*=\s*(?[^-]+)/m; + // Match both version and optional distribution identifier + javaVersionRegExp = + /^java\s*=\s*(?[^-\s]+)(?:-(?[a-z0-9]+))?/m; } else { javaVersionRegExp = /(?(?<=(^|\s|-))(\d+\S*))(\s|$)/; } - const capturedVersion = ((_b = (_a = content.match(javaVersionRegExp)) === null || _a === void 0 ? void 0 : _a.groups) === null || _b === void 0 ? void 0 : _b.version) - ? (_d = (_c = content.match(javaVersionRegExp)) === null || _c === void 0 ? void 0 : _c.groups) === null || _d === void 0 ? void 0 : _d.version + const match = content.match(javaVersionRegExp); + const capturedVersion = ((_a = match === null || match === void 0 ? void 0 : match.groups) === null || _a === void 0 ? void 0 : _a.version) + ? match.groups.version : ''; + // Extract distribution from .sdkmanrc file + if (versionFileName == '.sdkmanrc' && ((_b = match === null || match === void 0 ? void 0 : match.groups) === null || _b === void 0 ? void 0 : _b.distribution)) { + const sdkmanDist = match.groups.distribution; + extractedDistribution = mapSdkmanDistribution(sdkmanDist); + core.debug(`Parsed distribution '${extractedDistribution}' from SDKMAN identifier '${sdkmanDist}'`); + } + // Extract distribution from asdf .tool-versions file + if (versionFileName == '.tool-versions' && ((_c = match === null || match === void 0 ? void 0 : match.groups) === null || _c === void 0 ? void 0 : _c.distribution)) { + const asdfDist = match.groups.distribution; + extractedDistribution = mapAsdfDistribution(asdfDist); + if (extractedDistribution) { + core.debug(`Parsed distribution '${extractedDistribution}' from asdf identifier '${asdfDist}'`); + } + } core.debug(`Parsed version '${capturedVersion}' from file '${versionFileName}'`); if (!capturedVersion) { return null; @@ -52268,13 +52749,79 @@ function getVersionFromFileContent(content, distributionName, versionFile) { if (!version) { return null; } - if (constants_1.DISTRIBUTIONS_ONLY_MAJOR_VERSION.includes(distributionName)) { - const coerceVersion = (_e = semver.coerce(version)) !== null && _e !== void 0 ? _e : version; + // Apply DISTRIBUTIONS_ONLY_MAJOR_VERSION logic whenever the effective distribution + // (either explicitly provided or extracted from the version file) is in the list. + if (constants_1.DISTRIBUTIONS_ONLY_MAJOR_VERSION.includes(extractedDistribution || distributionName)) { + const coerceVersion = (_d = semver.coerce(version)) !== null && _d !== void 0 ? _d : version; version = semver.major(coerceVersion).toString(); } - return version.toString(); + return { + version: version.toString(), + distribution: extractedDistribution + }; } exports.getVersionFromFileContent = getVersionFromFileContent; +// Map SDKMAN distribution identifiers to setup-java distribution names +function mapSdkmanDistribution(sdkmanDist) { + const distributionMap = { + tem: 'temurin', + sem: 'semeru', + albba: 'dragonwell', + zulu: 'zulu', + amzn: 'corretto', + graal: 'graalvm', + graalce: 'graalvm', + librca: 'liberica', + ms: 'microsoft', + oracle: 'oracle', + sapmchn: 'sapmachine', + jbr: 'jetbrains', + dragonwell: 'dragonwell', + kona: 'kona' + }; + const mapped = distributionMap[sdkmanDist.toLowerCase()]; + if (!mapped) { + core.warning(`Unknown SDKMAN distribution identifier '${sdkmanDist}'. Please specify the distribution explicitly.`); + } + return mapped; +} +// Map asdf-java (.tool-versions) vendor identifiers to setup-java distribution names. +// asdf-java encodes the vendor as a prefix on the version string, e.g. +// `java temurin-17.0.3+7` or `java semeru-openj9-11.0.25+9`. Packaging variants +// (`-jre`, `-musl`, `-openj9`, `-crac`, `-javafx`, ...) are collapsed onto the +// base vendor since setup-java does not distinguish them here. +function mapAsdfDistribution(asdfDist) { + const normalized = asdfDist.toLowerCase(); + // Multi-segment vendors that map to a distinct setup-java distribution. + if (normalized.startsWith('graalvm-community')) { + return 'graalvm-community'; + } + if (normalized.startsWith('oracle-graalvm')) { + return 'graalvm'; + } + const baseVendor = normalized.split('-')[0]; + const distributionMap = { + temurin: 'temurin', + adoptopenjdk: 'temurin', + zulu: 'zulu', + corretto: 'corretto', + liberica: 'liberica', + microsoft: 'microsoft', + semeru: 'semeru', + ibm: 'semeru', + dragonwell: 'dragonwell', + graalvm: 'graalvm', + oracle: 'oracle', + sapmachine: 'sapmachine', + kona: 'kona', + jetbrains: 'jetbrains' + }; + const mapped = distributionMap[baseVendor]; + if (!mapped) { + core.warning(`Unknown asdf distribution identifier '${asdfDist}'. Please specify the distribution explicitly.`); + } + return mapped; +} // By convention, action expects version 8 in the format `8.*` instead of `1.8` function avoidOldNotation(content) { return content.startsWith('1.') ? content.substring(2) : content; @@ -93780,7 +94327,7 @@ function randomUUID() { /***/ ((module) => { "use strict"; -module.exports = /*#__PURE__*/JSON.parse('{"name":"@actions/cache","version":"5.0.5","preview":true,"description":"Actions cache lib","keywords":["github","actions","cache"],"homepage":"https://github.com/actions/toolkit/tree/main/packages/cache","license":"MIT","main":"lib/cache.js","types":"lib/cache.d.ts","directories":{"lib":"lib","test":"__tests__"},"files":["lib","!.DS_Store"],"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/actions/toolkit.git","directory":"packages/cache"},"scripts":{"audit-moderate":"npm install && npm audit --json --audit-level=moderate > audit.json","test":"echo \\"Error: run tests from root\\" && exit 1","tsc":"tsc"},"bugs":{"url":"https://github.com/actions/toolkit/issues"},"dependencies":{"@actions/core":"^2.0.0","@actions/exec":"^2.0.0","@actions/glob":"^0.5.1","@protobuf-ts/runtime-rpc":"^2.11.1","@actions/http-client":"^3.0.2","@actions/io":"^2.0.0","@azure/abort-controller":"^1.1.0","@azure/core-rest-pipeline":"^1.22.0","@azure/storage-blob":"^12.29.1","semver":"^6.3.1"},"devDependencies":{"@types/node":"^24.1.0","@types/semver":"^6.0.0","@protobuf-ts/plugin":"^2.9.4","typescript":"^5.2.2"},"overrides":{"uri-js":"npm:uri-js-replace@^1.0.1","node-fetch":"^3.3.2"}}'); +module.exports = /*#__PURE__*/JSON.parse('{"name":"@actions/cache","version":"5.1.0","preview":true,"description":"Actions cache lib","keywords":["github","actions","cache"],"homepage":"https://github.com/actions/toolkit/tree/main/packages/cache","license":"MIT","main":"lib/cache.js","types":"lib/cache.d.ts","directories":{"lib":"lib","test":"__tests__"},"files":["lib","!.DS_Store"],"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/actions/toolkit.git","directory":"packages/cache"},"scripts":{"audit-moderate":"npm install && npm audit --json --audit-level=moderate > audit.json","test":"echo \\"Error: run tests from root\\" && exit 1","tsc":"tsc"},"bugs":{"url":"https://github.com/actions/toolkit/issues"},"dependencies":{"@actions/core":"^2.0.0","@actions/exec":"^2.0.0","@actions/glob":"^0.5.1","@protobuf-ts/runtime-rpc":"^2.11.1","@actions/http-client":"^3.0.2","@actions/io":"^2.0.0","@azure/abort-controller":"^1.1.0","@azure/core-rest-pipeline":"^1.22.0","@azure/storage-blob":"^12.29.1","semver":"^6.3.1"},"devDependencies":{"@types/node":"^24.1.0","@types/semver":"^6.0.0","@protobuf-ts/plugin":"^2.9.4","typescript":"^5.2.2"},"overrides":{"uri-js":"npm:uri-js-replace@^1.0.1","node-fetch":"^3.3.2"}}'); /***/ }) diff --git a/dist/setup/index.js b/dist/setup/index.js index 7a6cdebb4..d4b76ff92 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -49,7 +49,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge }); }; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.FinalizeCacheError = exports.ReserveCacheError = exports.ValidationError = void 0; +exports.FinalizeCacheError = exports.CacheWriteDeniedError = exports.CACHE_WRITE_DENIED_PREFIX = exports.ReserveCacheError = exports.ValidationError = void 0; exports.isFeatureAvailable = isFeatureAvailable; exports.restoreCache = restoreCache; exports.saveCache = saveCache; @@ -77,6 +77,26 @@ class ReserveCacheError extends Error { } } exports.ReserveCacheError = ReserveCacheError; +/** + * Stable prefix used by the cache receiver to signal that the token has + * no writable scopes (read-only cache policy). Consumers can match on + * this prefix to distinguish policy denials from ordinary contention. + */ +exports.CACHE_WRITE_DENIED_PREFIX = 'cache write denied:'; +/** + * Extends ReserveCacheError for source-compatibility: existing + * `instanceof ReserveCacheError` checks and `typedError.name === + * ReserveCacheError.name` paths keep working, while consumers that want to + * distinguish a policy denial can check for CacheWriteDeniedError.name. + */ +class CacheWriteDeniedError extends ReserveCacheError { + constructor(message) { + super(message); + this.name = 'CacheWriteDeniedError'; + Object.setPrototypeOf(this, CacheWriteDeniedError.prototype); + } +} +exports.CacheWriteDeniedError = CacheWriteDeniedError; class FinalizeCacheError extends Error { constructor(message) { super(message); @@ -387,7 +407,11 @@ function saveCacheV1(paths_1, key_1, options_1) { throw new Error((_d = (_c = reserveCacheResponse === null || reserveCacheResponse === void 0 ? void 0 : reserveCacheResponse.error) === null || _c === void 0 ? void 0 : _c.message) !== null && _d !== void 0 ? _d : `Cache size of ~${Math.round(archiveFileSize / (1024 * 1024))} MB (${archiveFileSize} B) is over the data cap limit, not saving cache.`); } else { - throw new ReserveCacheError(`Unable to reserve cache with key ${key}, another job may be creating this cache. More details: ${(_e = reserveCacheResponse === null || reserveCacheResponse === void 0 ? void 0 : reserveCacheResponse.error) === null || _e === void 0 ? void 0 : _e.message}`); + const detailMessage = (_e = reserveCacheResponse === null || reserveCacheResponse === void 0 ? void 0 : reserveCacheResponse.error) === null || _e === void 0 ? void 0 : _e.message; + if (detailMessage === null || detailMessage === void 0 ? void 0 : detailMessage.startsWith(exports.CACHE_WRITE_DENIED_PREFIX)) { + throw new CacheWriteDeniedError(`Unable to reserve cache with key ${key}. More details: ${detailMessage}`); + } + throw new ReserveCacheError(`Unable to reserve cache with key ${key}, another job may be creating this cache. More details: ${detailMessage}`); } core.debug(`Saving Cache (ID: ${cacheId})`); yield cacheHttpClient.saveCache(cacheId, archivePath, '', options); @@ -397,6 +421,9 @@ function saveCacheV1(paths_1, key_1, options_1) { if (typedError.name === ValidationError.name) { throw error; } + else if (typedError.name === CacheWriteDeniedError.name) { + core.warning(`Failed to save: ${typedError.message}`); + } else if (typedError.name === ReserveCacheError.name) { core.info(`Failed to save: ${typedError.message}`); } @@ -435,6 +462,7 @@ function saveCacheV1(paths_1, key_1, options_1) { */ function saveCacheV2(paths_1, key_1, options_1) { return __awaiter(this, arguments, void 0, function* (paths, key, options, enableCrossOsArchive = false) { + var _a; // Override UploadOptions to force the use of Azure // ...options goes first because we want to override the default values // set in UploadOptions with these specific figures @@ -470,7 +498,11 @@ function saveCacheV2(paths_1, key_1, options_1) { try { const response = yield twirpClient.CreateCacheEntry(request); if (!response.ok) { - if (response.message) { + // Skip the redundant inner warning when the receiver signalled a + // policy denial: the outer catch arm below will log a single + // customer-facing warning. + if (response.message && + !response.message.startsWith(exports.CACHE_WRITE_DENIED_PREFIX)) { core.warning(`Cache reservation failed: ${response.message}`); } throw new Error(response.message || 'Response was not ok'); @@ -479,6 +511,10 @@ function saveCacheV2(paths_1, key_1, options_1) { } catch (error) { core.debug(`Failed to reserve cache: ${error}`); + const errorMessage = (_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : ''; + if (errorMessage.startsWith(exports.CACHE_WRITE_DENIED_PREFIX)) { + throw new CacheWriteDeniedError(`Unable to reserve cache with key ${key}. More details: ${errorMessage}`); + } throw new ReserveCacheError(`Unable to reserve cache with key ${key}, another job may be creating this cache.`); } core.debug(`Attempting to upload cache located at: ${archivePath}`); @@ -503,6 +539,9 @@ function saveCacheV2(paths_1, key_1, options_1) { if (typedError.name === ValidationError.name) { throw error; } + else if (typedError.name === CacheWriteDeniedError.name) { + core.warning(`Failed to save: ${typedError.message}`); + } else if (typedError.name === ReserveCacheError.name) { core.info(`Failed to save: ${typedError.message}`); } @@ -39730,14 +39769,17 @@ function useColors() { return false; } + let m; + // Is webkit? http://stackoverflow.com/a/16459606/376773 // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 + // eslint-disable-next-line no-return-assign return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) || // Is firebug? http://stackoverflow.com/a/398120/376773 (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) || // Is firefox >= v31? // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages - (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) || + (typeof navigator !== 'undefined' && navigator.userAgent && (m = navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)) && parseInt(m[1], 10) >= 31) || // Double check webkit in userAgent just in case we are in a worker (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)); } @@ -39821,7 +39863,7 @@ function save(namespaces) { function load() { let r; try { - r = exports.storage.getItem('debug'); + r = exports.storage.getItem('debug') || exports.storage.getItem('DEBUG') ; } catch (error) { // Swallow // XXX (@Qix-) should we be logging these? @@ -40047,24 +40089,62 @@ function setup(env) { createDebug.names = []; createDebug.skips = []; - let i; - const split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/); - const len = split.length; + const split = (typeof namespaces === 'string' ? namespaces : '') + .trim() + .replace(/\s+/g, ',') + .split(',') + .filter(Boolean); - for (i = 0; i < len; i++) { - if (!split[i]) { - // ignore empty strings - continue; + for (const ns of split) { + if (ns[0] === '-') { + createDebug.skips.push(ns.slice(1)); + } else { + createDebug.names.push(ns); } + } + } - namespaces = split[i].replace(/\*/g, '.*?'); - - if (namespaces[0] === '-') { - createDebug.skips.push(new RegExp('^' + namespaces.slice(1) + '$')); + /** + * Checks if the given string matches a namespace template, honoring + * asterisks as wildcards. + * + * @param {String} search + * @param {String} template + * @return {Boolean} + */ + function matchesTemplate(search, template) { + let searchIndex = 0; + let templateIndex = 0; + let starIndex = -1; + let matchIndex = 0; + + while (searchIndex < search.length) { + if (templateIndex < template.length && (template[templateIndex] === search[searchIndex] || template[templateIndex] === '*')) { + // Match character or proceed with wildcard + if (template[templateIndex] === '*') { + starIndex = templateIndex; + matchIndex = searchIndex; + templateIndex++; // Skip the '*' + } else { + searchIndex++; + templateIndex++; + } + } else if (starIndex !== -1) { // eslint-disable-line no-negated-condition + // Backtrack to the last '*' and try to match more characters + templateIndex = starIndex + 1; + matchIndex++; + searchIndex = matchIndex; } else { - createDebug.names.push(new RegExp('^' + namespaces + '$')); + return false; // No match } } + + // Handle trailing '*' in template + while (templateIndex < template.length && template[templateIndex] === '*') { + templateIndex++; + } + + return templateIndex === template.length; } /** @@ -40075,8 +40155,8 @@ function setup(env) { */ function disable() { const namespaces = [ - ...createDebug.names.map(toNamespace), - ...createDebug.skips.map(toNamespace).map(namespace => '-' + namespace) + ...createDebug.names, + ...createDebug.skips.map(namespace => '-' + namespace) ].join(','); createDebug.enable(''); return namespaces; @@ -40090,21 +40170,14 @@ function setup(env) { * @api public */ function enabled(name) { - if (name[name.length - 1] === '*') { - return true; - } - - let i; - let len; - - for (i = 0, len = createDebug.skips.length; i < len; i++) { - if (createDebug.skips[i].test(name)) { + for (const skip of createDebug.skips) { + if (matchesTemplate(name, skip)) { return false; } } - for (i = 0, len = createDebug.names.length; i < len; i++) { - if (createDebug.names[i].test(name)) { + for (const ns of createDebug.names) { + if (matchesTemplate(name, ns)) { return true; } } @@ -40112,19 +40185,6 @@ function setup(env) { return false; } - /** - * Convert regexp to namespace - * - * @param {RegExp} regxep - * @return {String} namespace - * @api private - */ - function toNamespace(regexp) { - return regexp.toString() - .substring(2, regexp.toString().length - 2) - .replace(/\.\*\?$/, '*'); - } - /** * Coerce `val`. * @@ -40366,11 +40426,11 @@ function getDate() { } /** - * Invokes `util.format()` with the specified arguments and writes to stderr. + * Invokes `util.formatWithOptions()` with the specified arguments and writes to stderr. */ function log(...args) { - return process.stderr.write(util.format(...args) + '\n'); + return process.stderr.write(util.formatWithOptions(exports.inspectOpts, ...args) + '\n'); } /** @@ -46064,7 +46124,7 @@ var y = d * 365.25; * @api public */ -module.exports = function(val, options) { +module.exports = function (val, options) { options = options || {}; var type = typeof val; if (type === 'string' && val.length > 0) { @@ -54003,8 +54063,6 @@ function defaultFactory (origin, opts) { class Agent extends DispatcherBase { constructor ({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) { - super() - if (typeof factory !== 'function') { throw new InvalidArgumentError('factory must be a function.') } @@ -54017,6 +54075,8 @@ class Agent extends DispatcherBase { throw new InvalidArgumentError('maxRedirections must be a positive number') } + super(options) + if (connect && typeof connect !== 'function') { connect = { ...connect } } @@ -54390,6 +54450,9 @@ const EMPTY_BUF = Buffer.alloc(0) const FastBuffer = Buffer[Symbol.species] const addListener = util.addListener const removeAllListeners = util.removeAllListeners +const kIdleSocketValidation = Symbol('kIdleSocketValidation') +const kIdleSocketValidationTimeout = Symbol('kIdleSocketValidationTimeout') +const kSocketUsed = Symbol('kSocketUsed') let extractBody @@ -54612,29 +54675,71 @@ class Parser { const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr - if (ret === constants.ERROR.PAUSED_UPGRADE) { - this.onUpgrade(data.slice(offset)) - } else if (ret === constants.ERROR.PAUSED) { - this.paused = true - socket.unshift(data.slice(offset)) - } else if (ret !== constants.ERROR.OK) { - const ptr = llhttp.llhttp_get_error_reason(this.ptr) - let message = '' - /* istanbul ignore else: difficult to make a test case for */ - if (ptr) { - const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0) - message = - 'Response does not match the HTTP/1.1 protocol (' + - Buffer.from(llhttp.memory.buffer, ptr, len).toString() + - ')' - } - throw new HTTPParserError(message, constants.ERROR[ret], data.slice(offset)) + if (ret !== constants.ERROR.OK) { + const body = data.subarray(offset) + + if (ret === constants.ERROR.PAUSED_UPGRADE) { + this.onUpgrade(body) + } else if (ret === constants.ERROR.PAUSED) { + this.paused = true + socket.unshift(body) + } else { + throw this.createError(ret, body) + } } } catch (err) { util.destroy(socket, err) } } + finish () { + assert(currentParser === null) + assert(this.ptr != null) + assert(!this.paused) + + const { llhttp } = this + + let ret + + try { + currentParser = this + ret = llhttp.llhttp_finish(this.ptr) + } finally { + currentParser = null + } + + if (ret === constants.ERROR.OK) { + return null + } + + if (ret === constants.ERROR.PAUSED || ret === constants.ERROR.PAUSED_UPGRADE) { + this.paused = true + return null + } + + return this.createError(ret, EMPTY_BUF) + } + + createError (ret, data) { + const { llhttp, contentLength, bytesRead } = this + + if (contentLength && bytesRead !== parseInt(contentLength, 10)) { + return new ResponseContentLengthMismatchError() + } + + const ptr = llhttp.llhttp_get_error_reason(this.ptr) + let message = '' + if (ptr) { + const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0) + message = + 'Response does not match the HTTP/1.1 protocol (' + + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + + ')' + } + + return new HTTPParserError(message, constants.ERROR[ret], data) + } + destroy () { assert(this.ptr != null) assert(currentParser == null) @@ -54662,6 +54767,11 @@ class Parser { return -1 } + if (client[kRunning] === 0) { + util.destroy(socket, new SocketError('bad response', util.getSocketInfo(socket))) + return -1 + } + const request = client[kQueue][client[kRunningIdx]] if (!request) { return -1 @@ -54765,6 +54875,11 @@ class Parser { return -1 } + if (client[kRunning] === 0) { + util.destroy(socket, new SocketError('bad response', util.getSocketInfo(socket))) + return -1 + } + const request = client[kQueue][client[kRunningIdx]] /* istanbul ignore next: difficult to make a test case for */ @@ -54938,6 +55053,7 @@ class Parser { request.onComplete(headers) client[kQueue][client[kRunningIdx]++] = null + socket[kSocketUsed] = true if (socket[kWriting]) { assert(client[kRunning] === 0) @@ -54996,6 +55112,9 @@ async function connectH1 (client, socket) { socket[kWriting] = false socket[kReset] = false socket[kBlocking] = false + socket[kIdleSocketValidation] = 0 + socket[kIdleSocketValidationTimeout] = null + socket[kSocketUsed] = false socket[kParser] = new Parser(client, socket, llhttpInstance) addListener(socket, 'error', function (err) { @@ -55006,8 +55125,11 @@ async function connectH1 (client, socket) { // On Mac OS, we get an ECONNRESET even if there is a full body to be forwarded // to the user. if (err.code === 'ECONNRESET' && parser.statusCode && !parser.shouldKeepAlive) { - // We treat all incoming data so for as a valid response. - parser.onMessageComplete() + const parserErr = parser.finish() + if (parserErr) { + this[kError] = parserErr + this[kClient][kOnError](parserErr) + } return } @@ -55026,8 +55148,10 @@ async function connectH1 (client, socket) { const parser = this[kParser] if (parser.statusCode && !parser.shouldKeepAlive) { - // We treat all incoming data so far as a valid response. - parser.onMessageComplete() + const parserErr = parser.finish() + if (parserErr) { + util.destroy(this, parserErr) + } return } @@ -55037,10 +55161,11 @@ async function connectH1 (client, socket) { const client = this[kClient] const parser = this[kParser] + clearIdleSocketValidation(this) + if (parser) { if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) { - // We treat all incoming data so far as a valid response. - parser.onMessageComplete() + this[kError] = parser.finish() || this[kError] } this[kParser].destroy() @@ -55103,7 +55228,7 @@ async function connectH1 (client, socket) { return socket.destroyed }, busy (request) { - if (socket[kWriting] || socket[kReset] || socket[kBlocking]) { + if (socket[kWriting] || socket[kReset] || socket[kBlocking] || socket[kIdleSocketValidation] === 1) { return true } @@ -55141,6 +55266,31 @@ async function connectH1 (client, socket) { } } +function clearIdleSocketValidation (socket) { + if (socket[kIdleSocketValidationTimeout]) { + clearTimeout(socket[kIdleSocketValidationTimeout]) + socket[kIdleSocketValidationTimeout] = null + } + + socket[kIdleSocketValidation] = 0 +} + +function scheduleIdleSocketValidation (client, socket) { + socket[kIdleSocketValidation] = 1 + socket[kIdleSocketValidationTimeout] = setTimeout(() => { + socket[kIdleSocketValidationTimeout] = null + socket[kIdleSocketValidation] = 2 + + if (client[kSocket] === socket && !socket.destroyed) { + client[kResume]() + } + }, 0) + socket[kIdleSocketValidationTimeout].unref?.() +} + +/** + * @param {import('./client.js')} client + */ function resumeH1 (client) { const socket = client[kSocket] @@ -55155,6 +55305,32 @@ function resumeH1 (client) { socket[kNoRef] = false } + if (client[kRunning] === 0 && client[kPending] > 0 && socket[kSocketUsed]) { + if (socket[kIdleSocketValidation] === 0) { + scheduleIdleSocketValidation(client, socket) + socket[kParser].readMore() + if (socket.destroyed) { + return + } + return + } + + if (socket[kIdleSocketValidation] === 1) { + socket[kParser].readMore() + if (socket.destroyed) { + return + } + return + } + } + + if (client[kRunning] === 0) { + socket[kParser].readMore() + if (socket.destroyed) { + return + } + } + if (client[kSize] === 0) { if (socket[kParser].timeoutType !== TIMEOUT_KEEP_ALIVE) { socket[kParser].setTimeout(client[kKeepAliveTimeoutValue], TIMEOUT_KEEP_ALIVE) @@ -55248,6 +55424,7 @@ function writeH1 (client, request) { } const socket = client[kSocket] + clearIdleSocketValidation(socket) const abort = (err) => { if (request.aborted || request.completed) { @@ -56569,9 +56746,10 @@ class Client extends DispatcherBase { autoSelectFamilyAttemptTimeout, // h2 maxConcurrentStreams, - allowH2 + allowH2, + webSocket } = {}) { - super() + super({ webSocket }) if (keepAlive !== undefined) { throw new InvalidArgumentError('unsupported keepAlive, use pipelining=0 instead') @@ -57104,15 +57282,24 @@ const { kDestroy, kClose, kClosed, kDestroyed, kDispatch, kInterceptors } = __nc const kOnDestroyed = Symbol('onDestroyed') const kOnClosed = Symbol('onClosed') const kInterceptedDispatch = Symbol('Intercepted Dispatch') +const kWebSocketOptions = Symbol('webSocketOptions') class DispatcherBase extends Dispatcher { - constructor () { + constructor (opts) { super() this[kDestroyed] = false this[kOnDestroyed] = null this[kClosed] = false this[kOnClosed] = [] + this[kWebSocketOptions] = opts?.webSocket ?? {} + } + + get webSocketOptions () { + return { + maxFragments: this[kWebSocketOptions].maxFragments ?? 131072, + maxPayloadSize: this[kWebSocketOptions].maxPayloadSize ?? 128 * 1024 * 1024 + } } get destroyed () { @@ -57676,8 +57863,8 @@ const kRemoveClient = Symbol('remove client') const kStats = Symbol('stats') class PoolBase extends DispatcherBase { - constructor () { - super() + constructor (opts) { + super(opts) this[kQueue] = new FixedQueue() this[kClients] = [] @@ -57937,8 +58124,6 @@ class Pool extends PoolBase { allowH2, ...options } = {}) { - super() - if (connections != null && (!Number.isFinite(connections) || connections < 0)) { throw new InvalidArgumentError('invalid connections') } @@ -57963,6 +58148,8 @@ class Pool extends PoolBase { }) } + super(options) + this[kInterceptors] = options.interceptors?.Pool && Array.isArray(options.interceptors.Pool) ? options.interceptors.Pool : [] @@ -63047,32 +63234,25 @@ function parseUnparsedAttributes (unparsedAttributes, cookieAttributeList = {}) // If the attribute-name case-insensitively matches the string // "SameSite", the user agent MUST process the cookie-av as follows: - // 1. Let enforcement be "Default". - let enforcement = 'Default' - const attributeValueLowercase = attributeValue.toLowerCase() - // 2. If cookie-av's attribute-value is a case-insensitive match for - // "None", set enforcement to "None". - if (attributeValueLowercase.includes('none')) { - enforcement = 'None' - } - // 3. If cookie-av's attribute-value is a case-insensitive match for - // "Strict", set enforcement to "Strict". - if (attributeValueLowercase.includes('strict')) { - enforcement = 'Strict' + // 1. If cookie-av's attribute-value is a case-insensitive match for + // "None", append an attribute to the cookie-attribute-list with an + // attribute-name of "SameSite" and an attribute-value of "None". + if (attributeValueLowercase === 'none') { + cookieAttributeList.sameSite = 'None' + } else if (attributeValueLowercase === 'strict') { + // 2. If cookie-av's attribute-value is a case-insensitive match for + // "Strict", append an attribute to the cookie-attribute-list with + // an attribute-name of "SameSite" and an attribute-value of + // "Strict". + cookieAttributeList.sameSite = 'Strict' + } else if (attributeValueLowercase === 'lax') { + // 3. If cookie-av's attribute-value is a case-insensitive match for + // "Lax", append an attribute to the cookie-attribute-list with an + // attribute-name of "SameSite" and an attribute-value of "Lax". + cookieAttributeList.sameSite = 'Lax' } - - // 4. If cookie-av's attribute-value is a case-insensitive match for - // "Lax", set enforcement to "Lax". - if (attributeValueLowercase.includes('lax')) { - enforcement = 'Lax' - } - - // 5. Append an attribute to the cookie-attribute-list with an - // attribute-name of "SameSite" and an attribute-value of - // enforcement. - cookieAttributeList.sameSite = enforcement } else { cookieAttributeList.unparsed ??= [] @@ -75778,40 +75958,35 @@ const tail = Buffer.from([0x00, 0x00, 0xff, 0xff]) const kBuffer = Symbol('kBuffer') const kLength = Symbol('kLength') -// Default maximum decompressed message size: 4 MB -const kDefaultMaxDecompressedSize = 4 * 1024 * 1024 - class PerMessageDeflate { /** @type {import('node:zlib').InflateRaw} */ #inflate #options = {} - /** @type {boolean} */ - #aborted = false - - /** @type {Function|null} */ - #currentCallback = null + #maxPayloadSize = 0 /** * @param {Map} extensions */ - constructor (extensions) { + constructor (extensions, options) { this.#options.serverNoContextTakeover = extensions.has('server_no_context_takeover') this.#options.serverMaxWindowBits = extensions.get('server_max_window_bits') + + this.#maxPayloadSize = options.maxPayloadSize } + /** + * Decompress a compressed payload. + * @param {Buffer} chunk Compressed data + * @param {boolean} fin Final fragment flag + * @param {Function} callback Callback function + */ decompress (chunk, fin, callback) { // An endpoint uses the following algorithm to decompress a message. // 1. Append 4 octets of 0x00 0x00 0xff 0xff to the tail end of the // payload of the message. // 2. Decompress the resulting data using DEFLATE. - - if (this.#aborted) { - callback(new MessageSizeExceededError()) - return - } - if (!this.#inflate) { let windowBits = Z_DEFAULT_WINDOWBITS @@ -75834,23 +76009,12 @@ class PerMessageDeflate { this.#inflate[kLength] = 0 this.#inflate.on('data', (data) => { - if (this.#aborted) { - return - } - this.#inflate[kLength] += data.length - if (this.#inflate[kLength] > kDefaultMaxDecompressedSize) { - this.#aborted = true + if (this.#maxPayloadSize > 0 && this.#inflate[kLength] > this.#maxPayloadSize) { + callback(new MessageSizeExceededError()) this.#inflate.removeAllListeners() - this.#inflate.destroy() this.#inflate = null - - if (this.#currentCallback) { - const cb = this.#currentCallback - this.#currentCallback = null - cb(new MessageSizeExceededError()) - } return } @@ -75863,14 +76027,13 @@ class PerMessageDeflate { }) } - this.#currentCallback = callback this.#inflate.write(chunk) if (fin) { this.#inflate.write(tail) } this.#inflate.flush(() => { - if (this.#aborted || !this.#inflate) { + if (!this.#inflate) { return } @@ -75878,7 +76041,6 @@ class PerMessageDeflate { this.#inflate[kBuffer].length = 0 this.#inflate[kLength] = 0 - this.#currentCallback = null callback(null, full) }) @@ -75914,6 +76076,12 @@ const { const { WebsocketFrameSend } = __nccwpck_require__(3264) const { closeWebSocketConnection } = __nccwpck_require__(86897) const { PerMessageDeflate } = __nccwpck_require__(19469) +const { MessageSizeExceededError } = __nccwpck_require__(68707) + +function failWebsocketConnectionWithCode (ws, code, reason) { + closeWebSocketConnection(ws, code, reason, Buffer.byteLength(reason)) + failWebsocketConnection(ws, reason) +} // This code was influenced by ws released under the MIT license. // Copyright (c) 2011 Einar Otto Stangvik @@ -75922,6 +76090,7 @@ const { PerMessageDeflate } = __nccwpck_require__(19469) class ByteParser extends Writable { #buffers = [] + #fragmentsBytes = 0 #byteOffset = 0 #loop = false @@ -75933,18 +76102,27 @@ class ByteParser extends Writable { /** @type {Map} */ #extensions + /** @type {number} */ + #maxFragments + + /** @type {number} */ + #maxPayloadSize + /** * @param {import('./websocket').WebSocket} ws * @param {Map|null} extensions + * @param {{ maxFragments?: number, maxPayloadSize?: number }} [options] */ - constructor (ws, extensions) { + constructor (ws, extensions, options = {}) { super() this.ws = ws this.#extensions = extensions == null ? new Map() : extensions + this.#maxFragments = options.maxFragments ?? 0 + this.#maxPayloadSize = options.maxPayloadSize ?? 0 if (this.#extensions.has('permessage-deflate')) { - this.#extensions.set('permessage-deflate', new PerMessageDeflate(extensions)) + this.#extensions.set('permessage-deflate', new PerMessageDeflate(extensions, options)) } } @@ -75960,6 +76138,19 @@ class ByteParser extends Writable { this.run(callback) } + #validatePayloadLength () { + if ( + this.#maxPayloadSize > 0 && + !isControlFrame(this.#info.opcode) && + this.#info.payloadLength + this.#fragmentsBytes > this.#maxPayloadSize + ) { + failWebsocketConnectionWithCode(this.ws, 1009, 'Payload size exceeds maximum allowed size') + return false + } + + return true + } + /** * Runs whenever a new chunk is received. * Callback is called whenever there are no more chunks buffering, @@ -76048,6 +76239,10 @@ class ByteParser extends Writable { if (payloadLength <= 125) { this.#info.payloadLength = payloadLength this.#state = parserStates.READ_DATA + + if (!this.#validatePayloadLength()) { + return + } } else if (payloadLength === 126) { this.#state = parserStates.PAYLOADLENGTH_16 } else if (payloadLength === 127) { @@ -76072,6 +76267,10 @@ class ByteParser extends Writable { this.#info.payloadLength = buffer.readUInt16BE(0) this.#state = parserStates.READ_DATA + + if (!this.#validatePayloadLength()) { + return + } } else if (this.#state === parserStates.PAYLOADLENGTH_64) { if (this.#byteOffset < 8) { return callback() @@ -76094,6 +76293,10 @@ class ByteParser extends Writable { this.#info.payloadLength = lower this.#state = parserStates.READ_DATA + + if (!this.#validatePayloadLength()) { + return + } } else if (this.#state === parserStates.READ_DATA) { if (this.#byteOffset < this.#info.payloadLength) { return callback() @@ -76106,42 +76309,58 @@ class ByteParser extends Writable { this.#state = parserStates.INFO } else { if (!this.#info.compressed) { - this.#fragments.push(body) + if (!this.writeFragments(body)) { + return + } + + if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { + failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message) + return + } // If the frame is not fragmented, a message has been received. // If the frame is fragmented, it will terminate with a fin bit set // and an opcode of 0 (continuation), therefore we handle that when // parsing continuation frames, not here. if (!this.#info.fragmented && this.#info.fin) { - const fullMessage = Buffer.concat(this.#fragments) - websocketMessageReceived(this.ws, this.#info.binaryType, fullMessage) - this.#fragments.length = 0 + websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments()) } this.#state = parserStates.INFO } else { - this.#extensions.get('permessage-deflate').decompress(body, this.#info.fin, (error, data) => { - if (error) { - failWebsocketConnection(this.ws, error.message) - return - } + this.#extensions.get('permessage-deflate').decompress( + body, + this.#info.fin, + (error, data) => { + if (error) { + const code = error instanceof MessageSizeExceededError ? 1009 : 1007 + failWebsocketConnectionWithCode(this.ws, code, error.message) + return + } - this.#fragments.push(data) + if (!this.writeFragments(data)) { + return + } + + if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { + failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message) + return + } + + if (!this.#info.fin) { + this.#state = parserStates.INFO + this.#loop = true + this.run(callback) + return + } + + websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments()) - if (!this.#info.fin) { - this.#state = parserStates.INFO this.#loop = true + this.#state = parserStates.INFO this.run(callback) - return } - - websocketMessageReceived(this.ws, this.#info.binaryType, Buffer.concat(this.#fragments)) - - this.#loop = true - this.#state = parserStates.INFO - this.#fragments.length = 0 - this.run(callback) - }) + ) this.#loop = false break @@ -76193,6 +76412,35 @@ class ByteParser extends Writable { return buffer } + writeFragments (fragment) { + if ( + this.#maxFragments > 0 && + this.#fragments.length === this.#maxFragments + ) { + failWebsocketConnectionWithCode(this.ws, 1008, 'Too many message fragments') + return false + } + + this.#fragmentsBytes += fragment.length + this.#fragments.push(fragment) + return true + } + + consumeFragments () { + const fragments = this.#fragments + + if (fragments.length === 1) { + this.#fragmentsBytes = 0 + return fragments.shift() + } + + const output = Buffer.concat(fragments, this.#fragmentsBytes) + this.#fragments = [] + this.#fragmentsBytes = 0 + + return output + } + parseCloseBody (data) { assert(data.length !== 1) @@ -77228,7 +77476,14 @@ class WebSocket extends EventTarget { // once this happens, the connection is open this[kResponse] = response - const parser = new ByteParser(this, parsedExtensions) + const webSocketOptions = this[kController]?.dispatcher?.webSocketOptions + const maxFragments = webSocketOptions?.maxFragments + const maxPayloadSize = webSocketOptions?.maxPayloadSize + + const parser = new ByteParser(this, parsedExtensions, { + maxFragments, + maxPayloadSize + }) parser.on('drain', onParserDrain) parser.on('error', onParserError.bind(this)) @@ -77472,6 +77727,7 @@ function generate(id, username, password, gpgPassphrase) { '@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, servers: { server: [ { @@ -77579,14 +77835,26 @@ const supportedPackageManager = [ id: 'maven', path: [(0, path_1.join)(os_1.default.homedir(), '.m2', 'repository')], // https://github.com/actions/cache/blob/0638051e9af2c23d10bb70fa9beffcad6cff9ce3/examples.md#java---maven - pattern: ['**/pom.xml'] + 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_1.join)(os_1.default.homedir(), '.m2', 'wrapper', 'dists')], + pattern: ['**/.mvn/wrapper/maven-wrapper.properties'] + } + ] }, { id: 'gradle', - path: [ - (0, path_1.join)(os_1.default.homedir(), '.gradle', 'caches'), - (0, path_1.join)(os_1.default.homedir(), '.gradle', 'wrapper') - ], + path: [(0, path_1.join)(os_1.default.homedir(), '.gradle', 'caches')], // https://github.com/actions/cache/blob/0638051e9af2c23d10bb70fa9beffcad6cff9ce3/examples.md#java---gradle pattern: [ '**/*.gradle*', @@ -77595,6 +77863,17 @@ const supportedPackageManager = [ 'buildSrc/**/Dependencies.kt', 'gradle/*.versions.toml', '**/versions.properties' + ], + // The Gradle wrapper distribution only depends on the wrapper properties, + // which change very rarely, so it is cached separately from the Gradle + // caches. This keeps it available across the frequent *.gradle* changes + // that rotate the main cache key. See issue #269. + additionalCaches: [ + { + name: 'gradle-wrapper', + path: [(0, path_1.join)(os_1.default.homedir(), '.gradle', 'wrapper')], + pattern: ['**/gradle-wrapper.properties'] + } ] }, { @@ -77630,6 +77909,19 @@ function findPackageManager(id) { } return packageManager; } +/** + * State keys used to carry an additional cache's restore-time information over + * to the post (save) action, scoped by the additional cache name. + */ +function additionalCachePrimaryKeyState(name) { + return `${STATE_CACHE_PRIMARY_KEY}-${name}`; +} +function additionalCacheMatchedKeyState(name) { + return `${CACHE_MATCHED_KEY}-${name}`; +} +function buildCacheKey(id, fileHash) { + return `${CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${process.arch}-${id}-${fileHash}`; +} /** * A function that generates a cache key to use. * Format of the generated key will be "${{ platform }}-${{ id }}-${{ fileHash }}"". @@ -77644,7 +77936,21 @@ function computeCacheKey(packageManager, cacheDependencyPath) { if (!fileHash) { throw new Error(`No file in ${process.cwd()} matched to [${pattern}], make sure you have checked out the target repository`); } - return `${CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${process.arch}-${packageManager.id}-${fileHash}`; + return buildCacheKey(packageManager.id, fileHash); + }); +} +/** + * Computes the cache key for an additional cache. Unlike {@link computeCacheKey} + * this returns undefined (instead of throwing) when no file matches the pattern, + * because additional caches are optional features that many projects do not use. + */ +function computeAdditionalCacheKey(additionalCache) { + return __awaiter(this, void 0, void 0, function* () { + const fileHash = yield glob.hashFiles(additionalCache.pattern.join('\n')); + if (!fileHash) { + return undefined; + } + return buildCacheKey(additionalCache.name, fileHash); }); } /** @@ -77653,11 +77959,13 @@ function computeCacheKey(packageManager, cacheDependencyPath) { * @param cacheDependencyPath The path to a dependency file */ function restore(id, cacheDependencyPath) { + var _a; return __awaiter(this, void 0, void 0, function* () { const packageManager = findPackageManager(id); const primaryKey = yield computeCacheKey(packageManager, cacheDependencyPath); core.debug(`primary key is ${primaryKey}`); core.saveState(STATE_CACHE_PRIMARY_KEY, primaryKey); + core.setOutput(STATE_CACHE_PRIMARY_KEY, 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 = yield cache.restoreCache(packageManager.path, primaryKey); if (matchedKey) { @@ -77669,19 +77977,48 @@ function restore(id, cacheDependencyPath) { core.setOutput('cache-hit', false); core.info(`${packageManager.id} cache is not found`); } + for (const additionalCache of (_a = packageManager.additionalCaches) !== null && _a !== void 0 ? _a : []) { + yield restoreAdditionalCache(additionalCache); + } }); } exports.restore = restore; +/** + * Restore an additional cache (e.g. a build-tool wrapper distribution) that is + * keyed independently of the main dependency cache so that it survives changes + * to volatile dependency files. Skips silently when the project does not use + * the corresponding feature. + */ +function restoreAdditionalCache(additionalCache) { + return __awaiter(this, void 0, void 0, function* () { + const primaryKey = yield computeAdditionalCacheKey(additionalCache); + if (!primaryKey) { + core.debug(`No file matched [${additionalCache.pattern}] for the ${additionalCache.name} cache, skipping.`); + return; + } + core.debug(`${additionalCache.name} primary key is ${primaryKey}`); + core.saveState(additionalCachePrimaryKeyState(additionalCache.name), primaryKey); + const matchedKey = yield cache.restoreCache(additionalCache.path, primaryKey); + if (matchedKey) { + core.saveState(additionalCacheMatchedKeyState(additionalCache.name), matchedKey); + core.info(`${additionalCache.name} cache restored from key: ${matchedKey}`); + } + }); +} /** * Save the dependency cache * @param id ID of the package manager, should be "maven" or "gradle" */ function save(id) { + var _a; return __awaiter(this, void 0, void 0, function* () { const packageManager = findPackageManager(id); const matchedKey = core.getState(CACHE_MATCHED_KEY); // Inputs are re-evaluated before the post action, so we want the original key used for restore const primaryKey = core.getState(STATE_CACHE_PRIMARY_KEY); + for (const additionalCache of (_a = packageManager.additionalCaches) !== null && _a !== void 0 ? _a : []) { + yield saveAdditionalCache(packageManager, additionalCache); + } if (!primaryKey) { core.warning('Error retrieving key from state.'); return; @@ -77692,7 +78029,15 @@ function save(id) { return; } try { - yield cache.saveCache(packageManager.path, primaryKey); + const cacheId = yield cache.saveCache(packageManager.path, 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. + core.debug(`Cache was not saved for the key: ${primaryKey}`); + return; + } core.info(`Cache saved with the key: ${primaryKey}`); } catch (error) { @@ -77710,6 +78055,52 @@ function save(id) { }); } exports.save = save; +/** + * 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. + */ +function saveAdditionalCache(packageManager, additionalCache) { + return __awaiter(this, void 0, void 0, function* () { + const primaryKey = core.getState(additionalCachePrimaryKeyState(additionalCache.name)); + const matchedKey = core.getState(additionalCacheMatchedKeyState(additionalCache.name)); + if (!primaryKey) { + // The feature is not used by this project, nothing to save. + core.debug(`No primary key for the ${additionalCache.name} cache, not saving cache.`); + return; + } + else if (matchedKey === primaryKey) { + core.info(`Cache hit occurred on the ${additionalCache.name} primary key ${primaryKey}, not saving cache.`); + return; + } + try { + const cacheId = yield cache.saveCache(additionalCache.path, primaryKey); + if (cacheId === -1) { + core.debug(`${additionalCache.name} cache was not saved for the key: ${primaryKey}`); + return; + } + core.info(`${additionalCache.name} cache saved with the key: ${primaryKey}`); + } + catch (error) { + const err = error; + if (err.name === cache.ValidationError.name) { + // The cache paths did not resolve, e.g. the wrapper distribution was + // never downloaded because a system build tool was used or the download + // failed. Optional wrapper caches must not fail the post step, so skip. + core.debug(`${additionalCache.name} cache paths do not exist, not saving cache: ${err.message}`); + return; + } + if (err.name === cache.ReserveCacheError.name) { + core.info(err.message); + } + else { + if (isProbablyGradleDaemonProblem(packageManager, err)) { + core.warning('Failed to save Gradle cache on Windows. If tar.exe reported "Permission denied", try to run Gradle with `--no-daemon` option. Refer to https://github.com/actions/cache/issues/454 for details.'); + } + throw error; + } + } + }); +} /** * @param packageManager the specified package manager by user * @param error the error thrown by the saveCache @@ -77734,15 +78125,19 @@ function isProbablyGradleDaemonProblem(packageManager, error) { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.DISTRIBUTIONS_ONLY_MAJOR_VERSION = exports.INPUT_MVN_TOOLCHAIN_VENDOR = exports.INPUT_MVN_TOOLCHAIN_ID = exports.MVN_TOOLCHAINS_FILE = exports.MVN_SETTINGS_FILE = exports.M2_DIR = exports.STATE_GPG_PRIVATE_KEY_FINGERPRINT = exports.INPUT_JOB_STATUS = exports.INPUT_CACHE_DEPENDENCY_PATH = exports.INPUT_CACHE = exports.INPUT_DEFAULT_GPG_PASSPHRASE = exports.INPUT_DEFAULT_GPG_PRIVATE_KEY = exports.INPUT_GPG_PASSPHRASE = exports.INPUT_GPG_PRIVATE_KEY = exports.INPUT_OVERWRITE_SETTINGS = exports.INPUT_SETTINGS_PATH = exports.INPUT_SERVER_PASSWORD = exports.INPUT_SERVER_USERNAME = exports.INPUT_SERVER_ID = exports.INPUT_CHECK_LATEST = exports.INPUT_JDK_FILE = exports.INPUT_DISTRIBUTION = exports.INPUT_JAVA_PACKAGE = exports.INPUT_ARCHITECTURE = exports.INPUT_JAVA_VERSION_FILE = exports.INPUT_JAVA_VERSION = exports.MACOS_JAVA_CONTENT_POSTFIX = void 0; +exports.DISTRIBUTIONS_ONLY_MAJOR_VERSION = exports.MAVEN_NO_TRANSFER_PROGRESS_LONG_FLAG = exports.MAVEN_NO_TRANSFER_PROGRESS_FLAG = exports.MAVEN_ARGS_ENV = exports.INPUT_SHOW_DOWNLOAD_PROGRESS = exports.INPUT_MVN_TOOLCHAIN_VENDOR = exports.INPUT_MVN_TOOLCHAIN_ID = exports.MVN_TOOLCHAINS_FILE = exports.MVN_SETTINGS_FILE = exports.M2_DIR = exports.STATE_GPG_PRIVATE_KEY_FINGERPRINT = exports.INPUT_JOB_STATUS = exports.INPUT_CACHE_DEPENDENCY_PATH = exports.INPUT_CACHE = exports.INPUT_DEFAULT_GPG_PASSPHRASE = exports.INPUT_DEFAULT_GPG_PRIVATE_KEY = exports.INPUT_GPG_PASSPHRASE = exports.INPUT_GPG_PRIVATE_KEY = exports.INPUT_OVERWRITE_SETTINGS = exports.INPUT_SETTINGS_PATH = exports.INPUT_SERVER_PASSWORD = exports.INPUT_SERVER_USERNAME = exports.INPUT_SERVER_ID = exports.INPUT_VERIFY_SIGNATURE_PUBLIC_KEY = exports.INPUT_VERIFY_SIGNATURE = exports.INPUT_SET_DEFAULT = exports.INPUT_CHECK_LATEST = exports.INPUT_JDK_FILE_DEPRECATED = exports.INPUT_JDK_FILE = exports.INPUT_DISTRIBUTION = exports.INPUT_JAVA_PACKAGE = exports.INPUT_ARCHITECTURE = exports.INPUT_JAVA_VERSION_FILE = exports.INPUT_JAVA_VERSION = exports.MACOS_JAVA_CONTENT_POSTFIX = void 0; exports.MACOS_JAVA_CONTENT_POSTFIX = 'Contents/Home'; exports.INPUT_JAVA_VERSION = 'java-version'; exports.INPUT_JAVA_VERSION_FILE = 'java-version-file'; exports.INPUT_ARCHITECTURE = 'architecture'; exports.INPUT_JAVA_PACKAGE = 'java-package'; exports.INPUT_DISTRIBUTION = 'distribution'; -exports.INPUT_JDK_FILE = 'jdkFile'; +exports.INPUT_JDK_FILE = 'jdk-file'; +exports.INPUT_JDK_FILE_DEPRECATED = 'jdkFile'; exports.INPUT_CHECK_LATEST = 'check-latest'; +exports.INPUT_SET_DEFAULT = 'set-default'; +exports.INPUT_VERIFY_SIGNATURE = 'verify-signature'; +exports.INPUT_VERIFY_SIGNATURE_PUBLIC_KEY = 'verify-signature-public-key'; exports.INPUT_SERVER_ID = 'server-id'; exports.INPUT_SERVER_USERNAME = 'server-username'; exports.INPUT_SERVER_PASSWORD = 'server-password'; @@ -77761,6 +78156,10 @@ exports.MVN_SETTINGS_FILE = 'settings.xml'; exports.MVN_TOOLCHAINS_FILE = 'toolchains.xml'; exports.INPUT_MVN_TOOLCHAIN_ID = 'mvn-toolchain-id'; exports.INPUT_MVN_TOOLCHAIN_VENDOR = 'mvn-toolchain-vendor'; +exports.INPUT_SHOW_DOWNLOAD_PROGRESS = 'show-download-progress'; +exports.MAVEN_ARGS_ENV = 'MAVEN_ARGS'; +exports.MAVEN_NO_TRANSFER_PROGRESS_FLAG = '-ntp'; +exports.MAVEN_NO_TRANSFER_PROGRESS_LONG_FLAG = '--no-transfer-progress'; exports.DISTRIBUTIONS_ONLY_MAJOR_VERSION = ['corretto']; @@ -78042,6 +78441,7 @@ const constants_1 = __nccwpck_require__(27242); const os_1 = __importDefault(__nccwpck_require__(70857)); class JavaBase { constructor(distribution, installerOptions) { + var _a; this.distribution = distribution; this.http = new httpm.HttpClient('actions/setup-java', undefined, { allowRetries: true, @@ -78051,10 +78451,19 @@ class JavaBase { this.architecture = installerOptions.architecture || os_1.default.arch(); this.packageType = installerOptions.packageType; this.checkLatest = installerOptions.checkLatest; + this.setDefault = + installerOptions.setDefault !== undefined + ? installerOptions.setDefault + : true; + this.verifySignature = (_a = installerOptions.verifySignature) !== null && _a !== void 0 ? _a : false; + this.verifySignaturePublicKey = installerOptions.verifySignaturePublicKey; } setupJava() { var _a, _b; return __awaiter(this, void 0, void 0, function* () { + if (this.verifySignature && !this.supportsSignatureVerification()) { + throw new Error(`Input 'verify-signature' is not supported for distribution '${this.distribution}'.`); + } let foundJava = this.findInToolcache(); if (foundJava && !this.checkLatest) { core.info(`Resolved Java ${foundJava.version} from tool-cache`); @@ -78166,14 +78575,23 @@ class JavaBase { if (process.platform === 'darwin' && fs.existsSync(macOSPostfixPath)) { foundJava.path = macOSPostfixPath; } - core.info(`Setting Java ${foundJava.version} as the default`); - this.setJavaDefault(foundJava.version, foundJava.path); + if (this.setDefault) { + core.info(`Setting Java ${foundJava.version} as the default`); + this.setJavaDefault(foundJava.version, foundJava.path); + } + else { + core.info(`Installing Java ${foundJava.version} (not setting as default)`); + this.setJavaEnvironment(foundJava.version, foundJava.path); + } return foundJava; }); } get toolcacheFolderName() { return `Java_${this.distribution}_${this.packageType}`; } + supportsSignatureVerification() { + return false; + } getToolcacheVersionName(version) { if (!this.stable) { if (version.includes('+')) { @@ -78265,9 +78683,12 @@ class JavaBase { return error; } setJavaDefault(version, toolPath) { - const majorVersion = version.split('.')[0]; core.exportVariable('JAVA_HOME', toolPath); core.addPath(path_1.default.join(toolPath, 'bin')); + this.setJavaEnvironment(version, toolPath); + } + setJavaEnvironment(version, toolPath) { + const majorVersion = version.split('.')[0]; core.setOutput('distribution', this.distribution); core.setOutput('path', toolPath); core.setOutput('version', version); @@ -78489,6 +78910,7 @@ const installer_10 = __nccwpck_require__(37675); const installer_11 = __nccwpck_require__(17557); const installer_12 = __nccwpck_require__(26968); const installer_13 = __nccwpck_require__(62282); +const installer_14 = __nccwpck_require__(48151); var JavaDistribution; (function (JavaDistribution) { JavaDistribution["Adopt"] = "adopt"; @@ -78505,7 +78927,9 @@ var JavaDistribution; JavaDistribution["Dragonwell"] = "dragonwell"; JavaDistribution["SapMachine"] = "sapmachine"; JavaDistribution["GraalVM"] = "graalvm"; + JavaDistribution["GraalVMCommunity"] = "graalvm-community"; JavaDistribution["JetBrains"] = "jetbrains"; + JavaDistribution["Kona"] = "kona"; })(JavaDistribution || (JavaDistribution = {})); function getJavaDistribution(distributionName, installerOptions, jdkFile) { switch (distributionName) { @@ -78536,8 +78960,12 @@ function getJavaDistribution(distributionName, installerOptions, jdkFile) { return new installer_11.SapMachineDistribution(installerOptions); case JavaDistribution.GraalVM: return new installer_12.GraalVMDistribution(installerOptions); + case JavaDistribution.GraalVMCommunity: + return new installer_12.GraalVMCommunityDistribution(installerOptions); case JavaDistribution.JetBrains: return new installer_13.JetBrainsDistribution(installerOptions); + case JavaDistribution.Kona: + return new installer_14.KonaDistribution(installerOptions); default: return null; } @@ -78803,23 +79231,29 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.GraalVMDistribution = void 0; +exports.GraalVMCommunityDistribution = exports.GraalVMDistribution = void 0; const core = __importStar(__nccwpck_require__(37484)); const tc = __importStar(__nccwpck_require__(33472)); const fs_1 = __importDefault(__nccwpck_require__(79896)); const path_1 = __importDefault(__nccwpck_require__(16928)); +const semver_1 = __importDefault(__nccwpck_require__(62088)); const base_installer_1 = __nccwpck_require__(79935); const http_client_1 = __nccwpck_require__(54844); const util_1 = __nccwpck_require__(54527); const GRAALVM_DL_BASE = 'https://download.oracle.com/graalvm'; const GRAALVM_DOWNLOAD_URL = 'https://www.graalvm.org/downloads/'; +const GRAALVM_COMMUNITY_RELEASES_URL = 'https://api.github.com/repos/graalvm/graalvm-ce-builds/releases?per_page=100'; +const GRAALVM_COMMUNITY_RELEASES_PAGE_ORIGIN = 'https://api.github.com'; +const GRAALVM_COMMUNITY_DOWNLOAD_URL = 'https://github.com/graalvm/graalvm-ce-builds/releases'; +const GRAALVM_COMMUNITY_ASSET_PREFIX = 'graalvm-community-jdk-'; +const GRAALVM_COMMUNITY_VERSION_PATTERN = /^\d+(?:\.\d+)*$/; const IS_WINDOWS = process.platform === 'win32'; const GRAALVM_PLATFORM = IS_WINDOWS ? 'windows' : process.platform; const GRAALVM_MIN_VERSION = 17; const SUPPORTED_ARCHITECTURES = ['x64', 'aarch64']; class GraalVMDistribution extends base_installer_1.JavaBase { - constructor(installerOptions) { - super('GraalVM', installerOptions); + constructor(installerOptions, distributionName = 'GraalVM') { + super(distributionName, installerOptions); } downloadTool(javaRelease) { return __awaiter(this, void 0, void 0, function* () { @@ -78853,36 +79287,50 @@ class GraalVMDistribution extends base_installer_1.JavaBase { } findPackageForDownload(range) { return __awaiter(this, void 0, void 0, function* () { - // Add input validation - if (!range || typeof range !== 'string') { - throw new Error('Version range is required and must be a string'); - } - const arch = this.distributionArchitecture(); - if (!SUPPORTED_ARCHITECTURES.includes(arch)) { - throw new Error(`Unsupported architecture: ${this.architecture}. Supported architectures are: ${SUPPORTED_ARCHITECTURES.join(', ')}`); - } + this.validateVersionRange(range); + const arch = this.getSupportedArchitecture(); if (!this.stable) { return this.findEABuildDownloadUrl(`${range}-ea`); } - if (this.packageType !== 'jdk') { - throw new Error('GraalVM provides only the `jdk` package type'); - } - const platform = this.getPlatform(); - const extension = (0, util_1.getDownloadArchiveExtension)(); - const major = range.includes('.') ? range.split('.')[0] : range; - const majorVersion = parseInt(major); - if (isNaN(majorVersion)) { - throw new Error(`Invalid version format: ${range}`); - } - if (majorVersion < GRAALVM_MIN_VERSION) { - throw new Error(`GraalVM is only supported for JDK ${GRAALVM_MIN_VERSION} and later. Requested version: ${major}`); - } + const { platform, extension, major } = this.validateStableBuildRequest(range); const fileUrl = this.constructFileUrl(range, major, platform, arch, extension); const response = yield this.http.head(fileUrl); this.handleHttpResponse(response, range); return { url: fileUrl, version: range }; }); } + validateVersionRange(range) { + if (!range || typeof range !== 'string') { + throw new Error('Version range is required and must be a string'); + } + } + getSupportedArchitecture() { + const arch = this.distributionArchitecture(); + if (!SUPPORTED_ARCHITECTURES.includes(arch)) { + throw new Error(`Unsupported architecture: ${this.architecture}. Supported architectures are: ${SUPPORTED_ARCHITECTURES.join(', ')}`); + } + return arch; + } + validateStableBuildRequest(range) { + if (this.packageType !== 'jdk') { + throw new Error(`${this.distribution} provides only the \`jdk\` package type`); + } + const platform = this.getPlatform(); + const extension = (0, util_1.getDownloadArchiveExtension)(); + const major = range.includes('.') ? range.split('.')[0] : range; + const majorVersion = parseInt(major); + if (isNaN(majorVersion)) { + throw new Error(`Invalid version format: ${range}`); + } + if (majorVersion < GRAALVM_MIN_VERSION) { + throw new Error(`${this.distribution} is only supported for JDK ${GRAALVM_MIN_VERSION} and later. Requested version: ${major}`); + } + return { + platform, + major, + extension + }; + } constructFileUrl(range, major, platform, arch, extension) { return range.includes('.') ? `${GRAALVM_DL_BASE}/${major}/archive/graalvm-jdk-${range}_${platform}-${arch}_bin.${extension}` @@ -78973,6 +79421,101 @@ class GraalVMDistribution extends base_installer_1.JavaBase { } } exports.GraalVMDistribution = GraalVMDistribution; +class GraalVMCommunityDistribution extends GraalVMDistribution { + constructor(installerOptions) { + super(installerOptions, 'GraalVM Community'); + } + get toolcacheFolderName() { + return `Java_GraalVM_Community_${this.packageType}`; + } + findPackageForDownload(range) { + return __awaiter(this, void 0, void 0, function* () { + this.validateVersionRange(range); + if (!this.stable) { + throw new Error('GraalVM Community does not provide early access builds'); + } + const arch = this.getSupportedArchitecture(); + const { platform, extension } = this.validateStableBuildRequest(range); + // GraalVM Community asset names embed the platform, architecture and + // archive type, e.g. `graalvm-community-jdk-21.0.2_linux-x64_bin.tar.gz`. + const assetSuffix = `_${platform}-${arch}_bin.${extension}`; + const availableVersions = yield this.getAvailableVersions(assetSuffix); + const satisfiedVersion = availableVersions + .filter(item => (0, util_1.isVersionSatisfies)(range, item.version)) + .sort((a, b) => -semver_1.default.compareBuild(a.version, b.version))[0]; + if (!satisfiedVersion) { + const error = this.createVersionNotFoundError(range, availableVersions.map(item => item.version), `Platform: ${platform}`); + error.message += `\nPlease check if this version is available at ${GRAALVM_COMMUNITY_DOWNLOAD_URL}.`; + throw error; + } + return satisfiedVersion; + }); + } + getAvailableVersions(assetSuffix) { + var _a; + return __awaiter(this, void 0, void 0, function* () { + const headers = (0, util_1.getGitHubHttpHeaders)(); + const versions = new Map(); + let releasesUrl = GRAALVM_COMMUNITY_RELEASES_URL; + for (let pageIndex = 0; releasesUrl && pageIndex < util_1.MAX_PAGINATION_PAGES; pageIndex++) { + const response = yield this.http.getJson(releasesUrl, headers); + // A successful GitHub releases listing is always a JSON array (possibly + // empty). Anything else indicates an unexpected/error payload (rate + // limiting, auth failure, etc.) that must be surfaced instead of being + // silently treated as "no releases", which would later look like a + // misleading "version not found" error. + if (!Array.isArray(response.result)) { + throw new Error(`Unexpected response while listing GraalVM Community releases from ${releasesUrl} ` + + `(HTTP status code: ${response.statusCode}). Expected a JSON array of releases. ` + + `Please check if the service is available at ${GRAALVM_COMMUNITY_DOWNLOAD_URL}.`); + } + const releases = response.result; + if (releases.length === 0) { + break; + } + for (const release of releases) { + if (release.draft || release.prerelease) { + continue; + } + for (const asset of (_a = release.assets) !== null && _a !== void 0 ? _a : []) { + const version = this.extractAssetVersion(asset.name, assetSuffix); + if (version) { + versions.set(version, { + version, + url: asset.browser_download_url + }); + } + } + } + releasesUrl = this.getNextReleasesUrl(response.headers); + } + return [...versions.values()]; + }); + } + // Returns the GraalVM JDK version encoded in a release asset name when it + // matches the requested platform/architecture/archive suffix, otherwise null. + extractAssetVersion(assetName, assetSuffix) { + if (!assetName.startsWith(GRAALVM_COMMUNITY_ASSET_PREFIX) || + !assetName.endsWith(assetSuffix)) { + return null; + } + const rawVersion = assetName.slice(GRAALVM_COMMUNITY_ASSET_PREFIX.length, -assetSuffix.length); + if (!GRAALVM_COMMUNITY_VERSION_PATTERN.test(rawVersion)) { + return null; + } + return (0, util_1.convertVersionToSemver)(rawVersion); + } + getNextReleasesUrl(headers) { + const nextUrl = (0, util_1.getNextPageUrlFromLinkHeader)(headers); + if (nextUrl && + !(0, util_1.validatePaginationUrl)(nextUrl, GRAALVM_COMMUNITY_RELEASES_PAGE_ORIGIN)) { + core.warning(`Ignoring pagination link with unexpected origin: ${nextUrl}`); + return null; + } + return nextUrl; + } +} +exports.GraalVMCommunityDistribution = GraalVMCommunityDistribution; /***/ }), @@ -79202,6 +79745,186 @@ class JetBrainsDistribution extends base_installer_1.JavaBase { exports.JetBrainsDistribution = JetBrainsDistribution; +/***/ }), + +/***/ 48151: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.KonaDistribution = void 0; +const core = __importStar(__nccwpck_require__(37484)); +const tc = __importStar(__nccwpck_require__(33472)); +const semver_1 = __importDefault(__nccwpck_require__(62088)); +const fs_1 = __importDefault(__nccwpck_require__(79896)); +const path_1 = __importDefault(__nccwpck_require__(16928)); +const base_installer_1 = __nccwpck_require__(79935); +const util_1 = __nccwpck_require__(54527); +class KonaDistribution extends base_installer_1.JavaBase { + constructor(installerOptions) { + super('Kona', installerOptions); + } + downloadTool(javaRelease) { + return __awaiter(this, void 0, void 0, function* () { + core.info(`Downloading Kona JDK ${javaRelease.version} (${this.distribution}) from ${javaRelease.url} ...`); + const javaArchivePath = yield tc.downloadTool(javaRelease.url); + core.info(`Extracting Java archive...`); + const extension = (0, util_1.getDownloadArchiveExtension)(); + const archivePath = process.platform === 'win32' + ? (0, util_1.renameWinArchive)(javaArchivePath) + : javaArchivePath; + const extractedJavaPath = yield (0, util_1.extractJdkFile)(archivePath, extension); + const archiveName = fs_1.default.readdirSync(extractedJavaPath)[0]; + const jdkDirectory = path_1.default.join(extractedJavaPath, archiveName); + const version = this.getToolcacheVersionName(javaRelease.version); + const javaPath = yield tc.cacheDir(jdkDirectory, this.toolcacheFolderName, version, this.architecture); + return { version: javaRelease.version, path: javaPath }; + }); + } + findPackageForDownload(version) { + return __awaiter(this, void 0, void 0, function* () { + if (!this.stable) { + throw new Error('Kona provides stable releases only'); + } + if (this.packageType !== 'jdk') { + throw new Error('Kona provides jdk only'); + } + const availableReleases = yield this.getAvailableReleases(); + const releases = availableReleases + .filter(item => { + return (0, util_1.isVersionSatisfies)(version, item.version); + }) + .map(item => { + return { + version: item.version, + url: item.downloadUrl + }; + }) + .sort((a, b) => -semver_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]; + }); + } + getAvailableReleases() { + return __awaiter(this, void 0, void 0, function* () { + if (core.isDebug()) { + console.time('Retrieving available releases for Kona took'); // eslint-disable-line no-console + } + const releaseInfo = yield this.fetchReleaseInfo(); + if (!releaseInfo) { + throw new Error(`Couldn't fetch Kona release information`); + } + const availableReleases = this.chooseReleases(this.getOs(), this.getArch(), releaseInfo); + if (core.isDebug()) { + core.startGroup('Print information about available releases'); + console.timeEnd('Retrieving available releases for Kona took'); // eslint-disable-line no-console + core.debug(availableReleases.map(item => item.version).join(', ')); + core.endGroup(); + } + return availableReleases; + }); + } + fetchReleaseInfo() { + return __awaiter(this, void 0, void 0, function* () { + const releasesInfoUrl = 'https://tencent.github.io/konajdk/releases/kona-v1.json'; + try { + core.debug(`Fetching Kona release info from URL: ${releasesInfoUrl}`); + return (yield this.http.getJson(releasesInfoUrl)) + .result; + } + catch (err) { + core.debug(`Fetching Kona release info from the URL: ${releasesInfoUrl} 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; + } + } +} +exports.KonaDistribution = KonaDistribution; + + /***/ }), /***/ 32063: @@ -79464,8 +80187,14 @@ class LocalDistribution extends base_installer_1.JavaBase { if (process.platform === 'darwin' && fs_1.default.existsSync(macOSPostfixPath)) { foundJava.path = macOSPostfixPath; } - core.info(`Setting Java ${foundJava.version} as default`); - this.setJavaDefault(foundJava.version, foundJava.path); + if (this.setDefault) { + core.info(`Setting Java ${foundJava.version} as the default`); + this.setJavaDefault(foundJava.version, foundJava.path); + } + else { + core.info(`Installing Java ${foundJava.version} (not setting as default)`); + this.setJavaEnvironment(foundJava.version, foundJava.path); + } return foundJava; }); } @@ -79528,21 +80257,38 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.MicrosoftDistributions = void 0; +exports.MicrosoftDistributions = exports.MICROSOFT_PUBLIC_KEY = void 0; const base_installer_1 = __nccwpck_require__(79935); const util_1 = __nccwpck_require__(54527); +const gpg = __importStar(__nccwpck_require__(88343)); +const microsoft_key_1 = __nccwpck_require__(56286); const core = __importStar(__nccwpck_require__(37484)); const tc = __importStar(__nccwpck_require__(33472)); const fs_1 = __importDefault(__nccwpck_require__(79896)); const path_1 = __importDefault(__nccwpck_require__(16928)); +var microsoft_key_2 = __nccwpck_require__(56286); +Object.defineProperty(exports, "MICROSOFT_PUBLIC_KEY", ({ enumerable: true, get: function () { return microsoft_key_2.MICROSOFT_PUBLIC_KEY; } })); class MicrosoftDistributions extends base_installer_1.JavaBase { constructor(installerOptions) { super('Microsoft', installerOptions); } downloadTool(javaRelease) { + var _a; return __awaiter(this, void 0, void 0, function* () { core.info(`Downloading Java ${javaRelease.version} (${this.distribution}) from ${javaRelease.url} ...`); let javaArchivePath = yield tc.downloadTool(javaRelease.url); + if (this.verifySignature) { + if (!javaRelease.signatureUrl) { + throw new Error(`Input 'verify-signature' is enabled, but no signature URL was found for Microsoft Build of OpenJDK version ${javaRelease.version}.`); + } + core.info(`Verifying Java package signature...`); + try { + yield gpg.verifyPackageSignature(javaArchivePath, javaRelease.signatureUrl, (_a = this.verifySignaturePublicKey) !== null && _a !== void 0 ? _a : microsoft_key_1.MICROSOFT_PUBLIC_KEY); + } + catch (error) { + throw new Error(`Failed to verify signature for Microsoft Build of OpenJDK version ${javaRelease.version}. Signature URL: ${javaRelease.signatureUrl}. Error: ${error.message}`); + } + } core.info(`Extracting Java archive...`); const extension = (0, util_1.getDownloadArchiveExtension)(); if (process.platform === 'win32') { @@ -79556,6 +80302,7 @@ class MicrosoftDistributions extends base_installer_1.JavaBase { }); } findPackageForDownload(range) { + var _a; return __awaiter(this, void 0, void 0, function* () { const arch = this.distributionArchitecture(); if (arch !== 'x64' && arch !== 'aarch64') { @@ -79576,12 +80323,18 @@ class MicrosoftDistributions extends base_installer_1.JavaBase { const availableVersionStrings = manifest.map(item => item.version); throw this.createVersionNotFoundError(range, availableVersionStrings); } + const file = foundRelease.files[0]; + const signatureUrl = (_a = file.signature_url) !== null && _a !== void 0 ? _a : `${file.download_url}.sig`; return { - url: foundRelease.files[0].download_url, + url: file.download_url, + signatureUrl, version: foundRelease.version }; }); } + supportsSignatureVerification() { + return true; + } getAvailableVersions() { return __awaiter(this, void 0, void 0, function* () { // TODO get these dynamically! @@ -79624,6 +80377,38 @@ class MicrosoftDistributions extends base_installer_1.JavaBase { exports.MicrosoftDistributions = MicrosoftDistributions; +/***/ }), + +/***/ 56286: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.MICROSOFT_PUBLIC_KEY = void 0; +// Microsoft Build of OpenJDK GPG signing key +// Retrieved from: https://download.visualstudio.microsoft.com/download/pr/b90071e2-e0cf-4411-98be-dbeb09d67bf0/8622862bcd54206e158c5abca0582c9b/464279_464280_aoc_20210208.asc +exports.MICROSOFT_PUBLIC_KEY = `-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: BSN Pgp v1.1.0.0 + +mQENBGAhlWcBCADCQjj6huLTenvZSLej35e9YKEHm4lix2uvPOONexMaU8V2v7KL +RGdoXF7jwHci7efnPZ+9zpS2+g3rhvv8M7yWy9E/1psEtGzvmp1IL/qIabMEQqi+ +UlhPGh7MQ/BkXAlic8Dyl3XYqr0EXS11iCiTr6Zkxs9Ee4V54gxL4gogRn4wk9sl +/nrjgDzMsUwla0pynoQQvYpqCdiAr3gKKllT1skCDqgVOMMyZxsx9HjZxg/3AJz6 +r5i512L2R+3Hkv+XmxT+mnGBCFcny0DM7PjNXEmIK3ZSkro1tQML90zx3Fyh5esx +fpVvuIXGFV75o35VVCBZoiD3hcfOnIJsPQ9nABEBAAG0OE1pY3Jvc29mdCBKYXZh +IEVuZ2luZWVyaW5nIDxqYXZhcGxhdGluZnJhQG1pY3Jvc29mdC5jb20+iQE4BBMB +CAAiBQJgIZVnAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRA1Ux0xWyHB +icwTCACJO2FGNocNvdUtAb+eDKuGwt0chAJdCES2ZtgBScwrwDyWpxpRznoXWBHL +MJeLyxJoKsCG3vVlY4uh48psCzVm3OKvi7MCPT955t8W6TzfSBxTpjR8zRgJkjPJ +EGhHTlusUfz7TtM5etJF0qscSJH1grcNsgtee97mk4QyEzT8Di83NQmYxKcBrliq +yK/SWWt8VkTyYAEO6L5PoB4L9r8ka27uQs+jgCw+/Z0JMtNmmhyNGY3+a1YtPeoy +JdQaI9LphfKGbVaz6SK2aol7vj+c2TG3TLUYdOYGMH1OZlri2GTkCVjwna2GC7p4 +Fa133tP85xzJEq1XeXm8WeLFo2wV +=rHCS +-----END PGP PUBLIC KEY BLOCK-----`; + + /***/ }), /***/ 11182: @@ -80174,6 +80959,50 @@ class SemeruDistribution extends base_installer_1.JavaBase { exports.SemeruDistribution = SemeruDistribution; +/***/ }), + +/***/ 80877: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.ADOPTIUM_PUBLIC_KEY = void 0; +// Adoptium GPG signing key (fingerprint: 3B04D753C9050D9A5D343F39843C48A565F8F04B) +// Retrieved from: https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3B04D753C9050D9A5D343F39843C48A565F8F04B +exports.ADOPTIUM_PUBLIC_KEY = `-----BEGIN PGP PUBLIC KEY BLOCK----- + +xsBNBGGTvTQBCAC6ey144n7CG8foafF6mwgIBN1fIm1ILZDuGS4tMr0/XI8pgJnT +QvsPxZWEvtSm7bEMObzEoZJcXwjBcJl1B0ui8k5kHMTI75gCmZPsoKLFWIEpuRBQ +PBocusw80apDmLnNDQLVQvDFtEua5gaNa/fRw9YsmBoXBqvgrjFUIdGyWoQvH5+a +9OYlWD9n5VV0gnVMb+aclwVzB/zJw3kHGSgzuMtlAHeQiah7Y8yomQn/UIX8yqDf ++11sP3+c87YcjkRqImRTtmKEDcEtGPAIXC6SYA+uEEkbYE0Fy0chkvtnVWJ597fa +Epai4rnICU8zoJ6X5z3v1aM2WerhX9oq9X8PABEBAAHNQEFkb3B0aXVtIEdQRyBL +ZXkgKERFQi9SUE0gU2lnbmluZyBLZXkpIDx0ZW11cmluLWRldkBlY2xpcHNlLm9y +Zz7CwJIEEwEIADwWIQQ7BNdTyQUNml00PzmEPEilZfjwSwUCYZO9NAIbAwULCQgH +AgMiAgEGFQoJCAsCBBYCAwECHgcCF4AACgkQhDxIpWX48Et4AggAjjJzYWuKV3nG +7ngInngl8G/m9JoHr7BmwgcQXYhdy5hVkMcUx5JLeXz2LMBUH/F2nD595hgjMabk +kVib20X8lq9RsNbdfc2hBcWU6qyHKxsIqT4boI2/XDyEzzMyyZWWNGo/27Ci7Xmj +pWu31nh0pDdPqdyWDIKojbVVnxlCRY8as8Sm+1ufi709KCi4MuwHNsUlCSwb/fju +NKeHkrHbLcHKUUIEcmTSKRWrpMYBzm1HYOGBz4xPuELwUfUp71ehfoyBZlp6RDRf +l5TYI1FmCyHuvjNhrJgWv7bOTcf8yObGY+TEUhzc4xQqCrF4ur9d3opvsuPBQsv+ +Klqi5KSZgs7ATQRhk700AQgAq14okly8cFrpYVenEQPiB75AUZfKRpMduiR6IxAj +SKcH7aSoFZ9AubUEBVpZsyT5svxoEPe1i4TdbF+m9FGy42EcOlLa3ArLTj5H8FRl +UdGZB9I5mk4GptOzPM+aHMMu92vW/ZwjuS8DvOiQSp+cUmG1EqOMJSM7e/4BM71z +E+OKaVJCj79pEzhG3SK/IC/OlxxyETT66NSfYJd7Sw5R6Vr19am/uNU690W0CJ+q +VQeFpmDMr7LnfdFRIh+lJe05+PvWXeidkGjox5cbG52wf8aRIR/FgkfcFvqRMN1f +B+dVOWueloUeVAnzcUznOKmUEs7LP9ObJhYHHgup4IAU2wARAQABwsB2BBgBCAAg +FiEEOwTXU8kFDZpdND85hDxIpWX48EsFAmGTvTQCGwwACgkQhDxIpWX48EvXHQf/ +Q0nZsGDXnZHiBoojeSdpkO7WBjMIP3w1GdLvRpPQrS8TfOPbZuoevzCNh38Y3gwF +yelJspvzDQrBXhgkzAGlucYg8Y7KHa5Ebm7iDgMzc37L1hYSZTYCqwd7aowfgy34 +hOk3B67LffkJpIh738Oa9CtlwxQ9xcytmBmQ1fBBOwm/9IhAwHPQuydYIs4DxWbj +0MGSP4fDntU7e4UjsHNmhudDcYol0FaqdHHIIB9C/G4CzetRwHFOn3b4JwXMU7YU +6aJA3mXhi3hggMC3wkT2HHZ/TquuOdNc02fypWOCDOHz0alBBJNqoVUNFNqU3tfJ +wI4qF/KKq9BfyfucAs0ykA== +=XLag +-----END PGP PUBLIC KEY BLOCK-----`; + + /***/ }), /***/ 91986: @@ -80217,14 +81046,18 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.TemurinDistribution = exports.TemurinImplementation = void 0; +exports.TemurinDistribution = exports.TemurinImplementation = exports.ADOPTIUM_PUBLIC_KEY = void 0; const core = __importStar(__nccwpck_require__(37484)); const tc = __importStar(__nccwpck_require__(33472)); const fs_1 = __importDefault(__nccwpck_require__(79896)); const path_1 = __importDefault(__nccwpck_require__(16928)); const semver_1 = __importDefault(__nccwpck_require__(62088)); +const gpg = __importStar(__nccwpck_require__(88343)); +const adoptium_key_1 = __nccwpck_require__(80877); const base_installer_1 = __nccwpck_require__(79935); const util_1 = __nccwpck_require__(54527); +var adoptium_key_2 = __nccwpck_require__(80877); +Object.defineProperty(exports, "ADOPTIUM_PUBLIC_KEY", ({ enumerable: true, get: function () { return adoptium_key_2.ADOPTIUM_PUBLIC_KEY; } })); var TemurinImplementation; (function (TemurinImplementation) { TemurinImplementation["Hotspot"] = "Hotspot"; @@ -80249,7 +81082,8 @@ class TemurinDistribution extends base_installer_1.JavaBase { : item.version_data.semver.replace('-beta+', '+'); return { version: formattedVersion, - url: item.binaries[0].package.link + url: item.binaries[0].package.link, + signatureUrl: item.binaries[0].package.signature_link }; }); const satisfiedVersions = availableVersionsWithBinaries @@ -80266,9 +81100,22 @@ class TemurinDistribution extends base_installer_1.JavaBase { }); } downloadTool(javaRelease) { + var _a; return __awaiter(this, void 0, void 0, function* () { core.info(`Downloading Java ${javaRelease.version} (${this.distribution}) from ${javaRelease.url} ...`); let javaArchivePath = yield tc.downloadTool(javaRelease.url); + if (this.verifySignature) { + if (!javaRelease.signatureUrl) { + throw new Error(`Input 'verify-signature' is enabled, but no signature URL was found for Temurin version ${javaRelease.version}.`); + } + core.info(`Verifying Java package signature...`); + try { + yield gpg.verifyPackageSignature(javaArchivePath, javaRelease.signatureUrl, (_a = this.verifySignaturePublicKey) !== null && _a !== void 0 ? _a : adoptium_key_1.ADOPTIUM_PUBLIC_KEY); + } + catch (error) { + throw new Error(`Failed to verify signature for Temurin version ${javaRelease.version} from ${javaRelease.signatureUrl}: ${error.message}`); + } + } core.info(`Extracting Java archive...`); const extension = (0, util_1.getDownloadArchiveExtension)(); if (process.platform === 'win32') { @@ -80285,6 +81132,9 @@ class TemurinDistribution extends base_installer_1.JavaBase { get toolcacheFolderName() { return super.toolcacheFolderName; } + supportsSignatureVerification() { + return true; + } getAvailableVersions() { return __awaiter(this, void 0, void 0, function* () { const platform = this.getPlatformOption(); @@ -80425,16 +81275,22 @@ class ZuluDistribution extends base_installer_1.JavaBase { return __awaiter(this, void 0, void 0, function* () { const availableVersionsRaw = yield this.getAvailableVersions(); const availableVersions = availableVersionsRaw.map(item => { + // The Azul Metadata API reports the JDK build number separately from + // java_version (e.g. java_version=[17,0,7], openjdk_build_number=7). + // Append it so the resulting semver retains the build (e.g. 17.0.7+7). + const javaVersion = item.openjdk_build_number != null + ? [...item.java_version, item.openjdk_build_number] + : item.java_version; return { - version: (0, util_1.convertVersionToSemver)(item.jdk_version), - url: item.url, - zuluVersion: (0, util_1.convertVersionToSemver)(item.zulu_version) + version: (0, util_1.convertVersionToSemver)(javaVersion), + url: item.download_url, + zuluVersion: (0, util_1.convertVersionToSemver)(item.distro_version) }; }); const satisfiedVersions = availableVersions .filter(item => (0, util_1.isVersionSatisfies)(version, item.version)) .sort((a, b) => { - // Azul provides two versions: jdk_version and azul_version + // Azul provides two versions: java_version and distro_version // we should sort by both fields by descending return (-semver_1.default.compareBuild(a.version, b.version) || -semver_1.default.compareBuild(a.zuluVersion, b.zuluVersion)); @@ -80472,37 +81328,60 @@ class ZuluDistribution extends base_installer_1.JavaBase { getAvailableVersions() { var _a, _b; return __awaiter(this, void 0, void 0, function* () { - const { arch, hw_bitness, abi } = this.getArchitectureOptions(); + const arch = this.getArchitectureOptions(); const [bundleType, features] = this.packageType.split('+'); const platform = this.getPlatformOption(); const extension = (0, util_1.getDownloadArchiveExtension)(); const javafx = (_a = features === null || features === void 0 ? void 0 : features.includes('fx')) !== null && _a !== void 0 ? _a : false; + const crac = (_b = features === null || features === void 0 ? void 0 : features.includes('crac')) !== null && _b !== void 0 ? _b : false; const releaseStatus = this.stable ? 'ga' : 'ea'; if (core.isDebug()) { console.time('Retrieving available versions for Zulu took'); // eslint-disable-line no-console } - const requestArguments = [ + const baseRequestArguments = [ `os=${platform}`, - `ext=${extension}`, - `bundle_type=${bundleType}`, - `javafx=${javafx}`, + `archive_type=${extension}`, + `java_package_type=${bundleType}`, + `javafx_bundled=${javafx}`, + `crac_supported=${crac}`, `arch=${arch}`, - `hw_bitness=${hw_bitness}`, `release_status=${releaseStatus}`, - abi ? `abi=${abi}` : null, - features ? `features=${features}` : null - ] - .filter(Boolean) - .join('&'); - const availableVersionsUrl = `https://api.azul.com/zulu/download/community/v1.0/bundles/?${requestArguments}`; - core.debug(`Gathering available versions from '${availableVersionsUrl}'`); - const availableVersions = (_b = (yield this.http.getJson(availableVersionsUrl)) - .result) !== null && _b !== void 0 ? _b : []; + `availability_types=ca` + ].join('&'); + // Need to iterate through all pages to retrieve the list of all versions. + // The Azul API doesn't return a total page count, so paginate until a page + // comes back empty (or short), guarding against a runaway loop with a cap. + const pageSize = 100; + const maxPages = 100; + let pageIndex = 1; + const availableVersions = []; + while (pageIndex <= maxPages) { + const requestArguments = `${baseRequestArguments}&page=${pageIndex}&page_size=${pageSize}`; + const availableVersionsUrl = `https://api.azul.com/metadata/v1/zulu/packages/?${requestArguments}`; + if (core.isDebug() && pageIndex === 1) { + // the url is identical except for the page number, so print it once for debug + core.debug(`Gathering available versions from '${availableVersionsUrl}'`); + } + const paginationPage = (yield this.http.getJson(availableVersionsUrl)).result; + if (!paginationPage || paginationPage.length === 0) { + // stop paginating because we have reached the end of the results + break; + } + availableVersions.push(...paginationPage); + if (paginationPage.length < pageSize) { + // a short page means this was the last one; avoid an extra empty request + break; + } + pageIndex++; + } + if (pageIndex > maxPages) { + core.warning(`Reached the maximum of ${maxPages} pages while listing Zulu versions; results may be truncated.`); + } if (core.isDebug()) { core.startGroup('Print information about available versions'); console.timeEnd('Retrieving available versions for Zulu took'); // eslint-disable-line no-console core.debug(`Available versions: [${availableVersions.length}]`); - core.debug(availableVersions.map(item => item.jdk_version.join('.')).join(', ')); + core.debug(availableVersions.map(item => item.java_version.join('.')).join(', ')); core.endGroup(); } return availableVersions; @@ -80512,14 +81391,18 @@ class ZuluDistribution extends base_installer_1.JavaBase { const arch = this.distributionArchitecture(); switch (arch) { case 'x64': - return { arch: 'x86', hw_bitness: '64', abi: '' }; + return 'x64'; case 'x86': - return { arch: 'x86', hw_bitness: '32', abi: '' }; + // The Azul Metadata API's "x86" value returns both 32-bit (i686) and + // 64-bit (x64) packages, which are indistinguishable by version and + // would let a 32-bit request resolve to a 64-bit JDK. Use "i686" to + // target only genuine 32-bit builds, matching the legacy API behavior. + return 'i686'; case 'aarch64': case 'arm64': - return { arch: 'arm', hw_bitness: '64', abi: '' }; + return 'aarch64'; default: - return { arch: arch, hw_bitness: '', abi: '' }; + return arch; } } getPlatformOption() { @@ -80529,6 +81412,10 @@ class ZuluDistribution extends base_installer_1.JavaBase { return 'macos'; case 'win32': return 'windows'; + case 'linux': + // The new Metadata API's "linux" value returns both glibc and musl packages; + // use "linux_glibc" to target only glibc, which is what standard runners use. + return 'linux_glibc'; default: return process.platform; } @@ -80577,14 +81464,27 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge }); }; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.deleteKey = exports.importKey = exports.PRIVATE_KEY_FILE = void 0; +exports.verifyPackageSignature = exports.deleteKey = exports.importKey = exports.toGpgPath = exports.PRIVATE_KEY_FILE = void 0; const fs = __importStar(__nccwpck_require__(79896)); const path = __importStar(__nccwpck_require__(16928)); const io = __importStar(__nccwpck_require__(94994)); const exec = __importStar(__nccwpck_require__(95236)); +const tc = __importStar(__nccwpck_require__(33472)); const util = __importStar(__nccwpck_require__(54527)); exports.PRIVATE_KEY_FILE = path.join(util.getTempDir(), 'private-key.asc'); const PRIVATE_KEY_FINGERPRINT_REGEX = /\w{40}/; +// Convert a Windows path (D:\a\_temp\...) to a POSIX path (/d/a/_temp/...). +// The Git-bundled GPG on Windows (MSYS2-based) uses POSIX path conventions +// internally. Passing Windows paths with backslashes can cause fatal GPG errors +// (exit code 2), so all paths passed to GPG must be in POSIX format on Windows. +function toGpgPath(p) { + if (process.platform !== 'win32') + return p; + return p + .replace(/\\/g, '/') + .replace(/^([A-Za-z]):\//, (_, drive) => `/${drive.toLowerCase()}/`); +} +exports.toGpgPath = toGpgPath; function importKey(privateKey) { return __awaiter(this, void 0, void 0, function* () { fs.writeFileSync(exports.PRIVATE_KEY_FILE, privateKey, { @@ -80621,6 +81521,130 @@ function deleteKey(keyFingerprint) { }); } exports.deleteKey = deleteKey; +function verifyPackageSignature(archivePath, signatureUrl, publicKeyContent) { + return __awaiter(this, void 0, void 0, function* () { + const signaturePath = yield tc.downloadTool(signatureUrl); + let gpgHome; + try { + gpgHome = fs.mkdtempSync(path.join(util.getTempDir(), 'verify-signature-gpg-home-')); + } + catch (error) { + try { + yield io.rmRF(signaturePath); + } + catch (_a) { + // ignore cleanup failures + } + throw new Error(`Failed to create temporary GPG home directory for signature verification: ${error.message}`); + } + try { + const publicKeyFile = path.join(gpgHome, 'public-key.asc'); + fs.writeFileSync(publicKeyFile, publicKeyContent, { encoding: 'utf-8' }); + const options = { silent: true }; + yield exec.exec('gpg', [ + '--homedir', + toGpgPath(gpgHome), + '--batch', + '--import', + toGpgPath(publicKeyFile) + ], options); + yield exec.exec('gpg', [ + '--homedir', + toGpgPath(gpgHome), + '--batch', + '--verify', + toGpgPath(signaturePath), + toGpgPath(archivePath) + ], options); + } + finally { + yield io.rmRF(signaturePath); + yield io.rmRF(gpgHome); + } + }); +} +exports.verifyPackageSignature = verifyPackageSignature; + + +/***/ }), + +/***/ 38172: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.configureMavenArgs = void 0; +const core = __importStar(__nccwpck_require__(37484)); +const util_1 = __nccwpck_require__(54527); +const constants_1 = __nccwpck_require__(27242); +/** + * 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() { + var _a; + const showDownloadProgress = (0, util_1.getBooleanInput)(constants_1.INPUT_SHOW_DOWNLOAD_PROGRESS, false); + if (showDownloadProgress) { + core.debug(`${constants_1.INPUT_SHOW_DOWNLOAD_PROGRESS} is true; leaving ${constants_1.MAVEN_ARGS_ENV} unchanged`); + return; + } + const existingArgs = ((_a = process.env[constants_1.MAVEN_ARGS_ENV]) !== null && _a !== void 0 ? _a : '').trim(); + const alreadyDisabled = existingArgs + .split(/\s+/) + .some(arg => arg === constants_1.MAVEN_NO_TRANSFER_PROGRESS_FLAG || + arg === constants_1.MAVEN_NO_TRANSFER_PROGRESS_LONG_FLAG); + if (alreadyDisabled) { + core.debug(`${constants_1.MAVEN_ARGS_ENV} already disables transfer progress; leaving it unchanged`); + return; + } + const updatedArgs = existingArgs + ? `${existingArgs} ${constants_1.MAVEN_NO_TRANSFER_PROGRESS_FLAG}` + : constants_1.MAVEN_NO_TRANSFER_PROGRESS_FLAG; + core.exportVariable(constants_1.MAVEN_ARGS_ENV, updatedArgs); + core.info(`Configured ${constants_1.MAVEN_ARGS_ENV} to include ${constants_1.MAVEN_NO_TRANSFER_PROGRESS_FLAG} to suppress Maven transfer progress logs. ` + + `Set '${constants_1.INPUT_SHOW_DOWNLOAD_PROGRESS}: true' to keep the download progress output.`); +} +exports.configureMavenArgs = configureMavenArgs; /***/ }), @@ -80675,20 +81699,22 @@ const constants = __importStar(__nccwpck_require__(27242)); const cache_1 = __nccwpck_require__(97377); const path = __importStar(__nccwpck_require__(16928)); const distribution_factory_1 = __nccwpck_require__(2970); +const maven_args_1 = __nccwpck_require__(38172); function run() { return __awaiter(this, void 0, void 0, function* () { try { const versions = core.getMultilineInput(constants.INPUT_JAVA_VERSION); - const distributionName = core.getInput(constants.INPUT_DISTRIBUTION, { - required: true - }); + let distributionName = core.getInput(constants.INPUT_DISTRIBUTION); const versionFile = core.getInput(constants.INPUT_JAVA_VERSION_FILE); const architecture = core.getInput(constants.INPUT_ARCHITECTURE); const packageType = core.getInput(constants.INPUT_JAVA_PACKAGE); - const jdkFile = core.getInput(constants.INPUT_JDK_FILE); + const jdkFile = getJdkFileInput(); const cache = core.getInput(constants.INPUT_CACHE); const cacheDependencyPath = core.getInput(constants.INPUT_CACHE_DEPENDENCY_PATH); const checkLatest = (0, util_1.getBooleanInput)(constants.INPUT_CHECK_LATEST, false); + const setDefault = (0, util_1.getBooleanInput)(constants.INPUT_SET_DEFAULT, true); + const verifySignature = (0, util_1.getBooleanInput)(constants.INPUT_VERIFY_SIGNATURE, false); + const verifySignaturePublicKey = core.getInput(constants.INPUT_VERIFY_SIGNATURE_PUBLIC_KEY) || undefined; let toolchainIds = core.getMultilineInput(constants.INPUT_MVN_TOOLCHAIN_ID); core.startGroup('Installed distributions'); if (versions.length !== toolchainIds.length) { @@ -80697,31 +81723,60 @@ function run() { if (!versions.length && !versionFile) { throw new Error('java-version or java-version-file input expected'); } - const installerInputsOptions = { - architecture, - packageType, - checkLatest, - distributionName, - jdkFile, - toolchainIds - }; if (!versions.length) { core.debug('java-version input is empty, looking for java-version-file input'); const content = fs_1.default.readFileSync(versionFile).toString().trim(); - const version = (0, util_1.getVersionFromFileContent)(content, distributionName, versionFile); - core.debug(`Parsed version from file '${version}'`); - if (!version) { + const versionInfo = (0, util_1.getVersionFromFileContent)(content, distributionName, versionFile); + core.debug(`Parsed version from file '${versionInfo === null || versionInfo === void 0 ? void 0 : versionInfo.version}'`); + if (!versionInfo) { throw new Error(`No supported version was found in file ${versionFile}`); } - yield installVersion(version, installerInputsOptions); + // Use distribution from file if available, otherwise use the input + if (versionInfo.distribution) { + core.info(`Using distribution '${versionInfo.distribution}' from ${versionFile}`); + distributionName = versionInfo.distribution; + } + else if (!distributionName) { + throw new Error('distribution input is required when not specified in the version file'); + } + const installerInputsOptions = { + architecture, + packageType, + checkLatest, + setDefault, + verifySignature, + verifySignaturePublicKey, + distributionName, + jdkFile, + toolchainIds + }; + yield installVersion(versionInfo.version, installerInputsOptions); } - for (const [index, version] of versions.entries()) { - yield installVersion(version, installerInputsOptions, index); + else { + // When using java-version input, distribution is still required + if (!distributionName) { + throw new Error('distribution input is required'); + } + const installerInputsOptions = { + architecture, + packageType, + checkLatest, + setDefault, + verifySignature, + verifySignaturePublicKey, + distributionName, + jdkFile, + toolchainIds + }; + for (const [index, version] of versions.entries()) { + yield installVersion(version, installerInputsOptions, index); + } } core.endGroup(); const matchersPath = path.join(__dirname, '..', '..', '.github'); core.info(`##[add-matcher]${path.join(matchersPath, 'java.json')}`); yield auth.configureAuthentication(); + (0, maven_args_1.configureMavenArgs)(); if (cache && (0, util_1.isCacheFeatureAvailable)()) { yield (0, cache_1.restore)(cache, cacheDependencyPath); } @@ -80732,13 +81787,24 @@ function run() { }); } run(); +function getJdkFileInput() { + const jdkFile = core.getInput(constants.INPUT_JDK_FILE); + const deprecatedJdkFile = core.getInput(constants.INPUT_JDK_FILE_DEPRECATED); + if (deprecatedJdkFile) { + core.warning(`The '${constants.INPUT_JDK_FILE_DEPRECATED}' input is deprecated and may be removed in a future release. Please use '${constants.INPUT_JDK_FILE}' instead.`); + } + return jdkFile || deprecatedJdkFile; +} function installVersion(version, options, toolchainId = 0) { return __awaiter(this, void 0, void 0, function* () { - const { distributionName, jdkFile, architecture, packageType, checkLatest, toolchainIds } = options; + const { distributionName, jdkFile, architecture, packageType, checkLatest, setDefault, verifySignature, verifySignaturePublicKey, toolchainIds } = options; const installerOptions = { architecture, packageType, checkLatest, + setDefault, + verifySignature, + verifySignaturePublicKey, version }; const distribution = (0, distribution_factory_1.getJavaDistribution)(distributionName, installerOptions, jdkFile); @@ -80804,7 +81870,6 @@ const path = __importStar(__nccwpck_require__(16928)); const core = __importStar(__nccwpck_require__(37484)); const io = __importStar(__nccwpck_require__(94994)); const constants = __importStar(__nccwpck_require__(27242)); -const util_1 = __nccwpck_require__(54527); const xmlbuilder2_1 = __nccwpck_require__(54697); function configureToolchains(version, distributionName, jdkHome, toolchainId) { return __awaiter(this, void 0, void 0, function* () { @@ -80812,7 +81877,6 @@ function configureToolchains(version, distributionName, jdkHome, toolchainId) { const id = toolchainId || `${vendor}_${version}`; const settingsDirectory = core.getInput(constants.INPUT_SETTINGS_PATH) || path.join(os.homedir(), constants.M2_DIR); - const overwriteSettings = (0, util_1.getBooleanInput)(constants.INPUT_OVERWRITE_SETTINGS, true); yield createToolchainsSettings({ jdkInfo: { version, @@ -80820,13 +81884,12 @@ function configureToolchains(version, distributionName, jdkHome, toolchainId) { id, jdkHome }, - settingsDirectory, - overwriteSettings + settingsDirectory }); }); } exports.configureToolchains = configureToolchains; -function createToolchainsSettings({ jdkInfo, settingsDirectory, overwriteSettings }) { +function createToolchainsSettings({ jdkInfo, settingsDirectory }) { return __awaiter(this, void 0, void 0, function* () { core.info(`Creating ${constants.MVN_TOOLCHAINS_FILE} for JDK version ${jdkInfo.version} from ${jdkInfo.vendor}`); // when an alternate m2 location is specified use only that location (no .m2 directory) @@ -80834,52 +81897,72 @@ function createToolchainsSettings({ jdkInfo, settingsDirectory, overwriteSetting yield io.mkdirP(settingsDirectory); const originalToolchains = yield readExistingToolchainsFile(settingsDirectory); const updatedToolchains = generateToolchainDefinition(originalToolchains, jdkInfo.version, jdkInfo.vendor, jdkInfo.id, jdkInfo.jdkHome); - yield writeToolchainsFileToDisk(settingsDirectory, updatedToolchains, overwriteSettings); + yield writeToolchainsFileToDisk(settingsDirectory, updatedToolchains); }); } exports.createToolchainsSettings = createToolchainsSettings; // only exported for testing purposes function generateToolchainDefinition(original, version, vendor, id, jdkHome) { - let xmlObj; + let jsToolchains = [ + { + type: 'jdk', + provides: { + version: `${version}`, + vendor: `${vendor}`, + id: `${id}` + }, + configuration: { + jdkHome: `${jdkHome}` + } + } + ]; + // default root attributes, used when the existing file does not declare its own + let rootAttributes = { + '@xmlns': 'http://maven.apache.org/TOOLCHAINS/1.1.0', + '@xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', + '@xsi:schemaLocation': 'http://maven.apache.org/TOOLCHAINS/1.1.0 https://maven.apache.org/xsd/toolchains-1.1.0.xsd' + }; if (original === null || original === void 0 ? void 0 : original.length) { - xmlObj = (0, xmlbuilder2_1.create)(original) + // convert existing toolchains into TS native objects for better handling + // xmlbuilder2 will convert the document into a `{toolchains: { toolchain: [] | {} }}` structure + // instead of the desired `toolchains: [{}]` one or simply `[{}]` + const jsObj = (0, xmlbuilder2_1.create)(original) .root() - .ele({ - toolchain: { - type: 'jdk', - provides: { - version: `${version}`, - vendor: `${vendor}`, - id: `${id}` - }, - configuration: { - jdkHome: `${jdkHome}` + .toObject(); + if (jsObj.toolchains) { + // preserve the existing root attributes (xmlns, schemaLocation, …) so we don't + // silently rewrite user-managed metadata or change the effective XML namespace; + // xmlbuilder2 exposes attributes as `@`-prefixed keys on the element object + const existingAttributes = Object.fromEntries(Object.entries(jsObj.toolchains).filter(([key]) => key.startsWith('@'))); + // fall back to the defaults only for attributes the existing file is missing + rootAttributes = Object.assign(Object.assign({}, rootAttributes), existingAttributes); + if (jsObj.toolchains.toolchain) { + // in case only a single child exists xmlbuilder2 will not create an array and using verbose = true equally doesn't work here + // See https://oozcitak.github.io/xmlbuilder2/serialization.html#js-object-and-map-serializers for details + if (Array.isArray(jsObj.toolchains.toolchain)) { + jsToolchains.push(...jsObj.toolchains.toolchain); + } + else { + jsToolchains.push(jsObj.toolchains.toolchain); } } + } + // remove potential duplicates based on type & id (which should be a unique combination); + // self.findIndex will only return the first occurrence, ensuring duplicates are skipped + jsToolchains = jsToolchains.filter((value, index, self) => { + var _a; + // ensure non-jdk toolchains are kept in the results, we must not touch them because they belong to the user + return value.type !== 'jdk' || + // keep toolchains that lack a usable string id (e.g. partially-formed user files); + // we cannot safely deduplicate them and must not crash while reading them + typeof ((_a = value.provides) === null || _a === void 0 ? void 0 : _a.id) !== 'string' || + index === + self.findIndex(t => { var _a, _b; return t.type === value.type && ((_a = t.provides) === null || _a === void 0 ? void 0 : _a.id) === ((_b = value.provides) === null || _b === void 0 ? void 0 : _b.id); }); }); } - else - xmlObj = (0, xmlbuilder2_1.create)({ - toolchains: { - '@xmlns': 'http://maven.apache.org/TOOLCHAINS/1.1.0', - '@xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', - '@xsi:schemaLocation': 'http://maven.apache.org/TOOLCHAINS/1.1.0 https://maven.apache.org/xsd/toolchains-1.1.0.xsd', - toolchain: [ - { - type: 'jdk', - provides: { - version: `${version}`, - vendor: `${vendor}`, - id: `${id}` - }, - configuration: { - jdkHome: `${jdkHome}` - } - } - ] - } - }); - return xmlObj.end({ + return (0, xmlbuilder2_1.create)({ + toolchains: Object.assign(Object.assign({}, rootAttributes), { toolchain: jsToolchains }) + }).end({ format: 'xml', wellFormed: false, headless: false, @@ -80900,19 +81983,21 @@ function readExistingToolchainsFile(directory) { return ''; }); } -function writeToolchainsFileToDisk(directory, settings, overwriteSettings) { +function writeToolchainsFileToDisk(directory, settings) { return __awaiter(this, void 0, void 0, function* () { const location = path.join(directory, constants.MVN_TOOLCHAINS_FILE); const settingsExists = fs.existsSync(location); - if (settingsExists && overwriteSettings) { - core.info(`Overwriting existing file ${location}`); - } - else if (!settingsExists) { - core.info(`Writing to ${location}`); + // The toolchains file is produced by a non-destructive merge (existing JDK, + // custom, and non-jdk toolchains are preserved – see generateToolchainDefinition), + // so it is always safe to write it. Unlike settings.xml, it is therefore not + // gated behind the `overwrite-settings` input; that would prevent subsequent + // setup-java runs from registering additional JDKs and silently drop the + // toolchain entries created by earlier runs. + if (settingsExists) { + core.info(`Updating existing file ${location}`); } else { - core.info(`Skipping generation of ${location} because file already exists and overwriting is not enabled`); - return; + core.info(`Writing to ${location}`); } return fs.writeFileSync(location, settings, { encoding: 'utf-8', @@ -81018,6 +82103,13 @@ function getDownloadArchiveExtension() { exports.getDownloadArchiveExtension = getDownloadArchiveExtension; function isVersionSatisfies(range, version) { var _a; + // Some distributions (e.g. JetBrains Runtime) publish 4-segment versions + // like '17.0.8.1+1080.1' that semver rejects. If the candidate version + // isn't valid semver, it can't match — bail out rather than letting + // compareBuild / satisfies throw. + if (!semver.valid(version)) { + return false; + } if (semver.valid(range)) { // if full version with build digit is provided as a range (such as '1.2.3+4') // we should check for exact equal via compareBuild @@ -81067,25 +82159,45 @@ function isCacheFeatureAvailable() { } exports.isCacheFeatureAvailable = isCacheFeatureAvailable; function getVersionFromFileContent(content, distributionName, versionFile) { - var _a, _b, _c, _d, _e; + var _a, _b, _c, _d; let javaVersionRegExp; + let extractedDistribution; function getFileName(versionFile) { return path_1.default.basename(versionFile); } const versionFileName = getFileName(versionFile); if (versionFileName == '.tool-versions') { + // Capture an optional asdf-java vendor prefix (e.g. `temurin-`, `corretto-`) + // in the `distribution` group so it can be mapped to a setup-java distribution. javaVersionRegExp = - /^java\s+(?:\S*-)?(?\d+(?:\.\d+)*([+_.-](?:openj9[-._]?\d[\w.-]*|java\d+|jre[-_\w]*|OpenJDK\d+[\w_.-]*|[a-z0-9]+))*)/im; + /^java\s+(?:(?\S*)-)?(?\d+(?:\.\d+)*([+_.-](?:openj9[-._]?\d[\w.-]*|java\d+|jre[-_\w]*|OpenJDK\d+[\w_.-]*|[a-z0-9]+))*)/im; } else if (versionFileName == '.sdkmanrc') { - javaVersionRegExp = /^java\s*=\s*(?[^-]+)/m; + // Match both version and optional distribution identifier + javaVersionRegExp = + /^java\s*=\s*(?[^-\s]+)(?:-(?[a-z0-9]+))?/m; } else { javaVersionRegExp = /(?(?<=(^|\s|-))(\d+\S*))(\s|$)/; } - const capturedVersion = ((_b = (_a = content.match(javaVersionRegExp)) === null || _a === void 0 ? void 0 : _a.groups) === null || _b === void 0 ? void 0 : _b.version) - ? (_d = (_c = content.match(javaVersionRegExp)) === null || _c === void 0 ? void 0 : _c.groups) === null || _d === void 0 ? void 0 : _d.version + const match = content.match(javaVersionRegExp); + const capturedVersion = ((_a = match === null || match === void 0 ? void 0 : match.groups) === null || _a === void 0 ? void 0 : _a.version) + ? match.groups.version : ''; + // Extract distribution from .sdkmanrc file + if (versionFileName == '.sdkmanrc' && ((_b = match === null || match === void 0 ? void 0 : match.groups) === null || _b === void 0 ? void 0 : _b.distribution)) { + const sdkmanDist = match.groups.distribution; + extractedDistribution = mapSdkmanDistribution(sdkmanDist); + core.debug(`Parsed distribution '${extractedDistribution}' from SDKMAN identifier '${sdkmanDist}'`); + } + // Extract distribution from asdf .tool-versions file + if (versionFileName == '.tool-versions' && ((_c = match === null || match === void 0 ? void 0 : match.groups) === null || _c === void 0 ? void 0 : _c.distribution)) { + const asdfDist = match.groups.distribution; + extractedDistribution = mapAsdfDistribution(asdfDist); + if (extractedDistribution) { + core.debug(`Parsed distribution '${extractedDistribution}' from asdf identifier '${asdfDist}'`); + } + } core.debug(`Parsed version '${capturedVersion}' from file '${versionFileName}'`); if (!capturedVersion) { return null; @@ -81099,13 +82211,79 @@ function getVersionFromFileContent(content, distributionName, versionFile) { if (!version) { return null; } - if (constants_1.DISTRIBUTIONS_ONLY_MAJOR_VERSION.includes(distributionName)) { - const coerceVersion = (_e = semver.coerce(version)) !== null && _e !== void 0 ? _e : version; + // Apply DISTRIBUTIONS_ONLY_MAJOR_VERSION logic whenever the effective distribution + // (either explicitly provided or extracted from the version file) is in the list. + if (constants_1.DISTRIBUTIONS_ONLY_MAJOR_VERSION.includes(extractedDistribution || distributionName)) { + const coerceVersion = (_d = semver.coerce(version)) !== null && _d !== void 0 ? _d : version; version = semver.major(coerceVersion).toString(); } - return version.toString(); + return { + version: version.toString(), + distribution: extractedDistribution + }; } exports.getVersionFromFileContent = getVersionFromFileContent; +// Map SDKMAN distribution identifiers to setup-java distribution names +function mapSdkmanDistribution(sdkmanDist) { + const distributionMap = { + tem: 'temurin', + sem: 'semeru', + albba: 'dragonwell', + zulu: 'zulu', + amzn: 'corretto', + graal: 'graalvm', + graalce: 'graalvm', + librca: 'liberica', + ms: 'microsoft', + oracle: 'oracle', + sapmchn: 'sapmachine', + jbr: 'jetbrains', + dragonwell: 'dragonwell', + kona: 'kona' + }; + const mapped = distributionMap[sdkmanDist.toLowerCase()]; + if (!mapped) { + core.warning(`Unknown SDKMAN distribution identifier '${sdkmanDist}'. Please specify the distribution explicitly.`); + } + return mapped; +} +// Map asdf-java (.tool-versions) vendor identifiers to setup-java distribution names. +// asdf-java encodes the vendor as a prefix on the version string, e.g. +// `java temurin-17.0.3+7` or `java semeru-openj9-11.0.25+9`. Packaging variants +// (`-jre`, `-musl`, `-openj9`, `-crac`, `-javafx`, ...) are collapsed onto the +// base vendor since setup-java does not distinguish them here. +function mapAsdfDistribution(asdfDist) { + const normalized = asdfDist.toLowerCase(); + // Multi-segment vendors that map to a distinct setup-java distribution. + if (normalized.startsWith('graalvm-community')) { + return 'graalvm-community'; + } + if (normalized.startsWith('oracle-graalvm')) { + return 'graalvm'; + } + const baseVendor = normalized.split('-')[0]; + const distributionMap = { + temurin: 'temurin', + adoptopenjdk: 'temurin', + zulu: 'zulu', + corretto: 'corretto', + liberica: 'liberica', + microsoft: 'microsoft', + semeru: 'semeru', + ibm: 'semeru', + dragonwell: 'dragonwell', + graalvm: 'graalvm', + oracle: 'oracle', + sapmachine: 'sapmachine', + kona: 'kona', + jetbrains: 'jetbrains' + }; + const mapped = distributionMap[baseVendor]; + if (!mapped) { + core.warning(`Unknown asdf distribution identifier '${asdfDist}'. Please specify the distribution explicitly.`); + } + return mapped; +} // By convention, action expects version 8 in the format `8.*` instead of `1.8` function avoidOldNotation(content) { return content.startsWith('1.') ? content.substring(2) : content; @@ -128071,7 +129249,7 @@ Object.defineProperty(exports, "YAMLWriter", ({ enumerable: true, get: function /***/ ((module) => { "use strict"; -module.exports = /*#__PURE__*/JSON.parse('{"name":"@actions/cache","version":"5.0.5","preview":true,"description":"Actions cache lib","keywords":["github","actions","cache"],"homepage":"https://github.com/actions/toolkit/tree/main/packages/cache","license":"MIT","main":"lib/cache.js","types":"lib/cache.d.ts","directories":{"lib":"lib","test":"__tests__"},"files":["lib","!.DS_Store"],"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/actions/toolkit.git","directory":"packages/cache"},"scripts":{"audit-moderate":"npm install && npm audit --json --audit-level=moderate > audit.json","test":"echo \\"Error: run tests from root\\" && exit 1","tsc":"tsc"},"bugs":{"url":"https://github.com/actions/toolkit/issues"},"dependencies":{"@actions/core":"^2.0.0","@actions/exec":"^2.0.0","@actions/glob":"^0.5.1","@protobuf-ts/runtime-rpc":"^2.11.1","@actions/http-client":"^3.0.2","@actions/io":"^2.0.0","@azure/abort-controller":"^1.1.0","@azure/core-rest-pipeline":"^1.22.0","@azure/storage-blob":"^12.29.1","semver":"^6.3.1"},"devDependencies":{"@types/node":"^24.1.0","@types/semver":"^6.0.0","@protobuf-ts/plugin":"^2.9.4","typescript":"^5.2.2"},"overrides":{"uri-js":"npm:uri-js-replace@^1.0.1","node-fetch":"^3.3.2"}}'); +module.exports = /*#__PURE__*/JSON.parse('{"name":"@actions/cache","version":"5.1.0","preview":true,"description":"Actions cache lib","keywords":["github","actions","cache"],"homepage":"https://github.com/actions/toolkit/tree/main/packages/cache","license":"MIT","main":"lib/cache.js","types":"lib/cache.d.ts","directories":{"lib":"lib","test":"__tests__"},"files":["lib","!.DS_Store"],"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/actions/toolkit.git","directory":"packages/cache"},"scripts":{"audit-moderate":"npm install && npm audit --json --audit-level=moderate > audit.json","test":"echo \\"Error: run tests from root\\" && exit 1","tsc":"tsc"},"bugs":{"url":"https://github.com/actions/toolkit/issues"},"dependencies":{"@actions/core":"^2.0.0","@actions/exec":"^2.0.0","@actions/glob":"^0.5.1","@protobuf-ts/runtime-rpc":"^2.11.1","@actions/http-client":"^3.0.2","@actions/io":"^2.0.0","@azure/abort-controller":"^1.1.0","@azure/core-rest-pipeline":"^1.22.0","@azure/storage-blob":"^12.29.1","semver":"^6.3.1"},"devDependencies":{"@types/node":"^24.1.0","@types/semver":"^6.0.0","@protobuf-ts/plugin":"^2.9.4","typescript":"^5.2.2"},"overrides":{"uri-js":"npm:uri-js-replace@^1.0.1","node-fetch":"^3.3.2"}}'); /***/ }) diff --git a/docs/adrs/0000-v2-setup-java.md b/docs/adrs/0000-v2-setup-java.md index 2d0c170d3..c8ea4502c 100644 --- a/docs/adrs/0000-v2-setup-java.md +++ b/docs/adrs/0000-v2-setup-java.md @@ -34,7 +34,7 @@ Requiring a default version will break users that are pinned to `@main` as they `setup-java` should be structured in such a way that will allow the open source community to easily add support for extra distributions. -Existing code will be restructured so that distribution specific code will be easily separated. Currently the core download logic is in a single file, `installer.ts`. This file will be split up and abstracted out so that there will be no vendor specified logic. Each distribution will have it's own files under `src/distributions` that will contain the core setup logic for a specific distribution. +Existing code will be restructured so that distribution specific code will be easily separated. Currently the core download logic is in a single file, `installer.ts`. This file will be split up and abstracted out so that there will be no vendor specified logic. Each distribution will have its own files under `src/distributions` that will contain the core setup logic for a specific distribution. ```yaml ∟ src/ diff --git a/docs/adrs/README.md b/docs/adrs/README.md index f23a8f723..e76d1d05e 100644 --- a/docs/adrs/README.md +++ b/docs/adrs/README.md @@ -16,4 +16,4 @@ This folder includes ADRs for the setup-java action. ADRs are proposed in the fo --- -- More information about ADRs can be found [here](https://github.com/joelparkerhenderson/architecture_decision_record). \ No newline at end of file +- See [more information about ADRs](https://github.com/joelparkerhenderson/architecture_decision_record). \ No newline at end of file diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md index b4035c6e6..bbd6a8903 100644 --- a/docs/advanced-usage.md +++ b/docs/advanced-usage.md @@ -10,17 +10,23 @@ - [Alibaba Dragonwell](#Alibaba-Dragonwell) - [SapMachine](#SapMachine) - [GraalVM](#GraalVM) + - [GraalVM Community](#GraalVM-Community) - [JetBrains](#JetBrains) + - [Tencent Kona](#Tencent-Kona) - [Installing custom Java package type](#Installing-custom-Java-package-type) + - [JavaFX Maven project](#JavaFX-Maven-project) - [Installing custom Java architecture](#Installing-custom-Java-architecture) +- [Installing JDK without setting as default](#Installing-JDK-without-setting-as-default) - [Installing custom Java distribution from local file](#Installing-Java-from-local-file) - [Testing against different Java distributions](#Testing-against-different-Java-distributions) - [Testing against different platforms](#Testing-against-different-platforms) - [Publishing using Apache Maven](#Publishing-using-Apache-Maven) +- [Maven transfer progress (download logs)](#Maven-transfer-progress-download-logs) - [Publishing using Gradle](#Publishing-using-Gradle) - [Hosted Tool Cache](#Hosted-Tool-Cache) - [Modifying Maven Toolchains](#Modifying-Maven-Toolchains) - [Java-version file](#Java-version-file) +- [Self-signed certificates and internal CAs (GitHub Enterprise)](#Self-signed-certificates-and-internal-CAs-GitHub-Enterprise) See [action.yml](../action.yml) for more details on task inputs. @@ -35,8 +41,8 @@ steps: - uses: actions/setup-java@v5 with: distribution: 'temurin' - java-version: '21' -- run: java -cp java HelloWorldApp + java-version: '25' +- run: java --version ``` ### Adopt @@ -49,7 +55,7 @@ steps: with: distribution: 'adopt-hotspot' java-version: '11' -- run: java -cp java HelloWorldApp +- run: java --version ``` ### Zulu @@ -60,9 +66,9 @@ steps: - uses: actions/setup-java@v5 with: distribution: 'zulu' - java-version: '21' - java-package: jdk # optional (jdk, jre, jdk+fx or jre+fx) - defaults to jdk -- run: java -cp java HelloWorldApp + java-version: '25' + java-package: jdk # optional (jdk, jre, jdk+fx, jre+fx, jdk+crac, or jre+crac) - defaults to jdk +- run: java --version ``` ### Liberica @@ -73,9 +79,9 @@ steps: - uses: actions/setup-java@v5 with: distribution: 'liberica' - java-version: '21' + java-version: '25' java-package: jdk # optional (jdk, jre, jdk+fx or jre+fx) - defaults to jdk -- run: java -cp java HelloWorldApp +- run: java --version ``` ### Microsoft @@ -86,8 +92,8 @@ steps: - uses: actions/setup-java@v5 with: distribution: 'microsoft' - java-version: '21' -- run: java -cp java HelloWorldApp + java-version: '25' +- run: java --version ``` ### Using Microsoft distribution on GHES @@ -101,7 +107,7 @@ uses: actions/setup-java@v5 with: token: ${{ secrets.GH_DOTCOM_TOKEN }} distribution: 'microsoft' - java-version: '21' + java-version: '25' ``` If the runner is not able to access github.com, any Java versions requested during a workflow run must come from the runner's tool cache. See "[Setting up the tool cache on self-hosted runners without internet access](https://docs.github.com/en/enterprise-server@3.2/admin/github-actions/managing-access-to-actions-from-githubcom/setting-up-the-tool-cache-on-self-hosted-runners-without-internet-access)" for more information. @@ -115,8 +121,8 @@ steps: - uses: actions/setup-java@v5 with: distribution: 'corretto' - java-version: '21' -- run: java -cp java HelloWorldApp + java-version: '25' +- run: java --version ``` ### Oracle @@ -128,8 +134,8 @@ steps: - uses: actions/setup-java@v5 with: distribution: 'oracle' - java-version: '21' -- run: java -cp java HelloWorldApp + java-version: '25' +- run: java --version ``` ### Alibaba Dragonwell @@ -142,7 +148,7 @@ steps: with: distribution: 'dragonwell' java-version: '8' -- run: java -cp java HelloWorldApp +- run: java --version ``` ### SapMachine @@ -153,8 +159,8 @@ steps: - uses: actions/setup-java@v5 with: distribution: 'sapmachine' - java-version: '21' -- run: java -cp java HelloWorldApp + java-version: '25' +- run: java --version ``` ### GraalVM @@ -166,17 +172,32 @@ steps: - uses: actions/setup-java@v5 with: distribution: 'graalvm' + java-version: '25' +- run: | + java --version + native-image --version +``` + +### GraalVM Community +**NOTE:** GraalVM Community is available for stable JDK 17 and later releases. + +```yaml +steps: +- uses: actions/checkout@v6 +- uses: actions/setup-java@v5 + with: + distribution: 'graalvm-community' java-version: '21' - run: | - java -cp java HelloWorldApp - native-image -cp java HelloWorldApp + java --version + native-image --version ``` ### JetBrains **NOTE:** JetBrains is only available for LTS versions on 11 or later (11, 17, 21, etc.). -Not all minor LTS versions are guarenteed to be available, since JetBrains considers what to ship IntelliJ IDEA with, most commonly on JDK 11. +Not all minor LTS versions are guaranteed to be available, since JetBrains considers what to ship IntelliJ IDEA with, most commonly on JDK 11. For example, `11.0.24` is not available but `11.0.16` is. ```yaml @@ -186,7 +207,7 @@ steps: with: distribution: 'jetbrains' java-version: '11' -- run: java -cp java HelloWorldApp +- run: java --version ``` The JetBrains installer uses the GitHub API to fetch the latest version. If you believe your project is going to be running into rate limits, you can provide a @@ -202,7 +223,7 @@ steps: java-package: 'jdk' # optional (jdk, jre, jdk+jcef, jre+jcef, jdk+ft, or jre+ft) - defaults to jdk env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -- run: java -cp java HelloWorldApp +- run: java --version ``` You can specify your package type (as shown in the [releases page](https://github.com/JetBrains/JetBrainsRuntime/releases/)) in the `java-package` parameter. @@ -215,6 +236,18 @@ The available package types are: - `jdk+ft` - JBRSDK (FreeType) - `jre+ft` - JBR (FreeType) +### Tencent Kona +**NOTE:** Tencent Kona supports major versions 8, 11, 17, 21 and 25, and provides jdk only. + +```yaml +steps: +- uses: actions/checkout@v6 +- uses: actions/setup-java@v5 + with: + distribution: 'kona' + java-version: '21' +- run: java --version +``` ## Installing custom Java package type ```yaml @@ -223,9 +256,33 @@ steps: - uses: actions/setup-java@v5 with: distribution: '' - java-version: '11' + java-version: '25' java-package: jdk # optional (jdk or jre) - defaults to jdk -- run: java -cp java HelloWorldApp +- run: java --version +``` + +### JavaFX Maven project + +For JavaFX projects that use Maven, use `jdk+fx` (or `jre+fx`) as the `java-package` value together with a distribution that supports it (e.g. `zulu` or `liberica`). Then include the [`javafx-maven-plugin`](https://openjfx.io/openjfx-docs/#maven) in your `pom.xml` as described in the [Getting Started with JavaFX](https://openjfx.io/openjfx-docs/#maven) guide. + +```yaml +steps: +- uses: actions/checkout@v6 +- uses: actions/setup-java@v5 + with: + distribution: 'zulu' + java-version: '25' + java-package: jdk+fx + cache: maven +- name: Build with Maven + run: mvn --no-transfer-progress compile +``` + +To run the JavaFX application in CI: + +```yaml +- name: Run with Maven + run: mvn --no-transfer-progress javafx:run ``` ## Installing custom Java architecture @@ -236,14 +293,45 @@ steps: - uses: actions/setup-java@v5 with: distribution: '' - java-version: '11' + java-version: '25' architecture: x86 # optional - default value derived from the runner machine -- run: java -cp java HelloWorldApp +- run: java --version ``` +## Installing JDK without setting as default + +When installing multiple JDKs, the last one installed becomes the default (`JAVA_HOME`, `PATH`). Use the `set-default` option to install a JDK without overriding the default. The installed JDK is still discoverable via the `JAVA_HOME__` environment variable (e.g. `JAVA_HOME_21_X64`). + +```yaml +steps: +- uses: actions/checkout@v6 +- uses: actions/setup-java@v5 + with: + distribution: 'temurin' + java-version: '17' +- uses: actions/setup-java@v5 + id: setup-java-21 + with: + distribution: 'temurin' + java-version: '21' + set-default: false +- run: | + echo "Default java:" + java -version + echo "Java 21 home: $JAVA_HOME_21_X64" + echo "Java 21 path from output: ${{ steps.setup-java-21.outputs.path }}" +``` + +In this example, `JAVA_HOME` and `java` on `PATH` point to Java 17, while Java 21 is available via `JAVA_HOME_21_X64` or the step output `path`. + +> **Note:** When a single step installs multiple JDKs via a multiline `java-version`, the `set-default` value applies to all of them. With `set-default: false`, none of those JDKs become the default; each remains discoverable through its `JAVA_HOME__` variable. Regardless of `set-default`, installed JDKs are still registered in the Maven toolchains file, so they can be selected via Maven toolchains. + ## Installing Java from local file If your use-case requires a custom distribution or a version that is not provided by setup-java, you can download it manually and setup-java will take care of the installation and caching on the VM: +> [!NOTE] +> This approach also lets you use builds that setup-java does not provide directly, such as **Early Access (EA)** or other unreleased JDK builds (for example, an upcoming feature release or a Loom/Valhalla preview build). Download the desired archive in a prior step and point `jdk-file` at it; setup-java will extract, install, and cache it just like a supported distribution. When targeting multiple architectures, select the correct binary per architecture in your workflow (for example, with a build matrix). + ```yaml steps: - run: | @@ -252,11 +340,28 @@ steps: - uses: actions/setup-java@v5 with: distribution: 'jdkfile' - jdkFile: ${{ runner.temp }}/java_package.tar.gz + jdk-file: ${{ runner.temp }}/java_package.tar.gz java-version: '11.0.0' architecture: x64 -- run: java -cp java HelloWorldApp +- run: java --version +``` + +For example, to use an **Early Access** build from [jdk.java.net](https://jdk.java.net/), download the archive for your runner OS/architecture and install it via `distribution: 'jdkfile'` (example below assumes Linux x64): + +```yaml +steps: +- run: | + download_url="https://download.java.net/java/early_access/jdk25/36/GPL/openjdk-25-ea+36_linux-x64_bin.tar.gz" + wget -O $RUNNER_TEMP/java_package.tar.gz $download_url +- uses: actions/setup-java@v5 + with: + distribution: 'jdkfile' + jdk-file: ${{ runner.temp }}/java_package.tar.gz + java-version: '25.0.0-ea.36' + architecture: x64 + +- run: java --version ``` If your use-case requires a custom distribution (in the example, alpine-linux is used) or a version that is not provided by setup-java and you want to always install the latest version during runtime, then you can use the following code to auto-download the latest JDK, determine the semver needed for setup-java, and setup-java will take care of the installation and caching on the VM: @@ -278,10 +383,10 @@ If your use-case requires a custom distribution (in the example, alpine-linux is - uses: actions/setup-java@v5 with: distribution: 'jdkfile' - jdkFile: ${{ runner.temp }}/java_package.tar.gz + jdk-file: ${{ runner.temp }}/java_package.tar.gz java-version: {{ steps.fetch_latest_jdk.outputs.java_version }} architecture: x64 - - run: java -cp java HelloWorldApp + - run: java --version ``` ## Testing against different Java distributions @@ -302,7 +407,7 @@ jobs: with: distribution: ${{ matrix.distribution }} java-version: ${{ matrix.java }} - - run: java -cp java HelloWorldApp + - run: java --version ``` #### Testing against different platforms @@ -322,7 +427,7 @@ jobs: with: distribution: 'temurin' java-version: ${{ matrix.java }} - - run: java -cp java HelloWorldApp + - run: java --version ``` ## Publishing using Apache Maven @@ -374,6 +479,7 @@ The two `settings.xml` files created from the above example look like the follow + false github @@ -393,6 +499,7 @@ The two `settings.xml` files created from the above example look like the follow + false maven @@ -409,6 +516,8 @@ The two `settings.xml` files created from the above example look like the follow ***NOTE***: The `settings.xml` file is created in the Actions `$HOME/.m2` directory. If you have an existing `settings.xml` file at that location, it will be overwritten. See [below](#apache-maven-with-a-settings-path) for using the `settings-path` to change your `settings.xml` file location. +***NOTE***: The generated `settings.xml` sets `false` so that Maven never blocks a CI run waiting on an interactive prompt. This is applied automatically whenever the action generates `settings.xml`. + If you don't want to overwrite the `settings.xml` file, you can set `overwrite-settings: false` ### Extra setup for pom.xml: @@ -464,6 +573,74 @@ jobs: GITHUB_TOKEN: ${{ github.token }} ``` +## Maven transfer progress (download logs) + +By default, Maven prints a line for every artifact it downloads, which can add hundreds of noisy lines to CI logs. To keep logs clean, `setup-java` sets the [`MAVEN_ARGS`](https://maven.apache.org/configure.html#maven_args-environment-variable) environment variable to include `-ntp` (`--no-transfer-progress`) so that subsequent Maven invocations in the job suppress this transfer progress output. + +This is enabled by default. Any existing `MAVEN_ARGS` value is preserved (the flag is appended, not overwritten), and the flag is not added twice if you already set it yourself. + +If you want to keep the download/transfer progress in your logs, set `show-download-progress: true`: + +```yaml +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-java@v5 + with: + distribution: '' + java-version: '21' + show-download-progress: true # keep Maven download/transfer progress in the logs + + - name: Build with Maven + run: mvn -B package --file pom.xml +``` + +***NOTES***: +- `MAVEN_ARGS` is honored by Maven 3.9.0+ and the Maven Wrapper (`mvnw`). Older Maven versions ignore it, so on those you can pass `--no-transfer-progress` on the command line instead. +- This setting only affects Maven. It has no effect on Gradle, sbt, or other build tools. +- `-ntp` only controls transfer/progress output; it does not change whether Maven runs in batch mode. Use `-B`/`--batch-mode` (or `false` in `settings.xml`) if you also want non-interactive runs. + +## Java problem matcher (compiler annotations) + +`setup-java` registers a [problem matcher](https://github.com/actions/toolkit/blob/main/docs/problem-matchers.md) for Java after installing the JDK. It scans the log output of subsequent steps and turns `javac` diagnostics into GitHub [annotations](https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#setting-a-warning-message) that appear in the run summary and inline on the affected files. It matches two kinds of lines: + +- Compiler errors and warnings, e.g. `App.java:12: error: cannot find symbol` (owner `javac`). +- Uncaught-exception header lines, e.g. `Exception in thread "main" ...`; because these lines have no file or line captures, they appear as log/run-level annotations rather than inline file annotations (owner `java`). + +This is enabled by default and requires no configuration. + +### Disabling the problem matcher + +There is no action input to turn the matcher off, but you can disable it for the rest of the job with the built-in [`remove-matcher`](https://github.com/actions/toolkit/blob/main/docs/problem-matchers.md#remove-a-problem-matcher) workflow command. Pass the matcher **owner** (not a file name); the Java matcher defines two owners, `javac` and `java`, so remove both to fully suppress it: + +```yaml +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-java@v5 + with: + distribution: '' + java-version: '21' + + - name: Disable the Java problem matcher + run: | + echo "::remove-matcher owner=javac::" + echo "::remove-matcher owner=java::" + + - name: Build with Maven + run: mvn -B package --file pom.xml +``` + +***NOTES***: +- `remove-matcher` only stops annotations from being created; the underlying compiler output is unchanged, so a failing `javac`/build still fails the step. +- The command is scoped to the job, so add the step right after `setup-java` (and before your build) in every job where you want the matcher disabled. + ## Publishing using Gradle ```yaml jobs: @@ -507,6 +684,8 @@ The `setup-java` action generates a basic [Maven Toolchains declaration](https:/ ### Installing Multiple JDKs With Toolchains Subsequent calls to `setup-java` with distinct distribution and version parameters will continue to extend the toolchains declaration and make all specified Java versions available. +Toolchain entries are always merged non-destructively: existing JDK, custom, and user-managed toolchains are preserved, and only an entry with the exact same `type` and `provides.id` is replaced. This behavior is independent of the `overwrite-settings` input, which only controls regeneration of `settings.xml`. As a result, running `setup-java` several times in the same job (for example in multiple steps or with multiple `java-version` values) accumulates every JDK in `toolchains.xml` instead of dropping previously registered entries. + ```yaml steps: - uses: actions/setup-java@v5 @@ -531,7 +710,7 @@ The result is a Toolchain with entries for JDKs 8, 11 and 15. You can even combi - uses: actions/setup-java@v5 with: distribution: 'jdkfile' - jdkFile: ${{ runner.temp }}/java_package.tar.gz + jdk-file: ${{ runner.temp }}/java_package.tar.gz java-version: '1.6' architecture: x64 ``` @@ -548,7 +727,7 @@ Each JDK provider will receive a default `vendor` using the `distribution` input - uses: actions/setup-java@v5 with: distribution: 'jdkfile' - jdkFile: ${{ runner.temp }}/java_package.tar.gz + jdk-file: ${{ runner.temp }}/java_package.tar.gz java-version: '1.6' architecture: x64 mvn-toolchain-vendor: 'Oracle' @@ -580,7 +759,7 @@ steps: distribution: 'temurin' java-version: '11' mvn-toolchain-id: 'some_other_id' -- run: java -cp java HelloWorldApp +- run: java --version ``` In case you install multiple versions of Java at once you can use the same syntax as used in `java-versions`. Please note that you have to declare an ID for all Java versions that will be installed or the `mvn-toolchain-id` instruction will be skipped wholesale due to mapping ambiguities. @@ -603,19 +782,55 @@ steps: Supported files are `.java-version`, `.tool-versions` and `.sdkmanrc`. * In `.java-version` file, only the version should be specified (e.g., 17.0.7). The `.java-version` file recognizes all variants of the version description according to [jenv](https://github.com/jenv/jenv). - * In `.tool-versions` file, java version should be preceded by the java keyword (e.g., java 17.0.7). The `.tool-versions` file supports version specifications in accordance with [asdf](https://github.com/asdf-vm/asdf) standards, adhering to Semantic Versioning ([semver](https://semver.org/)). - * In `.sdkmanrc` file, java version should be preceded by the `java=` prefix (e.g., java=17.0.7-tem) and include the distribution. The `.sdkmanrc` file supports version specifications in accordance with [file format](https://sdkman.io/usage#env-command), see [Sdkman! documentation](https://sdkman.io/jdks) for more information. + * In `.tool-versions` file, java version should be preceded by the java keyword (e.g., java 17.0.7). The `.tool-versions` file supports version specifications in accordance with [asdf](https://github.com/asdf-vm/asdf) standards, adhering to Semantic Versioning ([semver](https://semver.org/)). When the entry includes an [asdf-java](https://github.com/halcyon/asdf-java) vendor prefix (e.g. `java temurin-17.0.3+7`), setup-java can infer the `distribution` input automatically. Unrecognized vendor prefixes require setting `distribution` explicitly. + + Supported asdf-java vendor prefix mappings (packaging variants such as `-jre`, `-musl`, `-openj9`, `-crac`, `-javafx` are collapsed onto the base vendor): + + | asdf-java vendor prefix | setup-java distribution | + | ----------------------- | ----------------------- | + | `temurin` | `temurin` | + | `adoptopenjdk` | `temurin` | + | `zulu` | `zulu` | + | `corretto` | `corretto` | + | `liberica` | `liberica` | + | `microsoft` | `microsoft` | + | `semeru`, `ibm` | `semeru` | + | `dragonwell` | `dragonwell` | + | `graalvm`, `oracle-graalvm` | `graalvm` | + | `graalvm-community` | `graalvm-community` | + | `oracle` | `oracle` | + | `sapmachine` | `sapmachine` | + | `kona` | `kona` | + | `jetbrains` | `jetbrains` | + + * In `.sdkmanrc` file, java version should be preceded by the `java=` prefix (e.g., `java=17.0.7-tem`). When a recognized SDKMAN distribution suffix is present, setup-java can infer the `distribution` input automatically. Unrecognized suffixes require setting `distribution` explicitly. The `.sdkmanrc` file supports version specifications in accordance with [file format](https://sdkman.io/usage#env-command), see [Sdkman! documentation](https://sdkman.io/jdks) for more information. + + Supported SDKMAN suffix mappings: + + | SDKMAN suffix | setup-java distribution | + | ------------- | ----------------------- | + | `tem` | `temurin` | + | `sem` | `semeru` | + | `albba`, `dragonwell` | `dragonwell` | + | `zulu` | `zulu` | + | `amzn` | `corretto` | + | `graal`, `graalce` | `graalvm` | + | `librca` | `liberica` | + | `ms` | `microsoft` | + | `oracle` | `oracle` | + | `sapmchn` | `sapmachine` | + | `jbr` | `jetbrains` | + | `kona` | `kona` | If both `java-version` and `java-version-file` **inputs** are provided, the `java-version` input will be used. -**Example step using `Sdkman!`**: +**Example step using `Sdkman!`** (distribution inferred from `.sdkmanrc`): ```yml - name: Setup java uses: actions/setup-java@v5 with: java-version-file: '.sdkmanrc' - distribution: 'temurin' ``` **Example `.sdkmanrc`**: @@ -623,6 +838,19 @@ steps: java=17.0.7-tem ``` +**Example step using `asdf`** (distribution inferred from `.tool-versions`): +```yml + - name: Setup java + uses: actions/setup-java@v5 + with: + java-version-file: '.tool-versions' +``` + +**Example `.tool-versions`**: +``` +java temurin-17.0.7+7 +``` + Valid entry options (does not apply to `.sdkmanrc`): ``` major versions: 8, 11, 16, 17, 21 @@ -635,3 +863,94 @@ If the file contains multiple versions, only the first one will be recognized. ***NOTE***: For the tool-version file, ensure that you use standard semantic versioning (semver) formats, as non-standard formats (such as jetbrains-21b212.1) may not be parsed correctly. Additionally, for complex version strings containing multiple version-like segments (for example, java semeru-openj9-11.0.15+10_openj9-0.32.0), the extraction logic may incorrectly capture the last segment (0.32.0) instead of the main version (11.0.15+10). + +## Self-signed certificates and internal CAs (GitHub Enterprise) + +When `setup-java` dynamically downloads a JDK, it makes HTTPS requests both to fetch the available version metadata and to download the JDK archive. If your runners sit behind a **TLS-inspecting corporate proxy**, or you are on **GitHub Enterprise Server (GHES)** with an internal certificate authority, those requests can fail with an error such as: + +``` +Error: self signed certificate in certificate chain +``` + +This happens because the certificate presented to the runner is signed by an **internal or self-signed CA** that is not part of the runner's default trust store. The download itself is fine — the runner simply cannot verify the certificate chain. + +### Recommended fix: trust your internal CA + +The secure way to resolve this is to make the runner trust your organization's CA, which keeps TLS verification fully enabled. `setup-java` runs on Node.js, which honors the [`NODE_EXTRA_CA_CERTS`](https://nodejs.org/api/cli.html#node_extra_ca_certsfile) environment variable. Point it at your CA bundle (in PEM format) **before** the `actions/setup-java` step: + +```yaml +steps: + # The CA bundle is already present on the runner image in this example. + # Alternatively, write it from a secret in a previous step. + - name: Trust the internal CA + run: echo "NODE_EXTRA_CA_CERTS=/etc/ssl/certs/internal-ca.pem" >> "$GITHUB_ENV" + + - uses: actions/setup-java@v5 + with: + distribution: 'temurin' + java-version: '21' +``` + +If you keep the certificate in a secret rather than on the runner image, write it to disk first: + +```yaml +steps: + - name: Write and trust the internal CA + run: | + echo "${{ secrets.INTERNAL_CA_PEM }}" > "${RUNNER_TEMP}/internal-ca.pem" + echo "NODE_EXTRA_CA_CERTS=${RUNNER_TEMP}/internal-ca.pem" >> "$GITHUB_ENV" + + - uses: actions/setup-java@v5 + with: + distribution: 'temurin' + java-version: '21' +``` + +For **self-hosted runners**, you can instead install your CA into the operating system's trust store (for example, `update-ca-certificates` on Debian/Ubuntu or `update-ca-trust` on RHEL). This makes the certificate trusted for all tooling on the runner, not just `setup-java`. + +### GitHub Enterprise customers + +On **GitHub Enterprise Server**, traffic from your runners frequently passes through an organization-managed proxy or terminates TLS at an appliance using a certificate from an internal CA. If your workflows hit the error above, set `NODE_EXTRA_CA_CERTS` to your enterprise CA bundle (or bake the CA into your self-hosted runner image) as shown above. Coordinate with your platform team to obtain the correct PEM bundle for your appliance and proxy chain. + +### Security warning: do not disable certificate verification + +Do **not** work around this error by disabling TLS verification (for example, by setting `NODE_TLS_REJECT_UNAUTHORIZED=0`). `setup-java` does not verify a pinned checksum or signature of the downloaded archive, so **TLS is effectively the only integrity guarantee** on the JDK download. Disabling verification would expose your workflow to a man-in-the-middle attacker who could serve a tampered JDK — which then becomes the `java` used by the rest of your pipeline, with access to your secrets and credentials. Always extend trust to your CA instead of turning verification off. + +### Trusting an internal CA inside the installed JDK + +The guidance above makes the **runner** trust your CA so that the JDK can be *downloaded*. That is a separate layer from making the **installed JDK** trust your CA at *application runtime*. If your build steps (Maven/Gradle dependency resolution, integration tests, HTTPS calls from your app, etc.) connect to internal services that present a certificate from your internal CA, the JDK will reject them with errors such as: + +``` +PKIX path building failed: unable to find valid certification path to requested target +``` + +The JDK keeps its own trust store — a keystore named `cacerts` under `$JAVA_HOME/lib/security/cacerts` — which is independent of the operating system and Node trust stores. After `setup-java` has run (so that `JAVA_HOME` points at the freshly installed JDK), import your CA into that keystore with `keytool`: + +```yaml +steps: + - uses: actions/setup-java@v5 + with: + distribution: 'temurin' + java-version: '21' + + - name: Import internal CA into the JDK trust store + shell: bash + run: | + # Write the CA from a secret (or reference a file already on the runner) + echo "${{ secrets.INTERNAL_CA_PEM }}" > "${RUNNER_TEMP}/internal-ca.pem" + keytool -importcert -noprompt \ + -alias internal-ca \ + -file "${RUNNER_TEMP}/internal-ca.pem" \ + -keystore "${JAVA_HOME}/lib/security/cacerts" \ + -storepass changeit +``` + +Notes and caveats: + +- The default keystore password for `cacerts` is `changeit` unless your distribution overrides it. +- On **hosted runners** the change applies only to the current job's JDK and is discarded when the job ends, so include the import step in every job that needs it. +- On **self-hosted runners**, importing into a tool-cache JDK persists for as long as that cached version remains on the runner; if you want it to survive JDK reinstalls, pre-seed the CA into your runner image or re-run the import step each time. +- Prefer giving the certificate a stable, descriptive `-alias` so re-runs are idempotent (re-importing the same alias will fail; add `keytool -delete -alias internal-ca ...` first if you re-run within a long-lived runner). + +This documents the post-install workflow; there is no dedicated action input for supplying a custom `cacerts` file. + diff --git a/docs/contributors.md b/docs/contributors.md index 0d49925a0..771e3b7bf 100644 --- a/docs/contributors.md +++ b/docs/contributors.md @@ -6,13 +6,13 @@ We have prepared a short guide so that the process of making your contribution i ## How can I contribute... -* [Contribute Documentation:green_book:](#contribute-documentation) +* [:green_book: Contribute Documentation](#contribute-documentation) -* [Contribute Code :computer:](#contribute-code) +* [:computer: Contribute Code](#contribute-code) -* [Provide Support on Issues:pencil:](#provide-support-on-issues) +* [:pencil: Provide Support on Issues](#provide-support-on-issues) -* [Review Pull Requests:mag:](#review-pull-requests) +* [:mag: Review Pull Requests](#review-pull-requests) ## Contribute documentation @@ -63,6 +63,17 @@ Pull requests are the easiest way to contribute changes to git repos at GitHub. - To lint the code, **you need to run the `lint:fix` script** - To transpile source code to `javascript` we use [NCC](https://github.com/vercel/ncc). **It is very important to run the `build` script after making changes**, otherwise your changes will not get into the final `javascript` build +> [!TIP] +> Instead of running each script individually, you can run the aggregate scripts: +> +> - `npm run fix` — formats, lints (with autofix) and rebuilds the `dist/` bundle. +> - `npm run check` — runs the same validation as CI: `format-check`, `lint`, `build` and `test`. **Run this before pushing a pull request** to make sure it will pass the required checks. +> +> Git hooks are installed automatically when you run `npm install` (via [husky](https://typicode.github.io/husky/)): +> +> - a **pre-commit** hook formats and lints staged files with [lint-staged](https://github.com/lint-staged/lint-staged); +> - a **pre-push** hook rebuilds `dist/` and runs the test suite. + **Learn more about how to implement tests:** Adding or changing tests is an integral part of making a change to the code. @@ -111,4 +122,4 @@ Another great way to contribute is is to review pull request. Please, be extra k - Make sure you're familiar with the code or documentation is updated, unless it's a minor change (spellchecking, minor formatting, etc.) - Review changes using the GitHub functionality. You can ask a clarifying question, point out an error or suggest an alternative. > Note: You may ask for minor changes - "nitpicks", but consider whether they are real blockers to merging or not -- Submit your review, which may include comments, an approval, or a changes request \ No newline at end of file +- Submit your review, which may include comments, an approval, or a changes request diff --git a/package-lock.json b/package-lock.json index c2dd5b271..c5938e234 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "setup-java", - "version": "5.2.0", + "version": "5.6.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "setup-java", - "version": "5.2.0", + "version": "5.6.0", "license": "MIT", "dependencies": { - "@actions/cache": "^5.0.5", + "@actions/cache": "^5.1.0", "@actions/core": "^2.0.3", "@actions/exec": "^2.0.0", "@actions/glob": "^0.5.1", @@ -21,18 +21,20 @@ }, "devDependencies": { "@types/jest": "^30.0.0", - "@types/node": "^25.9.3", + "@types/node": "^26.0.0", "@types/semver": "^7.5.8", "@typescript-eslint/eslint-plugin": "^8.48.0", - "@typescript-eslint/parser": "^8.35.1", + "@typescript-eslint/parser": "^8.62.0", "@vercel/ncc": "^0.44.0", "eslint": "^8.57.0", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-jest": "^29.0.1", + "eslint-plugin-jest": "^29.15.4", "eslint-plugin-node": "^11.1.0", + "husky": "^9.1.7", "jest": "^30.4.2", "jest-circus": "^30.4.2", - "prettier": "^3.6.2", + "lint-staged": "^17.0.8", + "prettier": "^3.9.1", "ts-jest": "^29.4.11", "typescript": "^5.3.3" }, @@ -50,9 +52,9 @@ } }, "node_modules/@actions/cache": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/@actions/cache/-/cache-5.0.5.tgz", - "integrity": "sha512-jiQSg0gfd+C2KPgcmdCOq7dCuCIQQWQ4b1YfGIRaaA9w7PJbRwTOcCz4LiFEUnqZGf0ha/8OKL3BeNwetHzYsQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@actions/cache/-/cache-5.1.0.tgz", + "integrity": "sha512-kTIj4YPrjjRPKSGlj7f8eq+Pijoy/SKBEbJcAwNsQTFGEF29NGqj1mqD02/PmhV6r4bRAixycexAWpmUJ2aCwg==", "license": "MIT", "dependencies": { "@actions/core": "^2.0.0", @@ -1993,13 +1995,13 @@ } }, "node_modules/@types/node": { - "version": "25.9.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.3.tgz", - "integrity": "sha512-603BddQMv3pUcr4U2dhujk83N2tTDVr/34wII2B6bJy6g+8WD6yUb11jszNs0gdi4PesVWl7ABt8nYMVpnLUcg==", + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.0.0.tgz", + "integrity": "sha512-vf2YFi1iY9lHGwNJMs01biZFbKJkrZR1T6/MlzjhJLPdntOHLhTrDSnSVcdtvjihi4VQNlrFRIxLsDBlQpAipA==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": ">=7.24.0 <7.24.7" + "undici-types": "~8.3.0" } }, "node_modules/@types/semver": { @@ -2072,17 +2074,17 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.48.0.tgz", - "integrity": "sha512-jCzKdm/QK0Kg4V4IK/oMlRZlY+QOcdjv89U2NgKHZk1CYTj82/RVSx1mV/0gqCVMJ/DA+Zf/S4NBWNF8GQ+eqQ==", + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.62.0.tgz", + "integrity": "sha512-dzHeT2gySzZtLDsuqxU9AkYgIsQoHAHtRBpOqM+Ofzx1Bwrd2RcCjQJ+6iQbsHOIR6NS33bF2W1k3blN1zLDrA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.48.0", - "@typescript-eslint/types": "8.48.0", - "@typescript-eslint/typescript-estree": "8.48.0", - "@typescript-eslint/visitor-keys": "8.48.0", - "debug": "^4.3.4" + "@typescript-eslint/scope-manager": "8.62.0", + "@typescript-eslint/types": "8.62.0", + "@typescript-eslint/typescript-estree": "8.62.0", + "@typescript-eslint/visitor-keys": "8.62.0", + "debug": "^4.4.3" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2092,8 +2094,177 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/project-service": { + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.62.0.tgz", + "integrity": "sha512-wexnCqiTg7BOGtbLDftYpRWlmLq4xfoMd7BKFR6Y75sZS3QmRKLdN3yWLhmIYgqMmP/OXWpj3H8odkb5nGURCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.62.0", + "@typescript-eslint/types": "^8.62.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.62.0.tgz", + "integrity": "sha512-1lX38kNxXIRb8mEc3lbq5mdHq1Pf2+U0nFU65KfT18mtPxxl0fvjuEE92mHuXPuCtElJhOrddOpyMlM3Z0umEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.62.0", + "@typescript-eslint/visitor-keys": "8.62.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.62.0.tgz", + "integrity": "sha512-y2GAdB6ykaXUvuspbYnizQc4oDDz0Tz/Yc7iWrXf9mx8vm/L/0vLHCe0tS2boG96Zy+DivnVDQ9ZUEWoHqqx1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.62.0.tgz", + "integrity": "sha512-KvAclkktORPvM54TgLgA4z9HIV1M8zOgw9ZVNXl9f/8dLYfXYX1wkMXP7qmabpijQRV5bHJLOmoyGQbLMaUYeg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.62.0.tgz", + "integrity": "sha512-+hVbNxtW64pIcZWDPGbyaKF7vp2IBTVY5ma1blwwksrjdsbdqqEKvJWMGbBofei4F6Dovx1M0RJgoFeNu2279A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.62.0", + "@typescript-eslint/tsconfig-utils": "8.62.0", + "@typescript-eslint/types": "8.62.0", + "@typescript-eslint/visitor-keys": "8.62.0", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.62.0.tgz", + "integrity": "sha512-CY3uyFSRbcQv3nnSv8S0+lDftMVz6P963PoRlxrV7ew/Md564g9ut60PYzdLM5qW4jFn93GBF+Soi90ISAN+GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.62.0", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/@typescript-eslint/project-service": { @@ -3053,6 +3224,85 @@ "dev": true, "license": "MIT" }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.2.0.tgz", + "integrity": "sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^8.0.0", + "string-width": "^8.2.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/cli-truncate/node_modules/string-width": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.1.tgz", + "integrity": "sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -3131,11 +3381,12 @@ } }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -3233,6 +3484,19 @@ "dev": true, "license": "MIT" }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/error-ex": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", @@ -3356,10 +3620,11 @@ } }, "node_modules/eslint-plugin-jest": { - "version": "29.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-29.0.1.tgz", - "integrity": "sha512-EE44T0OSMCeXhDrrdsbKAhprobKkPtJTbQz5yEktysNpHeDZTAL1SfDTNKmcFfJkY6yrQLtTKZALrD3j/Gpmiw==", + "version": "29.15.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-29.15.4.tgz", + "integrity": "sha512-6ln5i9Nkrb27X4w91ZPt/xHDsVQnvxTS2ntgq6r32u+8gymdUrp88TdcBXSveZW0Dl+M5v2H6K75kJhMvUGhjg==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/utils": "^8.0.0" }, @@ -3368,8 +3633,9 @@ }, "peerDependencies": { "@typescript-eslint/eslint-plugin": "^8.0.0", - "eslint": "^8.57.0 || ^9.0.0", - "jest": "*" + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "jest": "*", + "typescript": ">=4.8.4 <7.0.0" }, "peerDependenciesMeta": { "@typescript-eslint/eslint-plugin": { @@ -3377,6 +3643,9 @@ }, "jest": { "optional": true + }, + "typescript": { + "optional": true } } }, @@ -3552,6 +3821,13 @@ "node": ">=0.10.0" } }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "dev": true, + "license": "MIT" + }, "node_modules/events": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", @@ -3813,6 +4089,19 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-east-asian-width": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-package-type": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", @@ -3981,6 +4270,22 @@ "node": ">=10.17.0" } }, + "node_modules/husky": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, "node_modules/ignore": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", @@ -5048,45 +5353,331 @@ "dev": true, "license": "MIT" }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "node_modules/lint-staged": { + "version": "17.0.8", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-17.0.8.tgz", + "integrity": "sha512-B2P/d+jVW0UXOQ0MVMLrB/9ydA1P+zz6jYfdrbbEd9ur3S2rcbduFWKiUCC02Sm5hbC8nrm7y24WuYMG54HfxA==", "dev": true, + "license": "MIT", "dependencies": { - "p-locate": "^5.0.0" + "listr2": "^10.2.1", + "picomatch": "^4.0.4", + "string-argv": "^0.3.2", + "tinyexec": "^1.2.4" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" }, "engines": { - "node": ">=10" + "node": ">=22.22.1" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/lint-staged" + }, + "optionalDependencies": { + "yaml": "^2.9.0" } }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "node_modules/lint-staged/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/make-dir": { - "version": "4.0.0", + "node_modules/listr2": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-10.2.2.tgz", + "integrity": "sha512-JtNtbZj8q5BnDMR7trpwvwk3RIrANtIVzEUm8w7amp6xelLgyuq+4WZoTH913XaQAoH/cNdYhaNzBPA2U3xbDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^5.2.0", + "eventemitter3": "^5.0.4", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^10.0.0" + }, + "engines": { + "node": ">=22.13.0" + } + }, + "node_modules/listr2/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/listr2/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/listr2/node_modules/string-width": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.1.tgz", + "integrity": "sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/listr2/node_modules/wrap-ansi": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-10.0.0.tgz", + "integrity": "sha512-SGcvg80f0wUy2/fXES19feHMz8E0JoXv2uNgHOu4Dgi2OrCy1lqwFYEJz1BLbDI0exjPMe/ZdzZ/YpGECBG/aQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.3", + "string-width": "^8.2.0", + "strip-ansi": "^7.1.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/log-update": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-escapes": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", + "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/log-update/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-update/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, @@ -5132,6 +5723,19 @@ "node": ">=6" } }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimatch": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", @@ -5165,9 +5769,10 @@ } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, "node_modules/napi-postinstall": { "version": "0.3.4", @@ -5537,9 +6142,9 @@ } }, "node_modules/prettier": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", - "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.1.tgz", + "integrity": "sha512-ppiDo2CSwexck1eyZUwJHg/N3nf1+6IRCv7W/VJ5vaLnVCmB7+3CdRfMwoCHBBX6xTrREDTksZ4OZl5SSf4zXA==", "dev": true, "license": "MIT", "bin": { @@ -5714,6 +6319,52 @@ "node": ">=4" } }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -5724,6 +6375,13 @@ "node": ">=0.10.0" } }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -5810,6 +6468,52 @@ "node": ">=8" } }, + "node_modules/slice-ansi": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-8.0.0.tgz", + "integrity": "sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.3", + "is-fullwidth-code-point": "^5.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -5861,6 +6565,16 @@ "node": ">=8" } }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, "node_modules/string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", @@ -6040,6 +6754,16 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "node_modules/tinyexec": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", + "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", @@ -6095,10 +6819,11 @@ "dev": true }, "node_modules/ts-api-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", - "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", "dev": true, + "license": "MIT", "engines": { "node": ">=18.12" }, @@ -6247,18 +6972,18 @@ } }, "node_modules/undici": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.24.1.tgz", - "integrity": "sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==", + "version": "6.27.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.27.0.tgz", + "integrity": "sha512-YmfV3YnEDzXRC5lZ2jWtWWHKGUm1zIt8AhesR1tens+HTNv+YZlN/dp6G727LOvMJ8xjP9Be7Y2Sdr96LDm+pg==", "license": "MIT", "engines": { "node": ">=18.17" } }, "node_modules/undici-types": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", - "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", + "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", "dev": true, "license": "MIT" }, @@ -6503,6 +7228,23 @@ "dev": true, "license": "ISC" }, + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "dev": true, + "license": "ISC", + "optional": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", diff --git a/package.json b/package.json index 89d842da6..6f5d50247 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "setup-java", - "version": "5.2.0", + "version": "5.6.0", "private": true, "description": "setup java action", "main": "dist/setup/index.js", @@ -13,10 +13,22 @@ "format-check": "prettier --no-error-on-unmatched-pattern --config ./.prettierrc.js --check \"**/*.{ts,yml,yaml}\"", "lint": "eslint --config ./.eslintrc.js \"**/*.ts\"", "lint:fix": "eslint --config ./.eslintrc.js \"**/*.ts\" --fix", + "check": "npm run format-check && npm run lint && npm run build && npm test", + "fix": "npm run format && npm run lint:fix && npm run build", + "prepare": "husky install", "prerelease": "npm run-script build", "release": "git add -f dist/setup/index.js dist/cleanup/index.js", "test": "jest" }, + "lint-staged": { + "*.ts": [ + "prettier --no-error-on-unmatched-pattern --config ./.prettierrc.js --write", + "eslint --config ./.eslintrc.js --fix" + ], + "*.{yml,yaml}": [ + "prettier --no-error-on-unmatched-pattern --config ./.prettierrc.js --write" + ] + }, "repository": { "type": "git", "url": "git+https://github.com/actions/setup-java.git" @@ -29,7 +41,7 @@ "author": "GitHub", "license": "MIT", "dependencies": { - "@actions/cache": "^5.0.5", + "@actions/cache": "^5.1.0", "@actions/core": "^2.0.3", "@actions/exec": "^2.0.0", "@actions/glob": "^0.5.1", @@ -41,18 +53,20 @@ }, "devDependencies": { "@types/jest": "^30.0.0", - "@types/node": "^25.9.3", + "@types/node": "^26.0.0", "@types/semver": "^7.5.8", "@typescript-eslint/eslint-plugin": "^8.48.0", - "@typescript-eslint/parser": "^8.35.1", + "@typescript-eslint/parser": "^8.62.0", "@vercel/ncc": "^0.44.0", "eslint": "^8.57.0", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-jest": "^29.0.1", + "eslint-plugin-jest": "^29.15.4", "eslint-plugin-node": "^11.1.0", + "husky": "^9.1.7", "jest": "^30.4.2", "jest-circus": "^30.4.2", - "prettier": "^3.6.2", + "lint-staged": "^17.0.8", + "prettier": "^3.9.1", "ts-jest": "^29.4.11", "typescript": "^5.3.3" }, diff --git a/src/auth.ts b/src/auth.ts index c8ea6291c..52ee3ede9 100644 --- a/src/auth.ts +++ b/src/auth.ts @@ -80,6 +80,7 @@ export function generate( '@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, servers: { server: [ { diff --git a/src/cache.ts b/src/cache.ts index 7d13839ee..1ca7e7628 100644 --- a/src/cache.ts +++ b/src/cache.ts @@ -12,6 +12,30 @@ const STATE_CACHE_PRIMARY_KEY = 'cache-primary-key'; const CACHE_MATCHED_KEY = 'cache-matched-key'; const CACHE_KEY_PREFIX = 'setup-java'; +/** + * An additional cache entry that is restored and saved independently of the + * main dependency cache. Used for build-tool wrapper distributions that rarely + * change (e.g. the Maven wrapper distribution) so that they are not evicted + * every time a volatile dependency file such as pom.xml changes. See + * https://github.com/actions/setup-java/issues/1095. + */ +interface AdditionalCache { + /** + * Short identifier for the cache, used to build its cache key and to scope + * the state keys that carry information from restore to save. + */ + name: string; + /** + * Paths that make up this cache entry. + */ + path: string[]; + /** + * Glob patterns whose hash forms the cache key. If no file matches, the + * cache is skipped silently (the project simply does not use this feature). + */ + pattern: string[]; +} + interface PackageManager { id: 'maven' | 'gradle' | 'sbt'; /** @@ -19,20 +43,36 @@ interface PackageManager { */ path: string[]; pattern: string[]; + /** + * Additional caches keyed independently of the main dependency cache. + */ + additionalCaches?: AdditionalCache[]; } const supportedPackageManager: PackageManager[] = [ { id: 'maven', path: [join(os.homedir(), '.m2', 'repository')], // https://github.com/actions/cache/blob/0638051e9af2c23d10bb70fa9beffcad6cff9ce3/examples.md#java---maven - pattern: ['**/pom.xml'] + pattern: [ + '**/pom.xml', + '**/.mvn/wrapper/maven-wrapper.properties', + '**/.mvn/extensions.xml' + ], + // The Maven wrapper distribution only depends on the wrapper properties, + // which change very rarely, so it is cached separately from the local + // repository. This keeps it available across the frequent pom.xml changes + // that rotate the main cache key. See issue #1095. + additionalCaches: [ + { + name: 'maven-wrapper', + path: [join(os.homedir(), '.m2', 'wrapper', 'dists')], + pattern: ['**/.mvn/wrapper/maven-wrapper.properties'] + } + ] }, { id: 'gradle', - path: [ - join(os.homedir(), '.gradle', 'caches'), - join(os.homedir(), '.gradle', 'wrapper') - ], + path: [join(os.homedir(), '.gradle', 'caches')], // https://github.com/actions/cache/blob/0638051e9af2c23d10bb70fa9beffcad6cff9ce3/examples.md#java---gradle pattern: [ '**/*.gradle*', @@ -41,6 +81,17 @@ const supportedPackageManager: PackageManager[] = [ 'buildSrc/**/Dependencies.kt', 'gradle/*.versions.toml', '**/versions.properties' + ], + // The Gradle wrapper distribution only depends on the wrapper properties, + // which change very rarely, so it is cached separately from the Gradle + // caches. This keeps it available across the frequent *.gradle* changes + // that rotate the main cache key. See issue #269. + additionalCaches: [ + { + name: 'gradle-wrapper', + path: [join(os.homedir(), '.gradle', 'wrapper')], + pattern: ['**/gradle-wrapper.properties'] + } ] }, { @@ -80,6 +131,21 @@ function findPackageManager(id: string): PackageManager { return packageManager; } +/** + * State keys used to carry an additional cache's restore-time information over + * to the post (save) action, scoped by the additional cache name. + */ +function additionalCachePrimaryKeyState(name: string): string { + return `${STATE_CACHE_PRIMARY_KEY}-${name}`; +} +function additionalCacheMatchedKeyState(name: string): string { + return `${CACHE_MATCHED_KEY}-${name}`; +} + +function buildCacheKey(id: string, fileHash: string): string { + return `${CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${process.arch}-${id}-${fileHash}`; +} + /** * A function that generates a cache key to use. * Format of the generated key will be "${{ platform }}-${{ id }}-${{ fileHash }}"". @@ -98,7 +164,22 @@ async function computeCacheKey( `No file in ${process.cwd()} matched to [${pattern}], make sure you have checked out the target repository` ); } - return `${CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${process.arch}-${packageManager.id}-${fileHash}`; + return buildCacheKey(packageManager.id, fileHash); +} + +/** + * Computes the cache key for an additional cache. Unlike {@link computeCacheKey} + * this returns undefined (instead of throwing) when no file matches the pattern, + * because additional caches are optional features that many projects do not use. + */ +async function computeAdditionalCacheKey( + additionalCache: AdditionalCache +): Promise { + const fileHash = await glob.hashFiles(additionalCache.pattern.join('\n')); + if (!fileHash) { + return undefined; + } + return buildCacheKey(additionalCache.name, fileHash); } /** @@ -111,6 +192,7 @@ export async function restore(id: string, cacheDependencyPath: string) { const primaryKey = await computeCacheKey(packageManager, cacheDependencyPath); core.debug(`primary key is ${primaryKey}`); core.saveState(STATE_CACHE_PRIMARY_KEY, primaryKey); + core.setOutput(STATE_CACHE_PRIMARY_KEY, 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(packageManager.path, primaryKey); @@ -122,6 +204,40 @@ export async function restore(id: string, cacheDependencyPath: string) { core.setOutput('cache-hit', false); core.info(`${packageManager.id} cache is not found`); } + + for (const additionalCache of packageManager.additionalCaches ?? []) { + await restoreAdditionalCache(additionalCache); + } +} + +/** + * Restore an additional cache (e.g. a build-tool wrapper distribution) that is + * keyed independently of the main dependency cache so that it survives changes + * to volatile dependency files. Skips silently when the project does not use + * the corresponding feature. + */ +async function restoreAdditionalCache(additionalCache: AdditionalCache) { + const primaryKey = await computeAdditionalCacheKey(additionalCache); + if (!primaryKey) { + core.debug( + `No file matched [${additionalCache.pattern}] for the ${additionalCache.name} cache, skipping.` + ); + return; + } + core.debug(`${additionalCache.name} primary key is ${primaryKey}`); + core.saveState( + additionalCachePrimaryKeyState(additionalCache.name), + primaryKey + ); + + const matchedKey = await cache.restoreCache(additionalCache.path, primaryKey); + if (matchedKey) { + core.saveState( + additionalCacheMatchedKeyState(additionalCache.name), + matchedKey + ); + core.info(`${additionalCache.name} cache restored from key: ${matchedKey}`); + } } /** @@ -135,6 +251,10 @@ export async function save(id: string) { // Inputs are re-evaluated before the post action, so we want the original key used for restore const primaryKey = core.getState(STATE_CACHE_PRIMARY_KEY); + for (const additionalCache of packageManager.additionalCaches ?? []) { + await saveAdditionalCache(packageManager, additionalCache); + } + if (!primaryKey) { core.warning('Error retrieving key from state.'); return; @@ -146,7 +266,15 @@ export async function save(id: string) { return; } try { - await cache.saveCache(packageManager.path, primaryKey); + const cacheId = await cache.saveCache(packageManager.path, 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. + core.debug(`Cache was not saved for the key: ${primaryKey}`); + return; + } core.info(`Cache saved with the key: ${primaryKey}`); } catch (error) { const err = error as Error; @@ -164,6 +292,70 @@ export async function save(id: string) { } } +/** + * Save an additional cache under its own key. Skips when no key was recorded at + * restore time (feature unused) or when the exact key was already restored. + */ +async function saveAdditionalCache( + packageManager: PackageManager, + additionalCache: AdditionalCache +) { + const primaryKey = core.getState( + additionalCachePrimaryKeyState(additionalCache.name) + ); + const matchedKey = core.getState( + additionalCacheMatchedKeyState(additionalCache.name) + ); + + if (!primaryKey) { + // The feature is not used by this project, nothing to save. + core.debug( + `No primary key for the ${additionalCache.name} cache, not saving cache.` + ); + return; + } else if (matchedKey === primaryKey) { + core.info( + `Cache hit occurred on the ${additionalCache.name} primary key ${primaryKey}, not saving cache.` + ); + return; + } + try { + const cacheId = await cache.saveCache(additionalCache.path, primaryKey); + if (cacheId === -1) { + core.debug( + `${additionalCache.name} cache was not saved for the key: ${primaryKey}` + ); + return; + } + core.info( + `${additionalCache.name} cache saved with the key: ${primaryKey}` + ); + } catch (error) { + const err = error as Error; + + if (err.name === cache.ValidationError.name) { + // The cache paths did not resolve, e.g. the wrapper distribution was + // never downloaded because a system build tool was used or the download + // failed. Optional wrapper caches must not fail the post step, so skip. + core.debug( + `${additionalCache.name} cache paths do not exist, not saving cache: ${err.message}` + ); + return; + } + + if (err.name === cache.ReserveCacheError.name) { + core.info(err.message); + } else { + if (isProbablyGradleDaemonProblem(packageManager, err)) { + core.warning( + 'Failed to save Gradle cache on Windows. If tar.exe reported "Permission denied", try to run Gradle with `--no-daemon` option. Refer to https://github.com/actions/cache/issues/454 for details.' + ); + } + throw error; + } + } +} + /** * @param packageManager the specified package manager by user * @param error the error thrown by the saveCache diff --git a/src/constants.ts b/src/constants.ts index 93af286f8..2f7362b05 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -4,8 +4,12 @@ export const INPUT_JAVA_VERSION_FILE = 'java-version-file'; export const INPUT_ARCHITECTURE = 'architecture'; export const INPUT_JAVA_PACKAGE = 'java-package'; export const INPUT_DISTRIBUTION = 'distribution'; -export const INPUT_JDK_FILE = 'jdkFile'; +export const INPUT_JDK_FILE = 'jdk-file'; +export const INPUT_JDK_FILE_DEPRECATED = 'jdkFile'; export const INPUT_CHECK_LATEST = 'check-latest'; +export const INPUT_SET_DEFAULT = 'set-default'; +export const INPUT_VERIFY_SIGNATURE = 'verify-signature'; +export const INPUT_VERIFY_SIGNATURE_PUBLIC_KEY = 'verify-signature-public-key'; export const INPUT_SERVER_ID = 'server-id'; export const INPUT_SERVER_USERNAME = 'server-username'; export const INPUT_SERVER_PASSWORD = 'server-password'; @@ -28,5 +32,10 @@ export const MVN_SETTINGS_FILE = 'settings.xml'; export const MVN_TOOLCHAINS_FILE = 'toolchains.xml'; export const INPUT_MVN_TOOLCHAIN_ID = 'mvn-toolchain-id'; export const INPUT_MVN_TOOLCHAIN_VENDOR = 'mvn-toolchain-vendor'; +export const INPUT_SHOW_DOWNLOAD_PROGRESS = 'show-download-progress'; + +export const MAVEN_ARGS_ENV = 'MAVEN_ARGS'; +export const MAVEN_NO_TRANSFER_PROGRESS_FLAG = '-ntp'; +export const MAVEN_NO_TRANSFER_PROGRESS_LONG_FLAG = '--no-transfer-progress'; export const DISTRIBUTIONS_ONLY_MAJOR_VERSION = ['corretto']; diff --git a/src/distributions/base-installer.ts b/src/distributions/base-installer.ts index 5d9f3c82a..bf8d9d3b7 100644 --- a/src/distributions/base-installer.ts +++ b/src/distributions/base-installer.ts @@ -20,6 +20,9 @@ export abstract class JavaBase { protected packageType: string; protected stable: boolean; protected checkLatest: boolean; + protected setDefault: boolean; + protected verifySignature: boolean; + protected verifySignaturePublicKey: string | undefined; constructor( protected distribution: string, @@ -36,6 +39,12 @@ export abstract class JavaBase { this.architecture = installerOptions.architecture || os.arch(); this.packageType = installerOptions.packageType; this.checkLatest = installerOptions.checkLatest; + this.setDefault = + installerOptions.setDefault !== undefined + ? installerOptions.setDefault + : true; + this.verifySignature = installerOptions.verifySignature ?? false; + this.verifySignaturePublicKey = installerOptions.verifySignaturePublicKey; } protected abstract downloadTool( @@ -46,6 +55,12 @@ export abstract class JavaBase { ): Promise; public async setupJava(): Promise { + if (this.verifySignature && !this.supportsSignatureVerification()) { + throw new Error( + `Input 'verify-signature' is not supported for distribution '${this.distribution}'.` + ); + } + let foundJava = this.findInToolcache(); if (foundJava && !this.checkLatest) { core.info(`Resolved Java ${foundJava.version} from tool-cache`); @@ -169,8 +184,15 @@ export abstract class JavaBase { foundJava.path = macOSPostfixPath; } - core.info(`Setting Java ${foundJava.version} as the default`); - this.setJavaDefault(foundJava.version, foundJava.path); + if (this.setDefault) { + core.info(`Setting Java ${foundJava.version} as the default`); + this.setJavaDefault(foundJava.version, foundJava.path); + } else { + core.info( + `Installing Java ${foundJava.version} (not setting as default)` + ); + this.setJavaEnvironment(foundJava.version, foundJava.path); + } return foundJava; } @@ -179,6 +201,10 @@ export abstract class JavaBase { return `Java_${this.distribution}_${this.packageType}`; } + protected supportsSignatureVerification(): boolean { + return false; + } + protected getToolcacheVersionName(version: string): string { if (!this.stable) { if (version.includes('+')) { @@ -298,9 +324,13 @@ export abstract class JavaBase { } protected setJavaDefault(version: string, toolPath: string) { - const majorVersion = version.split('.')[0]; core.exportVariable('JAVA_HOME', toolPath); core.addPath(path.join(toolPath, 'bin')); + this.setJavaEnvironment(version, toolPath); + } + + protected setJavaEnvironment(version: string, toolPath: string) { + const majorVersion = version.split('.')[0]; core.setOutput('distribution', this.distribution); core.setOutput('path', toolPath); core.setOutput('version', version); diff --git a/src/distributions/base-models.ts b/src/distributions/base-models.ts index 82344d585..b2ca3f0ff 100644 --- a/src/distributions/base-models.ts +++ b/src/distributions/base-models.ts @@ -3,6 +3,9 @@ export interface JavaInstallerOptions { architecture: string; packageType: string; checkLatest: boolean; + setDefault?: boolean; + verifySignature?: boolean; + verifySignaturePublicKey?: string; } export interface JavaInstallerResults { @@ -13,4 +16,5 @@ export interface JavaInstallerResults { export interface JavaDownloadRelease { version: string; url: string; + signatureUrl?: string; } diff --git a/src/distributions/corretto/installer.ts b/src/distributions/corretto/installer.ts index 52af2dd96..fd732899c 100644 --- a/src/distributions/corretto/installer.ts +++ b/src/distributions/corretto/installer.ts @@ -127,8 +127,7 @@ export class CorrettoDistribution extends JavaBase { private getAvailableVersionsForPlatform( eligibleVersions: - | ICorrettoAllAvailableVersions['os']['arch']['imageType'] - | undefined + ICorrettoAllAvailableVersions['os']['arch']['imageType'] | undefined ): ICorrettoAvailableVersions[] { const availableVersions: ICorrettoAvailableVersions[] = []; diff --git a/src/distributions/distribution-factory.ts b/src/distributions/distribution-factory.ts index 9cd459e65..22b48aee2 100644 --- a/src/distributions/distribution-factory.ts +++ b/src/distributions/distribution-factory.ts @@ -11,8 +11,12 @@ import {CorrettoDistribution} from './corretto/installer'; import {OracleDistribution} from './oracle/installer'; import {DragonwellDistribution} from './dragonwell/installer'; import {SapMachineDistribution} from './sapmachine/installer'; -import {GraalVMDistribution} from './graalvm/installer'; +import { + GraalVMCommunityDistribution, + GraalVMDistribution +} from './graalvm/installer'; import {JetBrainsDistribution} from './jetbrains/installer'; +import {KonaDistribution} from './kona/installer'; enum JavaDistribution { Adopt = 'adopt', @@ -29,7 +33,9 @@ enum JavaDistribution { Dragonwell = 'dragonwell', SapMachine = 'sapmachine', GraalVM = 'graalvm', - JetBrains = 'jetbrains' + GraalVMCommunity = 'graalvm-community', + JetBrains = 'jetbrains', + Kona = 'kona' } export function getJavaDistribution( @@ -74,8 +80,12 @@ export function getJavaDistribution( return new SapMachineDistribution(installerOptions); case JavaDistribution.GraalVM: return new GraalVMDistribution(installerOptions); + case JavaDistribution.GraalVMCommunity: + return new GraalVMCommunityDistribution(installerOptions); case JavaDistribution.JetBrains: return new JetBrainsDistribution(installerOptions); + case JavaDistribution.Kona: + return new KonaDistribution(installerOptions); default: return null; } diff --git a/src/distributions/graalvm/installer.ts b/src/distributions/graalvm/installer.ts index fea3b8f1e..861cf12a8 100644 --- a/src/distributions/graalvm/installer.ts +++ b/src/distributions/graalvm/installer.ts @@ -2,6 +2,7 @@ import * as core from '@actions/core'; import * as tc from '@actions/tool-cache'; import fs from 'fs'; import path from 'path'; +import semver from 'semver'; import {JavaBase} from '../base-installer'; import {HttpCodes} from '@actions/http-client'; import {GraalVMEAVersion} from './models'; @@ -11,14 +12,26 @@ import { JavaInstallerResults } from '../base-models'; import { + convertVersionToSemver, extractJdkFile, getDownloadArchiveExtension, getGitHubHttpHeaders, - renameWinArchive + getNextPageUrlFromLinkHeader, + isVersionSatisfies, + MAX_PAGINATION_PAGES, + renameWinArchive, + validatePaginationUrl } from '../../util'; const GRAALVM_DL_BASE = 'https://download.oracle.com/graalvm'; const GRAALVM_DOWNLOAD_URL = 'https://www.graalvm.org/downloads/'; +const GRAALVM_COMMUNITY_RELEASES_URL = + 'https://api.github.com/repos/graalvm/graalvm-ce-builds/releases?per_page=100'; +const GRAALVM_COMMUNITY_RELEASES_PAGE_ORIGIN = 'https://api.github.com'; +const GRAALVM_COMMUNITY_DOWNLOAD_URL = + 'https://github.com/graalvm/graalvm-ce-builds/releases'; +const GRAALVM_COMMUNITY_ASSET_PREFIX = 'graalvm-community-jdk-'; +const GRAALVM_COMMUNITY_VERSION_PATTERN = /^\d+(?:\.\d+)*$/; const IS_WINDOWS = process.platform === 'win32'; const GRAALVM_PLATFORM = IS_WINDOWS ? 'windows' : process.platform; const GRAALVM_MIN_VERSION = 17; @@ -26,9 +39,23 @@ const SUPPORTED_ARCHITECTURES = ['x64', 'aarch64'] as const; type SupportedArchitecture = (typeof SUPPORTED_ARCHITECTURES)[number]; type OsVersions = 'linux' | 'macos' | 'windows'; +interface GraalVMCommunityAsset { + name: string; + browser_download_url: string; +} + +interface GraalVMCommunityRelease { + draft: boolean; + prerelease: boolean; + assets: GraalVMCommunityAsset[]; +} + export class GraalVMDistribution extends JavaBase { - constructor(installerOptions: JavaInstallerOptions) { - super('GraalVM', installerOptions); + constructor( + installerOptions: JavaInstallerOptions, + distributionName = 'GraalVM' + ) { + super(distributionName, installerOptions); } protected async downloadTool( @@ -85,11 +112,36 @@ export class GraalVMDistribution extends JavaBase { protected async findPackageForDownload( range: string ): Promise { - // Add input validation + this.validateVersionRange(range); + const arch = this.getSupportedArchitecture(); + + if (!this.stable) { + return this.findEABuildDownloadUrl(`${range}-ea`); + } + + const {platform, extension, major} = this.validateStableBuildRequest(range); + + const fileUrl = this.constructFileUrl( + range, + major, + platform, + arch, + extension + ); + + const response = await this.http.head(fileUrl); + this.handleHttpResponse(response, range); + + return {url: fileUrl, version: range}; + } + + protected validateVersionRange(range: string): void { if (!range || typeof range !== 'string') { throw new Error('Version range is required and must be a string'); } + } + protected getSupportedArchitecture(): SupportedArchitecture { const arch = this.distributionArchitecture(); if (!SUPPORTED_ARCHITECTURES.includes(arch as SupportedArchitecture)) { throw new Error( @@ -97,12 +149,18 @@ export class GraalVMDistribution extends JavaBase { ); } - if (!this.stable) { - return this.findEABuildDownloadUrl(`${range}-ea`); - } + return arch as SupportedArchitecture; + } + protected validateStableBuildRequest(range: string): { + platform: OsVersions; + extension: string; + major: string; + } { if (this.packageType !== 'jdk') { - throw new Error('GraalVM provides only the `jdk` package type'); + throw new Error( + `${this.distribution} provides only the \`jdk\` package type` + ); } const platform = this.getPlatform(); @@ -116,22 +174,15 @@ export class GraalVMDistribution extends JavaBase { if (majorVersion < GRAALVM_MIN_VERSION) { throw new Error( - `GraalVM is only supported for JDK ${GRAALVM_MIN_VERSION} and later. Requested version: ${major}` + `${this.distribution} is only supported for JDK ${GRAALVM_MIN_VERSION} and later. Requested version: ${major}` ); } - const fileUrl = this.constructFileUrl( - range, - major, + return { platform, - arch, + major, extension - ); - - const response = await this.http.head(fileUrl); - this.handleHttpResponse(response, range); - - return {url: fileUrl, version: range}; + }; } private constructFileUrl( @@ -280,3 +331,144 @@ export class GraalVMDistribution extends JavaBase { return result; } } + +export class GraalVMCommunityDistribution extends GraalVMDistribution { + constructor(installerOptions: JavaInstallerOptions) { + super(installerOptions, 'GraalVM Community'); + } + + protected get toolcacheFolderName(): string { + return `Java_GraalVM_Community_${this.packageType}`; + } + + protected async findPackageForDownload( + range: string + ): Promise { + this.validateVersionRange(range); + + if (!this.stable) { + throw new Error('GraalVM Community does not provide early access builds'); + } + + const arch = this.getSupportedArchitecture(); + const {platform, extension} = this.validateStableBuildRequest(range); + // GraalVM Community asset names embed the platform, architecture and + // archive type, e.g. `graalvm-community-jdk-21.0.2_linux-x64_bin.tar.gz`. + const assetSuffix = `_${platform}-${arch}_bin.${extension}`; + const availableVersions = await this.getAvailableVersions(assetSuffix); + + const satisfiedVersion = availableVersions + .filter(item => isVersionSatisfies(range, item.version)) + .sort((a, b) => -semver.compareBuild(a.version, b.version))[0]; + + if (!satisfiedVersion) { + const error = this.createVersionNotFoundError( + range, + availableVersions.map(item => item.version), + `Platform: ${platform}` + ); + error.message += `\nPlease check if this version is available at ${GRAALVM_COMMUNITY_DOWNLOAD_URL}.`; + throw error; + } + + return satisfiedVersion; + } + + private async getAvailableVersions( + assetSuffix: string + ): Promise { + const headers = getGitHubHttpHeaders(); + const versions = new Map(); + let releasesUrl: string | null = GRAALVM_COMMUNITY_RELEASES_URL; + + for ( + let pageIndex = 0; + releasesUrl && pageIndex < MAX_PAGINATION_PAGES; + pageIndex++ + ) { + const response = await this.http.getJson( + releasesUrl, + headers + ); + + // A successful GitHub releases listing is always a JSON array (possibly + // empty). Anything else indicates an unexpected/error payload (rate + // limiting, auth failure, etc.) that must be surfaced instead of being + // silently treated as "no releases", which would later look like a + // misleading "version not found" error. + if (!Array.isArray(response.result)) { + throw new Error( + `Unexpected response while listing GraalVM Community releases from ${releasesUrl} ` + + `(HTTP status code: ${response.statusCode}). Expected a JSON array of releases. ` + + `Please check if the service is available at ${GRAALVM_COMMUNITY_DOWNLOAD_URL}.` + ); + } + + const releases = response.result; + if (releases.length === 0) { + break; + } + + for (const release of releases) { + if (release.draft || release.prerelease) { + continue; + } + + for (const asset of release.assets ?? []) { + const version = this.extractAssetVersion(asset.name, assetSuffix); + if (version) { + versions.set(version, { + version, + url: asset.browser_download_url + }); + } + } + } + + releasesUrl = this.getNextReleasesUrl(response.headers); + } + + return [...versions.values()]; + } + + // Returns the GraalVM JDK version encoded in a release asset name when it + // matches the requested platform/architecture/archive suffix, otherwise null. + private extractAssetVersion( + assetName: string, + assetSuffix: string + ): string | null { + if ( + !assetName.startsWith(GRAALVM_COMMUNITY_ASSET_PREFIX) || + !assetName.endsWith(assetSuffix) + ) { + return null; + } + + const rawVersion = assetName.slice( + GRAALVM_COMMUNITY_ASSET_PREFIX.length, + -assetSuffix.length + ); + + if (!GRAALVM_COMMUNITY_VERSION_PATTERN.test(rawVersion)) { + return null; + } + + return convertVersionToSemver(rawVersion); + } + + private getNextReleasesUrl( + headers: Record + ): string | null { + const nextUrl = getNextPageUrlFromLinkHeader(headers); + if ( + nextUrl && + !validatePaginationUrl(nextUrl, GRAALVM_COMMUNITY_RELEASES_PAGE_ORIGIN) + ) { + core.warning( + `Ignoring pagination link with unexpected origin: ${nextUrl}` + ); + return null; + } + return nextUrl; + } +} diff --git a/src/distributions/kona/installer.ts b/src/distributions/kona/installer.ts new file mode 100644 index 000000000..e2fb5de94 --- /dev/null +++ b/src/distributions/kona/installer.ts @@ -0,0 +1,191 @@ +import * as core from '@actions/core'; +import * as tc from '@actions/tool-cache'; +import semver from 'semver'; + +import fs from 'fs'; +import path from 'path'; + +import {JavaBase} from '../base-installer'; +import {IKonaReleaseInfo, IKonaRelease} from './models'; +import { + JavaDownloadRelease, + JavaInstallerOptions, + JavaInstallerResults +} from '../base-models'; +import { + extractJdkFile, + getDownloadArchiveExtension, + isVersionSatisfies, + renameWinArchive +} from '../../util'; + +export class KonaDistribution extends JavaBase { + constructor(installerOptions: JavaInstallerOptions) { + super('Kona', installerOptions); + } + + protected async downloadTool( + javaRelease: JavaDownloadRelease + ): Promise { + core.info( + `Downloading Kona JDK ${javaRelease.version} (${this.distribution}) from ${javaRelease.url} ...` + ); + const javaArchivePath = await tc.downloadTool(javaRelease.url); + + core.info(`Extracting Java archive...`); + + const extension = getDownloadArchiveExtension(); + const archivePath = + process.platform === 'win32' + ? renameWinArchive(javaArchivePath) + : javaArchivePath; + const extractedJavaPath = await extractJdkFile(archivePath, extension); + + const archiveName = fs.readdirSync(extractedJavaPath)[0]; + const jdkDirectory = path.join(extractedJavaPath, archiveName); + const version = this.getToolcacheVersionName(javaRelease.version); + + const javaPath = await tc.cacheDir( + jdkDirectory, + this.toolcacheFolderName, + version, + this.architecture + ); + + return {version: javaRelease.version, path: javaPath}; + } + + protected async findPackageForDownload( + version: string + ): Promise { + 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 isVersionSatisfies(version, item.version); + }) + .map(item => { + return { + version: item.version, + url: item.downloadUrl + } as JavaDownloadRelease; + }) + .sort((a, b) => -semver.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]; + } + + private async getAvailableReleases(): Promise { + if (core.isDebug()) { + 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 (core.isDebug()) { + core.startGroup('Print information about available releases'); + console.timeEnd('Retrieving available releases for Kona took'); // eslint-disable-line no-console + core.debug(availableReleases.map(item => item.version).join(', ')); + core.endGroup(); + } + + return availableReleases; + } + + private async fetchReleaseInfo(): Promise { + const releasesInfoUrl = + 'https://tencent.github.io/konajdk/releases/kona-v1.json'; + + try { + core.debug(`Fetching Kona release info from URL: ${releasesInfoUrl}`); + return (await this.http.getJson(releasesInfoUrl)) + .result; + } catch (err) { + core.debug( + `Fetching Kona release info from the URL: ${releasesInfoUrl} failed with the error: ${ + (err as Error).message + }` + ); + return null; + } + } + + private chooseReleases( + os: string, + arch: string, + releaseInfo: IKonaReleaseInfo + ): IKonaRelease[] { + const releases: IKonaRelease[] = []; + + 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; + } + + private getOs(): string { + switch (process.platform) { + case 'darwin': + return 'macos'; + case 'win32': + return 'windows'; + default: + return process.platform; + } + } + + private getArch(): string { + switch (this.architecture) { + case 'arm64': + return 'aarch64'; + case 'x64': + return 'x86_64'; + default: + return this.architecture; + } + } +} diff --git a/src/distributions/kona/models.ts b/src/distributions/kona/models.ts new file mode 100644 index 000000000..196ab693e --- /dev/null +++ b/src/distributions/kona/models.ts @@ -0,0 +1,25 @@ +export interface IKonaReleaseInfo { + [majorVersion: string]: { + version: string; + jdkVersion: string; + latest: boolean; + + baseUrl: string; + files: { + os: string; // linux, macos, windows + arch: string; // x86_64, aarch64 + + filename: string; + checksum: string; + }[]; + }[]; +} + +export interface IKonaRelease { + version: string; + jdkVersion: string; + os: string; // linux, macos, windows + arch: string; // x86_64, aarch64 + downloadUrl: string; + checksum: string; // SHA-256 digest +} diff --git a/src/distributions/liberica/models.ts b/src/distributions/liberica/models.ts index c9285fb7f..6f5a1de1e 100644 --- a/src/distributions/liberica/models.ts +++ b/src/distributions/liberica/models.ts @@ -4,11 +4,7 @@ export type Bitness = '32' | '64'; export type ArchType = 'arm' | 'ppc' | 'sparc' | 'x86'; export type OsVersions = - | 'linux' - | 'linux-musl' - | 'macos' - | 'solaris' - | 'windows'; + 'linux' | 'linux-musl' | 'macos' | 'solaris' | 'windows'; export interface ArchitectureOptions { bitness: Bitness; diff --git a/src/distributions/local/installer.ts b/src/distributions/local/installer.ts index adfac4998..cf422bc6a 100644 --- a/src/distributions/local/installer.ts +++ b/src/distributions/local/installer.ts @@ -69,9 +69,15 @@ export class LocalDistribution extends JavaBase { foundJava.path = macOSPostfixPath; } - core.info(`Setting Java ${foundJava.version} as default`); - - this.setJavaDefault(foundJava.version, foundJava.path); + if (this.setDefault) { + core.info(`Setting Java ${foundJava.version} as the default`); + this.setJavaDefault(foundJava.version, foundJava.path); + } else { + core.info( + `Installing Java ${foundJava.version} (not setting as default)` + ); + this.setJavaEnvironment(foundJava.version, foundJava.path); + } return foundJava; } diff --git a/src/distributions/microsoft/installer.ts b/src/distributions/microsoft/installer.ts index a48a3c2a3..9e8e03388 100644 --- a/src/distributions/microsoft/installer.ts +++ b/src/distributions/microsoft/installer.ts @@ -10,12 +10,16 @@ import { getGitHubHttpHeaders, renameWinArchive } from '../../util'; +import * as gpg from '../../gpg'; +import {MICROSOFT_PUBLIC_KEY} from './microsoft-key'; import * as core from '@actions/core'; import * as tc from '@actions/tool-cache'; import fs from 'fs'; import path from 'path'; import {TypedResponse} from '@actions/http-client/lib/interfaces'; +export {MICROSOFT_PUBLIC_KEY} from './microsoft-key'; + export class MicrosoftDistributions extends JavaBase { constructor(installerOptions: JavaInstallerOptions) { super('Microsoft', installerOptions); @@ -29,6 +33,26 @@ export class MicrosoftDistributions extends JavaBase { ); let javaArchivePath = await tc.downloadTool(javaRelease.url); + if (this.verifySignature) { + if (!javaRelease.signatureUrl) { + throw new Error( + `Input 'verify-signature' is enabled, but no signature URL was found for Microsoft Build of OpenJDK version ${javaRelease.version}.` + ); + } + core.info(`Verifying Java package signature...`); + try { + await gpg.verifyPackageSignature( + javaArchivePath, + javaRelease.signatureUrl, + this.verifySignaturePublicKey ?? MICROSOFT_PUBLIC_KEY + ); + } catch (error) { + throw new Error( + `Failed to verify signature for Microsoft Build of OpenJDK version ${javaRelease.version}. Signature URL: ${javaRelease.signatureUrl}. Error: ${(error as Error).message}` + ); + } + } + core.info(`Extracting Java archive...`); const extension = getDownloadArchiveExtension(); if (process.platform === 'win32') { @@ -80,12 +104,23 @@ export class MicrosoftDistributions extends JavaBase { throw this.createVersionNotFoundError(range, availableVersionStrings); } + const file = foundRelease.files[0] as { + download_url: string; + signature_url?: string; + }; + const signatureUrl = file.signature_url ?? `${file.download_url}.sig`; + return { - url: foundRelease.files[0].download_url, + url: file.download_url, + signatureUrl, version: foundRelease.version }; } + protected supportsSignatureVerification(): boolean { + return true; + } + private async getAvailableVersions(): Promise { // TODO get these dynamically! // We will need Microsoft to add an endpoint where we can query for versions. diff --git a/src/distributions/microsoft/microsoft-key.ts b/src/distributions/microsoft/microsoft-key.ts new file mode 100644 index 000000000..3cb1f42c4 --- /dev/null +++ b/src/distributions/microsoft/microsoft-key.ts @@ -0,0 +1,21 @@ +// Microsoft Build of OpenJDK GPG signing key +// Retrieved from: https://download.visualstudio.microsoft.com/download/pr/b90071e2-e0cf-4411-98be-dbeb09d67bf0/8622862bcd54206e158c5abca0582c9b/464279_464280_aoc_20210208.asc +export const MICROSOFT_PUBLIC_KEY = `-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: BSN Pgp v1.1.0.0 + +mQENBGAhlWcBCADCQjj6huLTenvZSLej35e9YKEHm4lix2uvPOONexMaU8V2v7KL +RGdoXF7jwHci7efnPZ+9zpS2+g3rhvv8M7yWy9E/1psEtGzvmp1IL/qIabMEQqi+ +UlhPGh7MQ/BkXAlic8Dyl3XYqr0EXS11iCiTr6Zkxs9Ee4V54gxL4gogRn4wk9sl +/nrjgDzMsUwla0pynoQQvYpqCdiAr3gKKllT1skCDqgVOMMyZxsx9HjZxg/3AJz6 +r5i512L2R+3Hkv+XmxT+mnGBCFcny0DM7PjNXEmIK3ZSkro1tQML90zx3Fyh5esx +fpVvuIXGFV75o35VVCBZoiD3hcfOnIJsPQ9nABEBAAG0OE1pY3Jvc29mdCBKYXZh +IEVuZ2luZWVyaW5nIDxqYXZhcGxhdGluZnJhQG1pY3Jvc29mdC5jb20+iQE4BBMB +CAAiBQJgIZVnAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRA1Ux0xWyHB +icwTCACJO2FGNocNvdUtAb+eDKuGwt0chAJdCES2ZtgBScwrwDyWpxpRznoXWBHL +MJeLyxJoKsCG3vVlY4uh48psCzVm3OKvi7MCPT955t8W6TzfSBxTpjR8zRgJkjPJ +EGhHTlusUfz7TtM5etJF0qscSJH1grcNsgtee97mk4QyEzT8Di83NQmYxKcBrliq +yK/SWWt8VkTyYAEO6L5PoB4L9r8ka27uQs+jgCw+/Z0JMtNmmhyNGY3+a1YtPeoy +JdQaI9LphfKGbVaz6SK2aol7vj+c2TG3TLUYdOYGMH1OZlri2GTkCVjwna2GC7p4 +Fa133tP85xzJEq1XeXm8WeLFo2wV +=rHCS +-----END PGP PUBLIC KEY BLOCK-----`; diff --git a/src/distributions/microsoft/microsoft-openjdk-versions.json b/src/distributions/microsoft/microsoft-openjdk-versions.json index 5c11c026b..1dd4a2319 100644 --- a/src/distributions/microsoft/microsoft-openjdk-versions.json +++ b/src/distributions/microsoft/microsoft-openjdk-versions.json @@ -171,6 +171,49 @@ } ] }, + { + "version": "17.0.18", + "stable": true, + "release_url": "https://aka.ms/download-jdk", + "files": [ + { + "filename": "microsoft-jdk-17.0.18-macos-x64.tar.gz", + "arch": "x64", + "platform": "darwin", + "download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-macos-x64.tar.gz" + }, + { + "filename": "microsoft-jdk-17.0.18-linux-x64.tar.gz", + "arch": "x64", + "platform": "linux", + "download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-linux-x64.tar.gz" + }, + { + "filename": "microsoft-jdk-17.0.18-windows-x64.zip", + "arch": "x64", + "platform": "win32", + "download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-windows-x64.zip" + }, + { + "filename": "microsoft-jdk-17.0.18-macos-aarch64.tar.gz", + "arch": "aarch64", + "platform": "darwin", + "download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-macos-aarch64.tar.gz" + }, + { + "filename": "microsoft-jdk-17.0.18-linux-aarch64.tar.gz", + "arch": "aarch64", + "platform": "linux", + "download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-linux-aarch64.tar.gz" + }, + { + "filename": "microsoft-jdk-17.0.18-windows-aarch64.zip", + "arch": "aarch64", + "platform": "win32", + "download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-windows-aarch64.zip" + } + ] + }, { "version": "17.0.10", "stable": true, @@ -180,7 +223,7 @@ "filename": "microsoft-jdk-17.0.10-macos-x64.tar.gz", "arch": "x64", "platform": "darwin", - "download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.7-macos-x64.tar.gz" + "download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.10-macos-x64.tar.gz" }, { "filename": "microsoft-jdk-17.0.10-linux-x64.tar.gz", diff --git a/src/distributions/temurin/adoptium-key.ts b/src/distributions/temurin/adoptium-key.ts new file mode 100644 index 000000000..f7466e5e2 --- /dev/null +++ b/src/distributions/temurin/adoptium-key.ts @@ -0,0 +1,33 @@ +// Adoptium GPG signing key (fingerprint: 3B04D753C9050D9A5D343F39843C48A565F8F04B) +// Retrieved from: https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3B04D753C9050D9A5D343F39843C48A565F8F04B +export const ADOPTIUM_PUBLIC_KEY = `-----BEGIN PGP PUBLIC KEY BLOCK----- + +xsBNBGGTvTQBCAC6ey144n7CG8foafF6mwgIBN1fIm1ILZDuGS4tMr0/XI8pgJnT +QvsPxZWEvtSm7bEMObzEoZJcXwjBcJl1B0ui8k5kHMTI75gCmZPsoKLFWIEpuRBQ +PBocusw80apDmLnNDQLVQvDFtEua5gaNa/fRw9YsmBoXBqvgrjFUIdGyWoQvH5+a +9OYlWD9n5VV0gnVMb+aclwVzB/zJw3kHGSgzuMtlAHeQiah7Y8yomQn/UIX8yqDf ++11sP3+c87YcjkRqImRTtmKEDcEtGPAIXC6SYA+uEEkbYE0Fy0chkvtnVWJ597fa +Epai4rnICU8zoJ6X5z3v1aM2WerhX9oq9X8PABEBAAHNQEFkb3B0aXVtIEdQRyBL +ZXkgKERFQi9SUE0gU2lnbmluZyBLZXkpIDx0ZW11cmluLWRldkBlY2xpcHNlLm9y +Zz7CwJIEEwEIADwWIQQ7BNdTyQUNml00PzmEPEilZfjwSwUCYZO9NAIbAwULCQgH +AgMiAgEGFQoJCAsCBBYCAwECHgcCF4AACgkQhDxIpWX48Et4AggAjjJzYWuKV3nG +7ngInngl8G/m9JoHr7BmwgcQXYhdy5hVkMcUx5JLeXz2LMBUH/F2nD595hgjMabk +kVib20X8lq9RsNbdfc2hBcWU6qyHKxsIqT4boI2/XDyEzzMyyZWWNGo/27Ci7Xmj +pWu31nh0pDdPqdyWDIKojbVVnxlCRY8as8Sm+1ufi709KCi4MuwHNsUlCSwb/fju +NKeHkrHbLcHKUUIEcmTSKRWrpMYBzm1HYOGBz4xPuELwUfUp71ehfoyBZlp6RDRf +l5TYI1FmCyHuvjNhrJgWv7bOTcf8yObGY+TEUhzc4xQqCrF4ur9d3opvsuPBQsv+ +Klqi5KSZgs7ATQRhk700AQgAq14okly8cFrpYVenEQPiB75AUZfKRpMduiR6IxAj +SKcH7aSoFZ9AubUEBVpZsyT5svxoEPe1i4TdbF+m9FGy42EcOlLa3ArLTj5H8FRl +UdGZB9I5mk4GptOzPM+aHMMu92vW/ZwjuS8DvOiQSp+cUmG1EqOMJSM7e/4BM71z +E+OKaVJCj79pEzhG3SK/IC/OlxxyETT66NSfYJd7Sw5R6Vr19am/uNU690W0CJ+q +VQeFpmDMr7LnfdFRIh+lJe05+PvWXeidkGjox5cbG52wf8aRIR/FgkfcFvqRMN1f +B+dVOWueloUeVAnzcUznOKmUEs7LP9ObJhYHHgup4IAU2wARAQABwsB2BBgBCAAg +FiEEOwTXU8kFDZpdND85hDxIpWX48EsFAmGTvTQCGwwACgkQhDxIpWX48EvXHQf/ +Q0nZsGDXnZHiBoojeSdpkO7WBjMIP3w1GdLvRpPQrS8TfOPbZuoevzCNh38Y3gwF +yelJspvzDQrBXhgkzAGlucYg8Y7KHa5Ebm7iDgMzc37L1hYSZTYCqwd7aowfgy34 +hOk3B67LffkJpIh738Oa9CtlwxQ9xcytmBmQ1fBBOwm/9IhAwHPQuydYIs4DxWbj +0MGSP4fDntU7e4UjsHNmhudDcYol0FaqdHHIIB9C/G4CzetRwHFOn3b4JwXMU7YU +6aJA3mXhi3hggMC3wkT2HHZ/TquuOdNc02fypWOCDOHz0alBBJNqoVUNFNqU3tfJ +wI4qF/KKq9BfyfucAs0ykA== +=XLag +-----END PGP PUBLIC KEY BLOCK-----`; diff --git a/src/distributions/temurin/installer.ts b/src/distributions/temurin/installer.ts index 109c2d413..16a896f60 100644 --- a/src/distributions/temurin/installer.ts +++ b/src/distributions/temurin/installer.ts @@ -4,7 +4,9 @@ import * as tc from '@actions/tool-cache'; import fs from 'fs'; import path from 'path'; import semver from 'semver'; +import * as gpg from '../../gpg'; +import {ADOPTIUM_PUBLIC_KEY} from './adoptium-key'; import {JavaBase} from '../base-installer'; import {ITemurinAvailableVersions} from './models'; import { @@ -22,6 +24,8 @@ import { validatePaginationUrl } from '../../util'; +export {ADOPTIUM_PUBLIC_KEY} from './adoptium-key'; + export enum TemurinImplementation { Hotspot = 'Hotspot' } @@ -50,7 +54,8 @@ export class TemurinDistribution extends JavaBase { : item.version_data.semver.replace('-beta+', '+'); return { version: formattedVersion, - url: item.binaries[0].package.link + url: item.binaries[0].package.link, + signatureUrl: item.binaries[0].package.signature_link } as JavaDownloadRelease; }); @@ -80,6 +85,28 @@ export class TemurinDistribution extends JavaBase { ); let javaArchivePath = await tc.downloadTool(javaRelease.url); + if (this.verifySignature) { + if (!javaRelease.signatureUrl) { + throw new Error( + `Input 'verify-signature' is enabled, but no signature URL was found for Temurin version ${javaRelease.version}.` + ); + } + core.info(`Verifying Java package signature...`); + try { + await gpg.verifyPackageSignature( + javaArchivePath, + javaRelease.signatureUrl, + this.verifySignaturePublicKey ?? ADOPTIUM_PUBLIC_KEY + ); + } catch (error) { + throw new Error( + `Failed to verify signature for Temurin version ${javaRelease.version} from ${javaRelease.signatureUrl}: ${ + (error as Error).message + }` + ); + } + } + core.info(`Extracting Java archive...`); const extension = getDownloadArchiveExtension(); if (process.platform === 'win32') { @@ -105,6 +132,10 @@ export class TemurinDistribution extends JavaBase { return super.toolcacheFolderName; } + protected supportsSignatureVerification(): boolean { + return true; + } + private async getAvailableVersions(): Promise { const platform = this.getPlatformOption(); const arch = this.distributionArchitecture(); diff --git a/src/distributions/temurin/models.ts b/src/distributions/temurin/models.ts index eb4b49b7b..c5bff9020 100644 --- a/src/distributions/temurin/models.ts +++ b/src/distributions/temurin/models.ts @@ -11,6 +11,7 @@ export interface ITemurinAvailableVersions { package: { checksum: string; checksum_link: string; + signature_link?: string; download_count: number; link: string; metadata_link: string; diff --git a/src/distributions/zulu/installer.ts b/src/distributions/zulu/installer.ts index 83f879461..9ae3ec615 100644 --- a/src/distributions/zulu/installer.ts +++ b/src/distributions/zulu/installer.ts @@ -30,17 +30,24 @@ export class ZuluDistribution extends JavaBase { ): Promise { const availableVersionsRaw = await this.getAvailableVersions(); const availableVersions = availableVersionsRaw.map(item => { + // The Azul Metadata API reports the JDK build number separately from + // java_version (e.g. java_version=[17,0,7], openjdk_build_number=7). + // Append it so the resulting semver retains the build (e.g. 17.0.7+7). + const javaVersion = + item.openjdk_build_number != null + ? [...item.java_version, item.openjdk_build_number] + : item.java_version; return { - version: convertVersionToSemver(item.jdk_version), - url: item.url, - zuluVersion: convertVersionToSemver(item.zulu_version) + version: convertVersionToSemver(javaVersion), + url: item.download_url, + zuluVersion: convertVersionToSemver(item.distro_version) }; }); const satisfiedVersions = availableVersions .filter(item => isVersionSatisfies(version, item.version)) .sort((a, b) => { - // Azul provides two versions: jdk_version and azul_version + // Azul provides two versions: java_version and distro_version // we should sort by both fields by descending return ( -semver.compareBuild(a.version, b.version) || @@ -95,45 +102,76 @@ export class ZuluDistribution extends JavaBase { } private async getAvailableVersions(): Promise { - const {arch, hw_bitness, abi} = this.getArchitectureOptions(); + const arch = this.getArchitectureOptions(); const [bundleType, features] = this.packageType.split('+'); const platform = this.getPlatformOption(); const extension = getDownloadArchiveExtension(); const javafx = features?.includes('fx') ?? false; + const crac = features?.includes('crac') ?? false; const releaseStatus = this.stable ? 'ga' : 'ea'; if (core.isDebug()) { console.time('Retrieving available versions for Zulu took'); // eslint-disable-line no-console } - const requestArguments = [ + const baseRequestArguments = [ `os=${platform}`, - `ext=${extension}`, - `bundle_type=${bundleType}`, - `javafx=${javafx}`, + `archive_type=${extension}`, + `java_package_type=${bundleType}`, + `javafx_bundled=${javafx}`, + `crac_supported=${crac}`, `arch=${arch}`, - `hw_bitness=${hw_bitness}`, `release_status=${releaseStatus}`, - abi ? `abi=${abi}` : null, - features ? `features=${features}` : null - ] - .filter(Boolean) - .join('&'); + `availability_types=ca` + ].join('&'); + + // Need to iterate through all pages to retrieve the list of all versions. + // The Azul API doesn't return a total page count, so paginate until a page + // comes back empty (or short), guarding against a runaway loop with a cap. + const pageSize = 100; + const maxPages = 100; + let pageIndex = 1; + const availableVersions: IZuluVersions[] = []; + while (pageIndex <= maxPages) { + const requestArguments = `${baseRequestArguments}&page=${pageIndex}&page_size=${pageSize}`; + const availableVersionsUrl = `https://api.azul.com/metadata/v1/zulu/packages/?${requestArguments}`; + if (core.isDebug() && pageIndex === 1) { + // the url is identical except for the page number, so print it once for debug + core.debug( + `Gathering available versions from '${availableVersionsUrl}'` + ); + } + + const paginationPage = ( + await this.http.getJson(availableVersionsUrl) + ).result; + if (!paginationPage || paginationPage.length === 0) { + // stop paginating because we have reached the end of the results + break; + } + + availableVersions.push(...paginationPage); - const availableVersionsUrl = `https://api.azul.com/zulu/download/community/v1.0/bundles/?${requestArguments}`; + if (paginationPage.length < pageSize) { + // a short page means this was the last one; avoid an extra empty request + break; + } - core.debug(`Gathering available versions from '${availableVersionsUrl}'`); + pageIndex++; + } - const availableVersions = - (await this.http.getJson>(availableVersionsUrl)) - .result ?? []; + if (pageIndex > maxPages) { + core.warning( + `Reached the maximum of ${maxPages} pages while listing Zulu versions; results may be truncated.` + ); + } if (core.isDebug()) { core.startGroup('Print information about available versions'); console.timeEnd('Retrieving available versions for Zulu took'); // eslint-disable-line no-console core.debug(`Available versions: [${availableVersions.length}]`); core.debug( - availableVersions.map(item => item.jdk_version.join('.')).join(', ') + availableVersions.map(item => item.java_version.join('.')).join(', ') ); core.endGroup(); } @@ -141,22 +179,22 @@ export class ZuluDistribution extends JavaBase { return availableVersions; } - private getArchitectureOptions(): { - arch: string; - hw_bitness: string; - abi: string; - } { + private getArchitectureOptions(): string { const arch = this.distributionArchitecture(); switch (arch) { case 'x64': - return {arch: 'x86', hw_bitness: '64', abi: ''}; + return 'x64'; case 'x86': - return {arch: 'x86', hw_bitness: '32', abi: ''}; + // The Azul Metadata API's "x86" value returns both 32-bit (i686) and + // 64-bit (x64) packages, which are indistinguishable by version and + // would let a 32-bit request resolve to a 64-bit JDK. Use "i686" to + // target only genuine 32-bit builds, matching the legacy API behavior. + return 'i686'; case 'aarch64': case 'arm64': - return {arch: 'arm', hw_bitness: '64', abi: ''}; + return 'aarch64'; default: - return {arch: arch, hw_bitness: '', abi: ''}; + return arch; } } @@ -167,6 +205,10 @@ export class ZuluDistribution extends JavaBase { return 'macos'; case 'win32': return 'windows'; + case 'linux': + // The new Metadata API's "linux" value returns both glibc and musl packages; + // use "linux_glibc" to target only glibc, which is what standard runners use. + return 'linux_glibc'; default: return process.platform; } diff --git a/src/distributions/zulu/models.ts b/src/distributions/zulu/models.ts index a97406f09..36d369e05 100644 --- a/src/distributions/zulu/models.ts +++ b/src/distributions/zulu/models.ts @@ -1,9 +1,12 @@ -// Models from https://app.swaggerhub.com/apis-docs/azul/zulu-download-community/1.0 +// Models from https://app.swaggerhub.com/apis/azul/metadata/1.0 export interface IZuluVersions { - id: number; + package_uuid: string; name: string; - url: string; - jdk_version: Array; - zulu_version: Array; + download_url: string; + java_version: Array; + distro_version: Array; + openjdk_build_number: number; + latest: boolean; + availability_type: string; } diff --git a/src/gpg.ts b/src/gpg.ts index 3b74c1516..3472e3b96 100644 --- a/src/gpg.ts +++ b/src/gpg.ts @@ -2,6 +2,7 @@ import * as fs from 'fs'; import * as path from 'path'; import * as io from '@actions/io'; import * as exec from '@actions/exec'; +import * as tc from '@actions/tool-cache'; import * as util from './util'; import {ExecOptions} from '@actions/exec/lib/interfaces'; @@ -9,6 +10,17 @@ export const PRIVATE_KEY_FILE = path.join(util.getTempDir(), 'private-key.asc'); const PRIVATE_KEY_FINGERPRINT_REGEX = /\w{40}/; +// Convert a Windows path (D:\a\_temp\...) to a POSIX path (/d/a/_temp/...). +// The Git-bundled GPG on Windows (MSYS2-based) uses POSIX path conventions +// internally. Passing Windows paths with backslashes can cause fatal GPG errors +// (exit code 2), so all paths passed to GPG must be in POSIX format on Windows. +export function toGpgPath(p: string): string { + if (process.platform !== 'win32') return p; + return p + .replace(/\\/g, '/') + .replace(/^([A-Za-z]):\//, (_, drive) => `/${drive.toLowerCase()}/`); +} + export async function importKey(privateKey: string) { fs.writeFileSync(PRIVATE_KEY_FILE, privateKey, { encoding: 'utf-8', @@ -53,3 +65,59 @@ export async function deleteKey(keyFingerprint: string) { } ); } + +export async function verifyPackageSignature( + archivePath: string, + signatureUrl: string, + publicKeyContent: string +) { + const signaturePath = await tc.downloadTool(signatureUrl); + let gpgHome: string; + try { + gpgHome = fs.mkdtempSync( + path.join(util.getTempDir(), 'verify-signature-gpg-home-') + ); + } catch (error) { + try { + await io.rmRF(signaturePath); + } catch { + // ignore cleanup failures + } + throw new Error( + `Failed to create temporary GPG home directory for signature verification: ${ + (error as Error).message + }` + ); + } + try { + const publicKeyFile = path.join(gpgHome, 'public-key.asc'); + fs.writeFileSync(publicKeyFile, publicKeyContent, {encoding: 'utf-8'}); + const options: ExecOptions = {silent: true}; + await exec.exec( + 'gpg', + [ + '--homedir', + toGpgPath(gpgHome), + '--batch', + '--import', + toGpgPath(publicKeyFile) + ], + options + ); + await exec.exec( + 'gpg', + [ + '--homedir', + toGpgPath(gpgHome), + '--batch', + '--verify', + toGpgPath(signaturePath), + toGpgPath(archivePath) + ], + options + ); + } finally { + await io.rmRF(signaturePath); + await io.rmRF(gpgHome); + } +} diff --git a/src/maven-args.ts b/src/maven-args.ts new file mode 100644 index 000000000..654bed27b --- /dev/null +++ b/src/maven-args.ts @@ -0,0 +1,69 @@ +import * as core from '@actions/core'; +import {getBooleanInput} from './util'; +import { + INPUT_SHOW_DOWNLOAD_PROGRESS, + MAVEN_ARGS_ENV, + MAVEN_NO_TRANSFER_PROGRESS_FLAG, + MAVEN_NO_TRANSFER_PROGRESS_LONG_FLAG +} from './constants'; + +/** + * 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. + */ +export function configureMavenArgs(): void { + const showDownloadProgress = getBooleanInput( + INPUT_SHOW_DOWNLOAD_PROGRESS, + false + ); + + if (showDownloadProgress) { + core.debug( + `${INPUT_SHOW_DOWNLOAD_PROGRESS} is true; leaving ${MAVEN_ARGS_ENV} unchanged` + ); + return; + } + + const existingArgs = (process.env[MAVEN_ARGS_ENV] ?? '').trim(); + + const alreadyDisabled = existingArgs + .split(/\s+/) + .some( + arg => + arg === MAVEN_NO_TRANSFER_PROGRESS_FLAG || + arg === MAVEN_NO_TRANSFER_PROGRESS_LONG_FLAG + ); + + if (alreadyDisabled) { + core.debug( + `${MAVEN_ARGS_ENV} already disables transfer progress; leaving it unchanged` + ); + return; + } + + const updatedArgs = existingArgs + ? `${existingArgs} ${MAVEN_NO_TRANSFER_PROGRESS_FLAG}` + : MAVEN_NO_TRANSFER_PROGRESS_FLAG; + + core.exportVariable(MAVEN_ARGS_ENV, updatedArgs); + core.info( + `Configured ${MAVEN_ARGS_ENV} to include ${MAVEN_NO_TRANSFER_PROGRESS_FLAG} to suppress Maven transfer progress logs. ` + + `Set '${INPUT_SHOW_DOWNLOAD_PROGRESS}: true' to keep the download progress output.` + ); +} diff --git a/src/setup-java.ts b/src/setup-java.ts index 73baf33a7..1d12b2906 100644 --- a/src/setup-java.ts +++ b/src/setup-java.ts @@ -12,22 +12,28 @@ import {restore} from './cache'; import * as path from 'path'; import {getJavaDistribution} from './distributions/distribution-factory'; import {JavaInstallerOptions} from './distributions/base-models'; +import {configureMavenArgs} from './maven-args'; async function run() { try { const versions = core.getMultilineInput(constants.INPUT_JAVA_VERSION); - const distributionName = core.getInput(constants.INPUT_DISTRIBUTION, { - required: true - }); + let distributionName = core.getInput(constants.INPUT_DISTRIBUTION); const versionFile = core.getInput(constants.INPUT_JAVA_VERSION_FILE); const architecture = core.getInput(constants.INPUT_ARCHITECTURE); const packageType = core.getInput(constants.INPUT_JAVA_PACKAGE); - const jdkFile = core.getInput(constants.INPUT_JDK_FILE); + const jdkFile = getJdkFileInput(); const cache = core.getInput(constants.INPUT_CACHE); const cacheDependencyPath = core.getInput( constants.INPUT_CACHE_DEPENDENCY_PATH ); const checkLatest = getBooleanInput(constants.INPUT_CHECK_LATEST, false); + const setDefault = getBooleanInput(constants.INPUT_SET_DEFAULT, true); + const verifySignature = getBooleanInput( + constants.INPUT_VERIFY_SIGNATURE, + false + ); + const verifySignaturePublicKey = + core.getInput(constants.INPUT_VERIFY_SIGNATURE_PUBLIC_KEY) || undefined; let toolchainIds = core.getMultilineInput(constants.INPUT_MVN_TOOLCHAIN_ID); core.startGroup('Installed distributions'); @@ -40,45 +46,78 @@ async function run() { throw new Error('java-version or java-version-file input expected'); } - const installerInputsOptions: installerInputsOptions = { - architecture, - packageType, - checkLatest, - distributionName, - jdkFile, - toolchainIds - }; - if (!versions.length) { core.debug( 'java-version input is empty, looking for java-version-file input' ); const content = fs.readFileSync(versionFile).toString().trim(); - const version = getVersionFromFileContent( + const versionInfo = getVersionFromFileContent( content, distributionName, versionFile ); - core.debug(`Parsed version from file '${version}'`); + core.debug(`Parsed version from file '${versionInfo?.version}'`); - if (!version) { + if (!versionInfo) { throw new Error( `No supported version was found in file ${versionFile}` ); } - await installVersion(version, installerInputsOptions); - } + // Use distribution from file if available, otherwise use the input + if (versionInfo.distribution) { + core.info( + `Using distribution '${versionInfo.distribution}' from ${versionFile}` + ); + distributionName = versionInfo.distribution; + } else if (!distributionName) { + throw new Error( + 'distribution input is required when not specified in the version file' + ); + } + + const installerInputsOptions: installerInputsOptions = { + architecture, + packageType, + checkLatest, + setDefault, + verifySignature, + verifySignaturePublicKey, + distributionName, + jdkFile, + toolchainIds + }; + + await installVersion(versionInfo.version, installerInputsOptions); + } else { + // When using java-version input, distribution is still required + if (!distributionName) { + throw new Error('distribution input is required'); + } - for (const [index, version] of versions.entries()) { - await installVersion(version, installerInputsOptions, index); + const installerInputsOptions: installerInputsOptions = { + architecture, + packageType, + checkLatest, + setDefault, + verifySignature, + verifySignaturePublicKey, + distributionName, + jdkFile, + toolchainIds + }; + + for (const [index, version] of versions.entries()) { + await installVersion(version, installerInputsOptions, index); + } } core.endGroup(); const matchersPath = path.join(__dirname, '..', '..', '.github'); core.info(`##[add-matcher]${path.join(matchersPath, 'java.json')}`); await auth.configureAuthentication(); + configureMavenArgs(); if (cache && isCacheFeatureAvailable()) { await restore(cache, cacheDependencyPath); } @@ -89,6 +128,19 @@ async function run() { run(); +function getJdkFileInput(): string { + const jdkFile = core.getInput(constants.INPUT_JDK_FILE); + const deprecatedJdkFile = core.getInput(constants.INPUT_JDK_FILE_DEPRECATED); + + if (deprecatedJdkFile) { + core.warning( + `The '${constants.INPUT_JDK_FILE_DEPRECATED}' input is deprecated and may be removed in a future release. Please use '${constants.INPUT_JDK_FILE}' instead.` + ); + } + + return jdkFile || deprecatedJdkFile; +} + async function installVersion( version: string, options: installerInputsOptions, @@ -100,6 +152,9 @@ async function installVersion( architecture, packageType, checkLatest, + setDefault, + verifySignature, + verifySignaturePublicKey, toolchainIds } = options; @@ -107,6 +162,9 @@ async function installVersion( architecture, packageType, checkLatest, + setDefault, + verifySignature, + verifySignaturePublicKey, version }; @@ -141,6 +199,9 @@ interface installerInputsOptions { architecture: string; packageType: string; checkLatest: boolean; + setDefault: boolean; + verifySignature: boolean; + verifySignaturePublicKey: string | undefined; distributionName: string; jdkFile: string; toolchainIds: Array; diff --git a/src/toolchains.ts b/src/toolchains.ts index 77cae83f7..103173e3c 100644 --- a/src/toolchains.ts +++ b/src/toolchains.ts @@ -5,7 +5,6 @@ import * as core from '@actions/core'; import * as io from '@actions/io'; import * as constants from './constants'; -import {getBooleanInput} from './util'; import {create as xmlCreate} from 'xmlbuilder2'; interface JdkInfo { @@ -27,10 +26,6 @@ export async function configureToolchains( const settingsDirectory = core.getInput(constants.INPUT_SETTINGS_PATH) || path.join(os.homedir(), constants.M2_DIR); - const overwriteSettings = getBooleanInput( - constants.INPUT_OVERWRITE_SETTINGS, - true - ); await createToolchainsSettings({ jdkInfo: { @@ -39,19 +34,16 @@ export async function configureToolchains( id, jdkHome }, - settingsDirectory, - overwriteSettings + settingsDirectory }); } export async function createToolchainsSettings({ jdkInfo, - settingsDirectory, - overwriteSettings + settingsDirectory }: { jdkInfo: JdkInfo; settingsDirectory: string; - overwriteSettings: boolean; }) { core.info( `Creating ${constants.MVN_TOOLCHAINS_FILE} for JDK version ${jdkInfo.version} from ${jdkInfo.vendor}` @@ -68,11 +60,7 @@ export async function createToolchainsSettings({ jdkInfo.id, jdkInfo.jdkHome ); - await writeToolchainsFileToDisk( - settingsDirectory, - updatedToolchains, - overwriteSettings - ); + await writeToolchainsFileToDisk(settingsDirectory, updatedToolchains); } // only exported for testing purposes @@ -83,47 +71,76 @@ export function generateToolchainDefinition( id: string, jdkHome: string ) { - let xmlObj; + let jsToolchains: Toolchain[] = [ + { + type: 'jdk', + provides: { + version: `${version}`, + vendor: `${vendor}`, + id: `${id}` + }, + configuration: { + jdkHome: `${jdkHome}` + } + } + ]; + // default root attributes, used when the existing file does not declare its own + let rootAttributes: Record = { + '@xmlns': 'http://maven.apache.org/TOOLCHAINS/1.1.0', + '@xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', + '@xsi:schemaLocation': + 'http://maven.apache.org/TOOLCHAINS/1.1.0 https://maven.apache.org/xsd/toolchains-1.1.0.xsd' + }; if (original?.length) { - xmlObj = xmlCreate(original) + // convert existing toolchains into TS native objects for better handling + // xmlbuilder2 will convert the document into a `{toolchains: { toolchain: [] | {} }}` structure + // instead of the desired `toolchains: [{}]` one or simply `[{}]` + const jsObj = xmlCreate(original) .root() - .ele({ - toolchain: { - type: 'jdk', - provides: { - version: `${version}`, - vendor: `${vendor}`, - id: `${id}` - }, - configuration: { - jdkHome: `${jdkHome}` - } + .toObject() as unknown as ExtractedToolchains; + if (jsObj.toolchains) { + // preserve the existing root attributes (xmlns, schemaLocation, …) so we don't + // silently rewrite user-managed metadata or change the effective XML namespace; + // xmlbuilder2 exposes attributes as `@`-prefixed keys on the element object + const existingAttributes = Object.fromEntries( + Object.entries(jsObj.toolchains).filter(([key]) => key.startsWith('@')) + ) as Record; + // fall back to the defaults only for attributes the existing file is missing + rootAttributes = {...rootAttributes, ...existingAttributes}; + + if (jsObj.toolchains.toolchain) { + // in case only a single child exists xmlbuilder2 will not create an array and using verbose = true equally doesn't work here + // See https://oozcitak.github.io/xmlbuilder2/serialization.html#js-object-and-map-serializers for details + if (Array.isArray(jsObj.toolchains.toolchain)) { + jsToolchains.push(...jsObj.toolchains.toolchain); + } else { + jsToolchains.push(jsObj.toolchains.toolchain); } - }); - } else - xmlObj = xmlCreate({ - toolchains: { - '@xmlns': 'http://maven.apache.org/TOOLCHAINS/1.1.0', - '@xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', - '@xsi:schemaLocation': - 'http://maven.apache.org/TOOLCHAINS/1.1.0 https://maven.apache.org/xsd/toolchains-1.1.0.xsd', - toolchain: [ - { - type: 'jdk', - provides: { - version: `${version}`, - vendor: `${vendor}`, - id: `${id}` - }, - configuration: { - jdkHome: `${jdkHome}` - } - } - ] } - }); + } - return xmlObj.end({ + // remove potential duplicates based on type & id (which should be a unique combination); + // self.findIndex will only return the first occurrence, ensuring duplicates are skipped + jsToolchains = jsToolchains.filter( + (value, index, self) => + // ensure non-jdk toolchains are kept in the results, we must not touch them because they belong to the user + value.type !== 'jdk' || + // keep toolchains that lack a usable string id (e.g. partially-formed user files); + // we cannot safely deduplicate them and must not crash while reading them + typeof value.provides?.id !== 'string' || + index === + self.findIndex( + t => t.type === value.type && t.provides?.id === value.provides?.id + ) + ); + } + + return xmlCreate({ + toolchains: { + ...rootAttributes, + toolchain: jsToolchains + } + }).end({ format: 'xml', wellFormed: false, headless: false, @@ -143,22 +160,19 @@ async function readExistingToolchainsFile(directory: string) { return ''; } -async function writeToolchainsFileToDisk( - directory: string, - settings: string, - overwriteSettings: boolean -) { +async function writeToolchainsFileToDisk(directory: string, settings: string) { const location = path.join(directory, constants.MVN_TOOLCHAINS_FILE); const settingsExists = fs.existsSync(location); - if (settingsExists && overwriteSettings) { - core.info(`Overwriting existing file ${location}`); - } else if (!settingsExists) { - core.info(`Writing to ${location}`); + // The toolchains file is produced by a non-destructive merge (existing JDK, + // custom, and non-jdk toolchains are preserved – see generateToolchainDefinition), + // so it is always safe to write it. Unlike settings.xml, it is therefore not + // gated behind the `overwrite-settings` input; that would prevent subsequent + // setup-java runs from registering additional JDKs and silently drop the + // toolchain entries created by earlier runs. + if (settingsExists) { + core.info(`Updating existing file ${location}`); } else { - core.info( - `Skipping generation of ${location} because file already exists and overwriting is not enabled` - ); - return; + core.info(`Writing to ${location}`); } return fs.writeFileSync(location, settings, { @@ -166,3 +180,24 @@ async function writeToolchainsFileToDisk( flag: 'w' }); } + +interface ExtractedToolchains { + toolchains: { + // root attributes such as xmlns / schemaLocation are exposed as `@`-prefixed keys + [attribute: `@${string}`]: string; + toolchain?: Toolchain[] | Toolchain; + }; +} + +// Toolchain type definition according to Maven Toolchains XSD 1.1.0 +interface Toolchain { + type: string; + provides: + | { + version: string; + vendor: string; + id: string; + } + | any; + configuration: any; +} diff --git a/src/util.ts b/src/util.ts index 5fe84c520..22121ee58 100644 --- a/src/util.ts +++ b/src/util.ts @@ -55,6 +55,14 @@ export function getDownloadArchiveExtension() { } export function isVersionSatisfies(range: string, version: string): boolean { + // Some distributions (e.g. JetBrains Runtime) publish 4-segment versions + // like '17.0.8.1+1080.1' that semver rejects. If the candidate version + // isn't valid semver, it can't match — bail out rather than letting + // compareBuild / satisfies throw. + if (!semver.valid(version)) { + return false; + } + if (semver.valid(range)) { // if full version with build digit is provided as a range (such as '1.2.3+4') // we should check for exact equal via compareBuild @@ -119,12 +127,18 @@ export function isCacheFeatureAvailable(): boolean { return false; } +export interface VersionInfo { + version: string; + distribution?: string; +} + export function getVersionFromFileContent( content: string, distributionName: string, versionFile: string -): string | null { +): VersionInfo | null { let javaVersionRegExp: RegExp; + let extractedDistribution: string | undefined; function getFileName(versionFile: string) { return path.basename(versionFile); @@ -132,18 +146,43 @@ export function getVersionFromFileContent( const versionFileName = getFileName(versionFile); if (versionFileName == '.tool-versions') { + // Capture an optional asdf-java vendor prefix (e.g. `temurin-`, `corretto-`) + // in the `distribution` group so it can be mapped to a setup-java distribution. javaVersionRegExp = - /^java\s+(?:\S*-)?(?\d+(?:\.\d+)*([+_.-](?:openj9[-._]?\d[\w.-]*|java\d+|jre[-_\w]*|OpenJDK\d+[\w_.-]*|[a-z0-9]+))*)/im; + /^java\s+(?:(?\S*)-)?(?\d+(?:\.\d+)*([+_.-](?:openj9[-._]?\d[\w.-]*|java\d+|jre[-_\w]*|OpenJDK\d+[\w_.-]*|[a-z0-9]+))*)/im; } else if (versionFileName == '.sdkmanrc') { - javaVersionRegExp = /^java\s*=\s*(?[^-]+)/m; + // Match both version and optional distribution identifier + javaVersionRegExp = + /^java\s*=\s*(?[^-\s]+)(?:-(?[a-z0-9]+))?/m; } else { javaVersionRegExp = /(?(?<=(^|\s|-))(\d+\S*))(\s|$)/; } - const capturedVersion = content.match(javaVersionRegExp)?.groups?.version - ? (content.match(javaVersionRegExp)?.groups?.version as string) + const match = content.match(javaVersionRegExp); + const capturedVersion = match?.groups?.version + ? (match.groups.version as string) : ''; + // Extract distribution from .sdkmanrc file + if (versionFileName == '.sdkmanrc' && match?.groups?.distribution) { + const sdkmanDist = match.groups.distribution; + extractedDistribution = mapSdkmanDistribution(sdkmanDist); + core.debug( + `Parsed distribution '${extractedDistribution}' from SDKMAN identifier '${sdkmanDist}'` + ); + } + + // Extract distribution from asdf .tool-versions file + if (versionFileName == '.tool-versions' && match?.groups?.distribution) { + const asdfDist = match.groups.distribution; + extractedDistribution = mapAsdfDistribution(asdfDist); + if (extractedDistribution) { + core.debug( + `Parsed distribution '${extractedDistribution}' from asdf identifier '${asdfDist}'` + ); + } + } + core.debug( `Parsed version '${capturedVersion}' from file '${versionFileName}'` ); @@ -164,12 +203,92 @@ export function getVersionFromFileContent( return null; } - if (DISTRIBUTIONS_ONLY_MAJOR_VERSION.includes(distributionName)) { + // Apply DISTRIBUTIONS_ONLY_MAJOR_VERSION logic whenever the effective distribution + // (either explicitly provided or extracted from the version file) is in the list. + if ( + DISTRIBUTIONS_ONLY_MAJOR_VERSION.includes( + extractedDistribution || distributionName + ) + ) { const coerceVersion = semver.coerce(version) ?? version; version = semver.major(coerceVersion).toString(); } - return version.toString(); + return { + version: version.toString(), + distribution: extractedDistribution + }; +} + +// Map SDKMAN distribution identifiers to setup-java distribution names +function mapSdkmanDistribution(sdkmanDist: string): string | undefined { + const distributionMap: Record = { + tem: 'temurin', + sem: 'semeru', + albba: 'dragonwell', + zulu: 'zulu', + amzn: 'corretto', + graal: 'graalvm', + graalce: 'graalvm', + librca: 'liberica', + ms: 'microsoft', + oracle: 'oracle', + sapmchn: 'sapmachine', + jbr: 'jetbrains', + dragonwell: 'dragonwell', + kona: 'kona' + }; + + const mapped = distributionMap[sdkmanDist.toLowerCase()]; + if (!mapped) { + core.warning( + `Unknown SDKMAN distribution identifier '${sdkmanDist}'. Please specify the distribution explicitly.` + ); + } + return mapped; +} + +// Map asdf-java (.tool-versions) vendor identifiers to setup-java distribution names. +// asdf-java encodes the vendor as a prefix on the version string, e.g. +// `java temurin-17.0.3+7` or `java semeru-openj9-11.0.25+9`. Packaging variants +// (`-jre`, `-musl`, `-openj9`, `-crac`, `-javafx`, ...) are collapsed onto the +// base vendor since setup-java does not distinguish them here. +function mapAsdfDistribution(asdfDist: string): string | undefined { + const normalized = asdfDist.toLowerCase(); + + // Multi-segment vendors that map to a distinct setup-java distribution. + if (normalized.startsWith('graalvm-community')) { + return 'graalvm-community'; + } + if (normalized.startsWith('oracle-graalvm')) { + return 'graalvm'; + } + + const baseVendor = normalized.split('-')[0]; + const distributionMap: Record = { + temurin: 'temurin', + adoptopenjdk: 'temurin', + zulu: 'zulu', + corretto: 'corretto', + liberica: 'liberica', + microsoft: 'microsoft', + semeru: 'semeru', + ibm: 'semeru', + dragonwell: 'dragonwell', + graalvm: 'graalvm', + oracle: 'oracle', + sapmachine: 'sapmachine', + kona: 'kona', + jetbrains: 'jetbrains' + }; + + const mapped = distributionMap[baseVendor]; + if (!mapped) { + core.warning( + `Unknown asdf distribution identifier '${asdfDist}'. Please specify the distribution explicitly.` + ); + } + return mapped; } // By convention, action expects version 8 in the format `8.*` instead of `1.8`