Compare commits

..

16 Commits

Author SHA1 Message Date
Bruno Borges
1a8f22b7f7 chore: streamline Dependabot updates (#1255)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 916e0cf3-84f7-43fa-9822-3dac5cf8c5e6
2026-08-24 12:32:37 -04:00
Bruno Borges
85030b78b5 docs: complete v6 release highlights (#1254)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: bb8de955-60c9-4a56-a7a2-d0be5d32dbc4
2026-08-24 12:03:01 -04:00
Bruno Borges
dd06d9cba3 Prepare documentation for v6 release (#1253)
Update public examples and release messaging to make v6 the recommended stable version, include late-cycle v6 features, and increase the JetBrains test timeout to avoid cold-run flakes.

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

Copilot-Session: 24e3d384-3bda-4ca3-b1fc-f49e340c174f
2026-08-24 11:49:23 -04:00
Bruno Borges
59b3450628 chore(deps): combine open Dependabot npm updates (#1252)
* Combine Dependabot npm updates

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

* Rebuild action bundles

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

Copilot-Session: a5d254ad-e29c-4477-ae66-cba6e36d7e03

* Update Licensed cache for XML dependencies

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

Copilot-Session: a5d254ad-e29c-4477-ae66-cba6e36d7e03

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a5d254ad-e29c-4477-ae66-cba6e36d7e03
2026-08-24 10:36:54 -04:00
John
b96213d9d2 Set default signature verification for supported distributions (#1246)
* Default signature verification for supported distributions

* Delegate signature defaults to installers
2026-08-24 10:08:03 -04:00
Bruno Borges
1dbac3c9e1 docs: expose contributing guide to GitHub (#1245)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 684fec44-989a-4d0e-a42b-79efbda28933
2026-08-18 14:16:28 -04:00
Philip Gai
11741d6cfa ci: constrain cache e2e job modes (#1244)
* ci: constrain cache e2e job modes

* ci: constrain cache benchmark job modes
2026-08-18 10:56:27 -04:00
Bruno Borges
ff99aa1c87 Fix Oracle macOS E2E version (#1243)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: d4f1997e-98a5-4dec-b5fc-2f0fcf1abd27
2026-08-17 21:23:19 -04:00
Bruno Borges
416c6d1e8a Add Red Hat Build of OpenJDK support (#1241)
* Add Red Hat Build of OpenJDK support

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

* Fix Red Hat tests on Windows

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>

* Update compiled Red Hat distribution

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

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-08-17 20:39:36 -04:00
Bruno Borges
5f75b27283 Add Maven dependency-resolution repositories (#1240)
* Add Maven dependency repositories

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

Copilot-Session: 8897ad63-2d05-4a6d-8ccd-c1155348b59e

* Potential fix for pull request finding

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

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot-Session: 8897ad63-2d05-4a6d-8ccd-c1155348b59e
2026-08-17 18:18:45 -04:00
Bruno Borges
a42a52cfb5 Add multiple Maven server credentials (#1239)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-08-17 17:05:55 -04:00
Bruno Borges
fb4abd7a70 test: cover JDK 26 from SDKMAN (#1238)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-08-17 17:05:27 -04:00
dependabot[bot]
d4f69b3990 chore(deps-dev): bump @typescript-eslint/eslint-plugin (#1232)
Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 8.65.0 to 8.67.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.67.0/packages/eslint-plugin)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-version: 8.66.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-17 14:58:47 -04:00
dependabot[bot]
7d5d4a7f19 chore(deps-dev): bump lint-staged from 17.2.0 to 17.3.0 (#1231)
Bumps [lint-staged](https://github.com/lint-staged/lint-staged) from 17.2.0 to 17.3.0.
- [Release notes](https://github.com/lint-staged/lint-staged/releases)
- [Changelog](https://github.com/lint-staged/lint-staged/blob/main/CHANGELOG.md)
- [Commits](https://github.com/lint-staged/lint-staged/compare/v17.2.0...v17.3.0)

---
updated-dependencies:
- dependency-name: lint-staged
  dependency-version: 17.3.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-17 14:48:50 -04:00
dependabot[bot]
f974fff346 chore(deps-dev): bump @types/semver from 7.7.1 to 7.8.0 (#1229)
Bumps [@types/semver](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/semver) from 7.7.1 to 7.8.0.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/semver)

---
updated-dependencies:
- dependency-name: "@types/semver"
  dependency-version: 7.8.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-17 14:48:25 -04:00
dependabot[bot]
e96da06a44 chore(deps-dev): bump globals from 17.8.0 to 17.9.0 (#1233)
Bumps [globals](https://github.com/sindresorhus/globals) from 17.8.0 to 17.9.0.
- [Release notes](https://github.com/sindresorhus/globals/releases)
- [Commits](https://github.com/sindresorhus/globals/compare/v17.8.0...v17.9.0)

---
updated-dependencies:
- dependency-name: globals
  dependency-version: 17.9.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Bruno Borges <brborges@microsoft.com>
2026-08-17 14:47:55 -04:00
40 changed files with 2261 additions and 286 deletions

View File

@@ -1,22 +1,25 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
version: 2
updates:
# Enable version updates for npm
- package-ecosystem: 'npm'
# Look for `package.json` and `lock` files in the `root` directory
directory: '/'
# Check the npm registry for updates every day (weekdays)
schedule:
interval: 'weekly'
interval: 'monthly'
cooldown:
default-days: 7
groups:
monthly-npm-updates:
applies-to: 'version-updates'
patterns:
- '*'
# Enable version updates for GitHub Actions
- package-ecosystem: 'github-actions'
# Workflow files stored in the default location of `.github/workflows`
# You don't need to specify `/.github/workflows` for `directory`. You can use `directory: "/"`.
directory: '/'
schedule:
interval: 'weekly'
interval: 'monthly'
cooldown:
default-days: 7
groups:
monthly-actions-updates:
applies-to: 'version-updates'
patterns:
- '*'

View File

@@ -24,6 +24,7 @@ jobs:
warm-caches:
name: Warm ${{ matrix.tool }} ${{ matrix.profile }} caches (${{ matrix.os }})
runs-on: ${{ matrix.os }}
cache-mode: write-only
strategy:
fail-fast: false
matrix:
@@ -65,6 +66,7 @@ jobs:
name: Benchmark ${{ matrix.tool }} ${{ matrix.profile }} (${{ matrix.os }})
needs: warm-caches
runs-on: ${{ matrix.os }}
cache-mode: read
strategy:
fail-fast: false
matrix:

View File

@@ -21,6 +21,7 @@ defaults:
jobs:
gradle-save:
runs-on: ${{ matrix.os }}
cache-mode: write-only
strategy:
fail-fast: false
matrix:
@@ -48,6 +49,7 @@ jobs:
bash __tests__/check-dir.sh "$HOME/.gradle/wrapper/dists"
gradle-restore:
runs-on: ${{ matrix.os }}
cache-mode: read
strategy:
fail-fast: false
matrix:
@@ -72,6 +74,7 @@ jobs:
run: bash __tests__/check-dir.sh "$HOME/.gradle/wrapper/dists"
maven-save:
runs-on: ${{ matrix.os }}
cache-mode: write-only
strategy:
fail-fast: false
matrix:
@@ -97,6 +100,7 @@ jobs:
bash __tests__/check-dir.sh "$HOME/.m2/wrapper/dists"
maven-restore:
runs-on: ${{ matrix.os }}
cache-mode: read
strategy:
fail-fast: false
matrix:
@@ -121,6 +125,7 @@ jobs:
run: bash __tests__/check-dir.sh "$HOME/.m2/wrapper/dists"
sbt-save:
runs-on: ${{ matrix.os }}
cache-mode: write-only
defaults:
run:
shell: bash
@@ -160,6 +165,7 @@ jobs:
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/.cache/coursier"
sbt-restore:
runs-on: ${{ matrix.os }}
cache-mode: read
defaults:
run:
shell: bash
@@ -194,6 +200,7 @@ jobs:
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/.cache/coursier"
gradle1-save:
runs-on: ${{ matrix.os }}
cache-mode: write-only
strategy:
fail-fast: false
matrix:
@@ -222,6 +229,7 @@ jobs:
bash __tests__/check-dir.sh "$HOME/.gradle/wrapper/dists"
gradle1-restore:
runs-on: ${{ matrix.os }}
cache-mode: read
strategy:
fail-fast: false
matrix:
@@ -246,6 +254,7 @@ jobs:
run: bash __tests__/check-dir.sh "$HOME/.gradle/wrapper/dists"
gradle2-restore:
runs-on: ${{ matrix.os }}
cache-mode: read
strategy:
fail-fast: false
matrix:
@@ -268,6 +277,7 @@ jobs:
run: bash __tests__/check-dir.sh "$HOME/.gradle/caches" absent
maven1-save:
runs-on: ${{ matrix.os }}
cache-mode: write-only
strategy:
fail-fast: false
matrix:
@@ -294,6 +304,7 @@ jobs:
bash __tests__/check-dir.sh "$HOME/.m2/wrapper/dists"
maven1-restore:
runs-on: ${{ matrix.os }}
cache-mode: read
strategy:
fail-fast: false
matrix:
@@ -318,6 +329,7 @@ jobs:
run: bash __tests__/check-dir.sh "$HOME/.m2/wrapper/dists"
maven2-restore:
runs-on: ${{ matrix.os }}
cache-mode: read
strategy:
fail-fast: false
matrix:
@@ -342,6 +354,7 @@ jobs:
run: bash __tests__/check-dir.sh "$HOME/.m2/repository" absent
sbt1-save:
runs-on: ${{ matrix.os }}
cache-mode: write-only
defaults:
run:
shell: bash
@@ -382,6 +395,7 @@ jobs:
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/.cache/coursier"
sbt1-restore:
runs-on: ${{ matrix.os }}
cache-mode: read
defaults:
run:
shell: bash
@@ -416,6 +430,7 @@ jobs:
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/.cache/coursier"
sbt2-restore:
runs-on: ${{ matrix.os }}
cache-mode: read
defaults:
run:
shell: bash
@@ -450,6 +465,7 @@ jobs:
run: bash "$GITHUB_WORKSPACE/__tests__/check-dir.sh" "$HOME/.cache/coursier" absent
custom-maven-path-save:
runs-on: ubuntu-latest
cache-mode: write-only
steps:
- name: Checkout
uses: actions/checkout@v7
@@ -474,6 +490,7 @@ jobs:
bash __tests__/check-dir.sh "$RUNNER_TEMP/setup-java-custom-maven-repository"
custom-maven-path-restore:
runs-on: ubuntu-latest
cache-mode: read
needs: custom-maven-path-save
steps:
- name: Checkout

View File

@@ -71,7 +71,7 @@ jobs:
version: 25
- distribution: oracle
os: macos-15-intel
version: 17
version: 21
- distribution: oracle
os: windows-latest
version: 21
@@ -636,6 +636,26 @@ jobs:
run: bash __tests__/verify-java.sh "17.0.10" "$JAVA_PATH"
shell: bash
setup-java-version-from-sdkman-major:
name: temurin 26 from .sdkmanrc - ubuntu-latest
runs-on: ubuntu-latest
steps:
- *checkout_step
- name: Create SDKMAN and Gradle files
run: |
echo "java=26-tem" > .sdkmanrc
touch build.gradle
- name: setup-java
uses: ./
id: setup-java
with:
java-version-file: .sdkmanrc
cache: gradle
- name: Verify Java
env:
JAVA_PATH: ${{ steps.setup-java.outputs.path }}
run: bash __tests__/verify-java.sh "26" "$JAVA_PATH"
setup-java-set-default:
name: set-default option - ${{ matrix.os }}
needs: setup-java-major-versions

View File

@@ -1,6 +1,6 @@
---
name: fast-xml-parser
version: 5.10.1
version: 5.11.0
type: npm
summary: Validate XML, Parse XML, Build XML without C/C++ based libraries
homepage:

View File

@@ -1,6 +1,6 @@
---
name: strnum
version: 2.4.1
version: 2.4.2
type: npm
summary: Parse String to Number based on configuration
homepage:

View File

@@ -9,22 +9,13 @@ Set up Java for GitHub Actions workflows. `setup-java` installs a requested Java
```yaml
steps:
- uses: actions/checkout@v7
- uses: actions/setup-java@v5
- uses: actions/setup-java@v6
with:
distribution: temurin
java-version: '25'
- run: java --version
```
> [!NOTE]
> V6 is still in development on the `main` branch and is not yet recommended for production workflows. To use it, you must explicitly reference the `main` branch in your workflow, as in
>
> ```yaml
> - uses: actions/setup-java@main
> ```
>
> For production workflows, it is recommended to use the latest stable release `v5`.
## Contents
- [What it does](#what-it-does)
@@ -54,15 +45,20 @@ steps:
## What's new
### V6 (in development)
### V6
- Migrated the action implementation to ESM to support the latest `@actions/*` packages.
- Added the `oracle-openjdk` distribution for OpenJDK builds from Oracle.
- Added Oracle OpenJDK (`oracle-openjdk`), Red Hat Build of OpenJDK (`redhat`), and Liberica Native Image Kit (`liberica-nik`), and expanded Tencent Kona support through JDK 25.
- Added `java-version: latest` to resolve the newest stable GA release from the distribution's remote metadata.
- JDK downloads now automatically verify authoritative checksums for [supported distributions](#download-integrity-and-signatures).
- Expanded install compatibility with JEP 322 multi-field versions such as `18.0.1.1`, Temurin `jdk+jmods` packages, and native musl artifacts on Alpine for Dragonwell, Corretto, Zulu, and Liberica.
- JDK downloads now automatically verify authoritative checksums, and package signature verification defaults to enabled for Temurin and Microsoft builds.
- Added `force-download: true` to bypass the tool cache and perform a reproducible fresh install.
- Dependency caching now supports custom paths with `cache-path` and restore-only operation with `cache-read-only: true`.
- Dependency cache keys now include `.mvn/extensions.xml` and `gradle.properties`, preventing stale restores when Maven extensions or Gradle dependency properties change.
- Downloaded JDKs are now [cached](#caching-jdk-installations) automatically when `cache` is set; use `cache-jdk` to enable or disable it independently.
- Warm JDK-cached jobs can reuse cached release metadata, avoiding vendor API calls while retaining a stale-metadata fallback for vendor outages and rate limits.
- Maven configuration now supports multiple server credentials and custom dependency-resolution repositories.
- Maven signing keys are imported into an isolated temporary GPG home instead of the runner's default keyring.
- Set `problem-matcher: false` to disable Java compiler and uncaught-exception annotations.
- GraalVM distributions now set `GRAALVM_HOME` in addition to `JAVA_HOME`.
- Invalid boolean values, unsupported distribution/package/platform combinations, and mismatched Maven toolchain ID counts now fail with targeted errors.
@@ -73,6 +69,7 @@ steps:
- Deprecated aliases still work, but emit warnings.
- Maven GPG passphrases are now passed through `gpg.passphraseEnvName` instead of a deprecated `gpg.passphrase` server entry in `settings.xml`. This requires `maven-gpg-plugin` 3.2.0 or newer. See [GPG](docs/advanced-usage.md#gpg).
- Legacy AdoptOpenJDK distributions were removed. Use `temurin` instead of `adopt` or `adopt-hotspot`, and `semeru` instead of `adopt-openj9`.
- See the [complete V6 release notes](https://github.com/actions/setup-java/releases/tag/v6.0.0) for all enhancements and fixes.
### V5
@@ -89,7 +86,7 @@ steps:
### Older versions
> [!WARNING]
> `actions/setup-java` versions `v1` through `v4` are deprecated. Upgrade workflows to `actions/setup-java@v5`, the latest stable release.
> `actions/setup-java` versions `v1` through `v4` are deprecated. Upgrade workflows to `actions/setup-java@v6`, the latest stable release.
## Usage
@@ -98,7 +95,7 @@ steps:
```yaml
steps:
- uses: actions/checkout@v7
- uses: actions/setup-java@v5
- uses: actions/setup-java@v6
with:
distribution: temurin
java-version: '25'
@@ -110,7 +107,7 @@ steps:
```yaml
steps:
- uses: actions/checkout@v7
- uses: actions/setup-java@v5
- uses: actions/setup-java@v6
with:
distribution: microsoft
java-version: '25'
@@ -122,7 +119,7 @@ steps:
```yaml
steps:
- uses: actions/checkout@v7
- uses: actions/setup-java@v5
- uses: actions/setup-java@v6
with:
distribution: temurin
java-version-file: .java-version
@@ -136,7 +133,7 @@ Supported version files are `.java-version`, `.tool-versions`, and `.sdkmanrc`.
```yaml
steps:
- uses: actions/checkout@v7
- uses: actions/setup-java@v5
- uses: actions/setup-java@v6
with:
distribution: temurin
java-version: latest
@@ -159,7 +156,7 @@ steps:
| `force-download` | Always download Java and replace any matching version in the tool cache. | `false` |
| `set-default` | Add Java to `PATH` and set `JAVA_HOME`. When `false`, only version-specific `JAVA_HOME_<major>_<arch>` variables are set. | `true` |
| `problem-matcher` | Register Java compiler and uncaught exception problem matchers. | `true` |
| `verify-signature` | Verify downloaded Java package signatures when supported. Currently supported for `temurin` and `microsoft`. | `false` |
| `verify-signature` | Verify downloaded Java package signatures when supported. Defaults to `true` for `temurin` and `microsoft`, and `false` for other distributions. | Automatically enabled for `temurin` and `microsoft` |
| `verify-signature-public-key` | ASCII-armored GPG public key to use for signature verification. Overrides the bundled key. | |
| `token` | Token for fetching GitHub.com-hosted version manifests, useful on GitHub Enterprise Server when unauthenticated requests are rate-limited. | `${{ github.token }}` on GitHub.com; empty string on GHES |
| `cache` | Enable dependency caching for `maven`, `gradle`, or `sbt`. | |
@@ -170,6 +167,10 @@ steps:
| `server-id` | Maven repository ID used in generated `settings.xml`. | `github` |
| `server-username-env-var` | Environment variable name for Maven repository username. | `GITHUB_ACTOR` |
| `server-password-env-var` | Environment variable name for Maven repository password or token. | `GITHUB_TOKEN` |
| `mvn-server-credentials` | Multiline Maven server credentials in the format `server-id:USERNAME_ENV:PASSWORD_ENV`. Replaces the single server configured by the three inputs above when set. | |
| `mvn-repositories` | Multiline Maven dependency repositories in the format `repository-id:repository-url:snapshots-enabled`. | |
| `mvn-repositories-include-central` | Include Maven Central in the generated dependency repositories profile. When `false`, Central is disabled unless an explicit `central` repository is declared. | `true` |
| `mvn-repositories-prioritize-central` | Place Maven Central before custom dependency repositories. Has no effect when Maven Central is excluded. | `true` |
| `settings-path` | Directory where `settings.xml` is written. | `~/.m2` |
| `overwrite-settings` | Overwrite an existing `settings.xml`. | `true` |
| `gpg-private-key` | GPG private key to import into an isolated temporary keyring. | |
@@ -207,6 +208,7 @@ Deprecated aliases `jdkFile`, `server-username`, `server-password`, and `gpg-pas
| `microsoft` | [Microsoft Build of OpenJDK](https://www.microsoft.com/openjdk) | [License](https://docs.microsoft.com/java/openjdk/faq) |
| `oracle` | [Oracle JDK](https://www.oracle.com/java/technologies/downloads/) | [License](https://java.com/freeuselicense) |
| `oracle-openjdk` | [Oracle OpenJDK](https://jdk.java.net/) | [License](https://openjdk.org/legal/gplv2+ce.html) |
| `redhat` | [Red Hat Build of OpenJDK](https://developers.redhat.com/products/openjdk/overview) | [License](https://openjdk.org/legal/gplv2+ce.html) |
| `sapmachine` | [SAP SapMachine JDK/JRE](https://sapmachine.io/) | [License](https://github.com/SAP/SapMachine/blob/sapmachine/LICENSE) |
| `semeru` | [IBM Semeru Runtime Open Edition](https://developer.ibm.com/languages/java/semeru-runtimes/downloads/) | [License](https://openjdk.java.net/legal/gplv2+ce.html) |
| `temurin` | [Eclipse Temurin](https://adoptium.net/) | [License](https://adoptium.net/about.html) |
@@ -262,7 +264,7 @@ Set `cache` to `maven`, `gradle`, or `sbt` to cache dependencies with minimal co
```yaml
steps:
- uses: actions/checkout@v7
- uses: actions/setup-java@v5
- uses: actions/setup-java@v6
with:
distribution: temurin
java-version: '25'
@@ -281,7 +283,7 @@ The primary dependency cache key is `setup-java-<runner-os>-<node-arch>-<package
Use `cache-dependency-path` to override the files used for key hashing, especially in monorepos:
```yaml
- uses: actions/setup-java@v5
- uses: actions/setup-java@v6
with:
distribution: temurin
java-version: '25'
@@ -294,7 +296,7 @@ Use `cache-dependency-path` to override the files used for key hashing, especial
Use `cache-path` when the build tool stores dependencies outside the default location:
```yaml
- uses: actions/setup-java@v5
- uses: actions/setup-java@v6
with:
distribution: temurin
java-version: '25'
@@ -333,7 +335,7 @@ The JDK cache stores the downloaded JDK installation so later runs skip the down
Set `cache-read-only: true` to restore dependency, wrapper, and JDK caches without saving changes in the post action. This is useful for pull requests, merge queues, short-lived branches, and matrix fan-out jobs that should only consume caches produced elsewhere.
```yaml
- uses: actions/setup-java@v5
- uses: actions/setup-java@v6
with:
distribution: temurin
java-version: '25'
@@ -349,7 +351,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-java@v5
- uses: actions/setup-java@v6
with:
distribution: temurin
java-version: '25'
@@ -364,7 +366,7 @@ jobs:
goal: [test, verify, package]
steps:
- uses: actions/checkout@v7
- uses: actions/setup-java@v5
- uses: actions/setup-java@v6
with:
distribution: temurin
java-version: '25'
@@ -382,7 +384,7 @@ env:
SEGMENT_DOWNLOAD_TIMEOUT_MINS: '5'
steps:
- uses: actions/checkout@v7
- uses: actions/setup-java@v5
- uses: actions/setup-java@v6
with:
distribution: temurin
java-version: '25'
@@ -396,7 +398,7 @@ Install multiple Java versions by providing a multiline `java-version` value. Al
```yaml
steps:
- uses: actions/setup-java@v5
- uses: actions/setup-java@v6
with:
distribution: temurin
java-version: |
@@ -423,7 +425,7 @@ jobs:
name: Java ${{ matrix.java }}
steps:
- uses: actions/checkout@v7
- uses: actions/setup-java@v5
- uses: actions/setup-java@v6
with:
distribution: temurin
java-version: ${{ matrix.java }}
@@ -440,7 +442,7 @@ jobs:
```yaml
steps:
- uses: actions/checkout@v7
- uses: actions/setup-java@v5
- uses: actions/setup-java@v6
with:
distribution: temurin
java-version: '25'
@@ -452,12 +454,17 @@ steps:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```
For dependencies hosted outside Maven Central, use `mvn-repositories` to add
resolution repositories to an active profile in the generated `settings.xml`.
Repository IDs can match `mvn-server-credentials` IDs when authentication is
required. See [Resolving Maven dependencies from custom repositories](docs/advanced-usage.md#resolving-maven-dependencies-from-custom-repositories).
### GPG signing
```yaml
steps:
- uses: actions/checkout@v7
- uses: actions/setup-java@v5
- uses: actions/setup-java@v6
with:
distribution: temurin
java-version: '25'
@@ -512,7 +519,7 @@ The scripts and documentation in this project are released under the [MIT Licens
## Contributions
Contributions are welcome. See our [Contributor's Guide](docs/contributors.md).
Contributions are welcome. See our [Contributor's Guide](docs/CONTRIBUTING.md).
## Code of Conduct

View File

@@ -26,7 +26,7 @@ jest.unstable_mockModule('@actions/core', () => ({
setOutput: jest.fn(),
getInput: jest.fn(),
getBooleanInput: jest.fn(),
getMultilineInput: jest.fn(),
getMultilineInput: jest.fn(() => []),
addPath: jest.fn(),
exportVariable: jest.fn(),
saveState: jest.fn(),
@@ -57,6 +57,18 @@ const {M2_DIR, MVN_SETTINGS_FILE, STATE_GPG_HOME} =
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const m2Dir = path.join(__dirname, M2_DIR);
const settingsFile = path.join(m2Dir, MVN_SETTINGS_FILE);
const credentials = (id: string, username: string, password: string) => [
{id, usernameEnvVar: username, passwordEnvVar: password}
];
const repositorySettings = (
repositories: auth.MavenRepository[],
includeCentral = true,
prioritizeCentral = true
): auth.MavenRepositorySettings => ({
repositories,
includeCentral,
prioritizeCentral
});
describe('auth tests', () => {
let spyOSHomedir: any;
@@ -73,6 +85,9 @@ describe('auth tests', () => {
afterEach(() => {
(core.getInput as jest.Mock).mockReset();
(core.getMultilineInput as jest.Mock).mockReset();
(core.getMultilineInput as jest.Mock).mockReturnValue([]);
(core.warning as jest.Mock).mockReset();
(core.exportVariable as jest.Mock).mockReset();
(gpg.importKey as jest.Mock).mockReset();
(gpg.removeGpgHome as jest.Mock).mockReset();
@@ -100,9 +115,7 @@ describe('auth tests', () => {
await io.rmRF(altHome); // ensure it doesn't already exist
await auth.createAuthenticationSettings(
id,
username,
password,
credentials(id, username, password),
altHome,
true
);
@@ -113,7 +126,7 @@ describe('auth tests', () => {
expect(fs.existsSync(altHome)).toBe(true);
expect(fs.existsSync(altSettingsFile)).toBe(true);
expect(fs.readFileSync(altSettingsFile, 'utf-8')).toEqual(
auth.generate(id, username, password)
auth.generate(credentials(id, username, password))
);
await io.rmRF(altHome);
@@ -125,9 +138,7 @@ describe('auth tests', () => {
const password = 'TOKEN';
await auth.createAuthenticationSettings(
id,
username,
password,
credentials(id, username, password),
m2Dir,
true
);
@@ -135,7 +146,7 @@ describe('auth tests', () => {
expect(fs.existsSync(m2Dir)).toBe(true);
expect(fs.existsSync(settingsFile)).toBe(true);
expect(fs.readFileSync(settingsFile, 'utf-8')).toEqual(
auth.generate(id, username, password)
auth.generate(credentials(id, username, password))
);
}, 100000);
@@ -146,9 +157,7 @@ describe('auth tests', () => {
const gpgPassphrase = 'GPG';
await auth.createAuthenticationSettings(
id,
username,
password,
credentials(id, username, password),
m2Dir,
true,
gpgPassphrase
@@ -157,7 +166,7 @@ describe('auth tests', () => {
expect(fs.existsSync(m2Dir)).toBe(true);
expect(fs.existsSync(settingsFile)).toBe(true);
expect(fs.readFileSync(settingsFile, 'utf-8')).toEqual(
auth.generate(id, username, password, gpgPassphrase)
auth.generate(credentials(id, username, password), gpgPassphrase)
);
}, 100000);
@@ -218,9 +227,7 @@ describe('auth tests', () => {
expect(fs.existsSync(settingsFile)).toBe(true);
await auth.createAuthenticationSettings(
id,
username,
password,
credentials(id, username, password),
m2Dir,
true
);
@@ -228,7 +235,7 @@ describe('auth tests', () => {
expect(fs.existsSync(m2Dir)).toBe(true);
expect(fs.existsSync(settingsFile)).toBe(true);
expect(fs.readFileSync(settingsFile, 'utf-8')).toEqual(
auth.generate(id, username, password)
auth.generate(credentials(id, username, password))
);
}, 100000);
@@ -243,9 +250,7 @@ describe('auth tests', () => {
expect(fs.existsSync(settingsFile)).toBe(true);
await auth.createAuthenticationSettings(
id,
username,
password,
credentials(id, username, password),
m2Dir,
false
);
@@ -273,7 +278,9 @@ describe('auth tests', () => {
</servers>
</settings>`;
expect(auth.generate(id, username, password)).toEqual(expectedSettings);
expect(auth.generate(credentials(id, username, password))).toEqual(
expectedSettings
);
});
it('generates valid settings.xml with additional configuration', () => {
@@ -306,9 +313,9 @@ describe('auth tests', () => {
</activeProfiles>
</settings>`;
expect(auth.generate(id, username, password, gpgPassphrase)).toEqual(
expectedSettings
);
expect(
auth.generate(credentials(id, username, password), gpgPassphrase)
).toEqual(expectedSettings);
});
it('does not add a gpg profile when the passphrase env var is the maven-gpg-plugin default', () => {
@@ -330,9 +337,9 @@ describe('auth tests', () => {
</servers>
</settings>`;
expect(auth.generate(id, username, password, gpgPassphrase)).toEqual(
expectedSettings
);
expect(
auth.generate(credentials(id, username, password), gpgPassphrase)
).toEqual(expectedSettings);
});
it('escapes settings.xml values while preserving parsed semantics', () => {
@@ -341,7 +348,10 @@ describe('auth tests', () => {
const password = `TOKEN&<>"'é`;
const gpgPassphrase = `GPG&<>"'é`;
const xml = auth.generate(id, username, password, gpgPassphrase);
const xml = auth.generate(
credentials(id, username, password),
gpgPassphrase
);
const parsed = parseXmlObject(xml) as any;
expect(parsed.settings.interactiveMode).toBe('false');
@@ -352,6 +362,447 @@ describe('auth tests', () => {
expect(parsed.settings.activeProfiles.activeProfile).toBe('setup-java-gpg');
});
it('generates ordered settings.xml entries for multiple servers', () => {
const servers = [
{
id: 'releases',
usernameEnvVar: 'RELEASES_USERNAME',
passwordEnvVar: 'RELEASES_PASSWORD'
},
{
id: 'snapshots',
usernameEnvVar: 'SNAPSHOTS_USERNAME',
passwordEnvVar: 'SNAPSHOTS_PASSWORD'
}
];
const parsed = parseXmlObject(auth.generate(servers)) as any;
expect(parsed.settings.servers.server).toEqual([
{
id: 'releases',
username: '${env.RELEASES_USERNAME}',
password: '${env.RELEASES_PASSWORD}'
},
{
id: 'snapshots',
username: '${env.SNAPSHOTS_USERNAME}',
password: '${env.SNAPSHOTS_PASSWORD}'
}
]);
});
it('generates an active profile with Central before custom repositories by default', () => {
const parsed = parseXmlObject(
auth.generate(
credentials('packages', 'USERNAME', 'PASSWORD'),
undefined,
repositorySettings([
{
id: 'private',
url: 'https://repo.example.com/maven',
snapshotsEnabled: true
}
])
)
) as any;
expect(parsed.settings.profiles.profile).toEqual({
id: 'setup-java-repositories',
repositories: {
repository: [
{
id: 'central',
url: 'https://repo.maven.apache.org/maven2',
snapshots: {enabled: 'false'}
},
{
id: 'private',
url: 'https://repo.example.com/maven',
snapshots: {enabled: 'true'}
}
]
}
});
expect(parsed.settings.activeProfiles.activeProfile).toBe(
'setup-java-repositories'
);
});
it('places custom repositories before Central when configured', () => {
const parsed = parseXmlObject(
auth.generate(
credentials('packages', 'USERNAME', 'PASSWORD'),
undefined,
repositorySettings(
[
{
id: 'first',
url: 'https://first.example.com',
snapshotsEnabled: false
},
{
id: 'second',
url: 'https://second.example.com',
snapshotsEnabled: true
}
],
true,
false
)
)
) as any;
expect(
parsed.settings.profiles.profile.repositories.repository.map(
(repository: {id: string}) => repository.id
)
).toEqual(['first', 'second', 'central']);
});
it('excludes Central from the generated repository profile when configured', () => {
const parsed = parseXmlObject(
auth.generate(
credentials('packages', 'USERNAME', 'PASSWORD'),
undefined,
repositorySettings(
[
{
id: 'private',
url: 'https://repo.example.com',
snapshotsEnabled: false
}
],
false
)
)
) as any;
expect(parsed.settings.profiles.profile.repositories.repository).toEqual([
{
id: 'private',
url: 'https://repo.example.com',
snapshots: {enabled: 'false'}
},
{
id: 'central',
url: 'https://repo.maven.apache.org/maven2',
releases: {enabled: 'false'},
snapshots: {enabled: 'false'}
}
]);
});
it('combines repository and GPG configuration in shared profile blocks', () => {
const parsed = parseXmlObject(
auth.generate(
credentials('packages', 'USERNAME', 'PASSWORD'),
'GPG_PASSPHRASE',
repositorySettings(
[
{
id: 'private',
url: 'https://repo.example.com',
snapshotsEnabled: false
}
],
false
)
)
) as any;
expect(parsed.settings.profiles.profile).toEqual([
{
id: 'setup-java-repositories',
repositories: {
repository: [
{
id: 'private',
url: 'https://repo.example.com',
snapshots: {enabled: 'false'}
},
{
id: 'central',
url: 'https://repo.maven.apache.org/maven2',
releases: {enabled: 'false'},
snapshots: {enabled: 'false'}
}
]
}
},
{
id: 'setup-java-gpg',
properties: {['gpg.passphraseEnvName']: 'GPG_PASSPHRASE'}
}
]);
expect(parsed.settings.activeProfiles.activeProfile).toEqual([
'setup-java-repositories',
'setup-java-gpg'
]);
});
it('escapes repository values while preserving parsed semantics', () => {
const repository = {
id: `private&<>"'é`,
url: `https://repo.example.com/a?x=1&y=<value>"'é`,
snapshotsEnabled: true
};
const xml = auth.generate(
credentials('packages', 'USERNAME', 'PASSWORD'),
undefined,
repositorySettings([repository], false)
);
const parsed = parseXmlObject(xml) as any;
expect(
parsed.settings.profiles.profile.repositories.repository.find(
(entry: {id: string}) => entry.id === repository.id
)
).toEqual({
id: repository.id,
url: repository.url,
snapshots: {enabled: 'true'}
});
});
it('parses and trims multiline Maven server credentials', () => {
expect(
auth.parseMavenServerCredentials([
'',
' releases : RELEASES_USERNAME : RELEASES_PASSWORD ',
'snapshots:SNAPSHOTS_USERNAME:SNAPSHOTS_PASSWORD'
])
).toEqual([
{
id: 'releases',
usernameEnvVar: 'RELEASES_USERNAME',
passwordEnvVar: 'RELEASES_PASSWORD'
},
{
id: 'snapshots',
usernameEnvVar: 'SNAPSHOTS_USERNAME',
passwordEnvVar: 'SNAPSHOTS_PASSWORD'
}
]);
});
it('parses Maven repositories while preserving colons in URLs', () => {
expect(
auth.parseMavenRepositories(
[
'',
' private : https://repo.example.com:8443/maven : true ',
'releases:https://repo.example.com/releases:false'
],
true
)
).toEqual([
{
id: 'private',
url: 'https://repo.example.com:8443/maven',
snapshotsEnabled: true
},
{
id: 'releases',
url: 'https://repo.example.com/releases',
snapshotsEnabled: false
}
]);
});
it.each([
{
entries: ['private'],
error:
'Invalid mvn-repositories entry at line 1. Expected format: repository-id:repository-url:snapshots-enabled'
},
{
entries: ['private:https://repo.example.com'],
error:
"Invalid snapshots-enabled value '//repo.example.com' in mvn-repositories entry at line 1. Expected true or false"
},
{
entries: ['private::true'],
error:
'Invalid mvn-repositories entry at line 1. repository-id, repository URL, and snapshots-enabled are required'
},
{
entries: ['private:https://repo.example.com:sometimes'],
error:
"Invalid snapshots-enabled value 'sometimes' in mvn-repositories entry at line 1. Expected true or false"
}
])('rejects malformed Maven repositories: $entries', ({entries, error}) => {
expect(() => auth.parseMavenRepositories(entries, true)).toThrow(error);
});
it('rejects duplicate Maven repository ids', () => {
expect(() =>
auth.parseMavenRepositories(
[
'private:https://first.example.com:false',
'private:https://second.example.com:true'
],
true
)
).toThrow("Duplicate repository-id 'private' in mvn-repositories input");
});
it('reserves the Central repository id only when automatic Central inclusion is enabled', () => {
const central = 'central:https://custom.example.com/maven:false';
expect(() => auth.parseMavenRepositories([central], true)).toThrow(
"Repository-id 'central' is reserved when mvn-repositories-include-central is enabled"
);
expect(auth.parseMavenRepositories([central], false)).toEqual([
{
id: 'central',
url: 'https://custom.example.com/maven',
snapshotsEnabled: false
}
]);
});
it('uses an explicit Central repository instead of adding a disabled override', () => {
const parsed = parseXmlObject(
auth.generate(
credentials('packages', 'USERNAME', 'PASSWORD'),
undefined,
repositorySettings(
auth.parseMavenRepositories(
['central:https://mirror.example.com/maven:true'],
false
),
false
)
)
) as any;
expect(parsed.settings.profiles.profile.repositories.repository).toEqual({
id: 'central',
url: 'https://mirror.example.com/maven',
snapshots: {enabled: 'true'}
});
});
it('reads Maven repository settings and Central controls', () => {
(core.getMultilineInput as jest.Mock).mockImplementation((name: string) =>
name === 'mvn-repositories'
? ['private:https://repo.example.com:true']
: []
);
(core.getInput as jest.Mock).mockImplementation((name: string) => {
const inputs: Record<string, string> = {
'mvn-repositories-include-central': 'false',
'mvn-repositories-prioritize-central': 'false'
};
return inputs[name] ?? '';
});
expect(auth.getMavenRepositorySettings()).toEqual({
repositories: [
{
id: 'private',
url: 'https://repo.example.com',
snapshotsEnabled: true
}
],
includeCentral: false,
prioritizeCentral: false
});
});
it('does not read repository controls when no repositories are configured', () => {
expect(auth.getMavenRepositorySettings()).toBeUndefined();
expect(core.getInput).not.toHaveBeenCalled();
});
it.each([
{
entries: ['releases:RELEASES_USERNAME'],
error:
'Invalid mvn-server-credentials entry at line 1. Expected format: server-id:USERNAME_ENV:PASSWORD_ENV'
},
{
entries: ['', 'releases:RELEASES_USERNAME:RELEASES_PASSWORD:EXTRA'],
error:
'Invalid mvn-server-credentials entry at line 2. Expected format: server-id:USERNAME_ENV:PASSWORD_ENV'
},
{
entries: ['releases::RELEASES_PASSWORD'],
error:
'Invalid mvn-server-credentials entry at line 1. server-id, username environment variable, and password environment variable are required'
}
])(
'rejects malformed Maven server credentials: $entries',
({entries, error}) => {
expect(() => auth.parseMavenServerCredentials(entries)).toThrow(error);
}
);
it('rejects duplicate Maven server ids', () => {
expect(() =>
auth.parseMavenServerCredentials([
'releases:RELEASES_USERNAME:RELEASES_PASSWORD',
'releases:OTHER_USERNAME:OTHER_PASSWORD'
])
).toThrow("Duplicate server-id 'releases' in mvn-server-credentials input");
});
it('uses multiline Maven server credentials instead of single-server inputs', () => {
(core.getMultilineInput as jest.Mock).mockReturnValue([
'releases:RELEASES_USERNAME:RELEASES_PASSWORD',
'snapshots:SNAPSHOTS_USERNAME:SNAPSHOTS_PASSWORD'
]);
expect(auth.getMavenServerSettings()).toEqual([
{
id: 'releases',
usernameEnvVar: 'RELEASES_USERNAME',
passwordEnvVar: 'RELEASES_PASSWORD'
},
{
id: 'snapshots',
usernameEnvVar: 'SNAPSHOTS_USERNAME',
passwordEnvVar: 'SNAPSHOTS_PASSWORD'
}
]);
expect(core.getInput).not.toHaveBeenCalled();
});
it('uses the existing single-server inputs when multiline credentials are absent', () => {
(core.getInput as jest.Mock).mockImplementation((name: string) =>
name === 'server-id' ? 'github' : ''
);
expect(auth.getMavenServerSettings()).toEqual([
{
id: 'github',
usernameEnvVar: 'GITHUB_ACTOR',
passwordEnvVar: 'GITHUB_TOKEN'
}
]);
});
it('preserves deprecated single-server aliases as fallback inputs', () => {
(core.getInput as jest.Mock).mockImplementation((name: string) => {
const inputs: Record<string, string> = {
'server-id': 'legacy',
'server-username': 'LEGACY_USERNAME',
'server-password': 'LEGACY_PASSWORD'
};
return inputs[name] ?? '';
});
expect(auth.getMavenServerSettings()).toEqual([
{
id: 'legacy',
usernameEnvVar: 'LEGACY_USERNAME',
passwordEnvVar: 'LEGACY_PASSWORD'
}
]);
expect(core.warning).toHaveBeenCalledTimes(2);
});
function xmlElementText(xml: string, tagName: string): string {
const match = new RegExp(`<${tagName}>([\\s\\S]*?)</${tagName}>`).exec(xml);
expect(match).not.toBeNull();

View File

@@ -0,0 +1,11 @@
{
"result": [
{
"filename": "java-21-openjdk-21.0.8.0.9-1.portable.jdk.x86_64.tar.xz",
"direct_download_uri": "https://developers.redhat.com/content-gateway/file/pub/openjdk/java-21-openjdk-21.0.8.0.9-1.portable.jdk.x86_64.tar.xz",
"checksum": "91a6f3284cbded9de17f65985a4fca48dd4fd0aa295162178631c23ade335aad",
"checksum_type": "sha256"
}
],
"message": ""
}

View File

@@ -0,0 +1,71 @@
{
"result": [
{
"id": "redhat-21.0.8-jdk-linux-x64",
"archive_type": "tar.xz",
"distribution": "redhat",
"java_version": "21.0.8+9",
"release_status": "ga",
"operating_system": "linux",
"architecture": "x64",
"package_type": "jdk",
"directly_downloadable": true
},
{
"id": "redhat-21.0.7-jdk-linux-x64",
"archive_type": "tar.xz",
"distribution": "redhat",
"java_version": "21.0.7+6",
"release_status": "ga",
"operating_system": "linux",
"architecture": "x64",
"package_type": "jdk",
"directly_downloadable": true
},
{
"id": "redhat-17.0.16-jdk-linux-x64",
"archive_type": "tar.xz",
"distribution": "redhat",
"java_version": "17.0.16+8",
"release_status": "ga",
"operating_system": "linux",
"architecture": "x64",
"package_type": "jdk",
"directly_downloadable": true
},
{
"id": "redhat-9-jdk-linux-x64",
"archive_type": "tar.xz",
"distribution": "redhat",
"java_version": "9+181",
"release_status": "ga",
"operating_system": "linux",
"architecture": "x64",
"package_type": "jdk",
"directly_downloadable": true
},
{
"id": "redhat-21.0.8-jre-linux-x64",
"archive_type": "tar.xz",
"distribution": "redhat",
"java_version": "21.0.8+9",
"release_status": "ga",
"operating_system": "linux",
"architecture": "x64",
"package_type": "jre",
"directly_downloadable": true
},
{
"id": "redhat-17.0.16-jdk-windows-x64",
"archive_type": "zip",
"distribution": "redhat",
"java_version": "17.0.16+8",
"release_status": "ga",
"operating_system": "windows",
"architecture": "x64",
"package_type": "jdk",
"directly_downloadable": true
}
],
"message": "6 package(s) found"
}

View File

@@ -78,6 +78,8 @@ function response(
}
describe('getAvailableVersions', () => {
jest.setTimeout(10_000);
let spyHttpClient: any;
let spyCoreError: any;
const originalGitHubToken = process.env.GITHUB_TOKEN;

View File

@@ -398,13 +398,12 @@ describe('downloadTool', () => {
jest.restoreAllMocks();
});
it('verifies signature when enabled', async () => {
it('verifies signatures by default', async () => {
const signedDistribution = new MicrosoftDistributions({
version: '17',
architecture: 'x64',
packageType: 'jdk',
checkLatest: false,
verifySignature: true
checkLatest: false
});
await signedDistribution['downloadTool']({

View File

@@ -0,0 +1,109 @@
import {beforeEach, describe, expect, it, jest} from '@jest/globals';
import path from 'path';
const mockReaddirSync = jest.fn();
const realFs = await import('fs');
jest.unstable_mockModule('fs', () => ({
...realFs,
default: {...realFs.default, readdirSync: mockReaddirSync},
readdirSync: mockReaddirSync
}));
jest.unstable_mockModule('@actions/core', () => ({
info: jest.fn(),
debug: jest.fn(),
isDebug: jest.fn(() => false),
startGroup: jest.fn(),
endGroup: jest.fn()
}));
const realUtil = await import('../../src/util.js');
const mockCacheJdkDir = jest.fn();
const mockExtractJdkFile = jest.fn();
const mockRenameWinArchive = jest.fn();
jest.unstable_mockModule('../../src/util.js', () => ({
...realUtil,
cacheJdkDir: mockCacheJdkDir,
extractJdkFile: mockExtractJdkFile,
renameWinArchive: mockRenameWinArchive
}));
const {RedHatDistribution} =
await import('../../src/distributions/redhat/installer.js');
const release = {
version: '21.0.8+9',
url: 'https://developers.redhat.com/openjdk-21.tar.xz',
checksum: {
algorithm: 'sha256' as const,
value: 'a'.repeat(64)
}
};
const createDistribution = () =>
new RedHatDistribution({
version: '21',
architecture: 'x64',
packageType: 'jdk',
checkLatest: false
});
beforeEach(() => {
jest.clearAllMocks();
mockReaddirSync.mockReturnValue(['jdk-21']);
mockExtractJdkFile.mockResolvedValue('/tmp/extracted');
mockCacheJdkDir.mockResolvedValue('/toolcache/Java_RedHat_jdk/21.0.8-9/x64');
mockRenameWinArchive.mockReturnValue('/tmp/download.zip');
});
describe('Red Hat package installation', () => {
it('extracts and caches Linux tar.xz archives', async () => {
const distribution = createDistribution();
distribution['downloadAndVerify'] = jest
.fn()
.mockResolvedValue('/tmp/download');
distribution['getArchiveType'] = () => 'tar.xz';
const result = await distribution['downloadTool'](release);
expect(mockExtractJdkFile).toHaveBeenCalledWith('/tmp/download', 'tar.xz');
expect(mockRenameWinArchive).not.toHaveBeenCalled();
expect(mockCacheJdkDir).toHaveBeenCalledWith(
path.join('/tmp/extracted', 'jdk-21'),
'Java_RedHat_jdk',
'21.0.8-9',
'x64'
);
expect(result).toEqual({
version: '21.0.8+9',
path: '/toolcache/Java_RedHat_jdk/21.0.8-9/x64'
});
});
it('renames downloaded Windows ZIP archives before extraction', async () => {
const distribution = createDistribution();
distribution['downloadAndVerify'] = jest
.fn()
.mockResolvedValue('/tmp/download');
distribution['getArchiveType'] = () => 'zip';
await distribution['downloadTool'](release);
expect(mockRenameWinArchive).toHaveBeenCalledWith('/tmp/download');
expect(mockExtractJdkFile).toHaveBeenCalledWith('/tmp/download.zip', 'zip');
});
it('fails when the extracted archive is empty', async () => {
mockReaddirSync.mockReturnValue([]);
const distribution = createDistribution();
distribution['downloadAndVerify'] = jest
.fn()
.mockResolvedValue('/tmp/download');
distribution['getArchiveType'] = () => 'tar.xz';
await expect(distribution['downloadTool'](release)).rejects.toThrow(
'The Red Hat archive for Java 21.0.8+9 was empty.'
);
expect(mockCacheJdkDir).not.toHaveBeenCalled();
});
});

View File

@@ -0,0 +1,181 @@
import {afterEach, describe, expect, it, jest} from '@jest/globals';
import {HttpClient} from '@actions/http-client';
import packageDetails from '../data/redhat-package-details.json' with {type: 'json'};
import packages from '../data/redhat-packages.json' with {type: 'json'};
import {RedHatDistribution} from '../../src/distributions/redhat/installer.js';
const createDistribution = (
version: string,
packageType = 'jdk'
): RedHatDistribution => {
const distribution = new RedHatDistribution({
version,
architecture: 'x64',
packageType,
checkLatest: false
});
distribution['getOperatingSystem'] = () => 'linux';
distribution['getArchiveType'] = () => 'tar.xz';
return distribution;
};
const mockDisco = (
packageResponse: unknown = packages,
detailsResponse: unknown = packageDetails
) =>
jest.spyOn(HttpClient.prototype, 'getJson').mockImplementation(async url => ({
result: url.includes('/packages?') ? packageResponse : detailsResponse,
statusCode: 200,
headers: {}
}));
afterEach(() => {
jest.restoreAllMocks();
});
describe('Red Hat package resolution', () => {
it('resolves the newest matching release and authoritative checksum', async () => {
const getJson = mockDisco();
const distribution = createDistribution('21');
const release = await distribution['findPackageForDownload']('21');
expect(release).toEqual({
version: '21.0.8+9',
url: packageDetails.result[0].direct_download_uri,
checksum: {
algorithm: 'sha256',
value: packageDetails.result[0].checksum,
source:
'https://api.foojay.io/disco/v3.0/ids/redhat-21.0.8-jdk-linux-x64'
}
});
expect(getJson).toHaveBeenNthCalledWith(
1,
expect.stringContaining(
'distro=redhat&release_status=ga&operating_system=linux&architecture=x64&package_type=jdk&archive_type=tar.xz&directly_downloadable=true'
)
);
expect(getJson).toHaveBeenNthCalledWith(
2,
'https://api.foojay.io/disco/v3.0/ids/redhat-21.0.8-jdk-linux-x64'
);
});
it('normalizes feature-only Disco versions before matching', async () => {
mockDisco(undefined, {
result: [
{
...packageDetails.result[0],
direct_download_uri: 'https://developers.redhat.com/openjdk-9.tar.xz'
}
],
message: ''
});
const distribution = createDistribution('9');
const release = await distribution['findPackageForDownload']('9');
expect(release.version).toBe('9.0.0+181');
});
it('selects the requested package type', async () => {
const getJson = mockDisco();
const distribution = createDistribution('21', 'jre');
await distribution['findPackageForDownload']('21');
expect(getJson).toHaveBeenNthCalledWith(
1,
expect.stringContaining('package_type=jre')
);
expect(getJson).toHaveBeenNthCalledWith(
2,
'https://api.foojay.io/disco/v3.0/ids/redhat-21.0.8-jre-linux-x64'
);
});
it('maps Windows to ZIP packages', async () => {
const getJson = mockDisco();
const distribution = createDistribution('17');
distribution['getOperatingSystem'] = () => 'windows';
distribution['getArchiveType'] = () => 'zip';
await distribution['findPackageForDownload']('17');
expect(getJson).toHaveBeenNthCalledWith(
1,
expect.stringContaining(
'operating_system=windows&architecture=x64&package_type=jdk&archive_type=zip'
)
);
expect(getJson).toHaveBeenNthCalledWith(
2,
'https://api.foojay.io/disco/v3.0/ids/redhat-17.0.16-jdk-windows-x64'
);
});
it('rejects Alpine before requesting glibc package metadata', async () => {
const getJson = mockDisco();
const distribution = new RedHatDistribution({
version: '21',
architecture: 'x64',
packageType: 'jdk',
checkLatest: false
});
expect(() => distribution['getOperatingSystem'](true)).toThrow(
"Distribution 'redhat' does not support Alpine Linux because Red Hat portable archives require glibc."
);
expect(getJson).not.toHaveBeenCalled();
});
it('rejects early-access versions before requesting metadata', async () => {
const getJson = mockDisco();
const distribution = createDistribution('21-ea');
await expect(distribution['findPackageForDownload']('21')).rejects.toThrow(
'Early access versions are not supported'
);
expect(getJson).not.toHaveBeenCalled();
});
it('reports available versions when no release matches', async () => {
mockDisco();
const distribution = createDistribution('25');
await expect(distribution['findPackageForDownload']('25')).rejects.toThrow(
"No matching version found for SemVer '25'.\nDistribution: RedHat"
);
});
it('fails when the package detail has no direct Red Hat URL', async () => {
mockDisco(packages, {result: [], message: ''});
const distribution = createDistribution('21');
await expect(distribution['findPackageForDownload']('21')).rejects.toThrow(
'returned no direct Red Hat download URL'
);
});
it('fails when the package detail has no SHA-256 checksum', async () => {
mockDisco(packages, {
result: [{...packageDetails.result[0], checksum: ''}],
message: ''
});
const distribution = createDistribution('21');
await expect(distribution['findPackageForDownload']('21')).rejects.toThrow(
'returned no SHA-256 checksum'
);
});
it('fails with a targeted error when package metadata is missing', async () => {
mockDisco(null);
const distribution = createDistribution('21');
await expect(distribution['findPackageForDownload']('21')).rejects.toThrow(
'Could not fetch Red Hat package metadata from Foojay Disco'
);
});
});

View File

@@ -457,14 +457,13 @@ describe('downloadTool', () => {
jest.restoreAllMocks();
});
it('verifies signature when enabled', async () => {
it('verifies signatures by default', async () => {
const distribution = new TemurinDistribution(
{
version: '17',
architecture: 'x64',
packageType: 'jdk',
checkLatest: false,
verifySignature: true
checkLatest: false
},
TemurinImplementation.Hotspot
);
@@ -482,6 +481,27 @@ describe('downloadTool', () => {
);
});
it('does not verify signatures when explicitly disabled', async () => {
const distribution = new TemurinDistribution(
{
version: '17',
architecture: 'x64',
packageType: 'jdk',
checkLatest: false,
verifySignature: false
},
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).not.toHaveBeenCalled();
});
it('downloads and adds matching JMODs to the JDK', async () => {
spyDownloadTool
.mockResolvedValueOnce('/tmp/jdk.tar.gz')
@@ -499,7 +519,8 @@ describe('downloadTool', () => {
version: '25',
architecture: 'x64',
packageType: 'jdk+jmods',
checkLatest: false
checkLatest: false,
verifySignature: false
},
TemurinImplementation.Hotspot
);

View File

@@ -161,6 +161,37 @@ describe('setup action orchestration', () => {
expect(factory.getJavaDistribution).not.toHaveBeenCalled();
});
it.each([
['temurin', undefined, undefined],
['zulu', undefined, undefined],
['temurin', false, false],
['zulu', true, true]
])(
'passes signature verification input for %s with explicit value %s as %s',
async (distribution, explicitValue, expectedValue) => {
inputs.set('distribution', distribution);
multilineInputs.set('java-version', ['21']);
if (explicitValue !== undefined) {
inputs.set('verify-signature', String(explicitValue));
booleanInputs.set('verify-signature', explicitValue);
}
(factory.getJavaDistribution as jest.Mock).mockReturnValue({
setupJava: jest.fn(async () => ({
version: '21.0.4+7',
path: '/opt/java/21'
}))
});
await run();
expect(factory.getJavaDistribution).toHaveBeenCalledWith(
distribution,
expect.objectContaining({verifySignature: expectedValue}),
''
);
}
);
it('requires distribution when it cannot be inferred from the version file', async () => {
inputs.set('java-version-file', '.java-version');
(fs.readFileSync as jest.Mock).mockReturnValue(Buffer.from('21'));
@@ -200,7 +231,6 @@ describe('setup action orchestration', () => {
booleanInputs.set('check-latest', true);
booleanInputs.set('force-download', true);
booleanInputs.set('set-default', false);
booleanInputs.set('verify-signature', true);
inputs.set('verify-signature-public-key', 'public-key');
(fs.readFileSync as jest.Mock).mockReturnValue(
Buffer.from('java=21.0.5-tem')
@@ -232,7 +262,7 @@ describe('setup action orchestration', () => {
forceDownload: true,
cacheJdk: false,
setDefault: false,
verifySignature: true,
verifySignature: undefined,
verifySignaturePublicKey: 'public-key'
},
'/tmp/java.tar.gz'

View File

@@ -405,6 +405,18 @@ describe('extractJdkFile', () => {
expect(io.which).not.toHaveBeenCalled();
});
it('extracts xz-compressed tarballs with xz tar flags', async () => {
(tc.extractTar as jest.Mock).mockResolvedValue('/extracted' as never);
await expect(extractJdkFile('/tmp/jdk.tar.xz')).resolves.toBe('/extracted');
expect(tc.extractTar).toHaveBeenCalledWith(
'/tmp/jdk.tar.xz',
undefined,
'xJ'
);
expect(io.which).not.toHaveBeenCalled();
});
it('uses the bundled tar.exe for zip archives on Windows', async () => {
setPlatform('win32');
const systemRoot = path.join(workDir, 'Windows');

View File

@@ -263,6 +263,7 @@ describe('validatePaginationUrl', () => {
describe('getVersionFromFileContent', () => {
describe('.sdkmanrc', () => {
it.each([
['java=26-tem', '26', 'temurin'],
['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'],

View File

@@ -41,7 +41,6 @@ inputs:
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
@@ -64,6 +63,20 @@ inputs:
server-password:
description: 'Deprecated alias for server-password-env-var'
required: false
mvn-server-credentials:
description: 'Multiline list of Maven server credentials in the format `server-id:USERNAME_ENV:PASSWORD_ENV`. When set, replaces the single server configured by server-id, server-username-env-var, and server-password-env-var.'
required: false
mvn-repositories:
description: 'Multiline list of Maven dependency repositories in the format `repository-id:repository-url:snapshots-enabled`.'
required: false
mvn-repositories-include-central:
description: 'Include Maven Central in the generated dependency repositories profile. When false, Central is disabled unless an explicit repository with ID `central` is declared.'
required: false
default: true
mvn-repositories-prioritize-central:
description: 'Place Maven Central before custom dependency repositories. Has no effect when Maven Central is excluded.'
required: false
default: true
settings-path:
description: 'Path to where the settings.xml file will be written. Default is ~/.m2.'
required: false

View File

@@ -18680,12 +18680,26 @@ class XmlNode {
this.child.push({ [node.tagname]: node.child });
}
// if requested, add the startIndex
this.addStartIndex(startIndex);
}
addStartIndex(startIndex) {
if (startIndex !== undefined) {
// Note: for now we just overwrite the metadata. If we had more complex metadata,
// we might need to do an object append here: metadata = { ...metadata, startIndex }
this.child[this.child.length - 1][METADATA_SYMBOL] = { startIndex };
}
}
addEndIndex(endIndex) {
const lastChild = this.child[this.child.length - 1];
// endIndex is write-once: when updateTag drops a node, the last child is a
// previously completed sibling whose endIndex must not be overwritten
if (lastChild !== undefined && lastChild[METADATA_SYMBOL] !== undefined
&& lastChild[METADATA_SYMBOL].endIndex === undefined) {
lastChild[METADATA_SYMBOL].endIndex = endIndex;
}
}
/** symbol used for metadata */
static getMetaDataSymbol() {
return METADATA_SYMBOL;
@@ -18718,8 +18732,23 @@ class DocTypeReader {
i = i + 9;
let angleBracketsCount = 1;
let hasBody = false, comment = false;
let quoteChar = null; // tracks an open SYSTEM/PUBLIC literal before the '[' body
let exp = "";
for (; i < xmlData.length; i++) {
// Inside a quoted external-identifier literal — XML allows '<'
// and '>' as plain data here, so they must not be interpreted
// as DOCTYPE structure until the matching quote closes.
if (quoteChar !== null) {
if (xmlData[i] === quoteChar) quoteChar = null;
exp += xmlData[i];
continue;
}
if (!hasBody && !comment && (xmlData[i] === '"' || xmlData[i] === "'")) {
quoteChar = xmlData[i];
exp += xmlData[i];
continue;
}
if (xmlData[i] === '<' && !comment) { //Determine the tag type
if (hasBody && hasSeq(xmlData, "!ENTITY", i)) {
i += 7;
@@ -18774,7 +18803,7 @@ class DocTypeReader {
exp += xmlData[i];
}
}
if (angleBracketsCount !== 0) {
if (quoteChar !== null || angleBracketsCount !== 0) {
throw new Error(`Unclosed DOCTYPE`);
}
} else {
@@ -19489,7 +19518,11 @@ function resolveEnotation(str, trimmedStr, options) {
*/
function trimZeros(numStr) {
if (numStr && numStr.indexOf(".") !== -1) {//float
numStr = numStr.replace(/0+$/, ""); //remove ending zeros
//remove ending zeros without the O(n^2) backtracking that /0+$/ hits
//when the string doesn't end in 0 but has a long internal zero-run
let end = numStr.length;
while (end > 0 && numStr.charCodeAt(end - 1) === 48 /* '0' */) end--;
numStr = numStr.slice(0, end);
if (numStr === ".") numStr = "0";
else if (numStr[0] === ".") numStr = "0" + numStr;
else if (numStr[numStr.length - 1] === ".") numStr = numStr.substring(0, numStr.length - 1);
@@ -22965,7 +22998,12 @@ const parseXml = function (xmlData) {
this.matcher.pop();
this.isCurrentNodeStopNode = false; // Reset flag when closing tag
currentNode = this.tagsNodeStack.pop();//avoid recursion, set the parent tag scope
//a closing tag with no matching opening tag leaves the stack empty
currentNode = this.tagsNodeStack.pop() || xmlObj;//avoid recursion, set the parent tag scope
if (options.captureMetaData && currentNode) {
currentNode.addEndIndex(closeIndex + 1);
}
textData = "";
i = closeIndex;
} else if (c1 === 63) { //'?'
@@ -22991,6 +23029,11 @@ const parseXml = function (xmlData) {
childNode[":@"] = attsMap
}
this.addChild(currentNode, childNode, this.readonlyMatcher, i);
if (options.captureMetaData) {
// closeIndex points at '?' of the closing '?>'
currentNode.addEndIndex(tagData.closeIndex + 2);
}
}
@@ -23155,6 +23198,10 @@ const parseXml = function (xmlData) {
this.isCurrentNodeStopNode = false; // Reset flag
this.addChild(currentNode, childNode, this.readonlyMatcher, startIndex);
if (options.captureMetaData) {
currentNode.addEndIndex(i + 1);
}
} else {
//selfClosing tag
if (isSelfClosing) {
@@ -23165,6 +23212,10 @@ const parseXml = function (xmlData) {
childNode[":@"] = prefixedAttrs;
}
this.addChild(currentNode, childNode, this.readonlyMatcher, startIndex);
if (options.captureMetaData) {
currentNode.addEndIndex(closeIndex + 1);
}
this.matcher.pop(); // Pop self-closing tag
this.isCurrentNodeStopNode = false; // Reset flag
}
@@ -23174,6 +23225,10 @@ const parseXml = function (xmlData) {
childNode[":@"] = prefixedAttrs;
}
this.addChild(currentNode, childNode, this.readonlyMatcher, startIndex);
if (options.captureMetaData) {
currentNode.addEndIndex(result.closeIndex + 1);
}
this.matcher.pop(); // Pop unpaired tag
this.isCurrentNodeStopNode = false; // Reset flag
i = result.closeIndex;

22
dist/cleanup/index.js vendored
View File

@@ -30774,7 +30774,7 @@ module.exports = {
/* harmony export */ gk: () => (/* binding */ INPUT_CACHE),
/* harmony export */ wG: () => (/* binding */ INPUT_JOB_STATUS)
/* harmony export */ });
/* unused harmony exports MACOS_JAVA_CONTENT_POSTFIX, INPUT_JAVA_VERSION, INPUT_JAVA_VERSION_FILE, INPUT_ARCHITECTURE, INPUT_JAVA_PACKAGE, INPUT_DISTRIBUTION, INPUT_JDK_FILE, INPUT_JDK_FILE_DEPRECATED, INPUT_CHECK_LATEST, INPUT_FORCE_DOWNLOAD, INPUT_SET_DEFAULT, INPUT_PROBLEM_MATCHER, INPUT_VERIFY_SIGNATURE, INPUT_VERIFY_SIGNATURE_PUBLIC_KEY, INPUT_SERVER_ID, INPUT_SERVER_USERNAME_ENV_VAR, INPUT_SERVER_PASSWORD_ENV_VAR, INPUT_SERVER_USERNAME_DEPRECATED, INPUT_SERVER_PASSWORD_DEPRECATED, INPUT_SETTINGS_PATH, INPUT_OVERWRITE_SETTINGS, INPUT_GPG_PRIVATE_KEY, INPUT_GPG_PASSPHRASE_ENV_VAR, INPUT_GPG_PASSPHRASE_DEPRECATED, INPUT_DEFAULT_SERVER_USERNAME, INPUT_DEFAULT_SERVER_PASSWORD, INPUT_DEFAULT_GPG_PRIVATE_KEY, INPUT_DEFAULT_GPG_PASSPHRASE, MAVEN_GPG_PASSPHRASE_DEFAULT_ENV, GPG_PASSPHRASE_PROFILE_ID, INPUT_CACHE_DEPENDENCY_PATH, INPUT_CACHE_PATH, M2_DIR, MVN_SETTINGS_FILE, MVN_TOOLCHAINS_FILE, INPUT_MVN_TOOLCHAIN_ID, INPUT_MVN_TOOLCHAIN_VENDOR, INPUT_SHOW_DOWNLOAD_PROGRESS, MAVEN_ARGS_ENV, MAVEN_NO_TRANSFER_PROGRESS_FLAG, MAVEN_NO_TRANSFER_PROGRESS_LONG_FLAG, DISTRIBUTIONS_ONLY_MAJOR_VERSION */
/* unused harmony exports MACOS_JAVA_CONTENT_POSTFIX, INPUT_JAVA_VERSION, INPUT_JAVA_VERSION_FILE, INPUT_ARCHITECTURE, INPUT_JAVA_PACKAGE, INPUT_DISTRIBUTION, INPUT_JDK_FILE, INPUT_JDK_FILE_DEPRECATED, INPUT_CHECK_LATEST, INPUT_FORCE_DOWNLOAD, INPUT_SET_DEFAULT, INPUT_PROBLEM_MATCHER, INPUT_VERIFY_SIGNATURE, INPUT_VERIFY_SIGNATURE_PUBLIC_KEY, INPUT_MVN_SERVER_CREDENTIALS, INPUT_MVN_REPOSITORIES, INPUT_MVN_REPOSITORIES_INCLUDE_CENTRAL, INPUT_MVN_REPOSITORIES_PRIORITIZE_CENTRAL, INPUT_SERVER_ID, INPUT_SERVER_USERNAME_ENV_VAR, INPUT_SERVER_PASSWORD_ENV_VAR, INPUT_SERVER_USERNAME_DEPRECATED, INPUT_SERVER_PASSWORD_DEPRECATED, INPUT_SETTINGS_PATH, INPUT_OVERWRITE_SETTINGS, INPUT_GPG_PRIVATE_KEY, INPUT_GPG_PASSPHRASE_ENV_VAR, INPUT_GPG_PASSPHRASE_DEPRECATED, INPUT_DEFAULT_SERVER_USERNAME, INPUT_DEFAULT_SERVER_PASSWORD, INPUT_DEFAULT_GPG_PRIVATE_KEY, INPUT_DEFAULT_GPG_PASSPHRASE, MAVEN_GPG_PASSPHRASE_DEFAULT_ENV, GPG_PASSPHRASE_PROFILE_ID, MAVEN_REPOSITORIES_PROFILE_ID, MAVEN_CENTRAL_REPOSITORY_ID, MAVEN_CENTRAL_REPOSITORY_URL, INPUT_CACHE_DEPENDENCY_PATH, INPUT_CACHE_PATH, M2_DIR, MVN_SETTINGS_FILE, MVN_TOOLCHAINS_FILE, INPUT_MVN_TOOLCHAIN_ID, INPUT_MVN_TOOLCHAIN_VENDOR, INPUT_SHOW_DOWNLOAD_PROGRESS, MAVEN_ARGS_ENV, MAVEN_NO_TRANSFER_PROGRESS_FLAG, MAVEN_NO_TRANSFER_PROGRESS_LONG_FLAG, DISTRIBUTIONS_ONLY_MAJOR_VERSION */
const MACOS_JAVA_CONTENT_POSTFIX = 'Contents/Home';
const INPUT_JAVA_VERSION = 'java-version';
const INPUT_JAVA_VERSION_FILE = 'java-version-file';
@@ -30789,6 +30789,10 @@ const INPUT_SET_DEFAULT = 'set-default';
const INPUT_PROBLEM_MATCHER = 'problem-matcher';
const INPUT_VERIFY_SIGNATURE = 'verify-signature';
const INPUT_VERIFY_SIGNATURE_PUBLIC_KEY = 'verify-signature-public-key';
const INPUT_MVN_SERVER_CREDENTIALS = 'mvn-server-credentials';
const INPUT_MVN_REPOSITORIES = 'mvn-repositories';
const INPUT_MVN_REPOSITORIES_INCLUDE_CENTRAL = 'mvn-repositories-include-central';
const INPUT_MVN_REPOSITORIES_PRIORITIZE_CENTRAL = 'mvn-repositories-prioritize-central';
const INPUT_SERVER_ID = 'server-id';
const INPUT_SERVER_USERNAME_ENV_VAR = 'server-username-env-var';
const INPUT_SERVER_PASSWORD_ENV_VAR = 'server-password-env-var';
@@ -30809,6 +30813,9 @@ const INPUT_DEFAULT_GPG_PASSPHRASE = 'GPG_PASSPHRASE';
const MAVEN_GPG_PASSPHRASE_DEFAULT_ENV = 'MAVEN_GPG_PASSPHRASE';
// Id of the settings.xml profile used to set `gpg.passphraseEnvName`.
const GPG_PASSPHRASE_PROFILE_ID = 'setup-java-gpg';
const MAVEN_REPOSITORIES_PROFILE_ID = 'setup-java-repositories';
const MAVEN_CENTRAL_REPOSITORY_ID = 'central';
const MAVEN_CENTRAL_REPOSITORY_URL = 'https://repo.maven.apache.org/maven2';
const INPUT_CACHE = 'cache';
const INPUT_CACHE_JDK = 'cache-jdk';
const INPUT_CACHE_DEPENDENCY_PATH = 'cache-dependency-path';
@@ -30898,7 +30905,9 @@ async function extractJdkFile(toolPath, extension) {
if (!extension) {
extension = toolPath.endsWith('.tar.gz')
? 'tar.gz'
: path.extname(toolPath);
: toolPath.endsWith('.tar.xz')
? 'tar.xz'
: path.extname(toolPath);
if (extension.startsWith('.')) {
extension = extension.substring(1);
}
@@ -30906,6 +30915,8 @@ async function extractJdkFile(toolPath, extension) {
switch (extension) {
case 'tar.gz':
return await extractTarGz(toolPath);
case 'tar.xz':
return await tc.extractTar(toolPath, undefined, 'xJ');
case 'tar':
return await tc.extractTar(toolPath);
case 'zip':
@@ -35564,6 +35575,9 @@ function _unique(values) {
/******/ __nccwpck_require__.m = __webpack_modules__;
/******/
/************************************************************************/
/******/ /* webpack/runtime/asset-relocator-loader */
/******/ if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = decodeURIComponent(new URL('.', import.meta.url).pathname).slice(import.meta.url.match(/^file:\/\/\/\w:/) ? 1 : 0, -1) + "/";
/******/
/******/ /* webpack/runtime/compat get default export */
/******/ (() => {
/******/ // getDefaultExport function for compatibility with non-harmony modules
@@ -35656,10 +35670,6 @@ function _unique(values) {
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/compat */
/******/
/******/ if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = new URL('.', import.meta.url).pathname.slice(import.meta.url.match(/^file:\/\/\/\w:/) ? 1 : 0, -1) + "/";
/******/
/******/ /* webpack/runtime/import chunk loading */
/******/ (() => {
/******/ // no baseURI

139
dist/setup/228.index.js vendored Normal file
View File

@@ -0,0 +1,139 @@
export const id = 228;
export const ids = [228];
export const modules = {
/***/ 8228:
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ RedHatDistribution: () => (/* binding */ RedHatDistribution)
/* harmony export */ });
/* harmony import */ var _actions_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(3838);
/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(9896);
/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6928);
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var semver__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(2088);
/* harmony import */ var semver__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(semver__WEBPACK_IMPORTED_MODULE_3__);
/* harmony import */ var _util_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(4527);
/* harmony import */ var _base_installer_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(6242);
/* harmony import */ var _platform_types_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(7444);
const DISCO_API_URL = 'https://api.foojay.io/disco/v3.0';
class RedHatDistribution extends _base_installer_js__WEBPACK_IMPORTED_MODULE_5__/* .JavaBase */ .O {
constructor(installerOptions) {
super('RedHat', installerOptions);
}
async findPackageForDownload(range) {
if (!this.stable) {
throw new Error('Early access versions are not supported');
}
const availablePackages = await this.getAvailablePackages();
const normalizedPackages = availablePackages
.map(item => ({
item,
version: this.normalizeDiscoVersion(item.java_version)
}))
.filter((item) => item.version !== null)
.sort((left, right) => -semver__WEBPACK_IMPORTED_MODULE_3___default().compareBuild(left.version, right.version));
const selectedPackage = normalizedPackages.find(item => (0,_util_js__WEBPACK_IMPORTED_MODULE_4__/* .isVersionSatisfies */ .y)(range, item.version));
if (!selectedPackage) {
throw this.createVersionNotFoundError(range, normalizedPackages.map(item => item.version), `Operating system: ${this.getOperatingSystem()}`);
}
const detailsUrl = `${DISCO_API_URL}/ids/${selectedPackage.item.id}`;
const response = await this.http.getJson(detailsUrl);
const details = response.result?.result?.[0];
if (!details?.direct_download_uri) {
throw new Error(`Foojay Disco returned no direct Red Hat download URL for package '${selectedPackage.item.id}'.`);
}
const checksum = details.checksum?.trim();
if (details.checksum_type?.toLowerCase() !== 'sha256' || !checksum) {
throw new Error(`Foojay Disco returned no SHA-256 checksum for Red Hat package '${selectedPackage.item.id}'.`);
}
return {
version: selectedPackage.version,
url: details.direct_download_uri,
checksum: {
algorithm: 'sha256',
value: checksum,
source: detailsUrl
}
};
}
async downloadTool(javaRelease) {
_actions_core__WEBPACK_IMPORTED_MODULE_0__/* .info */ .pq(`Downloading Java ${javaRelease.version} (${this.distribution}) from ${javaRelease.url} ...`);
let javaArchivePath = await this.downloadAndVerify(javaRelease);
_actions_core__WEBPACK_IMPORTED_MODULE_0__/* .info */ .pq('Extracting Java archive...');
const archiveType = this.getArchiveType();
if (archiveType === 'zip') {
javaArchivePath = (0,_util_js__WEBPACK_IMPORTED_MODULE_4__/* .renameWinArchive */ .n2)(javaArchivePath);
}
const extractedJavaPath = await (0,_util_js__WEBPACK_IMPORTED_MODULE_4__/* .extractJdkFile */ .PE)(javaArchivePath, archiveType);
const archiveName = fs__WEBPACK_IMPORTED_MODULE_1___default().readdirSync(extractedJavaPath)[0];
if (!archiveName) {
throw new Error(`The Red Hat archive for Java ${javaRelease.version} was empty.`);
}
const archivePath = path__WEBPACK_IMPORTED_MODULE_2___default().join(extractedJavaPath, archiveName);
const javaPath = await (0,_util_js__WEBPACK_IMPORTED_MODULE_4__/* .cacheJdkDir */ .Vj)(archivePath, this.toolcacheFolderName, this.getToolcacheVersionName(javaRelease.version), this.architecture);
return { version: javaRelease.version, path: javaPath };
}
async getAvailablePackages() {
const operatingSystem = this.getOperatingSystem();
const archiveType = this.getArchiveType();
const query = new URLSearchParams({
distro: 'redhat',
release_status: 'ga',
operating_system: operatingSystem,
architecture: this.distributionArchitecture(),
package_type: this.packageType,
archive_type: archiveType,
directly_downloadable: 'true'
});
const url = `${DISCO_API_URL}/packages?${query.toString()}`;
const response = await this.http.getJson(url);
const packages = response.result?.result;
if (!Array.isArray(packages)) {
throw new Error(`Could not fetch Red Hat package metadata from Foojay Disco: ${url}`);
}
return packages.filter(item => item.distribution === 'redhat' &&
item.release_status === 'ga' &&
item.operating_system === operatingSystem &&
item.architecture === this.distributionArchitecture() &&
item.package_type === this.packageType &&
item.archive_type === archiveType &&
item.directly_downloadable);
}
getOperatingSystem(alpine = (0,_platform_types_js__WEBPACK_IMPORTED_MODULE_6__/* .isAlpineLinux */ .G6)()) {
if (alpine) {
throw new Error("Distribution 'redhat' does not support Alpine Linux because Red Hat portable archives require glibc.");
}
return process.platform === 'win32' ? 'windows' : 'linux';
}
getArchiveType() {
return process.platform === 'win32' ? 'zip' : 'tar.xz';
}
normalizeDiscoVersion(version) {
let normalizedVersion = version.trim();
if (/^\d+\+\d+$/.test(normalizedVersion)) {
normalizedVersion = normalizedVersion.replace('+', '.0.0+');
}
else if (/^\d+$/.test(normalizedVersion)) {
normalizedVersion = `${normalizedVersion}.0.0`;
}
else if (/^\d+\.\d+$/.test(normalizedVersion)) {
normalizedVersion = `${normalizedVersion}.0`;
}
return semver__WEBPACK_IMPORTED_MODULE_3___default().valid(normalizedVersion) ? normalizedVersion : null;
}
}
/***/ })
};

View File

@@ -244,7 +244,8 @@ class JavaBase {
installerOptions.setDefault !== undefined
? installerOptions.setDefault
: true;
this.verifySignature = installerOptions.verifySignature ?? false;
this.verifySignature =
installerOptions.verifySignature ?? this.supportsSignatureVerification();
this.verifySignaturePublicKey = installerOptions.verifySignaturePublicKey;
}
async downloadAndVerify(javaRelease) {

168
dist/setup/81.index.js vendored
View File

@@ -10,7 +10,11 @@ __webpack_require__.r(__webpack_exports__);
/* harmony export */ configureAuthentication: () => (/* binding */ configureAuthentication),
/* harmony export */ createAuthenticationSettings: () => (/* binding */ createAuthenticationSettings),
/* harmony export */ generate: () => (/* binding */ generate),
/* harmony export */ getInputWithDeprecatedAlias: () => (/* binding */ getInputWithDeprecatedAlias)
/* harmony export */ getInputWithDeprecatedAlias: () => (/* binding */ getInputWithDeprecatedAlias),
/* harmony export */ getMavenRepositorySettings: () => (/* binding */ getMavenRepositorySettings),
/* harmony export */ getMavenServerSettings: () => (/* binding */ getMavenServerSettings),
/* harmony export */ parseMavenRepositories: () => (/* binding */ parseMavenRepositories),
/* harmony export */ parseMavenServerCredentials: () => (/* binding */ parseMavenServerCredentials)
/* harmony export */ });
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6928);
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_0__);
@@ -34,9 +38,8 @@ __webpack_require__.r(__webpack_exports__);
async function configureAuthentication() {
const id = _actions_core__WEBPACK_IMPORTED_MODULE_1__/* .getInput */ .V4(_constants_js__WEBPACK_IMPORTED_MODULE_7__/* .INPUT_SERVER_ID */ .fd);
const usernameEnvVar = getInputWithDeprecatedAlias(_constants_js__WEBPACK_IMPORTED_MODULE_7__/* .INPUT_SERVER_USERNAME_ENV_VAR */ .sc, _constants_js__WEBPACK_IMPORTED_MODULE_7__/* .INPUT_SERVER_USERNAME_DEPRECATED */ .sp, _constants_js__WEBPACK_IMPORTED_MODULE_7__/* .INPUT_DEFAULT_SERVER_USERNAME */ .Wj);
const passwordEnvVar = getInputWithDeprecatedAlias(_constants_js__WEBPACK_IMPORTED_MODULE_7__/* .INPUT_SERVER_PASSWORD_ENV_VAR */ .r4, _constants_js__WEBPACK_IMPORTED_MODULE_7__/* .INPUT_SERVER_PASSWORD_DEPRECATED */ .Vt, _constants_js__WEBPACK_IMPORTED_MODULE_7__/* .INPUT_DEFAULT_SERVER_PASSWORD */ .xp);
const servers = getMavenServerSettings();
const repositorySettings = getMavenRepositorySettings();
const settingsDirectory = _actions_core__WEBPACK_IMPORTED_MODULE_1__/* .getInput */ .V4(_constants_js__WEBPACK_IMPORTED_MODULE_7__/* .INPUT_SETTINGS_PATH */ .Xh) ||
path__WEBPACK_IMPORTED_MODULE_0__.join(os__WEBPACK_IMPORTED_MODULE_4__.homedir(), _constants_js__WEBPACK_IMPORTED_MODULE_7__/* .M2_DIR */ .iT);
const overwriteSettings = (0,_util_js__WEBPACK_IMPORTED_MODULE_6__/* .getBooleanInput */ .Vt)(_constants_js__WEBPACK_IMPORTED_MODULE_7__/* .INPUT_OVERWRITE_SETTINGS */ .TS, true);
@@ -46,7 +49,7 @@ async function configureAuthentication() {
if (gpgPrivateKey) {
_actions_core__WEBPACK_IMPORTED_MODULE_1__/* .setSecret */ .Pq(gpgPrivateKey);
}
await createAuthenticationSettings(id, usernameEnvVar, passwordEnvVar, settingsDirectory, overwriteSettings, gpgPassphraseEnvVar);
await createAuthenticationSettings(servers, settingsDirectory, overwriteSettings, gpgPassphraseEnvVar, repositorySettings);
if (gpgPrivateKey) {
_actions_core__WEBPACK_IMPORTED_MODULE_1__/* .info */ .pq('Importing private gpg key');
const gpgHome = await _gpg_js__WEBPACK_IMPORTED_MODULE_5__/* .importKey */ .Fh(gpgPrivateKey);
@@ -68,15 +71,106 @@ function getInputWithDeprecatedAlias(inputName, deprecatedInputName, defaultValu
}
return value || deprecatedValue || defaultValue || '';
}
async function createAuthenticationSettings(id, usernameEnvVar, passwordEnvVar, settingsDirectory, overwriteSettings, gpgPassphraseEnvVar = undefined) {
_actions_core__WEBPACK_IMPORTED_MODULE_1__/* .info */ .pq(`Creating ${_constants_js__WEBPACK_IMPORTED_MODULE_7__/* .MVN_SETTINGS_FILE */ .vO} with server-id: ${id}`);
// only exported for testing purposes
function getMavenServerSettings() {
const entries = _actions_core__WEBPACK_IMPORTED_MODULE_1__/* .getMultilineInput */ .q3(_constants_js__WEBPACK_IMPORTED_MODULE_7__/* .INPUT_MVN_SERVER_CREDENTIALS */ .MM);
if (entries.some(entry => entry.trim())) {
return parseMavenServerCredentials(entries);
}
return [
{
id: _actions_core__WEBPACK_IMPORTED_MODULE_1__/* .getInput */ .V4(_constants_js__WEBPACK_IMPORTED_MODULE_7__/* .INPUT_SERVER_ID */ .fd),
usernameEnvVar: getInputWithDeprecatedAlias(_constants_js__WEBPACK_IMPORTED_MODULE_7__/* .INPUT_SERVER_USERNAME_ENV_VAR */ .sc, _constants_js__WEBPACK_IMPORTED_MODULE_7__/* .INPUT_SERVER_USERNAME_DEPRECATED */ .sp, _constants_js__WEBPACK_IMPORTED_MODULE_7__/* .INPUT_DEFAULT_SERVER_USERNAME */ .Wj),
passwordEnvVar: getInputWithDeprecatedAlias(_constants_js__WEBPACK_IMPORTED_MODULE_7__/* .INPUT_SERVER_PASSWORD_ENV_VAR */ .r4, _constants_js__WEBPACK_IMPORTED_MODULE_7__/* .INPUT_SERVER_PASSWORD_DEPRECATED */ .Vt, _constants_js__WEBPACK_IMPORTED_MODULE_7__/* .INPUT_DEFAULT_SERVER_PASSWORD */ .xp)
}
];
}
// only exported for testing purposes
function parseMavenServerCredentials(entries) {
const servers = [];
const serverIds = new Set();
entries.forEach((entry, index) => {
if (!entry.trim()) {
return;
}
const fields = entry.split(':');
if (fields.length !== 3) {
throw new Error(`Invalid mvn-server-credentials entry at line ${index + 1}. Expected format: server-id:USERNAME_ENV:PASSWORD_ENV`);
}
const [id, usernameEnvVar, passwordEnvVar] = fields.map(field => field.trim());
if (!id || !usernameEnvVar || !passwordEnvVar) {
throw new Error(`Invalid mvn-server-credentials entry at line ${index + 1}. server-id, username environment variable, and password environment variable are required`);
}
if (serverIds.has(id)) {
throw new Error(`Duplicate server-id '${id}' in mvn-server-credentials input`);
}
serverIds.add(id);
servers.push({ id, usernameEnvVar, passwordEnvVar });
});
return servers;
}
// only exported for testing purposes
function getMavenRepositorySettings() {
const entries = _actions_core__WEBPACK_IMPORTED_MODULE_1__/* .getMultilineInput */ .q3(_constants_js__WEBPACK_IMPORTED_MODULE_7__/* .INPUT_MVN_REPOSITORIES */ .W2);
if (!entries.some(entry => entry.trim())) {
return undefined;
}
const includeCentral = (0,_util_js__WEBPACK_IMPORTED_MODULE_6__/* .getBooleanInput */ .Vt)(_constants_js__WEBPACK_IMPORTED_MODULE_7__/* .INPUT_MVN_REPOSITORIES_INCLUDE_CENTRAL */ .H5, true);
return {
repositories: parseMavenRepositories(entries, includeCentral),
includeCentral,
prioritizeCentral: (0,_util_js__WEBPACK_IMPORTED_MODULE_6__/* .getBooleanInput */ .Vt)(_constants_js__WEBPACK_IMPORTED_MODULE_7__/* .INPUT_MVN_REPOSITORIES_PRIORITIZE_CENTRAL */ .OT, true)
};
}
// only exported for testing purposes
function parseMavenRepositories(entries, includeCentral) {
const repositories = [];
const repositoryIds = new Set();
entries.forEach((entry, index) => {
if (!entry.trim()) {
return;
}
const firstSeparator = entry.indexOf(':');
const lastSeparator = entry.lastIndexOf(':');
if (firstSeparator <= 0 || lastSeparator <= firstSeparator) {
throw new Error(`Invalid mvn-repositories entry at line ${index + 1}. Expected format: repository-id:repository-url:snapshots-enabled`);
}
const id = entry.slice(0, firstSeparator).trim();
const url = entry.slice(firstSeparator + 1, lastSeparator).trim();
const snapshotsValue = entry
.slice(lastSeparator + 1)
.trim()
.toLowerCase();
if (!id || !url || !snapshotsValue) {
throw new Error(`Invalid mvn-repositories entry at line ${index + 1}. repository-id, repository URL, and snapshots-enabled are required`);
}
if (snapshotsValue !== 'true' && snapshotsValue !== 'false') {
throw new Error(`Invalid snapshots-enabled value '${snapshotsValue}' in mvn-repositories entry at line ${index + 1}. Expected true or false`);
}
if (repositoryIds.has(id)) {
throw new Error(`Duplicate repository-id '${id}' in mvn-repositories input`);
}
if (includeCentral && id === _constants_js__WEBPACK_IMPORTED_MODULE_7__/* .MAVEN_CENTRAL_REPOSITORY_ID */ .xg) {
throw new Error(`Repository-id '${_constants_js__WEBPACK_IMPORTED_MODULE_7__/* .MAVEN_CENTRAL_REPOSITORY_ID */ .xg}' is reserved when ${_constants_js__WEBPACK_IMPORTED_MODULE_7__/* .INPUT_MVN_REPOSITORIES_INCLUDE_CENTRAL */ .H5} is enabled`);
}
repositoryIds.add(id);
repositories.push({
id,
url,
snapshotsEnabled: snapshotsValue === 'true'
});
});
return repositories;
}
async function createAuthenticationSettings(servers, settingsDirectory, overwriteSettings, gpgPassphraseEnvVar = undefined, repositorySettings = undefined) {
_actions_core__WEBPACK_IMPORTED_MODULE_1__/* .info */ .pq(`Creating ${_constants_js__WEBPACK_IMPORTED_MODULE_7__/* .MVN_SETTINGS_FILE */ .vO} with server-id: ${servers.map(server => server.id).join(', ')}`);
// when an alternate m2 location is specified use only that location (no .m2 directory)
// otherwise use the home/.m2/ path
await _actions_io__WEBPACK_IMPORTED_MODULE_2__/* .mkdirP */ .U$(settingsDirectory);
await write(settingsDirectory, generate(id, usernameEnvVar, passwordEnvVar, gpgPassphraseEnvVar), overwriteSettings);
await write(settingsDirectory, generate(servers, gpgPassphraseEnvVar, repositorySettings), overwriteSettings);
}
// only exported for testing purposes
function generate(id, usernameEnvVar, passwordEnvVar, gpgPassphraseEnvVar) {
function generate(servers, gpgPassphraseEnvVar, repositorySettings) {
// The maven-gpg-plugin reads the passphrase from the environment variable
// named by the `gpg.passphraseEnvName` property (default MAVEN_GPG_PASSPHRASE).
// Only configure it when the requested env var name differs from that default;
@@ -90,16 +184,54 @@ function generate(id, usernameEnvVar, passwordEnvVar, gpgPassphraseEnvVar) {
' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"',
' xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">',
' <interactiveMode>false</interactiveMode>',
' <servers>',
' <server>',
` <id>${(0,_xml_js__WEBPACK_IMPORTED_MODULE_8__/* .escapeXmlText */ .I)(id)}</id>`,
` <username>${(0,_xml_js__WEBPACK_IMPORTED_MODULE_8__/* .escapeXmlText */ .I)(`\${env.${usernameEnvVar}}`)}</username>`,
` <password>${(0,_xml_js__WEBPACK_IMPORTED_MODULE_8__/* .escapeXmlText */ .I)(`\${env.${passwordEnvVar}}`)}</password>`,
' </server>',
' </servers>'
' <servers>'
];
if (includeGpgPassphraseProfile) {
lines.push(' <profiles>', ' <profile>', ` <id>${_constants_js__WEBPACK_IMPORTED_MODULE_7__/* .GPG_PASSPHRASE_PROFILE_ID */ .K$}</id>`, ' <properties>', ` <gpg.passphraseEnvName>${(0,_xml_js__WEBPACK_IMPORTED_MODULE_8__/* .escapeXmlText */ .I)(gpgPassphraseEnvVar)}</gpg.passphraseEnvName>`, ' </properties>', ' </profile>', ' </profiles>', ' <activeProfiles>', ` <activeProfile>${_constants_js__WEBPACK_IMPORTED_MODULE_7__/* .GPG_PASSPHRASE_PROFILE_ID */ .K$}</activeProfile>`, ' </activeProfiles>');
for (const server of servers) {
lines.push(' <server>', ` <id>${(0,_xml_js__WEBPACK_IMPORTED_MODULE_8__/* .escapeXmlText */ .I)(server.id)}</id>`, ` <username>${(0,_xml_js__WEBPACK_IMPORTED_MODULE_8__/* .escapeXmlText */ .I)(`\${env.${server.usernameEnvVar}}`)}</username>`, ` <password>${(0,_xml_js__WEBPACK_IMPORTED_MODULE_8__/* .escapeXmlText */ .I)(`\${env.${server.passwordEnvVar}}`)}</password>`, ' </server>');
}
lines.push(' </servers>');
if (repositorySettings || includeGpgPassphraseProfile) {
lines.push(' <profiles>');
if (repositorySettings) {
const centralRepository = {
id: _constants_js__WEBPACK_IMPORTED_MODULE_7__/* .MAVEN_CENTRAL_REPOSITORY_ID */ .xg,
url: _constants_js__WEBPACK_IMPORTED_MODULE_7__/* .MAVEN_CENTRAL_REPOSITORY_URL */ .jv,
snapshotsEnabled: false
};
const customCentralConfigured = repositorySettings.repositories.some(repository => repository.id === _constants_js__WEBPACK_IMPORTED_MODULE_7__/* .MAVEN_CENTRAL_REPOSITORY_ID */ .xg);
const repositories = repositorySettings.includeCentral
? repositorySettings.prioritizeCentral
? [centralRepository, ...repositorySettings.repositories]
: [...repositorySettings.repositories, centralRepository]
: customCentralConfigured
? repositorySettings.repositories
: [
...repositorySettings.repositories,
{ ...centralRepository, releasesEnabled: false }
];
lines.push(' <profile>', ` <id>${_constants_js__WEBPACK_IMPORTED_MODULE_7__/* .MAVEN_REPOSITORIES_PROFILE_ID */ .hq}</id>`, ' <repositories>');
for (const repository of repositories) {
lines.push(' <repository>', ` <id>${(0,_xml_js__WEBPACK_IMPORTED_MODULE_8__/* .escapeXmlText */ .I)(repository.id)}</id>`, ` <url>${(0,_xml_js__WEBPACK_IMPORTED_MODULE_8__/* .escapeXmlText */ .I)(repository.url)}</url>`, ...(repository.releasesEnabled === undefined
? []
: [
' <releases>',
` <enabled>${repository.releasesEnabled}</enabled>`,
' </releases>'
]), ' <snapshots>', ` <enabled>${repository.snapshotsEnabled}</enabled>`, ' </snapshots>', ' </repository>');
}
lines.push(' </repositories>', ' </profile>');
}
if (includeGpgPassphraseProfile) {
lines.push(' <profile>', ` <id>${_constants_js__WEBPACK_IMPORTED_MODULE_7__/* .GPG_PASSPHRASE_PROFILE_ID */ .K$}</id>`, ' <properties>', ` <gpg.passphraseEnvName>${(0,_xml_js__WEBPACK_IMPORTED_MODULE_8__/* .escapeXmlText */ .I)(gpgPassphraseEnvVar)}</gpg.passphraseEnvName>`, ' </properties>', ' </profile>');
}
lines.push(' </profiles>', ' <activeProfiles>');
if (repositorySettings) {
lines.push(` <activeProfile>${_constants_js__WEBPACK_IMPORTED_MODULE_7__/* .MAVEN_REPOSITORIES_PROFILE_ID */ .hq}</activeProfile>`);
}
if (includeGpgPassphraseProfile) {
lines.push(` <activeProfile>${_constants_js__WEBPACK_IMPORTED_MODULE_7__/* .GPG_PASSPHRASE_PROFILE_ID */ .K$}</activeProfile>`);
}
lines.push(' </activeProfiles>');
}
lines.push('</settings>');
return lines.join('\n');

View File

@@ -741,12 +741,26 @@ class XmlNode {
this.child.push({ [node.tagname]: node.child });
}
// if requested, add the startIndex
this.addStartIndex(startIndex);
}
addStartIndex(startIndex) {
if (startIndex !== undefined) {
// Note: for now we just overwrite the metadata. If we had more complex metadata,
// we might need to do an object append here: metadata = { ...metadata, startIndex }
this.child[this.child.length - 1][METADATA_SYMBOL] = { startIndex };
}
}
addEndIndex(endIndex) {
const lastChild = this.child[this.child.length - 1];
// endIndex is write-once: when updateTag drops a node, the last child is a
// previously completed sibling whose endIndex must not be overwritten
if (lastChild !== undefined && lastChild[METADATA_SYMBOL] !== undefined
&& lastChild[METADATA_SYMBOL].endIndex === undefined) {
lastChild[METADATA_SYMBOL].endIndex = endIndex;
}
}
/** symbol used for metadata */
static getMetaDataSymbol() {
return METADATA_SYMBOL;
@@ -781,8 +795,23 @@ class DocTypeReader {
i = i + 9;
let angleBracketsCount = 1;
let hasBody = false, comment = false;
let quoteChar = null; // tracks an open SYSTEM/PUBLIC literal before the '[' body
let exp = "";
for (; i < xmlData.length; i++) {
// Inside a quoted external-identifier literal — XML allows '<'
// and '>' as plain data here, so they must not be interpreted
// as DOCTYPE structure until the matching quote closes.
if (quoteChar !== null) {
if (xmlData[i] === quoteChar) quoteChar = null;
exp += xmlData[i];
continue;
}
if (!hasBody && !comment && (xmlData[i] === '"' || xmlData[i] === "'")) {
quoteChar = xmlData[i];
exp += xmlData[i];
continue;
}
if (xmlData[i] === '<' && !comment) { //Determine the tag type
if (hasBody && hasSeq(xmlData, "!ENTITY", i)) {
i += 7;
@@ -837,7 +866,7 @@ class DocTypeReader {
exp += xmlData[i];
}
}
if (angleBracketsCount !== 0) {
if (quoteChar !== null || angleBracketsCount !== 0) {
throw new Error(`Unclosed DOCTYPE`);
}
} else {
@@ -1552,7 +1581,11 @@ function resolveEnotation(str, trimmedStr, options) {
*/
function trimZeros(numStr) {
if (numStr && numStr.indexOf(".") !== -1) {//float
numStr = numStr.replace(/0+$/, ""); //remove ending zeros
//remove ending zeros without the O(n^2) backtracking that /0+$/ hits
//when the string doesn't end in 0 but has a long internal zero-run
let end = numStr.length;
while (end > 0 && numStr.charCodeAt(end - 1) === 48 /* '0' */) end--;
numStr = numStr.slice(0, end);
if (numStr === ".") numStr = "0";
else if (numStr[0] === ".") numStr = "0" + numStr;
else if (numStr[numStr.length - 1] === ".") numStr = numStr.substring(0, numStr.length - 1);
@@ -5032,7 +5065,12 @@ const parseXml = function (xmlData) {
this.matcher.pop();
this.isCurrentNodeStopNode = false; // Reset flag when closing tag
currentNode = this.tagsNodeStack.pop();//avoid recursion, set the parent tag scope
//a closing tag with no matching opening tag leaves the stack empty
currentNode = this.tagsNodeStack.pop() || xmlObj;//avoid recursion, set the parent tag scope
if (options.captureMetaData && currentNode) {
currentNode.addEndIndex(closeIndex + 1);
}
textData = "";
i = closeIndex;
} else if (c1 === 63) { //'?'
@@ -5058,6 +5096,11 @@ const parseXml = function (xmlData) {
childNode[":@"] = attsMap
}
this.addChild(currentNode, childNode, this.readonlyMatcher, i);
if (options.captureMetaData) {
// closeIndex points at '?' of the closing '?>'
currentNode.addEndIndex(tagData.closeIndex + 2);
}
}
@@ -5222,6 +5265,10 @@ const parseXml = function (xmlData) {
this.isCurrentNodeStopNode = false; // Reset flag
this.addChild(currentNode, childNode, this.readonlyMatcher, startIndex);
if (options.captureMetaData) {
currentNode.addEndIndex(i + 1);
}
} else {
//selfClosing tag
if (isSelfClosing) {
@@ -5232,6 +5279,10 @@ const parseXml = function (xmlData) {
childNode[":@"] = prefixedAttrs;
}
this.addChild(currentNode, childNode, this.readonlyMatcher, startIndex);
if (options.captureMetaData) {
currentNode.addEndIndex(closeIndex + 1);
}
this.matcher.pop(); // Pop self-closing tag
this.isCurrentNodeStopNode = false; // Reset flag
}
@@ -5241,6 +5292,10 @@ const parseXml = function (xmlData) {
childNode[":@"] = prefixedAttrs;
}
this.addChild(currentNode, childNode, this.readonlyMatcher, startIndex);
if (options.captureMetaData) {
currentNode.addEndIndex(result.closeIndex + 1);
}
this.matcher.pop(); // Pop unpaired tag
this.isCurrentNodeStopNode = false; // Reset flag
i = result.closeIndex;

56
dist/setup/index.js vendored
View File

@@ -30772,16 +30772,20 @@ module.exports = {
/* harmony export */ E8: () => (/* binding */ INPUT_SET_DEFAULT),
/* harmony export */ Fi: () => (/* binding */ STATE_GPG_HOME),
/* harmony export */ GL: () => (/* binding */ INPUT_CACHE_JDK),
/* harmony export */ H5: () => (/* binding */ INPUT_MVN_REPOSITORIES_INCLUDE_CENTRAL),
/* harmony export */ I9: () => (/* binding */ INPUT_FORCE_DOWNLOAD),
/* harmony export */ K$: () => (/* binding */ GPG_PASSPHRASE_PROFILE_ID),
/* harmony export */ LS: () => (/* binding */ INPUT_ARCHITECTURE),
/* harmony export */ MM: () => (/* binding */ INPUT_MVN_SERVER_CREDENTIALS),
/* harmony export */ OD: () => (/* binding */ INPUT_DEFAULT_GPG_PRIVATE_KEY),
/* harmony export */ OT: () => (/* binding */ INPUT_MVN_REPOSITORIES_PRIORITIZE_CENTRAL),
/* harmony export */ PG: () => (/* binding */ MACOS_JAVA_CONTENT_POSTFIX),
/* harmony export */ QM: () => (/* binding */ INPUT_JAVA_VERSION),
/* harmony export */ RX: () => (/* binding */ INPUT_DEFAULT_GPG_PASSPHRASE),
/* harmony export */ TS: () => (/* binding */ INPUT_OVERWRITE_SETTINGS),
/* harmony export */ TY: () => (/* binding */ INPUT_GPG_PASSPHRASE_DEPRECATED),
/* harmony export */ Vt: () => (/* binding */ INPUT_SERVER_PASSWORD_DEPRECATED),
/* harmony export */ W2: () => (/* binding */ INPUT_MVN_REPOSITORIES),
/* harmony export */ Wj: () => (/* binding */ INPUT_DEFAULT_SERVER_USERNAME),
/* harmony export */ Wt: () => (/* binding */ INPUT_PROBLEM_MATCHER),
/* harmony export */ Xh: () => (/* binding */ INPUT_SETTINGS_PATH),
@@ -30792,7 +30796,9 @@ module.exports = {
/* harmony export */ fd: () => (/* binding */ INPUT_SERVER_ID),
/* harmony export */ g_: () => (/* binding */ INPUT_DISTRIBUTION),
/* harmony export */ gk: () => (/* binding */ INPUT_CACHE),
/* harmony export */ hq: () => (/* binding */ MAVEN_REPOSITORIES_PROFILE_ID),
/* harmony export */ iT: () => (/* binding */ M2_DIR),
/* harmony export */ jv: () => (/* binding */ MAVEN_CENTRAL_REPOSITORY_URL),
/* harmony export */ kM: () => (/* binding */ INPUT_JDK_FILE),
/* harmony export */ kN: () => (/* binding */ MAVEN_NO_TRANSFER_PROGRESS_LONG_FLAG),
/* harmony export */ ko: () => (/* binding */ MAVEN_GPG_PASSPHRASE_DEFAULT_ENV),
@@ -30812,6 +30818,7 @@ module.exports = {
/* harmony export */ wX: () => (/* binding */ INPUT_SHOW_DOWNLOAD_PROGRESS),
/* harmony export */ wc: () => (/* binding */ INPUT_JDK_FILE_DEPRECATED),
/* harmony export */ wz: () => (/* binding */ INPUT_GPG_PRIVATE_KEY),
/* harmony export */ xg: () => (/* binding */ MAVEN_CENTRAL_REPOSITORY_ID),
/* harmony export */ xp: () => (/* binding */ INPUT_DEFAULT_SERVER_PASSWORD)
/* harmony export */ });
/* unused harmony exports INPUT_CACHE_READ_ONLY, INPUT_JOB_STATUS */
@@ -30829,6 +30836,10 @@ const INPUT_SET_DEFAULT = 'set-default';
const INPUT_PROBLEM_MATCHER = 'problem-matcher';
const INPUT_VERIFY_SIGNATURE = 'verify-signature';
const INPUT_VERIFY_SIGNATURE_PUBLIC_KEY = 'verify-signature-public-key';
const INPUT_MVN_SERVER_CREDENTIALS = 'mvn-server-credentials';
const INPUT_MVN_REPOSITORIES = 'mvn-repositories';
const INPUT_MVN_REPOSITORIES_INCLUDE_CENTRAL = 'mvn-repositories-include-central';
const INPUT_MVN_REPOSITORIES_PRIORITIZE_CENTRAL = 'mvn-repositories-prioritize-central';
const INPUT_SERVER_ID = 'server-id';
const INPUT_SERVER_USERNAME_ENV_VAR = 'server-username-env-var';
const INPUT_SERVER_PASSWORD_ENV_VAR = 'server-password-env-var';
@@ -30849,6 +30860,9 @@ const INPUT_DEFAULT_GPG_PASSPHRASE = 'GPG_PASSPHRASE';
const MAVEN_GPG_PASSPHRASE_DEFAULT_ENV = 'MAVEN_GPG_PASSPHRASE';
// Id of the settings.xml profile used to set `gpg.passphraseEnvName`.
const GPG_PASSPHRASE_PROFILE_ID = 'setup-java-gpg';
const MAVEN_REPOSITORIES_PROFILE_ID = 'setup-java-repositories';
const MAVEN_CENTRAL_REPOSITORY_ID = 'central';
const MAVEN_CENTRAL_REPOSITORY_URL = 'https://repo.maven.apache.org/maven2';
const INPUT_CACHE = 'cache';
const INPUT_CACHE_JDK = 'cache-jdk';
const INPUT_CACHE_DEPENDENCY_PATH = 'cache-dependency-path';
@@ -30901,6 +30915,7 @@ var JavaDistribution;
JavaDistribution["JetBrains"] = "jetbrains";
JavaDistribution["Kona"] = "kona";
JavaDistribution["OracleOpenJdk"] = "oracle-openjdk";
JavaDistribution["RedHat"] = "redhat";
})(JavaDistribution || (JavaDistribution = {}));
const JAVA_PACKAGE_CAPABILITIES = {
[JavaDistribution.Temurin]: ['jdk', 'jre', 'jdk+jmods'],
@@ -30932,7 +30947,8 @@ const JAVA_PACKAGE_CAPABILITIES = {
'jre+ft'
],
[JavaDistribution.Kona]: ['jdk'],
[JavaDistribution.OracleOpenJdk]: ['jdk']
[JavaDistribution.OracleOpenJdk]: ['jdk'],
[JavaDistribution.RedHat]: ['jdk', 'jre']
};
function validateJavaPackage(distributionName, packageType, version) {
if (!isJavaDistribution(distributionName)) {
@@ -31117,6 +31133,19 @@ const JAVA_PLATFORM_CAPABILITIES = {
macos: X64_ARM64,
windows: ['x64']
}
},
[_package_types_js__WEBPACK_IMPORTED_MODULE_2__/* .JavaDistribution */ .zS.RedHat]: {
platforms: {
linux: [
'x64',
{ architecture: 'aarch64', versionRange: '<12' },
{ architecture: 'ppc64le', versionRange: '<12' }
],
windows: [
{ architecture: 'x64', versionRange: '<22' },
{ architecture: 'x86', versionRange: '<11' }
]
}
}
};
const ARCHITECTURE_ALIASES = {
@@ -31332,7 +31361,9 @@ async function extractJdkFile(toolPath, extension) {
if (!extension) {
extension = toolPath.endsWith('.tar.gz')
? 'tar.gz'
: path__WEBPACK_IMPORTED_MODULE_1___default().extname(toolPath);
: toolPath.endsWith('.tar.xz')
? 'tar.xz'
: path__WEBPACK_IMPORTED_MODULE_1___default().extname(toolPath);
if (extension.startsWith('.')) {
extension = extension.substring(1);
}
@@ -31340,6 +31371,8 @@ async function extractJdkFile(toolPath, extension) {
switch (extension) {
case 'tar.gz':
return await extractTarGz(toolPath);
case 'tar.xz':
return await _actions_tool_cache__WEBPACK_IMPORTED_MODULE_5__/* .extractTar */ .nN(toolPath, undefined, 'xJ');
case 'tar':
return await _actions_tool_cache__WEBPACK_IMPORTED_MODULE_5__/* .extractTar */ .nN(toolPath);
case 'zip':
@@ -36032,6 +36065,9 @@ function _unique(values) {
/******/ __nccwpck_require__.m = __webpack_modules__;
/******/
/************************************************************************/
/******/ /* webpack/runtime/asset-relocator-loader */
/******/ if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = decodeURIComponent(new URL('.', import.meta.url).pathname).slice(import.meta.url.match(/^file:\/\/\/\w:/) ? 1 : 0, -1) + "/";
/******/
/******/ /* webpack/runtime/compat get default export */
/******/ (() => {
/******/ // getDefaultExport function for compatibility with non-harmony modules
@@ -36124,10 +36160,6 @@ function _unique(values) {
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/compat */
/******/
/******/ if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = new URL('.', import.meta.url).pathname.slice(import.meta.url.match(/^file:\/\/\/\w:/) ? 1 : 0, -1) + "/";
/******/
/******/ /* webpack/runtime/import chunk loading */
/******/ (() => {
/******/ // no baseURI
@@ -36295,6 +36327,10 @@ async function getJavaDistribution(distributionName, installerOptions, jdkFile)
const { OpenJdkDistribution } = await Promise.all(/* import() */[__nccwpck_require__.e(242), __nccwpck_require__.e(735)]).then(__nccwpck_require__.bind(__nccwpck_require__, 3735));
return new OpenJdkDistribution(normalizedInstallerOptions);
}
case package_types/* JavaDistribution */.zS.RedHat: {
const { RedHatDistribution } = await Promise.all(/* import() */[__nccwpck_require__.e(242), __nccwpck_require__.e(228)]).then(__nccwpck_require__.bind(__nccwpck_require__, 8228));
return new RedHatDistribution(normalizedInstallerOptions);
}
default:
return null;
}
@@ -36339,7 +36375,6 @@ async function run() {
const checkLatest = (0,util/* getBooleanInput */.Vt)(constants/* INPUT_CHECK_LATEST */.YM, false);
const forceDownload = (0,util/* getBooleanInput */.Vt)(constants/* INPUT_FORCE_DOWNLOAD */.I9, false);
const setDefault = (0,util/* getBooleanInput */.Vt)(constants/* INPUT_SET_DEFAULT */.E8, true);
const verifySignature = (0,util/* getBooleanInput */.Vt)(constants/* INPUT_VERIFY_SIGNATURE */.qy, false);
const verifySignaturePublicKey = setup_java_core/* getInput */.V4(constants/* INPUT_VERIFY_SIGNATURE_PUBLIC_KEY */.u) || undefined;
const toolchainIds = setup_java_core/* getMultilineInput */.q3(constants/* INPUT_MVN_TOOLCHAIN_ID */.nr);
let actionError;
@@ -36367,6 +36402,7 @@ async function run() {
else if (!distributionName) {
throw new Error('distribution input is required when not specified in the version file');
}
const verifySignature = getVerifySignatureInput();
const installerInputsOptions = {
architecture,
packageType,
@@ -36391,6 +36427,7 @@ async function run() {
if (!distributionName) {
throw new Error('distribution input is required');
}
const verifySignature = getVerifySignatureInput();
const installerInputsOptions = {
architecture,
packageType,
@@ -36455,6 +36492,11 @@ function getJdkFileInput() {
}
return jdkFile || deprecatedJdkFile;
}
function getVerifySignatureInput() {
return setup_java_core/* getInput */.V4(constants/* INPUT_VERIFY_SIGNATURE */.qy).trim()
? (0,util/* getBooleanInput */.Vt)(constants/* INPUT_VERIFY_SIGNATURE */.qy)
: undefined;
}
async function installVersion(version, options, toolchainId = 0) {
const { distributionName, jdkFile, architecture, packageType, checkLatest, forceDownload, cacheJdk, setDefault, verifySignature, verifySignaturePublicKey, toolchainIds } = options;
const installerOptions = {

View File

@@ -1,4 +1,4 @@
# Contributors
# Contributing
Thank you for contributing!

View File

@@ -27,6 +27,7 @@
- [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)
- [Publishing to multiple Maven servers](#publishing-to-multiple-maven-servers)
- [Apache Maven with a settings path](#apache-maven-with-a-settings-path)
- [Maven transfer progress (download logs)](#Maven-transfer-progress-download-logs)
- [Java problem matcher (compiler annotations)](#java-problem-matcher-compiler-annotations)
@@ -38,15 +39,6 @@
See [action.yml](../action.yml) for more details on task inputs.
> [!NOTE]
> The examples on this page reference `actions/setup-java@v6`, which is still in
> development on the `main` branch and is not yet published as a release tag. To
> try the V6 features documented here (`cache-jdk`, `force-download`,
> `problem-matcher`, `cache-path`, `cache-read-only`, `java-version: latest`,
> `oracle-openjdk`, and the `*-env-var` input names), reference
> `actions/setup-java@main`. For production workflows use the latest stable
> release, `actions/setup-java@v5`, as shown in the [README](../README.md).
## Selecting a Java distribution
`java-version` and `distribution` select what gets installed. `java-version` may be replaced by `java-version-file`, and `distribution` is optional only when `java-version-file` points to a `.sdkmanrc` or `.tool-versions` file that carries a recognized vendor identifier. In every other case both inputs must be provided. See [Supported distributions](../README.md#Supported-distributions) for a list of available options.
@@ -76,6 +68,19 @@ steps:
- run: java --version
```
### Red Hat Build of OpenJDK
```yaml
steps:
- uses: actions/checkout@v7
- uses: actions/setup-java@v6
with:
distribution: 'redhat'
java-version: '21'
java-package: jdk # optional (jdk or jre) - defaults to jdk
- run: java --version
```
### Liberica
```yaml
@@ -328,6 +333,7 @@ The package types have these meanings:
| `corretto` | `jdk`, `jre` | Accepts major versions only. JDK availability follows Amazon's platform catalog. For the operating systems directly selected by `setup-java`, JRE downloads are limited to Java 8 on Windows; Linux and macOS use `jdk`. |
| `oracle` | `jdk` | Stable Oracle JDK 17 and later only. |
| `oracle-openjdk` | `jdk` | Installs the GA or early-access JDK builds currently listed or archived on `jdk.java.net`; use a `-ea` version such as `27-ea` for early access. |
| `redhat` | `jdk`, `jre` | Stable builds only. Version availability follows the Foojay Disco catalog for Red Hat Build of OpenJDK and can lag Red Hat's downloads page. |
| `dragonwell` | `jdk` | Stable builds only. The current vendor catalog provides Java 8, 11, 17, 21, and 25. |
| `sapmachine` | `jdk`, `jre` | Follows the SapMachine catalog. Both editions are represented from Java 10 onward, but individual versions and platforms can differ. |
| `graalvm` | `jdk` | Stable Oracle GraalVM for JDK 17 and later only. |
@@ -643,6 +649,7 @@ absent from a vendor catalog.
| `corretto` | `x64`, `x86`, `armv7`, `aarch64` | `x64`, `aarch64` | `x64`, `x86` | `x86` is limited to Java 11 or earlier; Linux `armv7` is available for Java 11. |
| `oracle` | `x64`, `aarch64` | `x64`, `aarch64` | `x64` | |
| `oracle-openjdk` | `x64`, `aarch64` | `x64`, `aarch64` | `x64` | |
| `redhat` | `x64`, `aarch64`, `ppc64le` | — | `x64`, `x86` | Linux requires glibc; Alpine is unsupported. Linux `aarch64` and `ppc64le` are limited to Java 11 or earlier. Windows `x64` is limited to Java 21 or earlier and `x86` to Java 10 or earlier. |
| `dragonwell` | `x64`, `aarch64` | — | `x64` | |
| `sapmachine` | `x64`, `aarch64`, `ppc64le` | `x64`, `aarch64` | `x64`, `aarch64` | |
| `graalvm`, `graalvm-community` | `x64`, `aarch64` | `x64`, `aarch64` | `x64` | |
@@ -863,6 +870,125 @@ The two `settings.xml` files created from the above example look like the follow
If you don't want to overwrite the `settings.xml` file, you can set `overwrite-settings: false`
### Publishing to multiple Maven servers
Use `mvn-server-credentials` to add more than one credential entry to the generated `settings.xml`. Each line has the format `server-id:USERNAME_ENV:PASSWORD_ENV`. The username and password fields are environment variable names, not credential values.
When this input is set, it replaces the single server configured by `server-id`, `server-username-env-var`, and `server-password-env-var`.
```yaml
steps:
- uses: actions/checkout@v7
- name: Set up release and snapshot repositories
uses: actions/setup-java@v6
with:
distribution: 'temurin'
java-version: '21'
mvn-server-credentials: |
releases:RELEASES_USERNAME:RELEASES_PASSWORD
snapshots:SNAPSHOTS_USERNAME:SNAPSHOTS_PASSWORD
- name: Publish with Maven
run: mvn deploy
env:
RELEASES_USERNAME: ${{ secrets.RELEASES_USERNAME }}
RELEASES_PASSWORD: ${{ secrets.RELEASES_PASSWORD }}
SNAPSHOTS_USERNAME: ${{ secrets.SNAPSHOTS_USERNAME }}
SNAPSHOTS_PASSWORD: ${{ secrets.SNAPSHOTS_PASSWORD }}
```
This configuration produces the following server entries:
```xml
<servers>
<server>
<id>releases</id>
<username>${env.RELEASES_USERNAME}</username>
<password>${env.RELEASES_PASSWORD}</password>
</server>
<server>
<id>snapshots</id>
<username>${env.SNAPSHOTS_USERNAME}</username>
<password>${env.SNAPSHOTS_PASSWORD}</password>
</server>
</servers>
```
### Resolving Maven dependencies from custom repositories
Use `mvn-repositories` when Maven must download dependencies from repositories
outside Maven Central. Each line has the format
`repository-id:repository-url:snapshots-enabled`. The parser uses the first and
last colons as separators, so repository URLs can contain a scheme or port.
The repository ID can match a `mvn-server-credentials` server ID to authenticate
requests to a private repository:
```yaml
steps:
- uses: actions/checkout@v7
- name: Set up Java and private Maven repositories
uses: actions/setup-java@v6
with:
distribution: 'temurin'
java-version: '21'
mvn-server-credentials: |
private:PRIVATE_REPOSITORY_USERNAME:PRIVATE_REPOSITORY_TOKEN
mvn-repositories: |
private:https://maven.example.com:8443/releases:false
snapshots:https://maven.example.com:8443/snapshots:true
mvn-repositories-include-central: true
mvn-repositories-prioritize-central: true
- run: mvn --batch-mode verify
env:
PRIVATE_REPOSITORY_USERNAME: ${{ secrets.PRIVATE_REPOSITORY_USERNAME }}
PRIVATE_REPOSITORY_TOKEN: ${{ secrets.PRIVATE_REPOSITORY_TOKEN }}
```
This configuration adds the following active profile to `settings.xml`:
```xml
<profiles>
<profile>
<id>setup-java-repositories</id>
<repositories>
<repository>
<id>central</id>
<url>https://repo.maven.apache.org/maven2</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>private</id>
<url>https://maven.example.com:8443/releases</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>snapshots</id>
<url>https://maven.example.com:8443/snapshots</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
</profile>
</profiles>
<activeProfiles>
<activeProfile>setup-java-repositories</activeProfile>
</activeProfiles>
```
Maven Central is included first by default. Set
`mvn-repositories-prioritize-central: false` to place custom repositories
first, or set `mvn-repositories-include-central: false` to disable Central. The
generated profile overrides the Central repository inherited from Maven's Super
POM with releases and snapshots disabled. When automatic Central inclusion is
off, the ID `central` may instead be declared explicitly in `mvn-repositories`
to replace it with a user-specified repository; otherwise that ID is reserved
to prevent duplicate entries.
### GPG
The example above uses the [Maven GPG Plugin](https://maven.apache.org/plugins/maven-gpg-plugin/)'s Bouncy Castle signer (`-Dgpg.signer=bc`, available since `maven-gpg-plugin` 3.2.0). It is a pure-Java signer that reads the key directly from the `MAVEN_GPG_KEY` environment variable, so it does **not** require the `gpg` executable, importing the key into a GPG keychain, or the `--pinentry-mode loopback` workaround in your `pom.xml`. The key must be an ASCII-armored secret key (transferable secret key format).

182
package-lock.json generated
View File

@@ -16,25 +16,25 @@
"@actions/http-client": "^4.0.1",
"@actions/io": "^3.0.2",
"@actions/tool-cache": "^4.0.0",
"fast-xml-parser": "^5.10.1",
"fast-xml-parser": "^5.11.0",
"semver": "^7.8.5"
},
"devDependencies": {
"@eslint/js": "^10.0.1",
"@jest/globals": "^30.4.1",
"@types/node": "^26.1.1",
"@types/semver": "^7.7.0",
"@typescript-eslint/eslint-plugin": "^8.64.0",
"@types/node": "^26.2.0",
"@types/semver": "^7.8.0",
"@typescript-eslint/eslint-plugin": "^8.67.0",
"@typescript-eslint/parser": "^8.65.0",
"@vercel/ncc": "^0.44.0",
"@vercel/ncc": "^0.45.0",
"eslint": "^10.7.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-jest": "^29.15.4",
"eslint-plugin-n": "^18.2.2",
"globals": "^17.7.0",
"eslint-plugin-jest": "^29.16.1",
"eslint-plugin-n": "^18.3.0",
"globals": "^17.9.0",
"husky": "^9.1.7",
"jest": "^30.4.2",
"lint-staged": "^17.2.0",
"lint-staged": "^17.3.0",
"prettier": "^3.9.5",
"ts-jest": "^29.4.11",
"typescript": "^6.0.3"
@@ -1726,9 +1726,9 @@
"license": "MIT"
},
"node_modules/@types/node": {
"version": "26.1.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-26.1.2.tgz",
"integrity": "sha512-Vu4a5UFA9rIIFJ7rB/Vaafh9lrCQszopTCx6KjFboXTGQbPNasehVR5TEiithSDGyd1DEiUByggTZsg8jukeIg==",
"version": "26.2.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-26.2.0.tgz",
"integrity": "sha512-5IviulTZeRNp2vAJ514cc/HUlY5nZ9fCbq9DMyC52BrhFZACo3nI0R7qBxhQmo/d27NFe96ur/b7Wwxklda+kg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1736,9 +1736,9 @@
}
},
"node_modules/@types/semver": {
"version": "7.7.1",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz",
"integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==",
"version": "7.8.0",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.8.0.tgz",
"integrity": "sha512-1mAINjtQCXXeLkJ9ehXkwOcBpqtLxiVtKhpUf83DdRNdQKV0iXZpaHYqRr7nj+wvxuJzoAmAwXI+sCNMv1CzLQ==",
"dev": true,
"license": "MIT"
},
@@ -1767,17 +1767,17 @@
"license": "MIT"
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.65.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.65.0.tgz",
"integrity": "sha512-IEgob78X12rHpUmtcwFsXhZdVGJtwTVP8FiCLZkR6GlYVrl2PcuB+KhCE5BlVC/eQpQnu8WXRtkHZuPar+gCRA==",
"version": "8.67.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.67.0.tgz",
"integrity": "sha512-Un7Heoyj65NREbKAyIrFxeM143NZpExWmy1Nep4DLeQOeLlTeumPjoNKnBrU5D5moWXbPJgRa5Uwcdu0faVNGQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/regexpp": "^4.12.2",
"@typescript-eslint/scope-manager": "8.65.0",
"@typescript-eslint/type-utils": "8.65.0",
"@typescript-eslint/utils": "8.65.0",
"@typescript-eslint/visitor-keys": "8.65.0",
"@typescript-eslint/scope-manager": "8.67.0",
"@typescript-eslint/type-utils": "8.67.0",
"@typescript-eslint/utils": "8.67.0",
"@typescript-eslint/visitor-keys": "8.67.0",
"ignore": "^7.0.5",
"natural-compare": "^1.4.0",
"ts-api-utils": "^2.5.0"
@@ -1790,22 +1790,22 @@
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"@typescript-eslint/parser": "^8.65.0",
"@typescript-eslint/parser": "^8.67.0",
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
"typescript": ">=4.8.4 <6.1.0"
}
},
"node_modules/@typescript-eslint/parser": {
"version": "8.65.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.65.0.tgz",
"integrity": "sha512-CZ4nMxWwgu1HEEFNkeaCptra9QCtkmKdgf3sWh1rl1trIhmxLilgTV4cwcbQ4wemnT4sWQN8CaKOmdYx+g2gMA==",
"version": "8.67.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.67.0.tgz",
"integrity": "sha512-fUBfTuuEulWqX6V8+O3PtScV01tzYYRUDTAirHFKoRAt7nOzoGiPt0M/bB47wWNy0coOOcgEwAMUtBpykMxl6w==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/scope-manager": "8.65.0",
"@typescript-eslint/types": "8.65.0",
"@typescript-eslint/typescript-estree": "8.65.0",
"@typescript-eslint/visitor-keys": "8.65.0",
"@typescript-eslint/scope-manager": "8.67.0",
"@typescript-eslint/types": "8.67.0",
"@typescript-eslint/typescript-estree": "8.67.0",
"@typescript-eslint/visitor-keys": "8.67.0",
"debug": "^4.4.3"
},
"engines": {
@@ -1821,14 +1821,14 @@
}
},
"node_modules/@typescript-eslint/project-service": {
"version": "8.65.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.65.0.tgz",
"integrity": "sha512-SxnPhbTsGahizDgbu7oqFH/xVtzIqMd/s+WtnSxNxJZJpLbdT5IPdzg8EZxO3+PoKahXmwJLeNQOpKJb3/bi7Q==",
"version": "8.67.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.67.0.tgz",
"integrity": "sha512-cvE8c7ulYeXN9fYuszhCeCsbzyVEXuhrRCybnBre7TUmqb5nRmBfQAwCj0O3WJFDeyAZt4VYv51vMCC9LHSdYw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/tsconfig-utils": "^8.65.0",
"@typescript-eslint/types": "^8.65.0",
"@typescript-eslint/tsconfig-utils": "^8.67.0",
"@typescript-eslint/types": "^8.67.0",
"debug": "^4.4.3"
},
"engines": {
@@ -1843,14 +1843,14 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
"version": "8.65.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.65.0.tgz",
"integrity": "sha512-Esbl8OSYiVxBokYgWPf7VVWg/BE798wXhimnn9ML9Pt5qoDf8bfQlgjlKXR/k98+AcNzlLKYrpCcrcuZ9DZLgg==",
"version": "8.67.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.67.0.tgz",
"integrity": "sha512-EgvsleTwS4E+WzzSvem8fAUubLwatMNF1B5hHSLQxcvs7q2dtRhGyujHwLJSYlG41niJ7GP24Aha2+0mb1b2kg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.65.0",
"@typescript-eslint/visitor-keys": "8.65.0"
"@typescript-eslint/types": "8.67.0",
"@typescript-eslint/visitor-keys": "8.67.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1861,9 +1861,9 @@
}
},
"node_modules/@typescript-eslint/tsconfig-utils": {
"version": "8.65.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.65.0.tgz",
"integrity": "sha512-j6GzGqCiRdA7Qhur2VVmKZAkBLfnHFQfx4TaJGL9RMveZqCo48jSHHO0DTgizEnGhtWnqmbtCUSrqSkdiY/0Hg==",
"version": "8.67.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.67.0.tgz",
"integrity": "sha512-vV+LUSv5njUWsknE71fqKTlXUva+R76SaeORd6Zojcunk/6DvKFXONU3BrAs2H49mbygUXt6gbYunzwqNwlhdg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -1878,15 +1878,15 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
"version": "8.65.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.65.0.tgz",
"integrity": "sha512-YjaZ7PRI5qY7ax2L3PbvX0rRyGtipAReCWs0mhhDBHjH/vl0g0BonaGXrKdKpMbIIsMIwDgbk/xzkBTyAltS5g==",
"version": "8.67.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.67.0.tgz",
"integrity": "sha512-aVWDXbRmdXO9siTfX4ditQI1T9+zVcNazT48EJCD0v40/9RIFoUgZ05CmGEq9H2gixRpjUn/iplwvlcvutJW/Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.65.0",
"@typescript-eslint/typescript-estree": "8.65.0",
"@typescript-eslint/utils": "8.65.0",
"@typescript-eslint/types": "8.67.0",
"@typescript-eslint/typescript-estree": "8.67.0",
"@typescript-eslint/utils": "8.67.0",
"debug": "^4.4.3",
"ts-api-utils": "^2.5.0"
},
@@ -1903,9 +1903,9 @@
}
},
"node_modules/@typescript-eslint/types": {
"version": "8.65.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.65.0.tgz",
"integrity": "sha512-JSSwWNy+H0E/01jJEM+hrX6N0OFDzFzeIhHFSAS01tlVaevpG8cFyYRPhS5yjGOvBUx3sqQHVMjCL1CAZZMxBg==",
"version": "8.67.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.67.0.tgz",
"integrity": "sha512-sBtgslww8nsMYUjhdPBiSyUqSzT8uR6g93A2QXnQC8+cGdjz0CyaOdqHDRJb1AtORbZCNUJBBeFA/tNR2uQmww==",
"dev": true,
"license": "MIT",
"engines": {
@@ -1917,16 +1917,16 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
"version": "8.65.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.65.0.tgz",
"integrity": "sha512-JboAE2swaYt4tb1fHhHTABE2K+OLy09XfcTbhnk4Pw96f9dd2e9iYsJ28gBggHlo5z5x1rkyWvcPoTuNTd4oGg==",
"version": "8.67.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.67.0.tgz",
"integrity": "sha512-EKQBCE9yNlRJYm7jdTW5AhDacDUmSwQb0FAJAmK2EKYrNXIsa2vxcSZx6PvJ/dEdI6lS+Y9W+EXckLj0iPFGcw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/project-service": "8.65.0",
"@typescript-eslint/tsconfig-utils": "8.65.0",
"@typescript-eslint/types": "8.65.0",
"@typescript-eslint/visitor-keys": "8.65.0",
"@typescript-eslint/project-service": "8.67.0",
"@typescript-eslint/tsconfig-utils": "8.67.0",
"@typescript-eslint/types": "8.67.0",
"@typescript-eslint/visitor-keys": "8.67.0",
"debug": "^4.4.3",
"minimatch": "^10.2.2",
"semver": "^7.7.3",
@@ -1945,16 +1945,16 @@
}
},
"node_modules/@typescript-eslint/utils": {
"version": "8.65.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.65.0.tgz",
"integrity": "sha512-gXiwIHsYreboxeJucHKPvgwl7dXt50mF8s1/c00cP/WoVTyWKFdtfhRWwZiXYFU5H2O8vVoSLNrexFZjYS/SGA==",
"version": "8.67.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.67.0.tgz",
"integrity": "sha512-U9D1FdwEWBwok3hxxSdhclMb0twvt9QnjIQ0VfQ1AiX2epnpSgv2ubVDsayOFyY8K6FX+AQ7E0FKWVG3iKsj1A==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.9.1",
"@typescript-eslint/scope-manager": "8.65.0",
"@typescript-eslint/types": "8.65.0",
"@typescript-eslint/typescript-estree": "8.65.0"
"@typescript-eslint/scope-manager": "8.67.0",
"@typescript-eslint/types": "8.67.0",
"@typescript-eslint/typescript-estree": "8.67.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1969,13 +1969,13 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
"version": "8.65.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.65.0.tgz",
"integrity": "sha512-8C71BQkGjiMmXtop7pHVJu1l2NNShFdkCyD6a2ezzs5vU/L3LRtb69EtcteFwz0mYMPzIgOw0n6OV4VBUWZd7A==",
"version": "8.67.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.67.0.tgz",
"integrity": "sha512-fkv8dHRDqfGtTHuJeebdrQ7cX6Ad4WAS00rgHh9UGvMycF1mjBfsxry1XsLIFhWZ6Judlh6UdzK+TYlbpCXgnA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.65.0",
"@typescript-eslint/types": "8.67.0",
"eslint-visitor-keys": "^5.0.0"
},
"engines": {
@@ -2364,9 +2364,9 @@
]
},
"node_modules/@vercel/ncc": {
"version": "0.44.1",
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.44.1.tgz",
"integrity": "sha512-cUjIE5P2YY1n+Kt9rFIazMMpGoPn1Fic04rOmTkElMkiDP5oszGfERMpo2shVkFKDL7rVppdM2pqJKC59shQWQ==",
"version": "0.45.0",
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.45.0.tgz",
"integrity": "sha512-8zPi1yO2mHpoKTD+e+Bf0ZT3e+sWHSOyGapm9s7b5R0gxJi3CiFTqmeQiMEyu6ejrz2s09M8JkEoUaTWjBJPQQ==",
"dev": true,
"license": "MIT",
"bin": {
@@ -3123,9 +3123,9 @@
}
},
"node_modules/eslint-plugin-jest": {
"version": "29.16.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-29.16.0.tgz",
"integrity": "sha512-0WFBxDHlT2ratGQfnFQEVIsgQJ5cfd+0IV8Kc6U3X2onB8ATLG23voD2Ch5G9fCkEpCPmCMuzW0tbS0kYb8biw==",
"version": "29.16.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-29.16.1.tgz",
"integrity": "sha512-tfxOIsjzaBud+f74aLbBMRcnrztt5eCIgnAdeoGdnzMAQ4IdAa/s/p8Ls55mk9MC79N3j2jbv4Qetz6Hclbcfw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -3153,9 +3153,9 @@
}
},
"node_modules/eslint-plugin-n": {
"version": "18.2.2",
"resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-18.2.2.tgz",
"integrity": "sha512-gOO0lIqwEjZ750kv9/SptCWArUoAZXJoBr0vYWTO2dCBxctHUXlBIigiC8xuxxr/NKqgIT6Ehz1xRcilj8a5cA==",
"version": "18.3.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-18.3.0.tgz",
"integrity": "sha512-cPVguuDe6DrIPb/qUXHf8P89MaVTUmiYWwpt5gX5AILsvRIiZAxMFXcFR6QHYBksqKJpjfUBlL/RleCJUWcD7w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -3463,9 +3463,9 @@
}
},
"node_modules/fast-xml-parser": {
"version": "5.10.1",
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.10.1.tgz",
"integrity": "sha512-IEMIf7298kXuZSRFoGfMYrl7is8LpavODgbNz1cwIudv7KwVFnuU+UsMporfq6PD6aXSlawZlARiA3UywCTfMw==",
"version": "5.11.0",
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.11.0.tgz",
"integrity": "sha512-9IGxMqvqLOnqP+Egi1nqDHKv5k8aZ7r9n558enxcucmyVGEBNPAU+MOg/8jPIS7rO7sSq4gFm1/nHtiaubMruw==",
"funding": [
{
"type": "github",
@@ -3478,7 +3478,7 @@
"fast-xml-builder": "^1.2.0",
"is-unsafe": "^2.0.0",
"path-expression-matcher": "^1.6.2",
"strnum": "^2.4.1",
"strnum": "^2.4.2",
"xml-naming": "^0.3.0"
},
"bin": {
@@ -3691,9 +3691,9 @@
}
},
"node_modules/globals": {
"version": "17.8.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-17.8.0.tgz",
"integrity": "sha512-Zz/LMDZScFmkakeL2cTHzf+PbWKdpU3uclqkZT7TjDG58j5WPt0PpA+n9uPI24fZtlw07q0OtEi84K+umsRzqQ==",
"version": "17.9.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-17.9.0.tgz",
"integrity": "sha512-m/MvAW61QVU5VDNF1Vj8axt016h8w7L5TU1e9zlab7XIttAT2YAlCwl75K1fOqvMM9apmD7lbCIRhpfkhmxhCg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -4714,9 +4714,9 @@
"license": "MIT"
},
"node_modules/lint-staged": {
"version": "17.2.0",
"resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-17.2.0.tgz",
"integrity": "sha512-FchGnFe4i4B1C/a35SPU9bNGPEHSC1+1iV0plLjzBmKVe9klZrlRfSgK6Cw4VeHyqOXbJUXP0vON61uRftNQ0A==",
"version": "17.3.0",
"resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-17.3.0.tgz",
"integrity": "sha512-woZS3vNe3UKqBaLPvbLOtKRY4tLANpWQhom12MGWqC8Mh1lCOO+WgSwmX2amjJAqTY9BkXYW87fCUH5H9Ph6xw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -5530,9 +5530,9 @@
}
},
"node_modules/strnum": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/strnum/-/strnum-2.4.1.tgz",
"integrity": "sha512-M9eUSMT2dCB2cTNPG7UYj6KuK7RJR2SN2+yCV/fTW3xzTCS6EaGZ5pSMgDIjB7r8zSfTGk+dvvn9rTjpVS9Mwg==",
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/strnum/-/strnum-2.4.2.tgz",
"integrity": "sha512-rDG3Ah4TV0k1hWvLSzkZtMmLN9+eS+h3knq4MP6A42Y3Yh5qGNnOUs1jJkoSr8FG5dsL28c7KgkIBzSEykqtuw==",
"funding": [
{
"type": "github",

View File

@@ -49,25 +49,25 @@
"@actions/http-client": "^4.0.1",
"@actions/io": "^3.0.2",
"@actions/tool-cache": "^4.0.0",
"fast-xml-parser": "^5.10.1",
"fast-xml-parser": "^5.11.0",
"semver": "^7.8.5"
},
"devDependencies": {
"@eslint/js": "^10.0.1",
"@jest/globals": "^30.4.1",
"@types/node": "^26.1.1",
"@types/semver": "^7.7.0",
"@typescript-eslint/eslint-plugin": "^8.64.0",
"@types/node": "^26.2.0",
"@types/semver": "^7.8.0",
"@typescript-eslint/eslint-plugin": "^8.67.0",
"@typescript-eslint/parser": "^8.65.0",
"@vercel/ncc": "^0.44.0",
"@vercel/ncc": "^0.45.0",
"eslint": "^10.7.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-jest": "^29.15.4",
"eslint-plugin-n": "^18.2.2",
"globals": "^17.7.0",
"eslint-plugin-jest": "^29.16.1",
"eslint-plugin-n": "^18.3.0",
"globals": "^17.9.0",
"husky": "^9.1.7",
"jest": "^30.4.2",
"lint-staged": "^17.2.0",
"lint-staged": "^17.3.0",
"prettier": "^3.9.5",
"ts-jest": "^29.4.11",
"typescript": "^6.0.3"

View File

@@ -9,18 +9,28 @@ import * as gpg from './gpg.js';
import {getBooleanInput} from './util.js';
import {escapeXmlText} from './xml.js';
export interface MavenServerCredentials {
id: string;
usernameEnvVar: string;
passwordEnvVar: string;
}
export interface MavenRepository {
id: string;
url: string;
snapshotsEnabled: boolean;
releasesEnabled?: boolean;
}
export interface MavenRepositorySettings {
repositories: MavenRepository[];
includeCentral: boolean;
prioritizeCentral: boolean;
}
export async function configureAuthentication() {
const id = core.getInput(constants.INPUT_SERVER_ID);
const usernameEnvVar = getInputWithDeprecatedAlias(
constants.INPUT_SERVER_USERNAME_ENV_VAR,
constants.INPUT_SERVER_USERNAME_DEPRECATED,
constants.INPUT_DEFAULT_SERVER_USERNAME
);
const passwordEnvVar = getInputWithDeprecatedAlias(
constants.INPUT_SERVER_PASSWORD_ENV_VAR,
constants.INPUT_SERVER_PASSWORD_DEPRECATED,
constants.INPUT_DEFAULT_SERVER_PASSWORD
);
const servers = getMavenServerSettings();
const repositorySettings = getMavenRepositorySettings();
const settingsDirectory =
core.getInput(constants.INPUT_SETTINGS_PATH) ||
path.join(os.homedir(), constants.M2_DIR);
@@ -42,12 +52,11 @@ export async function configureAuthentication() {
}
await createAuthenticationSettings(
id,
usernameEnvVar,
passwordEnvVar,
servers,
settingsDirectory,
overwriteSettings,
gpgPassphraseEnvVar
gpgPassphraseEnvVar,
repositorySettings
);
if (gpgPrivateKey) {
@@ -80,31 +89,179 @@ export function getInputWithDeprecatedAlias(
return value || deprecatedValue || defaultValue || '';
}
// only exported for testing purposes
export function getMavenServerSettings(): MavenServerCredentials[] {
const entries = core.getMultilineInput(
constants.INPUT_MVN_SERVER_CREDENTIALS
);
if (entries.some(entry => entry.trim())) {
return parseMavenServerCredentials(entries);
}
return [
{
id: core.getInput(constants.INPUT_SERVER_ID),
usernameEnvVar: getInputWithDeprecatedAlias(
constants.INPUT_SERVER_USERNAME_ENV_VAR,
constants.INPUT_SERVER_USERNAME_DEPRECATED,
constants.INPUT_DEFAULT_SERVER_USERNAME
),
passwordEnvVar: getInputWithDeprecatedAlias(
constants.INPUT_SERVER_PASSWORD_ENV_VAR,
constants.INPUT_SERVER_PASSWORD_DEPRECATED,
constants.INPUT_DEFAULT_SERVER_PASSWORD
)
}
];
}
// only exported for testing purposes
export function parseMavenServerCredentials(
entries: string[]
): MavenServerCredentials[] {
const servers: MavenServerCredentials[] = [];
const serverIds = new Set<string>();
entries.forEach((entry, index) => {
if (!entry.trim()) {
return;
}
const fields = entry.split(':');
if (fields.length !== 3) {
throw new Error(
`Invalid mvn-server-credentials entry at line ${index + 1}. Expected format: server-id:USERNAME_ENV:PASSWORD_ENV`
);
}
const [id, usernameEnvVar, passwordEnvVar] = fields.map(field =>
field.trim()
);
if (!id || !usernameEnvVar || !passwordEnvVar) {
throw new Error(
`Invalid mvn-server-credentials entry at line ${index + 1}. server-id, username environment variable, and password environment variable are required`
);
}
if (serverIds.has(id)) {
throw new Error(
`Duplicate server-id '${id}' in mvn-server-credentials input`
);
}
serverIds.add(id);
servers.push({id, usernameEnvVar, passwordEnvVar});
});
return servers;
}
// only exported for testing purposes
export function getMavenRepositorySettings():
MavenRepositorySettings | undefined {
const entries = core.getMultilineInput(constants.INPUT_MVN_REPOSITORIES);
if (!entries.some(entry => entry.trim())) {
return undefined;
}
const includeCentral = getBooleanInput(
constants.INPUT_MVN_REPOSITORIES_INCLUDE_CENTRAL,
true
);
return {
repositories: parseMavenRepositories(entries, includeCentral),
includeCentral,
prioritizeCentral: getBooleanInput(
constants.INPUT_MVN_REPOSITORIES_PRIORITIZE_CENTRAL,
true
)
};
}
// only exported for testing purposes
export function parseMavenRepositories(
entries: string[],
includeCentral: boolean
): MavenRepository[] {
const repositories: MavenRepository[] = [];
const repositoryIds = new Set<string>();
entries.forEach((entry, index) => {
if (!entry.trim()) {
return;
}
const firstSeparator = entry.indexOf(':');
const lastSeparator = entry.lastIndexOf(':');
if (firstSeparator <= 0 || lastSeparator <= firstSeparator) {
throw new Error(
`Invalid mvn-repositories entry at line ${index + 1}. Expected format: repository-id:repository-url:snapshots-enabled`
);
}
const id = entry.slice(0, firstSeparator).trim();
const url = entry.slice(firstSeparator + 1, lastSeparator).trim();
const snapshotsValue = entry
.slice(lastSeparator + 1)
.trim()
.toLowerCase();
if (!id || !url || !snapshotsValue) {
throw new Error(
`Invalid mvn-repositories entry at line ${index + 1}. repository-id, repository URL, and snapshots-enabled are required`
);
}
if (snapshotsValue !== 'true' && snapshotsValue !== 'false') {
throw new Error(
`Invalid snapshots-enabled value '${snapshotsValue}' in mvn-repositories entry at line ${index + 1}. Expected true or false`
);
}
if (repositoryIds.has(id)) {
throw new Error(
`Duplicate repository-id '${id}' in mvn-repositories input`
);
}
if (includeCentral && id === constants.MAVEN_CENTRAL_REPOSITORY_ID) {
throw new Error(
`Repository-id '${constants.MAVEN_CENTRAL_REPOSITORY_ID}' is reserved when ${constants.INPUT_MVN_REPOSITORIES_INCLUDE_CENTRAL} is enabled`
);
}
repositoryIds.add(id);
repositories.push({
id,
url,
snapshotsEnabled: snapshotsValue === 'true'
});
});
return repositories;
}
export async function createAuthenticationSettings(
id: string,
usernameEnvVar: string,
passwordEnvVar: string,
servers: MavenServerCredentials[],
settingsDirectory: string,
overwriteSettings: boolean,
gpgPassphraseEnvVar: string | undefined = undefined
gpgPassphraseEnvVar: string | undefined = undefined,
repositorySettings: MavenRepositorySettings | undefined = undefined
) {
core.info(`Creating ${constants.MVN_SETTINGS_FILE} with server-id: ${id}`);
core.info(
`Creating ${constants.MVN_SETTINGS_FILE} with server-id: ${servers.map(server => server.id).join(', ')}`
);
// when an alternate m2 location is specified use only that location (no .m2 directory)
// otherwise use the home/.m2/ path
await io.mkdirP(settingsDirectory);
await write(
settingsDirectory,
generate(id, usernameEnvVar, passwordEnvVar, gpgPassphraseEnvVar),
generate(servers, gpgPassphraseEnvVar, repositorySettings),
overwriteSettings
);
}
// only exported for testing purposes
export function generate(
id: string,
usernameEnvVar: string,
passwordEnvVar: string,
gpgPassphraseEnvVar?: string | undefined
servers: MavenServerCredentials[],
gpgPassphraseEnvVar?: string | undefined,
repositorySettings?: MavenRepositorySettings | undefined
) {
// The maven-gpg-plugin reads the passphrase from the environment variable
// named by the `gpg.passphraseEnvName` property (default MAVEN_GPG_PASSPHRASE).
@@ -121,30 +278,90 @@ 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</interactiveMode>',
' <servers>',
' <server>',
` <id>${escapeXmlText(id)}</id>`,
` <username>${escapeXmlText(`\${env.${usernameEnvVar}}`)}</username>`,
` <password>${escapeXmlText(`\${env.${passwordEnvVar}}`)}</password>`,
' </server>',
' </servers>'
' <servers>'
];
if (includeGpgPassphraseProfile) {
for (const server of servers) {
lines.push(
' <profiles>',
' <profile>',
` <id>${constants.GPG_PASSPHRASE_PROFILE_ID}</id>`,
' <properties>',
` <gpg.passphraseEnvName>${escapeXmlText(gpgPassphraseEnvVar)}</gpg.passphraseEnvName>`,
' </properties>',
' </profile>',
' </profiles>',
' <activeProfiles>',
` <activeProfile>${constants.GPG_PASSPHRASE_PROFILE_ID}</activeProfile>`,
' </activeProfiles>'
' <server>',
` <id>${escapeXmlText(server.id)}</id>`,
` <username>${escapeXmlText(`\${env.${server.usernameEnvVar}}`)}</username>`,
` <password>${escapeXmlText(`\${env.${server.passwordEnvVar}}`)}</password>`,
' </server>'
);
}
lines.push(' </servers>');
if (repositorySettings || includeGpgPassphraseProfile) {
lines.push(' <profiles>');
if (repositorySettings) {
const centralRepository: MavenRepository = {
id: constants.MAVEN_CENTRAL_REPOSITORY_ID,
url: constants.MAVEN_CENTRAL_REPOSITORY_URL,
snapshotsEnabled: false
};
const customCentralConfigured = repositorySettings.repositories.some(
repository => repository.id === constants.MAVEN_CENTRAL_REPOSITORY_ID
);
const repositories = repositorySettings.includeCentral
? repositorySettings.prioritizeCentral
? [centralRepository, ...repositorySettings.repositories]
: [...repositorySettings.repositories, centralRepository]
: customCentralConfigured
? repositorySettings.repositories
: [
...repositorySettings.repositories,
{...centralRepository, releasesEnabled: false}
];
lines.push(
' <profile>',
` <id>${constants.MAVEN_REPOSITORIES_PROFILE_ID}</id>`,
' <repositories>'
);
for (const repository of repositories) {
lines.push(
' <repository>',
` <id>${escapeXmlText(repository.id)}</id>`,
` <url>${escapeXmlText(repository.url)}</url>`,
...(repository.releasesEnabled === undefined
? []
: [
' <releases>',
` <enabled>${repository.releasesEnabled}</enabled>`,
' </releases>'
]),
' <snapshots>',
` <enabled>${repository.snapshotsEnabled}</enabled>`,
' </snapshots>',
' </repository>'
);
}
lines.push(' </repositories>', ' </profile>');
}
if (includeGpgPassphraseProfile) {
lines.push(
' <profile>',
` <id>${constants.GPG_PASSPHRASE_PROFILE_ID}</id>`,
' <properties>',
` <gpg.passphraseEnvName>${escapeXmlText(gpgPassphraseEnvVar)}</gpg.passphraseEnvName>`,
' </properties>',
' </profile>'
);
}
lines.push(' </profiles>', ' <activeProfiles>');
if (repositorySettings) {
lines.push(
` <activeProfile>${constants.MAVEN_REPOSITORIES_PROFILE_ID}</activeProfile>`
);
}
if (includeGpgPassphraseProfile) {
lines.push(
` <activeProfile>${constants.GPG_PASSPHRASE_PROFILE_ID}</activeProfile>`
);
}
lines.push(' </activeProfiles>');
}
lines.push('</settings>');
return lines.join('\n');

View File

@@ -12,6 +12,12 @@ export const INPUT_SET_DEFAULT = 'set-default';
export const INPUT_PROBLEM_MATCHER = 'problem-matcher';
export const INPUT_VERIFY_SIGNATURE = 'verify-signature';
export const INPUT_VERIFY_SIGNATURE_PUBLIC_KEY = 'verify-signature-public-key';
export const INPUT_MVN_SERVER_CREDENTIALS = 'mvn-server-credentials';
export const INPUT_MVN_REPOSITORIES = 'mvn-repositories';
export const INPUT_MVN_REPOSITORIES_INCLUDE_CENTRAL =
'mvn-repositories-include-central';
export const INPUT_MVN_REPOSITORIES_PRIORITIZE_CENTRAL =
'mvn-repositories-prioritize-central';
export const INPUT_SERVER_ID = 'server-id';
export const INPUT_SERVER_USERNAME_ENV_VAR = 'server-username-env-var';
export const INPUT_SERVER_PASSWORD_ENV_VAR = 'server-password-env-var';
@@ -35,6 +41,10 @@ export const MAVEN_GPG_PASSPHRASE_DEFAULT_ENV = 'MAVEN_GPG_PASSPHRASE';
// Id of the settings.xml profile used to set `gpg.passphraseEnvName`.
export const GPG_PASSPHRASE_PROFILE_ID = 'setup-java-gpg';
export const MAVEN_REPOSITORIES_PROFILE_ID = 'setup-java-repositories';
export const MAVEN_CENTRAL_REPOSITORY_ID = 'central';
export const MAVEN_CENTRAL_REPOSITORY_URL =
'https://repo.maven.apache.org/maven2';
export const INPUT_CACHE = 'cache';
export const INPUT_CACHE_JDK = 'cache-jdk';

View File

@@ -68,7 +68,8 @@ export abstract class JavaBase {
installerOptions.setDefault !== undefined
? installerOptions.setDefault
: true;
this.verifySignature = installerOptions.verifySignature ?? false;
this.verifySignature =
installerOptions.verifySignature ?? this.supportsSignatureVerification();
this.verifySignaturePublicKey = installerOptions.verifySignaturePublicKey;
}

View File

@@ -98,6 +98,10 @@ export async function getJavaDistribution(
const {OpenJdkDistribution} = await import('./openjdk/installer.js');
return new OpenJdkDistribution(normalizedInstallerOptions);
}
case JavaDistribution.RedHat: {
const {RedHatDistribution} = await import('./redhat/installer.js');
return new RedHatDistribution(normalizedInstallerOptions);
}
default:
return null;
}

View File

@@ -17,7 +17,8 @@ export enum JavaDistribution {
GraalVMCommunity = 'graalvm-community',
JetBrains = 'jetbrains',
Kona = 'kona',
OracleOpenJdk = 'oracle-openjdk'
OracleOpenJdk = 'oracle-openjdk',
RedHat = 'redhat'
}
export const JAVA_PACKAGE_CAPABILITIES = {
@@ -50,7 +51,8 @@ export const JAVA_PACKAGE_CAPABILITIES = {
'jre+ft'
],
[JavaDistribution.Kona]: ['jdk'],
[JavaDistribution.OracleOpenJdk]: ['jdk']
[JavaDistribution.OracleOpenJdk]: ['jdk'],
[JavaDistribution.RedHat]: ['jdk', 'jre']
} as const satisfies Record<JavaDistribution, readonly string[]>;
export function validateJavaPackage(

View File

@@ -145,6 +145,19 @@ export const JAVA_PLATFORM_CAPABILITIES: Record<
macos: X64_ARM64,
windows: ['x64']
}
},
[JavaDistribution.RedHat]: {
platforms: {
linux: [
'x64',
{architecture: 'aarch64', versionRange: '<12'},
{architecture: 'ppc64le', versionRange: '<12'}
],
windows: [
{architecture: 'x64', versionRange: '<22'},
{architecture: 'x86', versionRange: '<11'}
]
}
}
};

View File

@@ -0,0 +1,180 @@
import * as core from '@actions/core';
import fs from 'fs';
import path from 'path';
import semver from 'semver';
import {
cacheJdkDir,
extractJdkFile,
isVersionSatisfies,
renameWinArchive
} from '../../util.js';
import {JavaBase} from '../base-installer.js';
import {
JavaDownloadRelease,
JavaInstallerOptions,
JavaInstallerResults
} from '../base-models.js';
import {
IDiscoPackage,
IDiscoPackageDetailsResponse,
IDiscoPackageListResponse
} from './models.js';
import {isAlpineLinux} from '../platform-types.js';
const DISCO_API_URL = 'https://api.foojay.io/disco/v3.0';
export class RedHatDistribution extends JavaBase {
constructor(installerOptions: JavaInstallerOptions) {
super('RedHat', installerOptions);
}
protected async findPackageForDownload(
range: string
): Promise<JavaDownloadRelease> {
if (!this.stable) {
throw new Error('Early access versions are not supported');
}
const availablePackages = await this.getAvailablePackages();
const normalizedPackages = availablePackages
.map(item => ({
item,
version: this.normalizeDiscoVersion(item.java_version)
}))
.filter(
(item): item is {item: IDiscoPackage; version: string} =>
item.version !== null
)
.sort((left, right) => -semver.compareBuild(left.version, right.version));
const selectedPackage = normalizedPackages.find(item =>
isVersionSatisfies(range, item.version)
);
if (!selectedPackage) {
throw this.createVersionNotFoundError(
range,
normalizedPackages.map(item => item.version),
`Operating system: ${this.getOperatingSystem()}`
);
}
const detailsUrl = `${DISCO_API_URL}/ids/${selectedPackage.item.id}`;
const response =
await this.http.getJson<IDiscoPackageDetailsResponse>(detailsUrl);
const details = response.result?.result?.[0];
if (!details?.direct_download_uri) {
throw new Error(
`Foojay Disco returned no direct Red Hat download URL for package '${selectedPackage.item.id}'.`
);
}
const checksum = details.checksum?.trim();
if (details.checksum_type?.toLowerCase() !== 'sha256' || !checksum) {
throw new Error(
`Foojay Disco returned no SHA-256 checksum for Red Hat package '${selectedPackage.item.id}'.`
);
}
return {
version: selectedPackage.version,
url: details.direct_download_uri,
checksum: {
algorithm: 'sha256',
value: checksum,
source: detailsUrl
}
};
}
protected async downloadTool(
javaRelease: JavaDownloadRelease
): Promise<JavaInstallerResults> {
core.info(
`Downloading Java ${javaRelease.version} (${this.distribution}) from ${javaRelease.url} ...`
);
let javaArchivePath = await this.downloadAndVerify(javaRelease);
core.info('Extracting Java archive...');
const archiveType = this.getArchiveType();
if (archiveType === 'zip') {
javaArchivePath = renameWinArchive(javaArchivePath);
}
const extractedJavaPath = await extractJdkFile(
javaArchivePath,
archiveType
);
const archiveName = fs.readdirSync(extractedJavaPath)[0];
if (!archiveName) {
throw new Error(
`The Red Hat archive for Java ${javaRelease.version} was empty.`
);
}
const archivePath = path.join(extractedJavaPath, archiveName);
const javaPath = await cacheJdkDir(
archivePath,
this.toolcacheFolderName,
this.getToolcacheVersionName(javaRelease.version),
this.architecture
);
return {version: javaRelease.version, path: javaPath};
}
private async getAvailablePackages(): Promise<IDiscoPackage[]> {
const operatingSystem = this.getOperatingSystem();
const archiveType = this.getArchiveType();
const query = new URLSearchParams({
distro: 'redhat',
release_status: 'ga',
operating_system: operatingSystem,
architecture: this.distributionArchitecture(),
package_type: this.packageType,
archive_type: archiveType,
directly_downloadable: 'true'
});
const url = `${DISCO_API_URL}/packages?${query.toString()}`;
const response = await this.http.getJson<IDiscoPackageListResponse>(url);
const packages = response.result?.result;
if (!Array.isArray(packages)) {
throw new Error(
`Could not fetch Red Hat package metadata from Foojay Disco: ${url}`
);
}
return packages.filter(
item =>
item.distribution === 'redhat' &&
item.release_status === 'ga' &&
item.operating_system === operatingSystem &&
item.architecture === this.distributionArchitecture() &&
item.package_type === this.packageType &&
item.archive_type === archiveType &&
item.directly_downloadable
);
}
private getOperatingSystem(alpine = isAlpineLinux()): string {
if (alpine) {
throw new Error(
"Distribution 'redhat' does not support Alpine Linux because Red Hat portable archives require glibc."
);
}
return process.platform === 'win32' ? 'windows' : 'linux';
}
private getArchiveType(): string {
return process.platform === 'win32' ? 'zip' : 'tar.xz';
}
private normalizeDiscoVersion(version: string): string | null {
let normalizedVersion = version.trim();
if (/^\d+\+\d+$/.test(normalizedVersion)) {
normalizedVersion = normalizedVersion.replace('+', '.0.0+');
} else if (/^\d+$/.test(normalizedVersion)) {
normalizedVersion = `${normalizedVersion}.0.0`;
} else if (/^\d+\.\d+$/.test(normalizedVersion)) {
normalizedVersion = `${normalizedVersion}.0`;
}
return semver.valid(normalizedVersion) ? normalizedVersion : null;
}
}

View File

@@ -0,0 +1,28 @@
export interface IDiscoPackage {
id: string;
archive_type: string;
distribution: string;
java_version: string;
release_status: string;
operating_system: string;
architecture: string;
package_type: string;
directly_downloadable: boolean;
}
export interface IDiscoPackageListResponse {
result: IDiscoPackage[];
message: string;
}
export interface IDiscoPackageDetails {
filename: string;
direct_download_uri: string;
checksum: string;
checksum_type: string;
}
export interface IDiscoPackageDetailsResponse {
result: IDiscoPackageDetails[];
message: string;
}

View File

@@ -29,10 +29,6 @@ export async function run() {
const checkLatest = getBooleanInput(constants.INPUT_CHECK_LATEST, false);
const forceDownload = getBooleanInput(constants.INPUT_FORCE_DOWNLOAD, 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;
const toolchainIds = core.getMultilineInput(constants.INPUT_MVN_TOOLCHAIN_ID);
@@ -80,6 +76,8 @@ export async function run() {
);
}
const verifySignature = getVerifySignatureInput();
const installerInputsOptions: installerInputsOptions = {
architecture,
packageType,
@@ -107,6 +105,8 @@ export async function run() {
throw new Error('distribution input is required');
}
const verifySignature = getVerifySignatureInput();
const installerInputsOptions: installerInputsOptions = {
architecture,
packageType,
@@ -192,6 +192,12 @@ function getJdkFileInput(): string {
return jdkFile || deprecatedJdkFile;
}
function getVerifySignatureInput(): boolean | undefined {
return core.getInput(constants.INPUT_VERIFY_SIGNATURE).trim()
? getBooleanInput(constants.INPUT_VERIFY_SIGNATURE)
: undefined;
}
async function installVersion(
version: string,
options: installerInputsOptions,
@@ -263,7 +269,7 @@ interface installerInputsOptions {
forceDownload: boolean;
cacheJdk: boolean;
setDefault: boolean;
verifySignature: boolean;
verifySignature: boolean | undefined;
verifySignaturePublicKey: string | undefined;
distributionName: string;
jdkFile: string;

View File

@@ -59,7 +59,9 @@ export async function extractJdkFile(toolPath: string, extension?: string) {
if (!extension) {
extension = toolPath.endsWith('.tar.gz')
? 'tar.gz'
: path.extname(toolPath);
: toolPath.endsWith('.tar.xz')
? 'tar.xz'
: path.extname(toolPath);
if (extension.startsWith('.')) {
extension = extension.substring(1);
}
@@ -68,6 +70,8 @@ export async function extractJdkFile(toolPath: string, extension?: string) {
switch (extension) {
case 'tar.gz':
return await extractTarGz(toolPath);
case 'tar.xz':
return await tc.extractTar(toolPath, undefined, 'xJ');
case 'tar':
return await tc.extractTar(toolPath);
case 'zip':