Compare commits

...

6 Commits

Author SHA1 Message Date
Bruno Borges 1bcf9fb12c dist: Address Copilot review suggestions from PR #1042 (GraalVM Community) (#1059)
- installer: surface a clear error when the GraalVM Community releases
  listing is not a JSON array, instead of silently treating an error
  payload (rate limit, auth failure, etc.) as "no releases" which later
  surfaced as a misleading "version not found" error.
- docs: fix the GraalVM Community advanced-usage example to check the
  installed binary versions (java/native-image --version) rather than
  running a non-existent HelloWorldApp classpath that fails when copied.
- tests: cover the new non-array release listing error path.

Rebuilt dist bundle.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-23 13:37:44 -04:00
Bruno Borges fa2c6508d1 docs: note jdkfile approach for Early Access / unreleased JDK builds (#1058)
* docs: note jdkfile approach for Early Access / unreleased JDK builds

Clarify in advanced-usage that the existing 'jdkfile' distribution can be
used to install Early Access (EA) or other unreleased JDK builds not
provided directly by setup-java, by downloading the archive in a prior
step and pointing jdkFile at it. Adds a concrete EA example.

Addresses #612.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-23 13:23:45 -04:00
Copilot 1d56e31dbb dist: Add GraalVM Community distribution support (#1042)
* Initial plan

* feat: add graalvm community distribution support

* build: update bundled dist for graalvm community support

* chore: address GraalVM community review feedback

* fix: tidy graalvm community validation follow-ups

* refactor: simplify GraalVM Community release resolution

* refactor: address review feedback on Community resolver

* refactor: rename pagination index for clarity

* test: fix graalvm installer test formatting

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Bruno Borges <brborges@microsoft.com>
2026-06-23 13:19:27 -04:00
Bruno Borges 1d25252804 chore: Harden workflows: least-privilege permissions + zizmor integration (#1039)
* Harden workflows with least-privilege permissions and zizmor

Apply GitHub Actions security best practices to the action's own
workflows and integrate zizmor to catch regressions.

- Add explicit least-privilege `permissions:` to every workflow
  (contents: read for read-only workflows; default-deny `{}` with
  job-scoped grants for codeql, publish-immutable-actions and
  update-config-files).
- Set `persist-credentials: false` on all checkout steps that don't
  need the GITHUB_TOKEN afterwards.
- Move `${{ ... }}` expansions out of `run:` blocks into `env:` vars
  to avoid template injection.
- Pin the alpine container image (alpine:latest -> alpine:3.21).
- Add a zizmor CI workflow that uploads SARIF to code scanning, plus a
  `.github/zizmor.yml` pinning policy (ref-pin for actions/* and
  github/*, hash-pin for third-party actions).

zizmor now reports no findings (offline and online).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Fix indentation of if: in zizmor SARIF upload step

The `if:` key on the "Upload SARIF results to code scanning" step had no
indentation, producing invalid YAML ("Nested mappings are not allowed in
compact mappings"). This broke `npm run format-check` (prettier) in Basic
validation.

Indent `if:` to 8 spaces so it nests under the step alongside uses/with.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-23 18:10:17 +01:00
Bruno Borges 668c1ea991 docs: add post-install keytool import for the JDK cacerts trust store (#1051)
Document how to make the installed JDK trust an internal CA at application
runtime by importing it into $JAVA_HOME/lib/security/cacerts with keytool
after setup-java runs. Clarifies this is the runtime trust layer, distinct
from the download/transport layer (NODE_EXTRA_CA_CERTS), and notes hosted vs
self-hosted persistence caveats.

Refs #640 #1035

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-22 21:59:01 -04:00
Bruno Borges a9a46fbe09 docs: document self-signed certificate / internal CA handling for GitHub Enterprise (#1050)
Adds an advanced-usage section explaining the 'self signed certificate in
certificate chain' error seen on GitHub Enterprise Server and behind
TLS-inspecting proxies. Recommends the secure fix of trusting the internal
CA via NODE_EXTRA_CA_CERTS (or the OS trust store on self-hosted runners),
with a GitHub Enterprise callout, and warns against disabling TLS
verification since the JDK download has no checksum fallback.

Refs #640

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-22 21:51:01 -04:00
19 changed files with 859 additions and 77 deletions
+3
View File
@@ -11,6 +11,9 @@ on:
paths-ignore: paths-ignore:
- '**.md' - '**.md'
permissions:
contents: read
jobs: jobs:
call-basic-validation: call-basic-validation:
name: Basic validation name: Basic validation
+3
View File
@@ -11,6 +11,9 @@ on:
- '**.md' - '**.md'
workflow_dispatch: workflow_dispatch:
permissions:
contents: read
jobs: jobs:
call-check-dist: call-check-dist:
name: Check dist/ name: Check dist/
+2
View File
@@ -8,6 +8,8 @@ on:
schedule: schedule:
- cron: '0 3 * * 0' - cron: '0 3 * * 0'
permissions: {}
jobs: jobs:
call-codeQL-analysis: call-codeQL-analysis:
permissions: permissions:
@@ -11,6 +11,9 @@ on:
paths-ignore: paths-ignore:
- '**.md' - '**.md'
permissions:
contents: read
defaults: defaults:
run: run:
shell: bash shell: bash
@@ -25,6 +28,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v7 uses: actions/checkout@v7
with:
persist-credentials: false
- name: Run setup-java with the cache for gradle - name: Run setup-java with the cache for gradle
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -52,6 +57,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v7 uses: actions/checkout@v7
with:
persist-credentials: false
- name: Run setup-java with the cache for gradle - name: Run setup-java with the cache for gradle
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -77,6 +84,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v7 uses: actions/checkout@v7
with:
persist-credentials: false
- name: Run setup-java with the cache for gradle - name: Run setup-java with the cache for gradle
uses: ./ uses: ./
id: setup-java id: setup-java
+15
View File
@@ -11,6 +11,9 @@ on:
paths-ignore: paths-ignore:
- '**.md' - '**.md'
permissions:
contents: read
defaults: defaults:
run: run:
shell: bash shell: bash
@@ -25,6 +28,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v7 uses: actions/checkout@v7
with:
persist-credentials: false
- name: Run setup-java with the cache for gradle - name: Run setup-java with the cache for gradle
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -51,6 +56,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v7 uses: actions/checkout@v7
with:
persist-credentials: false
- name: Run setup-java with the cache for gradle - name: Run setup-java with the cache for gradle
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -74,6 +81,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v7 uses: actions/checkout@v7
with:
persist-credentials: false
- name: Run setup-java with the cache for maven - name: Run setup-java with the cache for maven
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -98,6 +107,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v7 uses: actions/checkout@v7
with:
persist-credentials: false
- name: Run setup-java with the cache for maven - name: Run setup-java with the cache for maven
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -125,6 +136,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v7 uses: actions/checkout@v7
with:
persist-credentials: false
- name: Run setup-java with the cache for sbt - name: Run setup-java with the cache for sbt
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -175,6 +188,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v7 uses: actions/checkout@v7
with:
persist-credentials: false
- name: Run setup-java with the cache for sbt - name: Run setup-java with the cache for sbt
uses: ./ uses: ./
id: setup-java id: setup-java
+18 -3
View File
@@ -11,6 +11,9 @@ on:
paths-ignore: paths-ignore:
- '**.md' - '**.md'
permissions:
contents: read
jobs: jobs:
setup-java-local-file-adopt: setup-java-local-file-adopt:
name: Validate installation from local file Adopt name: Validate installation from local file Adopt
@@ -22,6 +25,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v7 uses: actions/checkout@v7
with:
persist-credentials: false
- name: Download Adopt OpenJDK file - name: Download Adopt OpenJDK file
run: | run: |
if ($IsLinux) { if ($IsLinux) {
@@ -46,7 +51,9 @@ jobs:
java-version: '11.0.0-ea' java-version: '11.0.0-ea'
architecture: x64 architecture: x64
- name: Verify Java version - 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 shell: bash
setup-java-local-file-zulu: setup-java-local-file-zulu:
@@ -59,6 +66,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v7 uses: actions/checkout@v7
with:
persist-credentials: false
- name: Download Zulu OpenJDK file - name: Download Zulu OpenJDK file
run: | run: |
if ($IsLinux) { if ($IsLinux) {
@@ -83,7 +92,9 @@ jobs:
java-version: '11.0.0-ea' java-version: '11.0.0-ea'
architecture: x64 architecture: x64
- name: Verify Java version - 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 shell: bash
setup-java-local-file-temurin: setup-java-local-file-temurin:
@@ -96,6 +107,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v7 uses: actions/checkout@v7
with:
persist-credentials: false
- name: Download Eclipse Temurin file - name: Download Eclipse Temurin file
run: | run: |
if ($IsLinux) { if ($IsLinux) {
@@ -120,5 +133,7 @@ jobs:
java-version: '11.0.0-ea' java-version: '11.0.0-ea'
architecture: x64 architecture: x64
- name: Verify Java version - 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 shell: bash
+11
View File
@@ -11,6 +11,9 @@ on:
paths-ignore: paths-ignore:
- '**.md' - '**.md'
permissions:
contents: read
defaults: defaults:
run: run:
shell: pwsh shell: pwsh
@@ -26,6 +29,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v7 uses: actions/checkout@v7
with:
persist-credentials: false
- name: setup-java - name: setup-java
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -61,6 +66,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v7 uses: actions/checkout@v7
with:
persist-credentials: false
- name: Create fake settings.xml - name: Create fake settings.xml
run: | run: |
$xmlDirectory = Join-Path $HOME ".m2" $xmlDirectory = Join-Path $HOME ".m2"
@@ -97,6 +104,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v7 uses: actions/checkout@v7
with:
persist-credentials: false
- name: Create fake settings.xml - name: Create fake settings.xml
run: | run: |
$xmlDirectory = Join-Path $HOME ".m2" $xmlDirectory = Join-Path $HOME ".m2"
@@ -134,6 +143,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v7 uses: actions/checkout@v7
with:
persist-credentials: false
- name: setup-java - name: setup-java
uses: ./ uses: ./
id: setup-java id: setup-java
+83 -16
View File
@@ -13,6 +13,10 @@ on:
schedule: schedule:
- cron: '0 */12 * * *' - cron: '0 */12 * * *'
workflow_dispatch: workflow_dispatch:
permissions:
contents: read
jobs: jobs:
setup-java-major-versions: setup-java-major-versions:
name: ${{ matrix.distribution }} ${{ matrix.version }} (jdk-x64) - ${{ matrix.os }} name: ${{ matrix.distribution }} ${{ matrix.version }} (jdk-x64) - ${{ matrix.os }}
@@ -74,6 +78,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v7 uses: actions/checkout@v7
with:
persist-credentials: false
- name: setup-java - name: setup-java
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -83,14 +89,17 @@ jobs:
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Verify Java - 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 shell: bash
setup-java-alpine-linux: setup-java-alpine-linux:
name: ${{ matrix.distribution }} ${{ matrix.version }} (jdk-x64) - alpine-linux - ${{ matrix.os }} name: ${{ matrix.distribution }} ${{ matrix.version }} (jdk-x64) - alpine-linux - ${{ matrix.os }}
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
container: container:
image: alpine:latest image: alpine:3.21
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -100,6 +109,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v7 uses: actions/checkout@v7
with:
persist-credentials: false
- name: Install bash - name: Install bash
run: apk add --no-cache bash run: apk add --no-cache bash
- name: setup-java - name: setup-java
@@ -109,7 +120,10 @@ jobs:
java-version: ${{ matrix.version }} java-version: ${{ matrix.version }}
distribution: ${{ matrix.distribution }} distribution: ${{ matrix.distribution }}
- name: Verify Java - 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 shell: bash
setup-java-major-minor-versions: setup-java-major-minor-versions:
@@ -150,6 +164,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v7 uses: actions/checkout@v7
with:
persist-credentials: false
- name: setup-java - name: setup-java
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -157,10 +173,12 @@ jobs:
java-version: ${{ matrix.version }} java-version: ${{ matrix.version }}
distribution: ${{ matrix.distribution }} distribution: ${{ matrix.distribution }}
- name: Verify Java - name: Verify Java
run: bash __tests__/verify-java.sh "${{ matrix.version }}" "${{ steps.setup-java.outputs.path }}"
shell: bash
env: env:
JAVA_VERSION: ${{ matrix.version }}
JAVA_PATH: ${{ steps.setup-java.outputs.path }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: bash __tests__/verify-java.sh "$JAVA_VERSION" "$JAVA_PATH"
shell: bash
setup-java-check-latest: setup-java-check-latest:
name: ${{ matrix.distribution }} ${{ matrix.version }} - check-latest flag - ${{ matrix.os }} name: ${{ matrix.distribution }} ${{ matrix.version }} - check-latest flag - ${{ matrix.os }}
@@ -185,6 +203,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v7 uses: actions/checkout@v7
with:
persist-credentials: false
- name: setup-java - name: setup-java
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -195,7 +215,9 @@ jobs:
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Verify Java - 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 shell: bash
setup-java-multiple-jdks: setup-java-multiple-jdks:
@@ -221,6 +243,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v7 uses: actions/checkout@v7
with:
persist-credentials: false
- name: setup-java - name: setup-java
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -245,7 +269,9 @@ jobs:
} }
shell: pwsh shell: pwsh
- name: Verify Java - 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 shell: bash
setup-java-ea-versions-zulu: setup-java-ea-versions-zulu:
@@ -260,6 +286,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v7 uses: actions/checkout@v7
with:
persist-credentials: false
- name: setup-java - name: setup-java
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -267,7 +295,10 @@ jobs:
java-version: ${{ matrix.version }} java-version: ${{ matrix.version }}
distribution: zulu distribution: zulu
- name: Verify Java - 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 shell: bash
setup-java-ea-versions-temurin: setup-java-ea-versions-temurin:
@@ -282,6 +313,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v7 uses: actions/checkout@v7
with:
persist-credentials: false
- name: setup-java - name: setup-java
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -289,7 +322,10 @@ jobs:
java-version: ${{ matrix.version }} java-version: ${{ matrix.version }}
distribution: temurin distribution: temurin
- name: Verify Java - 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 shell: bash
setup-java-ea-versions-sapmachine: setup-java-ea-versions-sapmachine:
@@ -304,6 +340,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v7 uses: actions/checkout@v7
with:
persist-credentials: false
- name: setup-java - name: setup-java
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -311,7 +349,10 @@ jobs:
java-version: ${{ matrix.version }} java-version: ${{ matrix.version }}
distribution: sapmachine distribution: sapmachine
- name: Verify Java - 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 shell: bash
setup-java-custom-package-type: setup-java-custom-package-type:
@@ -391,6 +432,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v7 uses: actions/checkout@v7
with:
persist-credentials: false
- name: setup-java - name: setup-java
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -401,7 +444,10 @@ jobs:
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Verify Java - 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 shell: bash
# Only Liberica and Zulu provide x86 # Only Liberica and Zulu provide x86
@@ -419,6 +465,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v7 uses: actions/checkout@v7
with:
persist-credentials: false
- name: setup-java - name: setup-java
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -427,7 +475,10 @@ jobs:
java-version: ${{ matrix.version }} java-version: ${{ matrix.version }}
architecture: 'x86' architecture: 'x86'
- name: Verify Java - 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 shell: bash
setup-java-version-both-version-inputs-presents: setup-java-version-both-version-inputs-presents:
@@ -442,6 +493,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v7 uses: actions/checkout@v7
with:
persist-credentials: false
- name: Create .java-version file - name: Create .java-version file
shell: bash shell: bash
run: echo "17" > .java-version run: echo "17" > .java-version
@@ -456,7 +509,9 @@ jobs:
java-version: 11 java-version: 11
java-version-file: ${{matrix.java-version-file }} java-version-file: ${{matrix.java-version-file }}
- name: Verify Java - 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 shell: bash
setup-java-version-from-file-major-notation: setup-java-version-from-file-major-notation:
@@ -471,6 +526,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v7 uses: actions/checkout@v7
with:
persist-credentials: false
- name: Create .java-version file - name: Create .java-version file
shell: bash shell: bash
run: echo "11" > .java-version run: echo "11" > .java-version
@@ -484,7 +541,9 @@ jobs:
distribution: ${{ matrix.distribution }} distribution: ${{ matrix.distribution }}
java-version-file: ${{matrix.java-version-file }} java-version-file: ${{matrix.java-version-file }}
- name: Verify Java - 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 shell: bash
setup-java-version-from-file-major-minor-patch-notation: setup-java-version-from-file-major-minor-patch-notation:
@@ -499,6 +558,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v7 uses: actions/checkout@v7
with:
persist-credentials: false
- name: Create .java-version file - name: Create .java-version file
shell: bash shell: bash
run: echo "17.0.10" > .java-version run: echo "17.0.10" > .java-version
@@ -512,7 +573,9 @@ jobs:
distribution: ${{ matrix.distribution }} distribution: ${{ matrix.distribution }}
java-version-file: ${{matrix.java-version-file }} java-version-file: ${{matrix.java-version-file }}
- name: Verify Java - 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 shell: bash
setup-java-version-from-file-major-minor-patch-with-dist: setup-java-version-from-file-major-minor-patch-with-dist:
@@ -527,6 +590,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v7 uses: actions/checkout@v7
with:
persist-credentials: false
- name: Create .java-version file - name: Create .java-version file
shell: bash shell: bash
run: echo "openjdk64-17.0.10" > .java-version run: echo "openjdk64-17.0.10" > .java-version
@@ -543,5 +608,7 @@ jobs:
distribution: ${{ matrix.distribution }} distribution: ${{ matrix.distribution }}
java-version-file: ${{matrix.java-version-file }} java-version-file: ${{matrix.java-version-file }}
- name: Verify Java - 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 shell: bash
+3
View File
@@ -9,6 +9,9 @@ on:
- main - main
workflow_dispatch: workflow_dispatch:
permissions:
contents: read
jobs: jobs:
call-licensed: call-licensed:
name: Licensed name: Licensed
@@ -5,6 +5,8 @@ on:
types: [released] types: [released]
workflow_dispatch: workflow_dispatch:
permissions: {}
jobs: jobs:
publish: publish:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -16,6 +18,8 @@ jobs:
steps: steps:
- name: Checking out - name: Checking out
uses: actions/checkout@v7 uses: actions/checkout@v7
with:
persist-credentials: false
- name: Publish - name: Publish
id: publish id: publish
uses: actions/publish-immutable-action@v0.0.4 uses: actions/publish-immutable-action@v0.0.4
@@ -5,7 +5,12 @@ on:
- cron: '0 3 * * 0' - cron: '0 3 * * 0'
workflow_dispatch: workflow_dispatch:
permissions: {}
jobs: jobs:
call-update-configuration-files: call-update-configuration-files:
name: 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 uses: actions/reusable-workflows/.github/workflows/update-config-files.yml@main
+48
View File
@@ -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@v6
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@v5
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@v3
with:
sarif_file: zizmor.sarif
category: zizmor
+11
View File
@@ -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
+2
View File
@@ -112,6 +112,7 @@ Currently, the following distributions are supported:
| `dragonwell` | [Alibaba Dragonwell JDK](https://dragonwell-jdk.io/) | [`dragonwell` license](https://www.aliyun.com/product/dragonwell/) | `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) | `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` | [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) | `jetbrains` | [JetBrains Runtime](https://github.com/JetBrains/JetBrainsRuntime/) | [`jetbrains` license](https://github.com/JetBrains/JetBrainsRuntime/blob/main/LICENSE)
| `jdkfile` | Custom JDK Installation | | | `jdkfile` | Custom JDK Installation | |
@@ -120,6 +121,7 @@ Currently, the following distributions are supported:
> - 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/). > - 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 architectures x64 and arm64 are mapped to x86 / arm with proper hw_bitness. > - For Azul Zulu OpenJDK architectures x64 and arm64 are mapped to x86 / arm with proper hw_bitness.
> - 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. > - 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. **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.
@@ -3,7 +3,11 @@ import * as tc from '@actions/tool-cache';
import * as http from '@actions/http-client'; import * as http from '@actions/http-client';
import fs from 'fs'; import fs from 'fs';
import path from 'path'; 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 {JavaInstallerOptions} from '../../src/distributions/base-models';
import * as util from '../../src/util'; import * as util from '../../src/util';
@@ -41,6 +45,7 @@ beforeAll(() => {
describe('GraalVMDistribution', () => { describe('GraalVMDistribution', () => {
let distribution: GraalVMDistribution; let distribution: GraalVMDistribution;
let communityDistribution: GraalVMCommunityDistribution;
let mockHttpClient: jest.Mocked<http.HttpClient>; let mockHttpClient: jest.Mocked<http.HttpClient>;
let spyCoreError: jest.SpyInstance; let spyCoreError: jest.SpyInstance;
@@ -55,9 +60,11 @@ describe('GraalVMDistribution', () => {
jest.clearAllMocks(); jest.clearAllMocks();
distribution = new GraalVMDistribution(defaultOptions); distribution = new GraalVMDistribution(defaultOptions);
communityDistribution = new GraalVMCommunityDistribution(defaultOptions);
mockHttpClient = new http.HttpClient() as jest.Mocked<http.HttpClient>; mockHttpClient = new http.HttpClient() as jest.Mocked<http.HttpClient>;
(distribution as any).http = mockHttpClient; (distribution as any).http = mockHttpClient;
(communityDistribution as any).http = mockHttpClient;
(util.getDownloadArchiveExtension as jest.Mock).mockReturnValue('tar.gz'); (util.getDownloadArchiveExtension as jest.Mock).mockReturnValue('tar.gz');
@@ -242,6 +249,23 @@ describe('GraalVMDistribution', () => {
path: '/cached/java/path' 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', () => { describe('findPackageForDownload', () => {
@@ -948,5 +972,121 @@ describe('GraalVMDistribution', () => {
configurable: true 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);
}); });
}); });
+142 -24
View File
@@ -78771,6 +78771,7 @@ var JavaDistribution;
JavaDistribution["Dragonwell"] = "dragonwell"; JavaDistribution["Dragonwell"] = "dragonwell";
JavaDistribution["SapMachine"] = "sapmachine"; JavaDistribution["SapMachine"] = "sapmachine";
JavaDistribution["GraalVM"] = "graalvm"; JavaDistribution["GraalVM"] = "graalvm";
JavaDistribution["GraalVMCommunity"] = "graalvm-community";
JavaDistribution["JetBrains"] = "jetbrains"; JavaDistribution["JetBrains"] = "jetbrains";
})(JavaDistribution || (JavaDistribution = {})); })(JavaDistribution || (JavaDistribution = {}));
function getJavaDistribution(distributionName, installerOptions, jdkFile) { function getJavaDistribution(distributionName, installerOptions, jdkFile) {
@@ -78802,6 +78803,8 @@ function getJavaDistribution(distributionName, installerOptions, jdkFile) {
return new installer_11.SapMachineDistribution(installerOptions); return new installer_11.SapMachineDistribution(installerOptions);
case JavaDistribution.GraalVM: case JavaDistribution.GraalVM:
return new installer_12.GraalVMDistribution(installerOptions); return new installer_12.GraalVMDistribution(installerOptions);
case JavaDistribution.GraalVMCommunity:
return new installer_12.GraalVMCommunityDistribution(installerOptions);
case JavaDistribution.JetBrains: case JavaDistribution.JetBrains:
return new installer_13.JetBrainsDistribution(installerOptions); return new installer_13.JetBrainsDistribution(installerOptions);
default: default:
@@ -79069,23 +79072,29 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod }; return (mod && mod.__esModule) ? mod : { "default": mod };
}; };
Object.defineProperty(exports, "__esModule", ({ value: true })); Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.GraalVMDistribution = void 0; exports.GraalVMCommunityDistribution = exports.GraalVMDistribution = void 0;
const core = __importStar(__nccwpck_require__(37484)); const core = __importStar(__nccwpck_require__(37484));
const tc = __importStar(__nccwpck_require__(33472)); const tc = __importStar(__nccwpck_require__(33472));
const fs_1 = __importDefault(__nccwpck_require__(79896)); const fs_1 = __importDefault(__nccwpck_require__(79896));
const path_1 = __importDefault(__nccwpck_require__(16928)); const path_1 = __importDefault(__nccwpck_require__(16928));
const semver_1 = __importDefault(__nccwpck_require__(62088));
const base_installer_1 = __nccwpck_require__(79935); const base_installer_1 = __nccwpck_require__(79935);
const http_client_1 = __nccwpck_require__(54844); const http_client_1 = __nccwpck_require__(54844);
const util_1 = __nccwpck_require__(54527); const util_1 = __nccwpck_require__(54527);
const GRAALVM_DL_BASE = 'https://download.oracle.com/graalvm'; const GRAALVM_DL_BASE = 'https://download.oracle.com/graalvm';
const GRAALVM_DOWNLOAD_URL = 'https://www.graalvm.org/downloads/'; 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 IS_WINDOWS = process.platform === 'win32';
const GRAALVM_PLATFORM = IS_WINDOWS ? 'windows' : process.platform; const GRAALVM_PLATFORM = IS_WINDOWS ? 'windows' : process.platform;
const GRAALVM_MIN_VERSION = 17; const GRAALVM_MIN_VERSION = 17;
const SUPPORTED_ARCHITECTURES = ['x64', 'aarch64']; const SUPPORTED_ARCHITECTURES = ['x64', 'aarch64'];
class GraalVMDistribution extends base_installer_1.JavaBase { class GraalVMDistribution extends base_installer_1.JavaBase {
constructor(installerOptions) { constructor(installerOptions, distributionName = 'GraalVM') {
super('GraalVM', installerOptions); super(distributionName, installerOptions);
} }
downloadTool(javaRelease) { downloadTool(javaRelease) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
@@ -79119,36 +79128,50 @@ class GraalVMDistribution extends base_installer_1.JavaBase {
} }
findPackageForDownload(range) { findPackageForDownload(range) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
// Add input validation this.validateVersionRange(range);
if (!range || typeof range !== 'string') { const arch = this.getSupportedArchitecture();
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(', ')}`);
}
if (!this.stable) { if (!this.stable) {
return this.findEABuildDownloadUrl(`${range}-ea`); return this.findEABuildDownloadUrl(`${range}-ea`);
} }
if (this.packageType !== 'jdk') { const { platform, extension, major } = this.validateStableBuildRequest(range);
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 fileUrl = this.constructFileUrl(range, major, platform, arch, extension); const fileUrl = this.constructFileUrl(range, major, platform, arch, extension);
const response = yield this.http.head(fileUrl); const response = yield this.http.head(fileUrl);
this.handleHttpResponse(response, range); this.handleHttpResponse(response, range);
return { url: fileUrl, version: 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) { constructFileUrl(range, major, platform, arch, extension) {
return range.includes('.') return range.includes('.')
? `${GRAALVM_DL_BASE}/${major}/archive/graalvm-jdk-${range}_${platform}-${arch}_bin.${extension}` ? `${GRAALVM_DL_BASE}/${major}/archive/graalvm-jdk-${range}_${platform}-${arch}_bin.${extension}`
@@ -79239,6 +79262,101 @@ class GraalVMDistribution extends base_installer_1.JavaBase {
} }
} }
exports.GraalVMDistribution = GraalVMDistribution; 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;
/***/ }), /***/ }),
+128
View File
@@ -10,6 +10,7 @@
- [Alibaba Dragonwell](#Alibaba-Dragonwell) - [Alibaba Dragonwell](#Alibaba-Dragonwell)
- [SapMachine](#SapMachine) - [SapMachine](#SapMachine)
- [GraalVM](#GraalVM) - [GraalVM](#GraalVM)
- [GraalVM Community](#GraalVM-Community)
- [JetBrains](#JetBrains) - [JetBrains](#JetBrains)
- [Installing custom Java package type](#Installing-custom-Java-package-type) - [Installing custom Java package type](#Installing-custom-Java-package-type)
- [JavaFX Maven project](#JavaFX-Maven-project) - [JavaFX Maven project](#JavaFX-Maven-project)
@@ -22,6 +23,7 @@
- [Hosted Tool Cache](#Hosted-Tool-Cache) - [Hosted Tool Cache](#Hosted-Tool-Cache)
- [Modifying Maven Toolchains](#Modifying-Maven-Toolchains) - [Modifying Maven Toolchains](#Modifying-Maven-Toolchains)
- [Java-version file](#Java-version-file) - [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. See [action.yml](../action.yml) for more details on task inputs.
@@ -173,6 +175,21 @@ steps:
native-image --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 --version
native-image --version
```
### JetBrains ### JetBrains
**NOTE:** JetBrains is only available for LTS versions on 11 or later (11, 17, 21, etc.). **NOTE:** JetBrains is only available for LTS versions on 11 or later (11, 17, 21, etc.).
@@ -269,6 +286,9 @@ steps:
## Installing Java from local file ## 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: 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 `jdkFile` 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 ```yaml
steps: steps:
- run: | - run: |
@@ -284,6 +304,23 @@ steps:
- run: java --version - 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'
jdkFile: ${{ 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: 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:
```yaml ```yaml
@@ -660,3 +697,94 @@ If the file contains multiple versions, only the first one will be recognized.
***NOTE***: ***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). 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.
+7 -1
View File
@@ -11,7 +11,10 @@ import {CorrettoDistribution} from './corretto/installer';
import {OracleDistribution} from './oracle/installer'; import {OracleDistribution} from './oracle/installer';
import {DragonwellDistribution} from './dragonwell/installer'; import {DragonwellDistribution} from './dragonwell/installer';
import {SapMachineDistribution} from './sapmachine/installer'; import {SapMachineDistribution} from './sapmachine/installer';
import {GraalVMDistribution} from './graalvm/installer'; import {
GraalVMCommunityDistribution,
GraalVMDistribution
} from './graalvm/installer';
import {JetBrainsDistribution} from './jetbrains/installer'; import {JetBrainsDistribution} from './jetbrains/installer';
enum JavaDistribution { enum JavaDistribution {
@@ -29,6 +32,7 @@ enum JavaDistribution {
Dragonwell = 'dragonwell', Dragonwell = 'dragonwell',
SapMachine = 'sapmachine', SapMachine = 'sapmachine',
GraalVM = 'graalvm', GraalVM = 'graalvm',
GraalVMCommunity = 'graalvm-community',
JetBrains = 'jetbrains' JetBrains = 'jetbrains'
} }
@@ -74,6 +78,8 @@ export function getJavaDistribution(
return new SapMachineDistribution(installerOptions); return new SapMachineDistribution(installerOptions);
case JavaDistribution.GraalVM: case JavaDistribution.GraalVM:
return new GraalVMDistribution(installerOptions); return new GraalVMDistribution(installerOptions);
case JavaDistribution.GraalVMCommunity:
return new GraalVMCommunityDistribution(installerOptions);
case JavaDistribution.JetBrains: case JavaDistribution.JetBrains:
return new JetBrainsDistribution(installerOptions); return new JetBrainsDistribution(installerOptions);
default: default:
+224 -32
View File
@@ -2,6 +2,7 @@ import * as core from '@actions/core';
import * as tc from '@actions/tool-cache'; import * as tc from '@actions/tool-cache';
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
import semver from 'semver';
import {JavaBase} from '../base-installer'; import {JavaBase} from '../base-installer';
import {HttpCodes} from '@actions/http-client'; import {HttpCodes} from '@actions/http-client';
import {GraalVMEAVersion} from './models'; import {GraalVMEAVersion} from './models';
@@ -11,14 +12,26 @@ import {
JavaInstallerResults JavaInstallerResults
} from '../base-models'; } from '../base-models';
import { import {
convertVersionToSemver,
extractJdkFile, extractJdkFile,
getDownloadArchiveExtension, getDownloadArchiveExtension,
getGitHubHttpHeaders, getGitHubHttpHeaders,
renameWinArchive getNextPageUrlFromLinkHeader,
isVersionSatisfies,
MAX_PAGINATION_PAGES,
renameWinArchive,
validatePaginationUrl
} from '../../util'; } from '../../util';
const GRAALVM_DL_BASE = 'https://download.oracle.com/graalvm'; const GRAALVM_DL_BASE = 'https://download.oracle.com/graalvm';
const GRAALVM_DOWNLOAD_URL = 'https://www.graalvm.org/downloads/'; 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 IS_WINDOWS = process.platform === 'win32';
const GRAALVM_PLATFORM = IS_WINDOWS ? 'windows' : process.platform; const GRAALVM_PLATFORM = IS_WINDOWS ? 'windows' : process.platform;
const GRAALVM_MIN_VERSION = 17; const GRAALVM_MIN_VERSION = 17;
@@ -26,9 +39,23 @@ const SUPPORTED_ARCHITECTURES = ['x64', 'aarch64'] as const;
type SupportedArchitecture = (typeof SUPPORTED_ARCHITECTURES)[number]; type SupportedArchitecture = (typeof SUPPORTED_ARCHITECTURES)[number];
type OsVersions = 'linux' | 'macos' | 'windows'; 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 { export class GraalVMDistribution extends JavaBase {
constructor(installerOptions: JavaInstallerOptions) { constructor(
super('GraalVM', installerOptions); installerOptions: JavaInstallerOptions,
distributionName = 'GraalVM'
) {
super(distributionName, installerOptions);
} }
protected async downloadTool( protected async downloadTool(
@@ -85,40 +112,14 @@ export class GraalVMDistribution extends JavaBase {
protected async findPackageForDownload( protected async findPackageForDownload(
range: string range: string
): Promise<JavaDownloadRelease> { ): Promise<JavaDownloadRelease> {
// Add input validation this.validateVersionRange(range);
if (!range || typeof range !== 'string') { const arch = this.getSupportedArchitecture();
throw new Error('Version range is required and must be a string');
}
const arch = this.distributionArchitecture();
if (!SUPPORTED_ARCHITECTURES.includes(arch as SupportedArchitecture)) {
throw new Error(
`Unsupported architecture: ${this.architecture}. Supported architectures are: ${SUPPORTED_ARCHITECTURES.join(', ')}`
);
}
if (!this.stable) { if (!this.stable) {
return this.findEABuildDownloadUrl(`${range}-ea`); return this.findEABuildDownloadUrl(`${range}-ea`);
} }
if (this.packageType !== 'jdk') { const {platform, extension, major} = this.validateStableBuildRequest(range);
throw new Error('GraalVM provides only the `jdk` package type');
}
const platform = this.getPlatform();
const extension = 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 fileUrl = this.constructFileUrl( const fileUrl = this.constructFileUrl(
range, range,
@@ -134,6 +135,56 @@ export class GraalVMDistribution extends JavaBase {
return {url: fileUrl, version: 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(
`Unsupported architecture: ${this.architecture}. Supported architectures are: ${SUPPORTED_ARCHITECTURES.join(', ')}`
);
}
return arch as SupportedArchitecture;
}
protected validateStableBuildRequest(range: string): {
platform: OsVersions;
extension: string;
major: string;
} {
if (this.packageType !== 'jdk') {
throw new Error(
`${this.distribution} provides only the \`jdk\` package type`
);
}
const platform = this.getPlatform();
const extension = 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
};
}
private constructFileUrl( private constructFileUrl(
range: string, range: string,
major: string, major: string,
@@ -280,3 +331,144 @@ export class GraalVMDistribution extends JavaBase {
return result; 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<JavaDownloadRelease> {
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<JavaDownloadRelease[]> {
const headers = getGitHubHttpHeaders();
const versions = new Map<string, JavaDownloadRelease>();
let releasesUrl: string | null = GRAALVM_COMMUNITY_RELEASES_URL;
for (
let pageIndex = 0;
releasesUrl && pageIndex < MAX_PAGINATION_PAGES;
pageIndex++
) {
const response = await this.http.getJson<GraalVMCommunityRelease[]>(
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, string | string[] | undefined>
): 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;
}
}