Compare commits

..

48 Commits

Author SHA1 Message Date
copilot-swe-agent[bot] 2061db5b9b test: fix graalvm installer test formatting 2026-06-23 01:29:03 +00:00
Bruno Borges c1835719f6 Merge branch 'main' into copilot/add-graalvm-community-edition 2026-06-22 18:16:10 -04:00
copilot-swe-agent[bot] 8a5fc42d92 refactor: rename pagination index for clarity 2026-06-22 22:13:29 +00:00
copilot-swe-agent[bot] 05917d5627 refactor: address review feedback on Community resolver 2026-06-22 22:11:16 +00:00
copilot-swe-agent[bot] 651865a8a8 refactor: simplify GraalVM Community release resolution 2026-06-22 22:08:46 +00:00
Copilot 5431e71f9a docs: add JavaFX Maven project configuration instructions (#1044)
* Initial plan

* docs: add JavaFX Maven project configuration instructions

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Bruno Borges <brborges@microsoft.com>
2026-06-22 18:04:38 -04:00
Copilot 4baa9b45d2 docs: replace non-existent HelloWorldApp references with java --version (#1043)
* Initial plan

* docs: replace HelloWorldApp references with java --version in README and advanced-usage

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-06-22 17:59:24 -04:00
Bruno Borges 34df7e6dff Merge branch 'main' into copilot/add-graalvm-community-edition 2026-06-22 17:45:12 -04:00
dependabot[bot] eab4b0854d Bump @types/node from 25.9.3 to 26.0.0 (#1031)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 25.9.3 to 26.0.0.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 26.0.0
  dependency-type: direct:development
  update-type: version-update:semver-major
...

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 <bruno.borges@gmail.com>
Co-authored-by: Bruno Borges <brborges@microsoft.com>
2026-06-22 17:16:03 -04:00
dependabot[bot] bf0c0e6df3 Bump actions/checkout from 6 to 7 (#1032)
Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

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-06-22 17:15:27 -04:00
Milos Pantic 92163d3dc6 Templates for new Java distributions (#429)
* Add templates for new Java distributions

* Update new pull request template

* Potential fix for pull request finding

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

* Address PR #429 review suggestions

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

---------

Co-authored-by: Bruno Borges <bruno.borges@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Bruno Borges <brborges@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-22 17:11:20 -04:00
Stephan Abel 679e4e46a7 docs: enhance custom jdk file installation (#996)
* docs: enhance custom jdk file installation

* Update jdkFile note for case sensitivity

Clarify that 'distribution' must be set to 'jdkfile' in lowercase when using jdkFile input.

---------

Co-authored-by: Bruno Borges <brborges@microsoft.com>
Co-authored-by: Bruno Borges <bruno.borges@gmail.com>
2026-06-22 17:10:15 -04:00
Bruno Borges 525097081d Update undici artifacts to 6.27.0 (license cache + dist) (#1040)
* Update undici license cache to 6.27.0

The Licensed check failed because the cached license record for undici
was pinned to 6.24.1 while the installed dependency is 6.27.0, causing
"license: mit, allowed: false" / source enumeration errors.

Regenerate the cached record with `licensed cache` so it matches the
installed version. `licensed status` now reports 0 errors.

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

* Rebuild dist with undici 6.27.0

The committed dist/ bundle was built with undici 6.24.1, but the
lockfile resolves undici 6.27.0. The check-dist workflow rebuilds the
bundle and detected this drift (uncommitted changes after build).

Rebuild dist/setup and dist/cleanup with `npm run build` so the
committed bundle matches the installed undici 6.27.0, aligning with the
license cache update in this PR.

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

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-22 16:43:17 -04:00
Copilot c09b25f3e7 Clarify README version syntax and migration guidance (#1038)
* Initial plan

* Clarify README version guidance

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-06-22 16:38:14 -04:00
Trass3r dc8e16ad37 add javac problem matcher (#562)
* add javac problemMatcher

* fix spaces

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

---------

Co-authored-by: Bruno Borges <bruno.borges@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-22 16:37:47 -04:00
copilot-swe-agent[bot] a263f84254 fix: tidy graalvm community validation follow-ups 2026-06-22 20:33:22 +00:00
copilot-swe-agent[bot] 6929a11922 chore: address GraalVM community review feedback 2026-06-22 20:30:01 +00:00
copilot-swe-agent[bot] ad52b8c6db build: update bundled dist for graalvm community support 2026-06-22 20:27:32 +00:00
copilot-swe-agent[bot] 2321ab295d feat: add graalvm community distribution support 2026-06-22 20:26:30 +00:00
Bruno Borges 3d27da4ac1 Update contributor guide with emoji for clarity (#1028) 2026-06-22 16:21:54 -04:00
copilot-swe-agent[bot] 849c8f0094 Initial plan 2026-06-22 20:19:46 +00:00
dependabot[bot] cefdecda46 Bump undici from 6.24.1 to 6.27.0 (#1033)
Bumps [undici](https://github.com/nodejs/undici) from 6.24.1 to 6.27.0.
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](https://github.com/nodejs/undici/compare/v6.24.1...v6.27.0)

---
updated-dependencies:
- dependency-name: undici
  dependency-version: 6.27.0
  dependency-type: indirect
...

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 <bruno.borges@gmail.com>
2026-06-22 13:07:33 -04:00
Markus Hoffrogge 347226bb3b Update README.md - use "alert syntax for Markdown" for notes (#924) 2026-06-22 11:58:00 -04:00
alexander 5866e121b4 feat: add microsoft openjdk 17.0.18 (#1002)
* feat: add microsoft openjdk 17.0.18

* fix: correct url microsoft-jdk-17.0.10-macos-x64
2026-06-22 11:56:08 -04:00
Kranthi Poturaju 2872526dc6 docs(action): fix missing required or default fields (#1007)
- Add required: false to java-version, java-version-file, job-status, and token, which had defaults or were optional but lacked the explicit flag
- Add default: '' to gpg-private-key to match its stated description
- Fix java-version-file description: the input accepts .java-version, .tool-versions, and .sdkmanrc, not only .java-version
- Fix gpg-passphrase description: GPG_PASSPHRASE is only defaulted when gpg-private-key is provided, not unconditionally

Co-authored-by: Kranthi Poturaju <Kranthi.Poturaju1@aexp.com>
Co-authored-by: Panuganti Saketh <sakethpanuganti@gmail.com>
Co-authored-by: Bruno Borges <bruno.borges@gmail.com>
2026-06-22 11:17:16 -04:00
Robert Stoll bb8b13a4a5 add link to advanced configuration for JetBrains (#850) 2026-06-22 11:13:36 -04:00
Josh Soref 957ad8b43e Spelling (#713)
* spelling: aarch

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: cannot

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: guaranteed

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: its

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: macos

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: on the fly

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: warn/fail

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* link: more information about ADRs

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* link: Distribution / Official site

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* link: License

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

---------

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
Co-authored-by: Bruno Borges <bruno.borges@gmail.com>
2026-06-22 10:57:54 -04:00
mahabaleshwars ce7f9ce621 Add Maven Wrapper cache feature (#1027)
* add Maven Wrapper distribution caching

* update test case

---------

Co-authored-by: Bruno Borges <bruno.borges@gmail.com>
2026-06-22 09:45:18 -05:00
Jason Ginchereau 6e9017e125 Bump @actions/cache to 5.1.0, handle cache write denied (#1026) 2026-06-22 09:16:01 +01:00
Sean Proctor baa1691374 fix: reject non-semver candidate versions in isVersionSatisfies (#1009)
Distributions like JetBrains Runtime publish 4-segment versions such as
'17.0.8.1+1080.1' that the semver package rejects. Both compareBuild and
satisfies throw on these, which surfaced to users as "Error: Invalid
Version: 17.0.8.1+1080.1" and aborted the whole install when any
available version was non-semver. Guard with an early semver.valid check
so unparseable versions are treated as a non-match.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-17 22:47:02 -05:00
George Adams bc52a13212 fix CodeQL permissions (#1025) 2026-06-17 07:58:23 -07:00
Josh Soref c9b6aee07e Fix codeql workflow permissions (#993)
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2026-06-17 07:52:02 -07:00
dependabot[bot] f300429fba Bump @typescript-eslint/parser from 8.48.0 to 8.61.1 (#1021)
* Bump @typescript-eslint/parser from 8.48.0 to 8.61.1

Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 8.48.0 to 8.61.1.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.61.1/packages/parser)

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

Signed-off-by: dependabot[bot] <support@github.com>

* run licensed and update dist

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: George Adams <georgeadams1995@gmail.com>
2026-06-16 15:12:38 -07:00
dependabot[bot] ad2b38190b Bump @vercel/ncc from 0.38.1 to 0.44.0 (#1018)
* Bump @vercel/ncc from 0.38.1 to 0.44.0

Bumps [@vercel/ncc](https://github.com/vercel/ncc) from 0.38.1 to 0.44.0.
- [Release notes](https://github.com/vercel/ncc/releases)
- [Commits](https://github.com/vercel/ncc/compare/0.38.1...0.44.0)

---
updated-dependencies:
- dependency-name: "@vercel/ncc"
  dependency-version: 0.44.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* recompile dist

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: George Adams <georgeadams1995@gmail.com>
2026-06-16 09:37:47 +02:00
John b24df5bba5 Make the Adoptopenjdk package type look at the Temurin repo first for latest assets (#522)
* Make the Adoptopenjdk package type look at the Temurin repo first for latest assets

* Address Copilot code review comments

- Use strict equality (===, !==) instead of loose equality (==, !=) for all comparisons
- Properly handle caught errors with instanceof type narrowing before accessing properties
- Only fall back to legacy AdoptOpenJDK for specific version-not-found errors
- Rethrow unexpected errors to avoid masking real issues (network failures, rate limits, etc.)
- Fix error message check to match actual error text ('No matching version found')
- Remove unnecessary undefined check since method return type is never undefined
- Add @internal JSDoc annotation to TemurinDistribution.findPackageForDownload()
- Update tests to properly mock Temurin lookup failures for fallback behavior testing
- Rebuild dist files

* Always fall back to legacy AdoptOpenJDK but log all Temurin failures

- Change error handling to gracefully fall back for all errors, not just version-not-found
- Log version-not-found errors as notices with migration guidance
- Log other Temurin failures as debug messages for troubleshooting
- Improves resilience: users always get a result even if Temurin API has issues
- Maintains visibility: failures are still logged for debugging

* Fixes from review

* Fixes from review

* Fixes from review

* Regenerate dist
2026-06-12 16:30:59 +01:00
John 43120bc3c3 Implement pagination with link headers for Adoptium based apis (#1014)
* Use Link headers for Adoptium pagination

* Fix nullable pagination URL types and rebuild dist

* Add 1000-page safeguard for JetBrains pagination

* Adjust plan for pagination safeguard scope

* Move pagination safeguard to non-JetBrains installers

* Add 1000-page safeguard to Adopt Temurin and Semeru pagination

* Fix Prettier formatting in adopt, semeru, and temurin installer files

* Fix CI audit failure by updating vulnerable transitive deps

* Address PR review: RFC-compliant Link parsing, SSRF validation, centralized constant

- Make getNextPageUrlFromLinkHeader RFC 8288 compliant by splitting
  link-values and checking for rel=next anywhere in the parameters,
  not just as the first parameter after the semicolon.
- Add validatePaginationUrl utility to reject pagination URLs that
  point to unexpected origins (SSRF mitigation).
- Centralize MAX_PAGINATION_PAGES in util.ts instead of duplicating
  across Adopt, Semeru, and Temurin installers.
- Add tests for rel not being the first parameter, and for URL
  origin validation.

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

* Address code review feedback on pagination implementation

- Tighten rel regex with word boundary to prevent false positives
  (e.g., rel="nextsomething" no longer matches).
- Use parsed.origin comparison in validatePaginationUrl to correctly
  handle explicit default ports (e.g., :443 for HTTPS).
- Fix pagination safeguard tests to use same-origin URLs so they
  actually exercise the 1000-page limit instead of being rejected
  by origin validation on the first request.
- Add test for rel="nextsomething" not matching.
- Add test for explicit default port acceptance.

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

* Fix prettier formatting in util.test.ts

* Rebuild dist/ to fix check-dist CI failure

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-12 11:50:16 +01:00
dependabot[bot] ad9d6a6320 Bump @types/node from 24.1.0 to 25.9.3 (#950)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 24.1.0 to 25.9.3.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 24.9.1
  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-06-12 10:21:27 +01:00
dependabot[bot] 039af37997 Bump picomatch, @types/jest, jest, jest-circus and ts-jest (#1016)
* Bump picomatch, @types/jest, jest, jest-circus and ts-jest

Bumps [picomatch](https://github.com/micromatch/picomatch) to 4.0.4 and updates ancestor dependencies [picomatch](https://github.com/micromatch/picomatch), [@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest), [jest](https://github.com/jestjs/jest/tree/HEAD/packages/jest), [jest-circus](https://github.com/jestjs/jest/tree/HEAD/packages/jest-circus) and [ts-jest](https://github.com/kulshekhar/ts-jest). These dependencies need to be updated together.


Updates `picomatch` from 4.0.3 to 4.0.4
- [Release notes](https://github.com/micromatch/picomatch/releases)
- [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/picomatch/compare/4.0.3...4.0.4)

Updates `@types/jest` from 29.5.14 to 30.0.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jest)

Updates `jest` from 29.7.0 to 30.4.2
- [Release notes](https://github.com/jestjs/jest/releases)
- [Changelog](https://github.com/jestjs/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jestjs/jest/commits/v30.4.2/packages/jest)

Updates `jest-circus` from 29.7.0 to 30.4.2
- [Release notes](https://github.com/jestjs/jest/releases)
- [Changelog](https://github.com/jestjs/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jestjs/jest/commits/v30.4.2/packages/jest-circus)

Updates `ts-jest` from 29.3.0 to 29.4.11
- [Release notes](https://github.com/kulshekhar/ts-jest/releases)
- [Changelog](https://github.com/kulshekhar/ts-jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/kulshekhar/ts-jest/compare/v29.3.0...v29.4.11)

---
updated-dependencies:
- dependency-name: "@types/jest"
  dependency-version: 30.0.0
  dependency-type: direct:development
- dependency-name: jest
  dependency-version: 30.4.2
  dependency-type: direct:development
- dependency-name: jest-circus
  dependency-version: 30.4.2
  dependency-type: direct:development
- dependency-name: picomatch
  dependency-version: 4.0.4
  dependency-type: indirect
- dependency-name: ts-jest
  dependency-version: 29.4.11
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>

* run licensed and update dist

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: George Adams <georgeadams1995@gmail.com>
2026-06-12 10:05:41 +01:00
dependabot[bot] 1756ab6acd Bump eslint-config-prettier from 8.10.0 to 10.1.8 (#881)
Bumps [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier) from 8.10.0 to 10.1.8.
- [Release notes](https://github.com/prettier/eslint-config-prettier/releases)
- [Changelog](https://github.com/prettier/eslint-config-prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/eslint-config-prettier/compare/v8.10.0...v10.1.8)

---
updated-dependencies:
- dependency-name: eslint-config-prettier
  dependency-version: 10.1.8
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-12 09:55:04 +01:00
dependabot[bot] 662bb59f48 Bump @typescript-eslint/eslint-plugin from 8.35.1 to 8.46.2 (#952)
Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 8.35.1 to 8.46.2.
- [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.46.2/packages/eslint-plugin)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-version: 8.46.2
  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-06-12 09:52:03 +01:00
George Adams 1071fc12d6 fix: resolve npm audit vulnerabilities in fast-xml-builder and fast-xml-parser (#1015)
* fix: update dependency license records and resolve npm audit vulnerabilities

- Bump fast-xml-builder 1.1.4 → 1.2.0 (GHSA-5wm8-gmm8-39j9)
- Bump fast-xml-parser 5.5.10 → 5.8.0 (GHSA-gh4j-gqv2-49f6)
- Bump strnum 2.2.3 → 2.4.0
- Bump path-expression-matcher 1.4.0 → 1.5.0
- Add license records for new deps @nodable/entities and xml-naming

* fix: add anynum license record and rebuild dist

* re-run licensed
2026-06-12 09:49:51 +01:00
George Adams 576b821f29 Merge pull request #674 from gdams/alpine
temurin: add support for Alpine Linux
2026-06-12 09:18:56 +01:00
mahabaleshwars 307d3a25a0 update readme for ubuntu sudo java_home behavior (#1013) 2026-06-08 11:34:56 -05:00
mahabaleshwars b622de1dfa Add Oracle JDK 17 licensing limitation note (#1001)
* note for oracle jdk17. in Readme.md

* docs: fix Oracle JDK 17 NOTE

* docs: fix duplicate NOTE prefix and improve Oracle JDK 17 license link phrasing in READMEn
2026-04-15 12:33:22 -05:00
Copilot c76542e033 chore: upgrade dependencies (@actions/core, cache, glob, http-client, tool-cache, xmlbuilder2) (#999)
* chore: upgrade dependencies and update license cache

Agent-Logs-Url: https://github.com/actions/setup-java/sessions/55ba1e4b-a515-4177-8a35-44bffa4ad0c0

Co-authored-by: lmvysakh <187510632+lmvysakh@users.noreply.github.com>

* chore: upgrade @actions/exec ^1.0.4→^2.0.0 and @actions/io ^1.0.2→^2.0.0

Agent-Logs-Url: https://github.com/actions/setup-java/sessions/8be3df50-f347-42da-9734-73f71bf89d40

Co-authored-by: lmvysakh <187510632+lmvysakh@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: lmvysakh <187510632+lmvysakh@users.noreply.github.com>
2026-04-15 12:30:24 -05:00
Chiranjib Swain 0756542bc5 Refactor error handling and improve test logging for installers (#989)
* Refactor error handling for version not found cases across multiple installers

* Mock core.error in tests to suppress error logs

* fix(graalvm): improve error messages for EA version not found scenarios

* refactor(tests): update error messages for version not found scenarios

* fix(graalvm): enhance error messages for version not found scenarios

* fix(graalvm): improve error messages for version not found scenarios with updated download URL

* fix(graalvm): improve error handling for EA version not found scenarios with clearer messages
2026-04-13 12:44:45 -05:00
dependabot[bot] 1d018f9b8b Bump minimatch from 3.1.2 to 3.1.5 (#984)
* Bump minimatch from 3.1.2 to 3.1.5

Bumps [minimatch](https://github.com/isaacs/minimatch) from 3.1.2 to 3.1.5.
- [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md)
- [Commits](https://github.com/isaacs/minimatch/compare/v3.1.2...v3.1.5)

---
updated-dependencies:
- dependency-name: minimatch
  dependency-version: 3.1.5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* Check failure fix

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: gowridurgad <gowridurgad@gmail.com>
2026-03-02 15:50:04 -06:00
ian zhang fe779bf55e feat(readme): update Java version to 25 in setup examples (#969)
Updated the Java version in the README setup examples from 21 to 25
to reflect the latest supported version. This change ensures that
users are guided to use the most current Java version for their
projects.

- Updated all instances of 'java-version: 21' to 'java-version: 25'
- Modified supported version syntax to include '25'
2026-02-19 11:38:18 -06:00
95 changed files with 61466 additions and 60367 deletions
@@ -0,0 +1,22 @@
---
name: New Java distribution template
about: Suggest a new Java distribution
title: ''
labels: feature request, needs triage
assignees: ''
---
**Description:**
Describe your proposal.
**Justification:**
Justification or a use case for your proposal.
**Download URL:**
Download URL for the new distribution.
**License:**
Link to the license for the new distribution.
**Are you willing to submit a PR?**
<!--- We accept contributions! -->
@@ -0,0 +1,16 @@
**Description:**
Describe your changes.
**Related issue:**
Add link to the related issue.
**Download URL:**
Download URL for the new distribution.
**License:**
Link to the license for the new distribution.
**Check list:**
- [ ] Mark if documentation changes are required.
- [ ] Mark if tests were added or updated to cover the changes.
- [ ] Mark if new distribution is being added.
+12
View File
@@ -9,6 +9,18 @@
"message": 3 "message": 3
} }
] ]
},
{
"owner": "javac",
"pattern": [
{
"regexp": "^([^:]+):(\\d+): (warning|error): (.+?)$",
"file": 1,
"line": 2,
"severity": 3,
"message": 4
}
]
} }
] ]
} }
+4
View File
@@ -10,5 +10,9 @@ on:
jobs: jobs:
call-codeQL-analysis: call-codeQL-analysis:
permissions:
actions: read
contents: read
security-events: write
name: CodeQL analysis name: CodeQL analysis
uses: actions/reusable-workflows/.github/workflows/codeql-analysis.yml@main uses: actions/reusable-workflows/.github/workflows/codeql-analysis.yml@main
@@ -24,7 +24,7 @@ jobs:
os: [macos-latest, windows-latest, ubuntu-latest] os: [macos-latest, windows-latest, ubuntu-latest]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: Run setup-java with the cache for gradle - name: Run setup-java with the cache for gradle
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -51,7 +51,7 @@ jobs:
needs: gradle1-save needs: gradle1-save
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: Run setup-java with the cache for gradle - name: Run setup-java with the cache for gradle
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -76,7 +76,7 @@ jobs:
needs: gradle1-save needs: gradle1-save
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: Run setup-java with the cache for gradle - name: Run setup-java with the cache for gradle
uses: ./ uses: ./
id: setup-java id: setup-java
+6 -6
View File
@@ -24,7 +24,7 @@ jobs:
os: [macos-15-intel, windows-latest, ubuntu-latest] os: [macos-15-intel, windows-latest, ubuntu-latest]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: Run setup-java with the cache for gradle - name: Run setup-java with the cache for gradle
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -50,7 +50,7 @@ jobs:
needs: gradle-save needs: gradle-save
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: Run setup-java with the cache for gradle - name: Run setup-java with the cache for gradle
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -73,7 +73,7 @@ jobs:
os: [macos-15-intel, windows-latest, ubuntu-latest] os: [macos-15-intel, windows-latest, ubuntu-latest]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: Run setup-java with the cache for maven - name: Run setup-java with the cache for maven
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -97,7 +97,7 @@ jobs:
needs: maven-save needs: maven-save
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: Run setup-java with the cache for maven - name: Run setup-java with the cache for maven
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -124,7 +124,7 @@ jobs:
os: [macos-15-intel, windows-latest, ubuntu-22.04] os: [macos-15-intel, windows-latest, ubuntu-22.04]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: Run setup-java with the cache for sbt - name: Run setup-java with the cache for sbt
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -174,7 +174,7 @@ jobs:
needs: sbt-save needs: sbt-save
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: Run setup-java with the cache for sbt - name: Run setup-java with the cache for sbt
uses: ./ uses: ./
id: setup-java id: setup-java
+3 -3
View File
@@ -21,7 +21,7 @@ jobs:
os: [macos-latest, windows-latest, ubuntu-latest] os: [macos-latest, windows-latest, ubuntu-latest]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: Download Adopt OpenJDK file - name: Download Adopt OpenJDK file
run: | run: |
if ($IsLinux) { if ($IsLinux) {
@@ -58,7 +58,7 @@ jobs:
os: [macos-latest, windows-latest, ubuntu-latest] os: [macos-latest, windows-latest, ubuntu-latest]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: Download Zulu OpenJDK file - name: Download Zulu OpenJDK file
run: | run: |
if ($IsLinux) { if ($IsLinux) {
@@ -95,7 +95,7 @@ jobs:
os: [macos-latest, windows-latest, ubuntu-latest] os: [macos-latest, windows-latest, ubuntu-latest]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: Download Eclipse Temurin file - name: Download Eclipse Temurin file
run: | run: |
if ($IsLinux) { if ($IsLinux) {
+4 -4
View File
@@ -25,7 +25,7 @@ jobs:
os: [macos-latest, windows-latest, ubuntu-latest] os: [macos-latest, windows-latest, ubuntu-latest]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: setup-java - name: setup-java
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -60,7 +60,7 @@ jobs:
os: [macos-latest, windows-latest, ubuntu-latest] os: [macos-latest, windows-latest, ubuntu-latest]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: Create fake settings.xml - name: Create fake settings.xml
run: | run: |
$xmlDirectory = Join-Path $HOME ".m2" $xmlDirectory = Join-Path $HOME ".m2"
@@ -96,7 +96,7 @@ jobs:
os: [macos-latest, windows-latest, ubuntu-latest] os: [macos-latest, windows-latest, ubuntu-latest]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: Create fake settings.xml - name: Create fake settings.xml
run: | run: |
$xmlDirectory = Join-Path $HOME ".m2" $xmlDirectory = Join-Path $HOME ".m2"
@@ -133,7 +133,7 @@ jobs:
os: [macos-latest, windows-latest, ubuntu-latest] os: [macos-latest, windows-latest, ubuntu-latest]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: setup-java - name: setup-java
uses: ./ uses: ./
id: setup-java id: setup-java
+39 -13
View File
@@ -73,7 +73,7 @@ jobs:
version: '24-ea' version: '24-ea'
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: setup-java - name: setup-java
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -86,6 +86,32 @@ jobs:
run: bash __tests__/verify-java.sh "${{ matrix.version }}" "${{ steps.setup-java.outputs.path }}" run: bash __tests__/verify-java.sh "${{ matrix.version }}" "${{ steps.setup-java.outputs.path }}"
shell: bash shell: bash
setup-java-alpine-linux:
name: ${{ matrix.distribution }} ${{ matrix.version }} (jdk-x64) - alpine-linux - ${{ matrix.os }}
runs-on: ${{ matrix.os }}
container:
image: alpine:latest
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
distribution: ['temurin', 'sapmachine']
version: ['21', '17']
steps:
- name: Checkout
uses: actions/checkout@v7
- name: Install bash
run: apk add --no-cache bash
- name: setup-java
uses: ./
id: setup-java
with:
java-version: ${{ matrix.version }}
distribution: ${{ matrix.distribution }}
- name: Verify Java
run: bash __tests__/verify-java.sh "${{ matrix.version }}" "${{ steps.setup-java.outputs.path }}"
shell: bash
setup-java-major-minor-versions: setup-java-major-minor-versions:
name: ${{ matrix.distribution }} ${{ matrix.version }} (jdk-x64) - ${{ matrix.os }} name: ${{ matrix.distribution }} ${{ matrix.version }} (jdk-x64) - ${{ matrix.os }}
needs: setup-java-major-versions needs: setup-java-major-versions
@@ -123,7 +149,7 @@ jobs:
version: '17.0.7' version: '17.0.7'
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: setup-java - name: setup-java
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -158,7 +184,7 @@ jobs:
os: macos-latest os: macos-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: setup-java - name: setup-java
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -194,7 +220,7 @@ jobs:
os: macos-latest os: macos-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: setup-java - name: setup-java
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -233,7 +259,7 @@ jobs:
version: ['17-ea', '15.0.0-ea.14'] version: ['17-ea', '15.0.0-ea.14']
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: setup-java - name: setup-java
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -255,7 +281,7 @@ jobs:
version: ['17-ea'] version: ['17-ea']
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: setup-java - name: setup-java
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -277,7 +303,7 @@ jobs:
version: ['17-ea', '21-ea'] version: ['17-ea', '21-ea']
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: setup-java - name: setup-java
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -364,7 +390,7 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: setup-java - name: setup-java
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -392,7 +418,7 @@ jobs:
version: ['11'] version: ['11']
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: setup-java - name: setup-java
uses: ./ uses: ./
id: setup-java id: setup-java
@@ -415,7 +441,7 @@ jobs:
java-version-file: ['.java-version', '.tool-versions'] java-version-file: ['.java-version', '.tool-versions']
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: Create .java-version file - name: Create .java-version file
shell: bash shell: bash
run: echo "17" > .java-version run: echo "17" > .java-version
@@ -444,7 +470,7 @@ jobs:
java-version-file: ['.java-version', '.tool-versions'] java-version-file: ['.java-version', '.tool-versions']
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: Create .java-version file - name: Create .java-version file
shell: bash shell: bash
run: echo "11" > .java-version run: echo "11" > .java-version
@@ -472,7 +498,7 @@ jobs:
java-version-file: ['.java-version', '.tool-versions'] java-version-file: ['.java-version', '.tool-versions']
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: Create .java-version file - name: Create .java-version file
shell: bash shell: bash
run: echo "17.0.10" > .java-version run: echo "17.0.10" > .java-version
@@ -500,7 +526,7 @@ jobs:
java-version-file: ['.java-version', '.tool-versions', '.sdkmanrc'] java-version-file: ['.java-version', '.tool-versions', '.sdkmanrc']
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: Create .java-version file - name: Create .java-version file
shell: bash shell: bash
run: echo "openjdk64-17.0.10" > .java-version run: echo "openjdk64-17.0.10" > .java-version
@@ -15,7 +15,7 @@ jobs:
steps: steps:
- name: Checking out - name: Checking out
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: Publish - name: Publish
id: publish id: publish
uses: actions/publish-immutable-action@v0.0.4 uses: actions/publish-immutable-action@v0.0.4
+1
View File
@@ -14,3 +14,4 @@ allowed:
reviewed: reviewed:
npm: npm:
- "@actions/http-client" # MIT (license text present), but detected as "other" - "@actions/http-client" # MIT (license text present), but detected as "other"
- "argparse" # Python Software Foundation License (PSF), but detected as "other"
+1 -1
View File
@@ -1,6 +1,6 @@
--- ---
name: "@actions/cache" name: "@actions/cache"
version: 5.0.1 version: 5.1.0
type: npm type: npm
summary: Actions cache lib summary: Actions cache lib
homepage: https://github.com/actions/toolkit/tree/main/packages/cache homepage: https://github.com/actions/toolkit/tree/main/packages/cache
-20
View File
@@ -1,20 +0,0 @@
---
name: "@actions/core"
version: 1.11.1
type: npm
summary: Actions core lib
homepage: https://github.com/actions/toolkit/tree/main/packages/core
license: mit
licenses:
- sources: LICENSE.md
text: |-
The MIT License (MIT)
Copyright 2019 GitHub
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
notices: []
@@ -1,6 +1,6 @@
--- ---
name: "@actions/core" name: "@actions/core"
version: 2.0.1 version: 2.0.3
type: npm type: npm
summary: Actions core lib summary: Actions core lib
homepage: https://github.com/actions/toolkit/tree/main/packages/core homepage: https://github.com/actions/toolkit/tree/main/packages/core
-20
View File
@@ -1,20 +0,0 @@
---
name: "@actions/exec"
version: 1.1.1
type: npm
summary: Actions exec lib
homepage: https://github.com/actions/toolkit/tree/main/packages/exec
license: mit
licenses:
- sources: LICENSE.md
text: |-
The MIT License (MIT)
Copyright 2019 GitHub
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
notices: []
+1 -1
View File
@@ -1,6 +1,6 @@
--- ---
name: "@actions/glob" name: "@actions/glob"
version: 0.5.0 version: 0.5.1
type: npm type: npm
summary: Actions glob lib summary: Actions glob lib
homepage: https://github.com/actions/toolkit/tree/main/packages/glob homepage: https://github.com/actions/toolkit/tree/main/packages/glob
-32
View File
@@ -1,32 +0,0 @@
---
name: "@actions/http-client"
version: 2.2.3
type: npm
summary: Actions Http Client
homepage: https://github.com/actions/toolkit/tree/main/packages/http-client
license: other
licenses:
- sources: LICENSE
text: |
Actions Http Client for Node.js
Copyright (c) GitHub, Inc.
All rights reserved.
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
notices: []
@@ -1,6 +1,6 @@
--- ---
name: "@actions/http-client" name: "@actions/http-client"
version: 3.0.0 version: 3.0.2
type: npm type: npm
summary: Actions Http Client summary: Actions Http Client
homepage: https://github.com/actions/toolkit/tree/main/packages/http-client homepage: https://github.com/actions/toolkit/tree/main/packages/http-client
-20
View File
@@ -1,20 +0,0 @@
---
name: "@actions/io"
version: 1.1.3
type: npm
summary: Actions io lib
homepage: https://github.com/actions/toolkit/tree/main/packages/io
license: mit
licenses:
- sources: LICENSE.md
text: |-
The MIT License (MIT)
Copyright 2019 GitHub
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
notices: []
+1 -1
View File
@@ -1,6 +1,6 @@
--- ---
name: "@actions/tool-cache" name: "@actions/tool-cache"
version: 2.0.1 version: 3.0.1
type: npm type: npm
summary: Actions tool-cache lib summary: Actions tool-cache lib
homepage: https://github.com/actions/toolkit/tree/main/packages/tool-cache homepage: https://github.com/actions/toolkit/tree/main/packages/tool-cache
+11
View File
@@ -0,0 +1,11 @@
---
name: "@nodable/entities"
version: 2.2.0
type: npm
summary: Entity parser for XML, HTML, External entites with security and NCR control
homepage:
license: mit
licenses:
- sources: README.md
text: MIT
notices: []
+1 -1
View File
@@ -1,6 +1,6 @@
--- ---
name: "@oozcitak/dom" name: "@oozcitak/dom"
version: 1.15.8 version: 2.0.2
type: npm type: npm
summary: A modern DOM implementation summary: A modern DOM implementation
homepage: http://github.com/oozcitak/dom homepage: http://github.com/oozcitak/dom
+1 -1
View File
@@ -1,6 +1,6 @@
--- ---
name: "@oozcitak/infra" name: "@oozcitak/infra"
version: 1.0.8 version: 2.0.2
type: npm type: npm
summary: An implementation of the Infra Living Standard summary: An implementation of the Infra Living Standard
homepage: http://github.com/oozcitak/infra homepage: http://github.com/oozcitak/infra
+1 -1
View File
@@ -1,6 +1,6 @@
--- ---
name: "@oozcitak/url" name: "@oozcitak/url"
version: 1.0.4 version: 3.0.0
type: npm type: npm
summary: An implementation of the URL Living Standard summary: An implementation of the URL Living Standard
homepage: http://github.com/oozcitak/url homepage: http://github.com/oozcitak/url
+1 -1
View File
@@ -1,6 +1,6 @@
--- ---
name: "@oozcitak/util" name: "@oozcitak/util"
version: 8.3.8 version: 10.0.0
type: npm type: npm
summary: Utility functions summary: Utility functions
homepage: http://github.com/oozcitak/util homepage: http://github.com/oozcitak/util
-32
View File
@@ -1,32 +0,0 @@
---
name: "@types/node"
version: 24.1.0
type: npm
summary: TypeScript definitions for node
homepage: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node
license: mit
licenses:
- sources: LICENSE
text: |2
MIT License
Copyright (c) Microsoft Corporation.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE
notices: []
+9 -15
View File
@@ -1,16 +1,17 @@
--- ---
name: uuid name: anynum
version: 3.4.0 version: 1.0.0
type: npm type: npm
summary: RFC4122 (v1, v4, and v5) UUIDs summary: Normalize all Unicode decimal digits (Devanagari, Arabic, Thai, etc.) to
homepage: https://github.com/uuidjs/uuid#readme ASCII numerals. Zero dependencies, performance-first.
homepage:
license: mit license: mit
licenses: licenses:
- sources: LICENSE.md - sources: LICENSE
text: | text: |
The MIT License (MIT) MIT License
Copyright (c) 2010-2016 Robert Kieffer and other contributors Copyright (c) 2026 Natural Intelligence
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -29,11 +30,4 @@ licenses:
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
notices: notices: []
- sources: AUTHORS
text: |-
Robert Kieffer <robert@broofa.com>
Christoph Tavan <dev@tavan.de>
AJ ONeal <coolaj86@gmail.com>
Vincent Voyer <vincent@zeroload.net>
Roman Shtylman <shtylman@gmail.com>
+254 -27
View File
@@ -1,38 +1,265 @@
--- ---
name: argparse name: argparse
version: 1.0.10 version: 2.0.1
type: npm type: npm
summary: Very powerful CLI arguments parser. Native port of argparse - python's options summary: CLI arguments parser. Native port of python's argparse.
parsing library homepage:
homepage: https://github.com/nodeca/argparse#readme license: other
license: mit
licenses: licenses:
- sources: LICENSE - sources: LICENSE
text: | text: |
(The MIT License) A. HISTORY OF THE SOFTWARE
==========================
Copyright (C) 2012 by Vitaly Puzrin Python was created in the early 1990s by Guido van Rossum at Stichting
Mathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands
as a successor of a language called ABC. Guido remains Python's
principal author, although it includes many contributions from others.
Permission is hereby granted, free of charge, to any person obtaining a copy In 1995, Guido continued his work on Python at the Corporation for
of this software and associated documentation files (the "Software"), to deal National Research Initiatives (CNRI, see http://www.cnri.reston.va.us)
in the Software without restriction, including without limitation the rights in Reston, Virginia where he released several versions of the
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell software.
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in In May 2000, Guido and the Python core development team moved to
all copies or substantial portions of the Software. BeOpen.com to form the BeOpen PythonLabs team. In October of the same
year, the PythonLabs team moved to Digital Creations, which became
Zope Corporation. In 2001, the Python Software Foundation (PSF, see
https://www.python.org/psf/) was formed, a non-profit organization
created specifically to own Python-related Intellectual Property.
Zope Corporation was a sponsoring member of the PSF.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR All Python releases are Open Source (see http://www.opensource.org for
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, the Open Source Definition). Historically, most, but not all, Python
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE releases have also been GPL-compatible; the table below summarizes
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER the various releases.
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN Release Derived Year Owner GPL-
THE SOFTWARE. from compatible? (1)
- sources: README.md
text: |- 0.9.0 thru 1.2 1991-1995 CWI yes
Copyright (c) 2012 [Vitaly Puzrin](https://github.com/puzrin). 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes
Released under the MIT license. See 1.6 1.5.2 2000 CNRI no
[LICENSE](https://github.com/nodeca/argparse/blob/master/LICENSE) for details. 2.0 1.6 2000 BeOpen.com no
1.6.1 1.6 2001 CNRI yes (2)
2.1 2.0+1.6.1 2001 PSF no
2.0.1 2.0+1.6.1 2001 PSF yes
2.1.1 2.1+2.0.1 2001 PSF yes
2.1.2 2.1.1 2002 PSF yes
2.1.3 2.1.2 2002 PSF yes
2.2 and above 2.1.1 2001-now PSF yes
Footnotes:
(1) GPL-compatible doesn't mean that we're distributing Python under
the GPL. All Python licenses, unlike the GPL, let you distribute
a modified version without making your changes open source. The
GPL-compatible licenses make it possible to combine Python with
other software that is released under the GPL; the others don't.
(2) According to Richard Stallman, 1.6.1 is not GPL-compatible,
because its license has a choice of law clause. According to
CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1
is "not incompatible" with the GPL.
Thanks to the many outside volunteers who have worked under Guido's
direction to make these releases possible.
B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON
===============================================================
PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
--------------------------------------------
1. This LICENSE AGREEMENT is between the Python Software Foundation
("PSF"), and the Individual or Organization ("Licensee") accessing and
otherwise using this software ("Python") in source or binary form and
its associated documentation.
2. Subject to the terms and conditions of this License Agreement, PSF hereby
grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
analyze, test, perform and/or display publicly, prepare derivative works,
distribute, and otherwise use Python alone or in any derivative version,
provided, however, that PSF's License Agreement and PSF's notice of copyright,
i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Python Software Foundation;
All Rights Reserved" are retained in Python alone or in any derivative version
prepared by Licensee.
3. In the event Licensee prepares a derivative work that is based on
or incorporates Python or any part thereof, and wants to make
the derivative work available to others as provided herein, then
Licensee hereby agrees to include in any such work a brief summary of
the changes made to Python.
4. PSF is making Python available to Licensee on an "AS IS"
basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
INFRINGE ANY THIRD PARTY RIGHTS.
5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
6. This License Agreement will automatically terminate upon a material
breach of its terms and conditions.
7. Nothing in this License Agreement shall be deemed to create any
relationship of agency, partnership, or joint venture between PSF and
Licensee. This License Agreement does not grant permission to use PSF
trademarks or trade name in a trademark sense to endorse or promote
products or services of Licensee, or any third party.
8. By copying, installing or otherwise using Python, Licensee
agrees to be bound by the terms and conditions of this License
Agreement.
BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0
-------------------------------------------
BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1
1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an
office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the
Individual or Organization ("Licensee") accessing and otherwise using
this software in source or binary form and its associated
documentation ("the Software").
2. Subject to the terms and conditions of this BeOpen Python License
Agreement, BeOpen hereby grants Licensee a non-exclusive,
royalty-free, world-wide license to reproduce, analyze, test, perform
and/or display publicly, prepare derivative works, distribute, and
otherwise use the Software alone or in any derivative version,
provided, however, that the BeOpen Python License is retained in the
Software, alone or in any derivative version prepared by Licensee.
3. BeOpen is making the Software available to Licensee on an "AS IS"
basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT
INFRINGE ANY THIRD PARTY RIGHTS.
4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS
AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY
DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
5. This License Agreement will automatically terminate upon a material
breach of its terms and conditions.
6. This License Agreement shall be governed by and interpreted in all
respects by the law of the State of California, excluding conflict of
law provisions. Nothing in this License Agreement shall be deemed to
create any relationship of agency, partnership, or joint venture
between BeOpen and Licensee. This License Agreement does not grant
permission to use BeOpen trademarks or trade names in a trademark
sense to endorse or promote products or services of Licensee, or any
third party. As an exception, the "BeOpen Python" logos available at
http://www.pythonlabs.com/logos.html may be used according to the
permissions granted on that web page.
7. By copying, installing or otherwise using the software, Licensee
agrees to be bound by the terms and conditions of this License
Agreement.
CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1
---------------------------------------
1. This LICENSE AGREEMENT is between the Corporation for National
Research Initiatives, having an office at 1895 Preston White Drive,
Reston, VA 20191 ("CNRI"), and the Individual or Organization
("Licensee") accessing and otherwise using Python 1.6.1 software in
source or binary form and its associated documentation.
2. Subject to the terms and conditions of this License Agreement, CNRI
hereby grants Licensee a nonexclusive, royalty-free, world-wide
license to reproduce, analyze, test, perform and/or display publicly,
prepare derivative works, distribute, and otherwise use Python 1.6.1
alone or in any derivative version, provided, however, that CNRI's
License Agreement and CNRI's notice of copyright, i.e., "Copyright (c)
1995-2001 Corporation for National Research Initiatives; All Rights
Reserved" are retained in Python 1.6.1 alone or in any derivative
version prepared by Licensee. Alternately, in lieu of CNRI's License
Agreement, Licensee may substitute the following text (omitting the
quotes): "Python 1.6.1 is made available subject to the terms and
conditions in CNRI's License Agreement. This Agreement together with
Python 1.6.1 may be located on the Internet using the following
unique, persistent identifier (known as a handle): 1895.22/1013. This
Agreement may also be obtained from a proxy server on the Internet
using the following URL: http://hdl.handle.net/1895.22/1013".
3. In the event Licensee prepares a derivative work that is based on
or incorporates Python 1.6.1 or any part thereof, and wants to make
the derivative work available to others as provided herein, then
Licensee hereby agrees to include in any such work a brief summary of
the changes made to Python 1.6.1.
4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS"
basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT
INFRINGE ANY THIRD PARTY RIGHTS.
5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1,
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
6. This License Agreement will automatically terminate upon a material
breach of its terms and conditions.
7. This License Agreement shall be governed by the federal
intellectual property law of the United States, including without
limitation the federal copyright law, and, to the extent such
U.S. federal law does not apply, by the law of the Commonwealth of
Virginia, excluding Virginia's conflict of law provisions.
Notwithstanding the foregoing, with regard to derivative works based
on Python 1.6.1 that incorporate non-separable material that was
previously distributed under the GNU General Public License (GPL), the
law of the Commonwealth of Virginia shall govern this License
Agreement only as to issues arising under or with respect to
Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this
License Agreement shall be deemed to create any relationship of
agency, partnership, or joint venture between CNRI and Licensee. This
License Agreement does not grant permission to use CNRI trademarks or
trade name in a trademark sense to endorse or promote products or
services of Licensee, or any third party.
8. By clicking on the "ACCEPT" button where indicated, or by copying,
installing or otherwise using Python 1.6.1, Licensee agrees to be
bound by the terms and conditions of this License Agreement.
ACCEPT
CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2
--------------------------------------------------
Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam,
The Netherlands. All rights reserved.
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of Stichting Mathematisch
Centrum or CWI not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
notices: [] notices: []
+1 -1
View File
@@ -1,6 +1,6 @@
--- ---
name: brace-expansion name: brace-expansion
version: 1.1.12 version: 1.1.13
type: npm type: npm
summary: Brace expansion as known from sh/bash summary: Brace expansion as known from sh/bash
homepage: https://github.com/juliangruber/brace-expansion homepage: https://github.com/juliangruber/brace-expansion
+1 -1
View File
@@ -1,6 +1,6 @@
--- ---
name: debug name: debug
version: 4.3.4 version: 4.4.3
type: npm type: npm
summary: Lightweight debugging utility for Node.js and the browser summary: Lightweight debugging utility for Node.js and the browser
homepage: homepage:
-32
View File
@@ -1,32 +0,0 @@
---
name: esprima
version: 4.0.1
type: npm
summary: ECMAScript parsing infrastructure for multipurpose analysis
homepage: http://esprima.org
license: bsd-2-clause
licenses:
- sources: LICENSE.BSD
text: |
Copyright JS Foundation and other contributors, https://js.foundation/
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
notices: []
@@ -1,16 +1,16 @@
--- ---
name: undici-types name: fast-xml-builder
version: 7.8.0 version: 1.2.0
type: npm type: npm
summary: A stand-alone types package for Undici summary: Build XML from JSON without C/C++ based libraries
homepage: https://undici.nodejs.org homepage:
license: mit license: mit
licenses: licenses:
- sources: LICENSE - sources: LICENSE
text: | text: |
MIT License MIT License
Copyright (c) Matteo Collina and Undici contributors Copyright (c) 2026 Natural Intelligence
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,6 +1,6 @@
--- ---
name: fast-xml-parser name: fast-xml-parser
version: 5.3.3 version: 5.8.0
type: npm type: npm
summary: Validate XML, Parse XML, Build XML without C/C++ based libraries summary: Validate XML, Parse XML, Build XML without C/C++ based libraries
homepage: homepage:
+2 -2
View File
@@ -1,9 +1,9 @@
--- ---
name: js-yaml name: js-yaml
version: 3.14.0 version: 4.1.1
type: npm type: npm
summary: YAML 1.2 parser and serializer summary: YAML 1.2 parser and serializer
homepage: https://github.com/nodeca/js-yaml homepage:
license: mit license: mit
licenses: licenses:
- sources: LICENSE - sources: LICENSE
+2 -2
View File
@@ -1,9 +1,9 @@
--- ---
name: minimatch name: minimatch
version: 3.1.2 version: 3.1.5
type: npm type: npm
summary: a glob matcher in javascript summary: a glob matcher in javascript
homepage: https://github.com/isaacs/minimatch#readme homepage:
license: isc license: isc
licenses: licenses:
- sources: LICENSE - sources: LICENSE
+2 -2
View File
@@ -1,6 +1,6 @@
--- ---
name: ms name: ms
version: 2.1.2 version: 2.1.3
type: npm type: npm
summary: Tiny millisecond conversion utility summary: Tiny millisecond conversion utility
homepage: homepage:
@@ -10,7 +10,7 @@ licenses:
text: | text: |
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2016 Zeit, Inc. Copyright (c) 2020 Vercel, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -1,30 +1,32 @@
--- ---
name: "@fastify/busboy" name: path-expression-matcher
version: 2.1.0 version: 1.5.0
type: npm type: npm
summary: A streaming parser for HTML form data for node.js summary: Efficient path tracking and pattern matching for XML/JSON parsers
homepage: homepage: https://github.com/NaturalIntelligence/path-expression-matcher#readme
license: mit license: mit
licenses: licenses:
- sources: LICENSE - sources: LICENSE
text: |- text: |
Copyright Brian White. All rights reserved. MIT License
Copyright (c) 2024
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to of this software and associated documentation files (the "Software"), to deal
deal in the Software without restriction, including without limitation the in the Software without restriction, including without limitation the rights
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
sell copies of the Software, and to permit persons to whom the Software is copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions: furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in The above copyright notice and this permission notice shall be included in all
all copies or substantial portions of the Software. copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
IN THE SOFTWARE. SOFTWARE.
notices: [] notices: []
@@ -1,6 +1,6 @@
--- ---
name: semver name: semver
version: 7.7.1 version: 7.8.4
type: npm type: npm
summary: The semantic version parser used by npm. summary: The semantic version parser used by npm.
homepage: homepage:
-37
View File
@@ -1,37 +0,0 @@
---
name: sprintf-js
version: 1.0.3
type: npm
summary: JavaScript sprintf implementation
homepage: https://github.com/alexei/sprintf.js#readme
license: bsd-3-clause
licenses:
- sources: LICENSE
text: |
Copyright (c) 2007-2014, Alexandru Marasteanu <hello [at) alexei (dot] ro>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of this software nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- sources: README.md
text: "**sprintf.js** is licensed under the terms of the 3-clause BSD license."
notices: []
+1 -1
View File
@@ -1,6 +1,6 @@
--- ---
name: strnum name: strnum
version: 2.1.2 version: 2.4.0
type: npm type: npm
summary: Parse String to Number based on configuration summary: Parse String to Number based on configuration
homepage: homepage:
+1 -1
View File
@@ -1,6 +1,6 @@
--- ---
name: undici name: undici
version: 5.29.0 version: 6.27.0
type: npm type: npm
summary: An HTTP/1.1 client, written from scratch for Node.js summary: An HTTP/1.1 client, written from scratch for Node.js
homepage: https://undici.nodejs.org homepage: https://undici.nodejs.org
+12
View File
@@ -0,0 +1,12 @@
---
name: xml-naming
version: 0.1.0
type: npm
summary: Validates XML name productions — Name, NCName, QName, NMToken, NMTokens —
for XML 1.0 and 1.1
homepage:
license: mit
licenses:
- sources: README.md
text: MIT
notices: []
+3 -3
View File
@@ -1,12 +1,12 @@
--- ---
name: xmlbuilder2 name: xmlbuilder2
version: 2.4.1 version: 4.0.3
type: npm type: npm
summary: An XML builder for node.js summary: An XML builder for node.js
homepage: http://github.com/oozcitak/xmlbuilder2 homepage: https://github.com/oozcitak/xmlbuilder2
license: mit license: mit
licenses: licenses:
- sources: LICENSE - sources: LICENSE.txt
text: | text: |
MIT License MIT License
+52 -44
View File
@@ -25,13 +25,6 @@ This action allows you to work with Java and Scala projects.
For more details, see the full release notes on the [releases page](https://github.com/actions/setup-java/releases/tag/v5.0.0) For more details, see the full release notes on the [releases page](https://github.com/actions/setup-java/releases/tag/v5.0.0)
## V2 vs V1
- V2 supports custom distributions and provides support for Azul Zulu OpenJDK, Eclipse Temurin and AdoptOpenJDK out of the box. V1 supports only Azul Zulu OpenJDK.
- V2 requires you to specify distribution along with the version. V1 defaults to Azul Zulu OpenJDK, only version input is required. Follow [the migration guide](docs/switching-to-v2.md) to switch from V1 to V2.
For information about the latest releases, recent updates, and newly supported distributions, please refer to the `setup-java` [Releases](https://github.com/actions/setup-java/releases).
## Usage ## Usage
- `java-version`: The Java version that is going to be set up. Takes a whole or [semver](#supported-version-syntax) Java version. If not specified, the action will expect `java-version-file` input to be specified. - `java-version`: The Java version that is going to be set up. Takes a whole or [semver](#supported-version-syntax) Java version. If not specified, the action will expect `java-version-file` input to be specified.
@@ -44,7 +37,7 @@ For information about the latest releases, recent updates, and newly supported d
- `architecture`: The target architecture of the package. Possible values: `x86`, `x64`, `armv7`, `aarch64`, `ppc64le`. Default value: Derived from the runner machine. - `architecture`: The target architecture of the package. Possible values: `x86`, `x64`, `armv7`, `aarch64`, `ppc64le`. Default value: Derived from the runner machine.
- `jdkFile`: If a use-case requires a custom distribution setup-java uses the compressed JDK from the location pointed by this input and will take care of the installation and caching on the VM. - `jdkFile`: If a use-case requires a custom distribution setup-java uses the compressed JDK from the location pointed by this input and will take care of the installation and caching on the VM. Note: `distribution` must be set to 'jdkfile' (case-sensitive; all lowercase) when using this option.
- `check-latest`: Setting this option makes the action to check for the latest available version for the version spec. - `check-latest`: Setting this option makes the action to check for the latest available version for the version spec.
@@ -82,8 +75,8 @@ steps:
- uses: actions/setup-java@v5 - uses: actions/setup-java@v5
with: with:
distribution: 'temurin' # See 'Supported distributions' for available options distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '21' java-version: '25'
- run: java HelloWorldApp.java - run: java --version
``` ```
#### Azul Zulu OpenJDK #### Azul Zulu OpenJDK
@@ -93,47 +86,52 @@ steps:
- uses: actions/setup-java@v5 - uses: actions/setup-java@v5
with: with:
distribution: 'zulu' # See 'Supported distributions' for available options distribution: 'zulu' # See 'Supported distributions' for available options
java-version: '21' java-version: '25'
- run: java HelloWorldApp.java - run: java --version
``` ```
#### Supported version syntax #### Supported version syntax
The `java-version` input supports an exact version or a version range using [SemVer](https://semver.org/) notation: The `java-version` input supports an exact version or a version range using [SemVer](https://semver.org/) notation. The values below are examples, not an exhaustive list:
- major versions: `8`, `11`, `16`, `17`, `21` - major versions, such as: `8`, `11`, `16`, `17`, `21`, `25`
- more specific versions: `8.0.282+8`, `8.0.232`, `11.0`, `11.0.4`, `17.0` - more specific versions: `8.0.282+8`, `8.0.232`, `11.0`, `11.0.4`, `17.0`
- early access (EA) versions: `15-ea`, `15.0.0-ea` - early access (EA) versions: `15-ea`, `15.0.0-ea`
#### Supported distributions #### Supported distributions
Currently, the following distributions are supported: Currently, the following distributions are supported:
| Keyword | Distribution | Official site | License | Keyword | Distribution / Official site | License
|-|-|-|-| |-|-|-|
| `temurin` | Eclipse Temurin | [Link](https://adoptium.net/) | [Link](https://adoptium.net/about.html) | `temurin` | [Eclipse Temurin](https://adoptium.net/) | [`temurin` license](https://adoptium.net/about.html)
| `zulu` | Azul Zulu OpenJDK | [Link](https://www.azul.com/downloads/zulu-community/?package=jdk) | [Link](https://www.azul.com/products/zulu-and-zulu-enterprise/zulu-terms-of-use/) | | `zulu` | [Azul Zulu OpenJDK](https://www.azul.com/downloads/zulu-community/?package=jdk) | [`zulu` license](https://www.azul.com/products/zulu-and-zulu-enterprise/zulu-terms-of-use/) |
| `adopt` or `adopt-hotspot` | AdoptOpenJDK Hotspot | [Link](https://adoptopenjdk.net/) | [Link](https://adoptopenjdk.net/about.html) | | `adopt` or `adopt-hotspot` | [AdoptOpenJDK Hotspot](https://adoptopenjdk.net/) | [`adopt-hotspot` license](https://adoptopenjdk.net/about.html) |
| `adopt-openj9` | AdoptOpenJDK OpenJ9 | [Link](https://adoptopenjdk.net/) | [Link](https://adoptopenjdk.net/about.html) | | `adopt-openj9` | [AdoptOpenJDK OpenJ9](https://adoptopenjdk.net/) | [`adopt-openj9` license](https://adoptopenjdk.net/about.html) |
| `liberica` | Liberica JDK | [Link](https://bell-sw.com/) | [Link](https://bell-sw.com/liberica_eula/) | | `liberica` | [Liberica JDK](https://bell-sw.com/) | [`liberica` license](https://bell-sw.com/liberica_eula/) |
| `microsoft` | Microsoft Build of OpenJDK | [Link](https://www.microsoft.com/openjdk) | [Link](https://docs.microsoft.com/java/openjdk/faq) | `microsoft` | [Microsoft Build of OpenJDK](https://www.microsoft.com/openjdk) | [`microsoft` license](https://docs.microsoft.com/java/openjdk/faq)
| `corretto` | Amazon Corretto Build of OpenJDK | [Link](https://aws.amazon.com/corretto/) | [Link](https://aws.amazon.com/corretto/faqs/) | `corretto` | [Amazon Corretto Build of OpenJDK](https://aws.amazon.com/corretto/) | [`corretto` license](https://aws.amazon.com/corretto/faqs/)
| `semeru` | IBM Semeru Runtime Open Edition | [Link](https://developer.ibm.com/languages/java/semeru-runtimes/downloads/) | [Link](https://openjdk.java.net/legal/gplv2+ce.html) | | `semeru` | [IBM Semeru Runtime Open Edition](https://developer.ibm.com/languages/java/semeru-runtimes/downloads/) | [`semeru` license](https://openjdk.java.net/legal/gplv2+ce.html) |
| `oracle` | Oracle JDK | [Link](https://www.oracle.com/java/technologies/downloads/) | [Link](https://java.com/freeuselicense) | `oracle` | [Oracle JDK](https://www.oracle.com/java/technologies/downloads/) | [`oracle` license](https://java.com/freeuselicense)
| `dragonwell` | Alibaba Dragonwell JDK | [Link](https://dragonwell-jdk.io/) | [Link](https://www.aliyun.com/product/dragonwell/) | `dragonwell` | [Alibaba Dragonwell JDK](https://dragonwell-jdk.io/) | [`dragonwell` license](https://www.aliyun.com/product/dragonwell/)
| `sapmachine` | SAP SapMachine JDK/JRE | [Link](https://sapmachine.io/) | [Link](https://github.com/SAP/SapMachine/blob/sapmachine/LICENSE) | `sapmachine` | [SAP SapMachine JDK/JRE](https://sapmachine.io/) | [`sapmachine` license](https://github.com/SAP/SapMachine/blob/sapmachine/LICENSE)
| `graalvm` | Oracle GraalVM | [Link](https://www.graalvm.org/) | [Link](https://www.oracle.com/downloads/licenses/graal-free-license.html) | `graalvm` | [Oracle GraalVM](https://www.graalvm.org/) | [`graalvm` license](https://www.oracle.com/downloads/licenses/graal-free-license.html)
| `jetbrains` | JetBrains Runtime | [Link](https://github.com/JetBrains/JetBrainsRuntime/) | [Link](https://github.com/JetBrains/JetBrainsRuntime/blob/main/LICENSE) | `graalvm-community` | [GraalVM Community](https://github.com/graalvm/graalvm-ce-builds/releases) | [`graalvm-community` license](https://github.com/oracle/graal/blob/master/LICENSE)
| `jetbrains` | [JetBrains Runtime](https://github.com/JetBrains/JetBrainsRuntime/) | [`jetbrains` license](https://github.com/JetBrains/JetBrainsRuntime/blob/main/LICENSE)
| `jdkfile` | Custom JDK Installation | |
**NOTE:** The different distributors can provide discrepant list of available versions / supported configurations. Please refer to the official documentation to see the list of supported versions. > [!NOTE]
> - The different distributors can provide discrepant list of available versions / supported configurations. Please refer to the official documentation to see the list of supported versions.
> - AdoptOpenJDK got moved to Eclipse Temurin and won't be updated anymore. It is highly recommended to migrate workflows from `adopt` and `adopt-openj9`, to `temurin` and `semeru` respectively, to keep receiving software and security updates. See more details in the [Good-bye AdoptOpenJDK post](https://blog.adoptopenjdk.net/2021/08/goodbye-adoptopenjdk-hello-adoptium/).
> - For Azul Zulu OpenJDK architectures x64 and arm64 are mapped to x86 / arm with proper hw_bitness.
> - To comply with the GraalVM Free Terms and Conditions (GFTC) license, it is recommended to use GraalVM JDK 17 version 17.0.12, as this is the only version of GraalVM JDK 17 available under the GFTC license. Additionally, it is encouraged to consider upgrading to GraalVM JDK 21, which offers the latest features and improvements.
> - GraalVM Community is available as `distribution: 'graalvm-community'` for stable JDK 17 and later releases published on GitHub.
**NOTE:** AdoptOpenJDK got moved to Eclipse Temurin and won't be updated anymore. It is highly recommended to migrate workflows from `adopt` and `adopt-openj9`, to `temurin` and `semeru` respectively, to keep receiving software and security updates. See more details in the [Good-bye AdoptOpenJDK post](https://blog.adoptopenjdk.net/2021/08/goodbye-adoptopenjdk-hello-adoptium/). **NOTE:** Oracle JDK 17 licensing varies by patch level. As shown on the [JDK 17 Archive](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html) (versions up to 17.0.12 are under the [NFTC](https://www.oracle.com/downloads/licenses/no-fee-license.html) license) and the [JDK 17.0.13+ Archive](https://www.oracle.com/java/technologies/javase/jdk17-0-13-later-archive-downloads.html) (versions 17.0.13 and later are under the [OTN](https://www.oracle.com/downloads/licenses/javase-license1.html) license). To stay on the free NFTC license, use `distribution: 'oracle'` with `java-version: '17.0.12'` (or earlier) instead of the floating `'17'`. Alternatively, upgrade to Oracle JDK 21+, which remains under the NFTC license.
**NOTE:** For Azul Zulu OpenJDK architectures x64 and arm64 are mapped to x86 / arm with proper hw_bitness. **NOTE:** On Ubuntu runners, commands executed via `sudo` do not inherit the `JAVA_HOME` and `PATH` set by `setup-java` and will fall back to the runner image's system-default JDK.
**NOTE:** To comply with the GraalVM Free Terms and Conditions (GFTC) license, it is recommended to use GraalVM JDK 17 version 17.0.12, as this is the only version of GraalVM JDK 17 available under the GFTC license. Additionally, it is encouraged to consider upgrading to GraalVM JDK 21, which offers the latest features and improvements.
### Caching packages dependencies ### Caching packages dependencies
The action has a built-in functionality for caching and restoring dependencies. It uses [toolkit/cache](https://github.com/actions/toolkit/tree/main/packages/cache) under hood for caching dependencies but requires less configuration settings. Supported package managers are gradle, maven and sbt. The format of the used cache key is `setup-java-${{ platform }}-${{ packageManager }}-${{ fileHash }}`, where the hash is based on the following files: The action has a built-in functionality for caching and restoring dependencies. It uses [toolkit/cache](https://github.com/actions/toolkit/tree/main/packages/cache) under hood for caching dependencies but requires less configuration settings. Supported package managers are gradle, maven and sbt. The format of the used cache key is `setup-java-${{ platform }}-${{ packageManager }}-${{ fileHash }}`, where the hash is based on the following files:
- gradle: `**/*.gradle*`, `**/gradle-wrapper.properties`, `buildSrc/**/Versions.kt`, `buildSrc/**/Dependencies.kt`, `gradle/*.versions.toml`, and `**/versions.properties` - gradle: `**/*.gradle*`, `**/gradle-wrapper.properties`, `buildSrc/**/Versions.kt`, `buildSrc/**/Dependencies.kt`, `gradle/*.versions.toml`, and `**/versions.properties`
- maven: `**/pom.xml` - maven: `**/pom.xml` and `**/.mvn/wrapper/maven-wrapper.properties`
- sbt: all sbt build definition files `**/*.sbt`, `**/project/build.properties`, `**/project/**.scala`, `**/project/**.sbt` - sbt: all sbt build definition files `**/*.sbt`, `**/project/build.properties`, `**/project/**.scala`, `**/project/**.sbt`
When the option `cache-dependency-path` is specified, the hash is based on the matching file. This option supports wildcards and a list of file names, and is especially useful for monorepos. When the option `cache-dependency-path` is specified, the hash is based on the matching file. This option supports wildcards and a list of file names, and is especially useful for monorepos.
@@ -149,7 +147,7 @@ steps:
- uses: actions/setup-java@v5 - uses: actions/setup-java@v5
with: with:
distribution: 'temurin' distribution: 'temurin'
java-version: '21' java-version: '25'
cache: 'gradle' cache: 'gradle'
cache-dependency-path: | # optional cache-dependency-path: | # optional
sub-project/*.gradle* sub-project/*.gradle*
@@ -169,7 +167,7 @@ steps:
- uses: actions/setup-java@v5 - uses: actions/setup-java@v5
with: with:
distribution: 'temurin' distribution: 'temurin'
java-version: '21' java-version: '25'
cache: 'maven' cache: 'maven'
cache-dependency-path: 'sub-project/pom.xml' # optional cache-dependency-path: 'sub-project/pom.xml' # optional
- name: Build with Maven - name: Build with Maven
@@ -183,7 +181,7 @@ steps:
- uses: actions/setup-java@v5 - uses: actions/setup-java@v5
with: with:
distribution: 'temurin' distribution: 'temurin'
java-version: '21' java-version: '25'
cache: 'sbt' cache: 'sbt'
cache-dependency-path: | # optional cache-dependency-path: | # optional
sub-project/build.sbt sub-project/build.sbt
@@ -203,7 +201,7 @@ steps:
- uses: actions/setup-java@v5 - uses: actions/setup-java@v5
with: with:
distribution: 'temurin' distribution: 'temurin'
java-version: '21' java-version: '25'
cache: 'gradle' cache: 'gradle'
- run: ./gradlew build --no-daemon - run: ./gradlew build --no-daemon
``` ```
@@ -214,7 +212,7 @@ In the basic examples above, the `check-latest` flag defaults to `false`. When s
If `check-latest` is set to `true`, the action first checks if the cached version is the latest one. If the locally cached version is not the most up-to-date, the latest version of Java will be downloaded. Set `check-latest` to `true` if you want the most up-to-date version of Java to always be used. Setting `check-latest` to `true` has performance implications as downloading versions of Java is slower than using cached versions. If `check-latest` is set to `true`, the action first checks if the cached version is the latest one. If the locally cached version is not the most up-to-date, the latest version of Java will be downloaded. Set `check-latest` to `true` if you want the most up-to-date version of Java to always be used. Setting `check-latest` to `true` has performance implications as downloading versions of Java is slower than using cached versions.
For Java distributions that are not cached on Hosted images, `check-latest` always behaves as `true` and downloads Java on-flight. Check out [Hosted Tool Cache](docs/advanced-usage.md#Hosted-Tool-Cache) for more details about pre-cached Java versions. For Java distributions that are not cached on Hosted images, `check-latest` always behaves as `true` and downloads Java on the fly. Check out [Hosted Tool Cache](docs/advanced-usage.md#Hosted-Tool-Cache) for more details about pre-cached Java versions.
```yaml ```yaml
@@ -223,9 +221,9 @@ steps:
- uses: actions/setup-java@v5 - uses: actions/setup-java@v5
with: with:
distribution: 'temurin' distribution: 'temurin'
java-version: '21' java-version: '25'
check-latest: true check-latest: true
- run: java HelloWorldApp.java - run: java --version
``` ```
### Testing against different Java versions ### Testing against different Java versions
@@ -235,7 +233,7 @@ jobs:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
strategy: strategy:
matrix: matrix:
java: [ '8', '11', '17', '21' ] java: [ '8', '11', '17', '21', '25' ]
name: Java ${{ matrix.Java }} sample name: Java ${{ matrix.Java }} sample
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v6
@@ -244,7 +242,7 @@ jobs:
with: with:
distribution: '<distribution>' distribution: '<distribution>'
java-version: ${{ matrix.java }} java-version: ${{ matrix.java }}
- run: java HelloWorldApp.java - run: java --version
``` ```
### Install multiple JDKs ### Install multiple JDKs
@@ -278,6 +276,7 @@ In the example above multiple JDKs are installed for the same job. The result af
- [Alibaba Dragonwell](docs/advanced-usage.md#Alibaba-Dragonwell) - [Alibaba Dragonwell](docs/advanced-usage.md#Alibaba-Dragonwell)
- [SapMachine](docs/advanced-usage.md#SapMachine) - [SapMachine](docs/advanced-usage.md#SapMachine)
- [GraalVM](docs/advanced-usage.md#GraalVM) - [GraalVM](docs/advanced-usage.md#GraalVM)
- [JetBrains](docs/advanced-usage.md#JetBrains)
- [Installing custom Java package type](docs/advanced-usage.md#Installing-custom-Java-package-type) - [Installing custom Java package type](docs/advanced-usage.md#Installing-custom-Java-package-type)
- [Installing custom Java architecture](docs/advanced-usage.md#Installing-custom-Java-architecture) - [Installing custom Java architecture](docs/advanced-usage.md#Installing-custom-Java-architecture)
- [Installing custom Java distribution from local file](docs/advanced-usage.md#Installing-Java-from-local-file) - [Installing custom Java distribution from local file](docs/advanced-usage.md#Installing-Java-from-local-file)
@@ -289,6 +288,15 @@ In the example above multiple JDKs are installed for the same job. The result af
- [Modifying Maven Toolchains](docs/advanced-usage.md#Modifying-Maven-Toolchains) - [Modifying Maven Toolchains](docs/advanced-usage.md#Modifying-Maven-Toolchains)
- [Java Version File](docs/advanced-usage.md#Java-version-file) - [Java Version File](docs/advanced-usage.md#Java-version-file)
## V2 vs V1
Examples in this README use `actions/setup-java@v5`, but the main migration note from V1 still applies to all later major versions (`v2`, `v3`, `v4`, and `v5`):
- Starting with V2, the action supports custom distributions. V1 supports only Azul Zulu OpenJDK.
- Starting with V2, you must specify distribution along with the version. V1 defaults to Azul Zulu OpenJDK, so only version input is required. Follow [the migration guide](docs/switching-to-v2.md) to switch from V1 to V2.
For information about the latest releases, recent updates, and newly supported distributions, please refer to the `setup-java` [Releases](https://github.com/actions/setup-java/releases).
## Recommended permissions ## Recommended permissions
When using the `setup-java` action in your GitHub Actions workflow, it is recommended to set the following permissions to ensure proper functionality: When using the `setup-java` action in your GitHub Actions workflow, it is recommended to set the following permissions to ensure proper functionality:
+47 -7
View File
@@ -17,6 +17,7 @@ describe('dependency cache', () => {
let spyWarning: jest.SpyInstance<void, Parameters<typeof core.warning>>; let spyWarning: jest.SpyInstance<void, Parameters<typeof core.warning>>;
let spyDebug: jest.SpyInstance<void, Parameters<typeof core.debug>>; let spyDebug: jest.SpyInstance<void, Parameters<typeof core.debug>>;
let spySaveState: jest.SpyInstance<void, Parameters<typeof core.saveState>>; let spySaveState: jest.SpyInstance<void, Parameters<typeof core.saveState>>;
let spyCoreError: jest.SpyInstance;
beforeEach(() => { beforeEach(() => {
workspace = mkdtempSync(join(tmpdir(), 'setup-java-cache-')); workspace = mkdtempSync(join(tmpdir(), 'setup-java-cache-'));
@@ -51,6 +52,10 @@ describe('dependency cache', () => {
spySaveState = jest.spyOn(core, 'saveState'); spySaveState = jest.spyOn(core, 'saveState');
spySaveState.mockImplementation(() => null); spySaveState.mockImplementation(() => null);
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError.mockImplementation(() => {});
}); });
afterEach(() => { afterEach(() => {
@@ -58,6 +63,10 @@ describe('dependency cache', () => {
process.env['GITHUB_WORKSPACE'] = ORIGINAL_GITHUB_WORKSPACE; process.env['GITHUB_WORKSPACE'] = ORIGINAL_GITHUB_WORKSPACE;
process.env['RUNNER_OS'] = ORIGINAL_RUNNER_OS; process.env['RUNNER_OS'] = ORIGINAL_RUNNER_OS;
resetState(); resetState();
jest.resetAllMocks();
jest.clearAllMocks();
jest.restoreAllMocks();
}); });
describe('restore', () => { describe('restore', () => {
@@ -87,19 +96,48 @@ describe('dependency cache', () => {
}); });
describe('for maven', () => { describe('for maven', () => {
it('throws error if no pom.xml found', async () => { it('throws error if no pom.xml or maven-wrapper.properties found', async () => {
await expect(restore('maven', '')).rejects.toThrow( await expect(restore('maven', '')).rejects.toThrow(
`No file in ${projectRoot( `No file in ${projectRoot(
workspace workspace
)} matched to [**/pom.xml], make sure you have checked out the target repository` )} matched to [**/pom.xml,**/.mvn/wrapper/maven-wrapper.properties], make sure you have checked out the target repository`
); );
}); });
it('downloads cache', async () => { it('downloads cache based on pom.xml', async () => {
createFile(join(workspace, 'pom.xml')); createFile(join(workspace, 'pom.xml'));
await restore('maven', ''); await restore('maven', '');
expect(spyCacheRestore).toHaveBeenCalled(); expect(spyCacheRestore).toHaveBeenCalledWith(
expect(spyGlobHashFiles).toHaveBeenCalledWith('**/pom.xml'); [
join(os.homedir(), '.m2', 'repository'),
join(os.homedir(), '.m2', 'wrapper', 'dists')
],
expect.any(String)
);
expect(spyGlobHashFiles).toHaveBeenCalledWith(
'**/pom.xml\n**/.mvn/wrapper/maven-wrapper.properties'
);
expect(spyWarning).not.toHaveBeenCalled();
expect(spyInfo).toHaveBeenCalledWith('maven cache is not found');
});
it('downloads cache based on maven-wrapper.properties', async () => {
createDirectory(join(workspace, '.mvn'));
createDirectory(join(workspace, '.mvn', 'wrapper'));
createFile(
join(workspace, '.mvn', 'wrapper', 'maven-wrapper.properties')
);
await restore('maven', '');
expect(spyCacheRestore).toHaveBeenCalledWith(
[
join(os.homedir(), '.m2', 'repository'),
join(os.homedir(), '.m2', 'wrapper', 'dists')
],
expect.any(String)
);
expect(spyGlobHashFiles).toHaveBeenCalledWith(
'**/pom.xml\n**/.mvn/wrapper/maven-wrapper.properties'
);
expect(spyWarning).not.toHaveBeenCalled(); expect(spyWarning).not.toHaveBeenCalled();
expect(spyInfo).toHaveBeenCalledWith('maven cache is not found'); expect(spyInfo).toHaveBeenCalledWith('maven cache is not found');
}); });
@@ -282,10 +320,12 @@ describe('dependency cache', () => {
await save('maven'); await save('maven');
expect(spyCacheSave).toHaveBeenCalled(); expect(spyCacheSave).toHaveBeenCalled();
expect(spyWarning).not.toHaveBeenCalled(); expect(spyWarning).not.toHaveBeenCalled();
expect(spyInfo).toHaveBeenCalled(); expect(spyInfo).not.toHaveBeenCalledWith(
expect(spyInfo).toHaveBeenCalledWith(
expect.stringMatching(/^Cache saved with the key:.*/) expect.stringMatching(/^Cache saved with the key:.*/)
); );
expect(spyDebug).toHaveBeenCalledWith(
expect.stringMatching(/^Cache was not saved for the key:.*/)
);
}); });
it('saves with error from toolkit, should fail workflow', async () => { it('saves with error from toolkit, should fail workflow', async () => {
+14 -1
View File
@@ -11,22 +11,35 @@ describe('cleanup', () => {
Parameters<typeof cache.saveCache> Parameters<typeof cache.saveCache>
>; >;
let spyJobStatusSuccess: jest.SpyInstance; let spyJobStatusSuccess: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
beforeEach(() => { beforeEach(() => {
spyWarning = jest.spyOn(core, 'warning'); spyWarning = jest.spyOn(core, 'warning');
spyWarning.mockImplementation(() => null); spyWarning.mockImplementation(() => null);
spyInfo = jest.spyOn(core, 'info'); spyInfo = jest.spyOn(core, 'info');
spyInfo.mockImplementation(() => null); spyInfo.mockImplementation(() => null);
spyCacheSave = jest.spyOn(cache, 'saveCache'); spyCacheSave = jest.spyOn(cache, 'saveCache');
spyJobStatusSuccess = jest.spyOn(util, 'isJobStatusSuccess'); spyJobStatusSuccess = jest.spyOn(util, 'isJobStatusSuccess');
spyJobStatusSuccess.mockReturnValue(true); spyJobStatusSuccess.mockReturnValue(true);
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError.mockImplementation(() => {});
createStateForSuccessfulRestore(); createStateForSuccessfulRestore();
}); });
afterEach(() => { afterEach(() => {
resetState(); resetState();
jest.resetAllMocks();
jest.clearAllMocks();
jest.restoreAllMocks();
}); });
it('does not fail nor warn even when the save process throws a ReserveCacheError', async () => { it('does not warn/fail even when the save process throws a ReserveCacheError', async () => {
spyCacheSave.mockImplementation((paths: string[], key: string) => spyCacheSave.mockImplementation((paths: string[], key: string) =>
Promise.reject( Promise.reject(
new cache.ReserveCacheError( new cache.ReserveCacheError(
+43
View File
@@ -79,6 +79,49 @@
} }
] ]
}, },
{
"version": "17.0.18",
"stable": true,
"release_url": "https://aka.ms/download-jdk",
"files": [
{
"filename": "microsoft-jdk-17.0.18-macos-x64.tar.gz",
"arch": "x64",
"platform": "darwin",
"download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-macos-x64.tar.gz"
},
{
"filename": "microsoft-jdk-17.0.18-linux-x64.tar.gz",
"arch": "x64",
"platform": "linux",
"download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-linux-x64.tar.gz"
},
{
"filename": "microsoft-jdk-17.0.18-windows-x64.zip",
"arch": "x64",
"platform": "win32",
"download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-windows-x64.zip"
},
{
"filename": "microsoft-jdk-17.0.18-macos-aarch64.tar.gz",
"arch": "aarch64",
"platform": "darwin",
"download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-macos-aarch64.tar.gz"
},
{
"filename": "microsoft-jdk-17.0.18-linux-aarch64.tar.gz",
"arch": "aarch64",
"platform": "linux",
"download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-linux-aarch64.tar.gz"
},
{
"filename": "microsoft-jdk-17.0.18-windows-aarch64.zip",
"arch": "aarch64",
"platform": "win32",
"download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-windows-aarch64.zip"
}
]
},
{ {
"version": "17.0.7", "version": "17.0.7",
"stable": true, "stable": true,
+1 -1
View File
@@ -247,7 +247,7 @@
{ {
"id": 12446, "id": 12446,
"url": "https://cdn.azul.com/zulu/bin/zulu17.48.15-ca-jdk17.0.10-windows_aarch64.zip", "url": "https://cdn.azul.com/zulu/bin/zulu17.48.15-ca-jdk17.0.10-windows_aarch64.zip",
"name": "zulu17.48.15-ca-jdk17.0.10-win_aarhc4.zip", "name": "zulu17.48.15-ca-jdk17.0.10-win_aarch4.zip",
"zulu_version": [17, 48, 15, 0], "zulu_version": [17, 48, 15, 0],
"jdk_version": [17, 0, 10, 7] "jdk_version": [17, 0, 10, 7]
} }
+96 -9
View File
@@ -4,14 +4,18 @@ import {
AdoptDistribution, AdoptDistribution,
AdoptImplementation AdoptImplementation
} from '../../src/distributions/adopt/installer'; } from '../../src/distributions/adopt/installer';
import {TemurinDistribution} from '../../src/distributions/temurin/installer';
import {JavaInstallerOptions} from '../../src/distributions/base-models'; import {JavaInstallerOptions} from '../../src/distributions/base-models';
import os from 'os'; import os from 'os';
import manifestData from '../data/adopt.json'; import manifestData from '../data/adopt.json';
import * as core from '@actions/core';
describe('getAvailableVersions', () => { describe('getAvailableVersions', () => {
let spyHttpClient: jest.SpyInstance; let spyHttpClient: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
let spyCoreWarning: jest.SpyInstance;
beforeEach(() => { beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@@ -20,6 +24,12 @@ describe('getAvailableVersions', () => {
headers: {}, headers: {},
result: [] result: []
}); });
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError.mockImplementation(() => {});
spyCoreWarning = jest.spyOn(core, 'warning');
spyCoreWarning.mockImplementation(() => {});
}); });
afterEach(() => { afterEach(() => {
@@ -130,22 +140,19 @@ describe('getAvailableVersions', () => {
); );
it('load available versions', async () => { it('load available versions', async () => {
const nextPageUrl =
'https://api.adoptopenjdk.net/v3/assets/version/%5B1.0,100.0%5D?page=1&page_size=20';
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
spyHttpClient spyHttpClient
.mockReturnValueOnce({ .mockReturnValueOnce({
statusCode: 200, statusCode: 200,
headers: {}, headers: {link: `<${nextPageUrl}>; rel="next"`},
result: manifestData as any result: manifestData as any
}) })
.mockReturnValueOnce({ .mockReturnValueOnce({
statusCode: 200, statusCode: 200,
headers: {}, headers: {},
result: manifestData as any result: manifestData as any
})
.mockReturnValueOnce({
statusCode: 200,
headers: {},
result: []
}); });
const distribution = new AdoptDistribution( const distribution = new AdoptDistribution(
@@ -160,6 +167,34 @@ describe('getAvailableVersions', () => {
const availableVersions = await distribution['getAvailableVersions'](); const availableVersions = await distribution['getAvailableVersions']();
expect(availableVersions).not.toBeNull(); expect(availableVersions).not.toBeNull();
expect(availableVersions.length).toBe(manifestData.length * 2); expect(availableVersions.length).toBe(manifestData.length * 2);
expect(spyHttpClient).toHaveBeenNthCalledWith(2, nextPageUrl);
});
it('stops pagination after 1000 pages as a safeguard', async () => {
const nextPageUrl =
'https://api.adoptopenjdk.net/v3/assets/version/%5B1.0,100.0%5D?page=2&page_size=20';
spyHttpClient.mockReturnValue({
statusCode: 200,
headers: {link: `<${nextPageUrl}>; rel="next"`},
result: [{version_data: {semver: '17.0.1'}, binaries: []}] as any
});
const distribution = new AdoptDistribution(
{
version: '11',
architecture: 'x64',
packageType: 'jdk',
checkLatest: false
},
AdoptImplementation.Hotspot
);
await distribution['getAvailableVersions']();
expect(spyHttpClient).toHaveBeenCalledTimes(1000);
expect(spyCoreWarning).toHaveBeenCalledWith(
expect.stringContaining('Reached pagination safeguard limit (1000 pages)')
);
}); });
it.each([ it.each([
@@ -222,6 +257,38 @@ describe('getAvailableVersions', () => {
}); });
describe('findPackageForDownload', () => { describe('findPackageForDownload', () => {
it('returns Temurin result and does not query Adopt API when Temurin succeeds', async () => {
const temurinRelease = {
version: '11.0.31+11',
url: 'https://example.test/temurin-11.tar.gz'
};
const temurinFindPackageForDownload = jest
.fn()
.mockResolvedValue(temurinRelease);
const temurinDistribution = {
findPackageForDownload: temurinFindPackageForDownload
} as unknown as TemurinDistribution;
const distribution = new AdoptDistribution(
{
version: '11',
architecture: 'x64',
packageType: 'jdk',
checkLatest: false
},
AdoptImplementation.Hotspot,
temurinDistribution
);
const adoptLookupSpy = jest.fn();
distribution['getAvailableVersions'] = adoptLookupSpy;
const resolvedVersion = await distribution['findPackageForDownload']('11');
expect(resolvedVersion).toEqual(temurinRelease);
expect(temurinFindPackageForDownload).toHaveBeenCalledWith('11');
expect(adoptLookupSpy).not.toHaveBeenCalled();
});
it.each([ it.each([
['9', '9.0.7+10'], ['9', '9.0.7+10'],
['15', '15.0.2+7'], ['15', '15.0.2+7'],
@@ -244,6 +311,11 @@ describe('findPackageForDownload', () => {
}, },
AdoptImplementation.Hotspot AdoptImplementation.Hotspot
); );
// Mock Temurin to fail so fallback to AdoptOpenJDK is tested
distribution['temurinDistribution']!['findPackageForDownload'] =
async () => {
throw new Error('No matching version found for SemVer');
};
distribution['getAvailableVersions'] = async () => manifestData as any; distribution['getAvailableVersions'] = async () => manifestData as any;
const resolvedVersion = await distribution['findPackageForDownload'](input); const resolvedVersion = await distribution['findPackageForDownload'](input);
expect(resolvedVersion.version).toBe(expected); expect(resolvedVersion.version).toBe(expected);
@@ -259,10 +331,15 @@ describe('findPackageForDownload', () => {
}, },
AdoptImplementation.Hotspot AdoptImplementation.Hotspot
); );
// Mock Temurin to fail so fallback to AdoptOpenJDK is tested
distribution['temurinDistribution']!['findPackageForDownload'] =
async () => {
throw new Error('No matching version found for SemVer');
};
distribution['getAvailableVersions'] = async () => manifestData as any; distribution['getAvailableVersions'] = async () => manifestData as any;
await expect( await expect(
distribution['findPackageForDownload']('9.0.8') distribution['findPackageForDownload']('9.0.8')
).rejects.toThrow(/Could not find satisfied version for SemVer */); ).rejects.toThrow(/No matching version found for SemVer */);
}); });
it('version is not found', async () => { it('version is not found', async () => {
@@ -275,9 +352,14 @@ describe('findPackageForDownload', () => {
}, },
AdoptImplementation.Hotspot AdoptImplementation.Hotspot
); );
// Mock Temurin to fail so fallback to AdoptOpenJDK is tested
distribution['temurinDistribution']!['findPackageForDownload'] =
async () => {
throw new Error('No matching version found for SemVer');
};
distribution['getAvailableVersions'] = async () => manifestData as any; distribution['getAvailableVersions'] = async () => manifestData as any;
await expect(distribution['findPackageForDownload']('7.x')).rejects.toThrow( await expect(distribution['findPackageForDownload']('7.x')).rejects.toThrow(
/Could not find satisfied version for SemVer */ /No matching version found for SemVer */
); );
}); });
@@ -291,9 +373,14 @@ describe('findPackageForDownload', () => {
}, },
AdoptImplementation.Hotspot AdoptImplementation.Hotspot
); );
// Mock Temurin to fail so fallback to AdoptOpenJDK is tested
distribution['temurinDistribution']!['findPackageForDownload'] =
async () => {
throw new Error('No matching version found for SemVer');
};
distribution['getAvailableVersions'] = async () => []; distribution['getAvailableVersions'] = async () => [];
await expect(distribution['findPackageForDownload']('11')).rejects.toThrow( await expect(distribution['findPackageForDownload']('11')).rejects.toThrow(
/Could not find satisfied version for SemVer */ /No matching version found for SemVer */
); );
}); });
}); });
+100 -7
View File
@@ -38,7 +38,7 @@ class EmptyJavaBase extends JavaBase {
): Promise<JavaDownloadRelease> { ): Promise<JavaDownloadRelease> {
const availableVersion = '11.0.9'; const availableVersion = '11.0.9';
if (!semver.satisfies(availableVersion, range)) { if (!semver.satisfies(availableVersion, range)) {
throw new Error('Available version not found'); throw this.createVersionNotFoundError(range, [availableVersion]);
} }
return { return {
@@ -248,6 +248,7 @@ describe('setupJava', () => {
let spyCoreExportVariable: jest.SpyInstance; let spyCoreExportVariable: jest.SpyInstance;
let spyCoreAddPath: jest.SpyInstance; let spyCoreAddPath: jest.SpyInstance;
let spyCoreSetOutput: jest.SpyInstance; let spyCoreSetOutput: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
beforeEach(() => { beforeEach(() => {
spyGetToolcachePath = jest.spyOn(util, 'getToolcachePath'); spyGetToolcachePath = jest.spyOn(util, 'getToolcachePath');
@@ -287,6 +288,10 @@ describe('setupJava', () => {
spyCoreSetOutput = jest.spyOn(core, 'setOutput'); spyCoreSetOutput = jest.spyOn(core, 'setOutput');
spyCoreSetOutput.mockImplementation(() => undefined); spyCoreSetOutput.mockImplementation(() => undefined);
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError.mockImplementation(() => undefined);
jest.spyOn(os, 'arch').mockReturnValue('x86' as ReturnType<typeof os.arch>); jest.spyOn(os, 'arch').mockReturnValue('x86' as ReturnType<typeof os.arch>);
}); });
@@ -530,19 +535,16 @@ describe('setupJava', () => {
checkLatest: false checkLatest: false
} }
] ]
])( ])('should throw an error for version not found for %s', async input => {
'should throw an error for Available version not found for %s',
async input => {
mockJavaBase = new EmptyJavaBase(input); mockJavaBase = new EmptyJavaBase(input);
await expect(mockJavaBase.setupJava()).rejects.toThrow( await expect(mockJavaBase.setupJava()).rejects.toThrow(
'Available version not found' `No matching version found for SemVer '${input.version}'`
); );
expect(spyTcFindAllVersions).toHaveBeenCalled(); expect(spyTcFindAllVersions).toHaveBeenCalled();
expect(spyCoreAddPath).not.toHaveBeenCalled(); expect(spyCoreAddPath).not.toHaveBeenCalled();
expect(spyCoreExportVariable).not.toHaveBeenCalled(); expect(spyCoreExportVariable).not.toHaveBeenCalled();
expect(spyCoreSetOutput).not.toHaveBeenCalled(); expect(spyCoreSetOutput).not.toHaveBeenCalled();
} });
);
}); });
describe('normalizeVersion', () => { describe('normalizeVersion', () => {
@@ -570,6 +572,97 @@ describe('normalizeVersion', () => {
}); });
}); });
describe('createVersionNotFoundError', () => {
it('should include all required fields in error message without available versions', () => {
const mockJavaBase = new EmptyJavaBase({
version: '17.0.5',
architecture: 'x64',
packageType: 'jdk',
checkLatest: false
});
const error = (mockJavaBase as any).createVersionNotFoundError('17.0.5');
expect(error.message).toContain(
"No matching version found for SemVer '17.0.5'"
);
expect(error.message).toContain('Distribution: Empty');
expect(error.message).toContain('Package type: jdk');
expect(error.message).toContain('Architecture: x64');
});
it('should include available versions when provided', () => {
const mockJavaBase = new EmptyJavaBase({
version: '17.0.5',
architecture: 'x64',
packageType: 'jdk',
checkLatest: false
});
const availableVersions = ['11.0.1', '11.0.2', '17.0.1', '17.0.2'];
const error = (mockJavaBase as any).createVersionNotFoundError(
'17.0.5',
availableVersions
);
expect(error.message).toContain(
"No matching version found for SemVer '17.0.5'"
);
expect(error.message).toContain('Distribution: Empty');
expect(error.message).toContain('Package type: jdk');
expect(error.message).toContain('Architecture: x64');
expect(error.message).toContain(
'Available versions: 11.0.1, 11.0.2, 17.0.1, 17.0.2'
);
});
it('should truncate available versions when there are many', () => {
const mockJavaBase = new EmptyJavaBase({
version: '17.0.5',
architecture: 'x64',
packageType: 'jdk',
checkLatest: false
});
// Create 60 versions to test truncation
const availableVersions = Array.from({length: 60}, (_, i) => `11.0.${i}`);
const error = (mockJavaBase as any).createVersionNotFoundError(
'17.0.5',
availableVersions
);
expect(error.message).toContain('Available versions:');
expect(error.message).toContain('...');
expect(error.message).toContain('(showing first 50 of 60 versions');
});
it('should include additional context when provided', () => {
const mockJavaBase = new EmptyJavaBase({
version: '17.0.5',
architecture: 'x64',
packageType: 'jdk',
checkLatest: false
});
const availableVersions = ['11.0.1', '11.0.2'];
const additionalContext = 'Platform: linux';
const error = (mockJavaBase as any).createVersionNotFoundError(
'17.0.5',
availableVersions,
additionalContext
);
expect(error.message).toContain(
"No matching version found for SemVer '17.0.5'"
);
expect(error.message).toContain('Distribution: Empty');
expect(error.message).toContain('Package type: jdk');
expect(error.message).toContain('Architecture: x64');
expect(error.message).toContain('Platform: linux');
expect(error.message).toContain('Available versions: 11.0.1, 11.0.2');
});
});
describe('getToolcacheVersionName', () => { describe('getToolcacheVersionName', () => {
const DummyJavaBase = JavaBase as any; const DummyJavaBase = JavaBase as any;
@@ -4,13 +4,14 @@ import {JavaInstallerOptions} from '../../src/distributions/base-models';
import {CorrettoDistribution} from '../../src/distributions/corretto/installer'; import {CorrettoDistribution} from '../../src/distributions/corretto/installer';
import * as util from '../../src/util'; import * as util from '../../src/util';
import os from 'os'; import os from 'os';
import {isGeneratorFunction} from 'util/types'; import * as core from '@actions/core';
import manifestData from '../data/corretto.json'; import manifestData from '../data/corretto.json';
describe('getAvailableVersions', () => { describe('getAvailableVersions', () => {
let spyHttpClient: jest.SpyInstance; let spyHttpClient: jest.SpyInstance;
let spyGetDownloadArchiveExtension: jest.SpyInstance; let spyGetDownloadArchiveExtension: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
beforeEach(() => { beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@@ -23,6 +24,10 @@ describe('getAvailableVersions', () => {
util, util,
'getDownloadArchiveExtension' 'getDownloadArchiveExtension'
); );
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError.mockImplementation(() => {});
}); });
afterEach(() => { afterEach(() => {
@@ -198,7 +203,7 @@ describe('getAvailableVersions', () => {
await expect( await expect(
distribution['findPackageForDownload'](version) distribution['findPackageForDownload'](version)
).rejects.toThrow("Could not find satisfied version for SemVer '4'"); ).rejects.toThrow("No matching version found for SemVer '4'");
}); });
it.each([ it.each([
@@ -1,12 +1,14 @@
import {HttpClient} from '@actions/http-client'; import {HttpClient} from '@actions/http-client';
import {DragonwellDistribution} from '../../src/distributions/dragonwell/installer'; import {DragonwellDistribution} from '../../src/distributions/dragonwell/installer';
import * as utils from '../../src/util'; import * as utils from '../../src/util';
import * as core from '@actions/core';
import manifestData from '../data/dragonwell.json'; import manifestData from '../data/dragonwell.json';
describe('getAvailableVersions', () => { describe('getAvailableVersions', () => {
let spyHttpClient: jest.SpyInstance; let spyHttpClient: jest.SpyInstance;
let spyUtilGetDownloadArchiveExtension: jest.SpyInstance; let spyUtilGetDownloadArchiveExtension: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
beforeEach(() => { beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@@ -21,6 +23,10 @@ describe('getAvailableVersions', () => {
'getDownloadArchiveExtension' 'getDownloadArchiveExtension'
); );
spyUtilGetDownloadArchiveExtension.mockReturnValue('tar.gz'); spyUtilGetDownloadArchiveExtension.mockReturnValue('tar.gz');
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError.mockImplementation(() => {});
}); });
afterEach(() => { afterEach(() => {
@@ -232,7 +238,7 @@ describe('getAvailableVersions', () => {
await expect( await expect(
distribution['findPackageForDownload'](jdkVersion) distribution['findPackageForDownload'](jdkVersion)
).rejects.toThrow( ).rejects.toThrow(
`Couldn't find any satisfied version for the specified java-version: "${jdkVersion}" and architecture: "${arch}".` `No matching version found for SemVer '${jdkVersion}'`
); );
} }
); );
+165 -11
View File
@@ -3,7 +3,11 @@ import * as tc from '@actions/tool-cache';
import * as http from '@actions/http-client'; import * as http from '@actions/http-client';
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
import {GraalVMDistribution} from '../../src/distributions/graalvm/installer'; import {
GraalVMCommunityDistribution,
GraalVMDistribution
} from '../../src/distributions/graalvm/installer';
import {getJavaDistribution} from '../../src/distributions/distribution-factory';
import {JavaInstallerOptions} from '../../src/distributions/base-models'; import {JavaInstallerOptions} from '../../src/distributions/base-models';
import * as util from '../../src/util'; import * as util from '../../src/util';
@@ -41,7 +45,9 @@ beforeAll(() => {
describe('GraalVMDistribution', () => { describe('GraalVMDistribution', () => {
let distribution: GraalVMDistribution; let distribution: GraalVMDistribution;
let communityDistribution: GraalVMCommunityDistribution;
let mockHttpClient: jest.Mocked<http.HttpClient>; let mockHttpClient: jest.Mocked<http.HttpClient>;
let spyCoreError: jest.SpyInstance;
const defaultOptions: JavaInstallerOptions = { const defaultOptions: JavaInstallerOptions = {
version: '17', version: '17',
@@ -54,11 +60,17 @@ describe('GraalVMDistribution', () => {
jest.clearAllMocks(); jest.clearAllMocks();
distribution = new GraalVMDistribution(defaultOptions); distribution = new GraalVMDistribution(defaultOptions);
communityDistribution = new GraalVMCommunityDistribution(defaultOptions);
mockHttpClient = new http.HttpClient() as jest.Mocked<http.HttpClient>; mockHttpClient = new http.HttpClient() as jest.Mocked<http.HttpClient>;
(distribution as any).http = mockHttpClient; (distribution as any).http = mockHttpClient;
(communityDistribution as any).http = mockHttpClient;
(util.getDownloadArchiveExtension as jest.Mock).mockReturnValue('tar.gz'); (util.getDownloadArchiveExtension as jest.Mock).mockReturnValue('tar.gz');
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError.mockImplementation(() => {});
}); });
afterAll(() => { afterAll(() => {
@@ -237,6 +249,23 @@ describe('GraalVMDistribution', () => {
path: '/cached/java/path' path: '/cached/java/path'
}); });
}); });
it('should use a dedicated toolcache folder for GraalVM Community', async () => {
const result = await (communityDistribution as any).downloadTool(
javaRelease
);
expect(tc.cacheDir).toHaveBeenCalledWith(
path.join('/tmp/extracted', 'graalvm-jdk-17.0.5'),
'Java_GraalVM_Community_jdk',
'17.0.5',
'x64'
);
expect(result).toEqual({
version: '17.0.5',
path: '/cached/java/path'
});
});
}); });
describe('findPackageForDownload', () => { describe('findPackageForDownload', () => {
@@ -348,11 +377,19 @@ describe('GraalVMDistribution', () => {
} as http.HttpClientResponse; } as http.HttpClientResponse;
mockHttpClient.head.mockResolvedValue(mockResponse); mockHttpClient.head.mockResolvedValue(mockResponse);
// Verify the error is thrown with the expected message
await expect( await expect(
(distribution as any).findPackageForDownload('17.0.99') (distribution as any).findPackageForDownload('17.0.99')
).rejects.toThrow( ).rejects.toThrow("No matching version found for SemVer '17.0.99'");
'Could not find GraalVM for SemVer 17.0.99. Please check if this version is available at https://download.oracle.com/graalvm' // Verify distribution info is included
); await expect(
(distribution as any).findPackageForDownload('17.0.99')
).rejects.toThrow('GraalVM');
// Verify the hint about checking the base URL is included
await expect(
(distribution as any).findPackageForDownload('17.0.99')
).rejects.toThrow('https://www.graalvm.org/downloads/');
}); });
it('should throw error for unauthorized access (401)', async () => { it('should throw error for unauthorized access (401)', async () => {
@@ -496,12 +533,19 @@ describe('GraalVMDistribution', () => {
await expect( await expect(
(distribution as any).findPackageForDownload('23') (distribution as any).findPackageForDownload('23')
).rejects.toThrow("Unable to find latest version for '23-ea'"); ).rejects.toThrow("No matching version found for SemVer '23-ea'");
// Verify error logging await expect(
expect(core.error).toHaveBeenCalledWith( (distribution as any).findPackageForDownload('23')
'Available versions: 23-ea-20240716' ).rejects.toThrow(
'Note: No EA build is marked as latest for this version.'
); );
await expect(
(distribution as any).findPackageForDownload('23')
).rejects.toThrow('23-ea-20240716');
// Verify error logging - removed as we now use the helper method which doesn't call core.error
}); });
it('should throw error when no matching file for architecture in EA build', async () => { it('should throw error when no matching file for architecture in EA build', async () => {
@@ -708,11 +752,19 @@ describe('GraalVMDistribution', () => {
await expect( await expect(
(distribution as any).findEABuildDownloadUrl('23-ea') (distribution as any).findEABuildDownloadUrl('23-ea')
).rejects.toThrow("Unable to find latest version for '23-ea'"); ).rejects.toThrow("No matching version found for SemVer '23-ea'");
expect(core.error).toHaveBeenCalledWith( await expect(
'Available versions: 23-ea-20240716, 23-ea-20240709' (distribution as any).findEABuildDownloadUrl('23-ea')
).rejects.toThrow(
'Note: No EA build is marked as latest for this version.'
); );
await expect(
(distribution as any).findEABuildDownloadUrl('23-ea')
).rejects.toThrow('23-ea-20240716');
// Verify error logging - removed as we now use the helper method which doesn't call core.error
}); });
it('should throw error when no matching file for architecture', async () => { it('should throw error when no matching file for architecture', async () => {
@@ -920,5 +972,107 @@ describe('GraalVMDistribution', () => {
configurable: true configurable: true
}); });
}); });
describe('GraalVMCommunityDistribution', () => {
beforeEach(() => {
jest
.spyOn(communityDistribution, 'getPlatform')
.mockReturnValue('linux');
});
it('should resolve an exact GraalVM Community version from GitHub releases', async () => {
mockHttpClient.getJson.mockResolvedValue({
result: [
{
draft: false,
prerelease: false,
assets: [
{
name: 'graalvm-community-jdk-21.0.2_linux-x64_bin.tar.gz',
browser_download_url:
'https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-21.0.2/graalvm-community-jdk-21.0.2_linux-x64_bin.tar.gz'
}
]
}
],
statusCode: 200,
headers: {}
});
const result = await (
communityDistribution as any
).findPackageForDownload('21.0.2');
expect(result).toEqual({
url: 'https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-21.0.2/graalvm-community-jdk-21.0.2_linux-x64_bin.tar.gz',
version: '21.0.2'
});
});
it('should resolve the latest GraalVM Community release for a major version', async () => {
mockHttpClient.getJson.mockResolvedValue({
result: [
{
draft: false,
prerelease: false,
assets: [
{
name: 'graalvm-community-jdk-21.0.1_linux-x64_bin.tar.gz',
browser_download_url:
'https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-21.0.1/graalvm-community-jdk-21.0.1_linux-x64_bin.tar.gz'
}
]
},
{
draft: false,
prerelease: false,
assets: [
{
name: 'graalvm-community-jdk-21.0.2_linux-x64_bin.tar.gz',
browser_download_url:
'https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-21.0.2/graalvm-community-jdk-21.0.2_linux-x64_bin.tar.gz'
}
]
}
],
statusCode: 200,
headers: {}
});
const result = await (
communityDistribution as any
).findPackageForDownload('21');
expect(result).toEqual({
url: 'https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-21.0.2/graalvm-community-jdk-21.0.2_linux-x64_bin.tar.gz',
version: '21.0.2'
});
});
it('should reject GraalVM Community early access requests', async () => {
(communityDistribution as any).stable = false;
await expect(
(communityDistribution as any).findPackageForDownload('23')
).rejects.toThrow(
'GraalVM Community does not provide early access builds'
);
});
});
});
});
describe('distribution factory', () => {
const defaultOptions: JavaInstallerOptions = {
version: '17',
architecture: 'x64',
packageType: 'jdk',
checkLatest: false
};
it('should map graalvm-community to the community installer', () => {
const community = getJavaDistribution('graalvm-community', defaultOptions);
expect(community).toBeInstanceOf(GraalVMCommunityDistribution);
}); });
}); });
@@ -4,9 +4,11 @@ import {JetBrainsDistribution} from '../../src/distributions/jetbrains/installer
import manifestData from '../data/jetbrains.json'; import manifestData from '../data/jetbrains.json';
import os from 'os'; import os from 'os';
import * as core from '@actions/core';
describe('getAvailableVersions', () => { describe('getAvailableVersions', () => {
let spyHttpClient: jest.SpyInstance; let spyHttpClient: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
beforeEach(() => { beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@@ -15,6 +17,10 @@ describe('getAvailableVersions', () => {
headers: {}, headers: {},
result: [] result: []
}); });
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError.mockImplementation(() => {});
}); });
afterEach(() => { afterEach(() => {
@@ -98,7 +104,7 @@ describe('findPackageForDownload', () => {
}); });
distribution['getAvailableVersions'] = async () => manifestData as any; distribution['getAvailableVersions'] = async () => manifestData as any;
await expect(distribution['findPackageForDownload']('8.x')).rejects.toThrow( await expect(distribution['findPackageForDownload']('8.x')).rejects.toThrow(
/Could not find satisfied version for SemVer */ /No matching version found for SemVer */
); );
}); });
@@ -111,7 +117,7 @@ describe('findPackageForDownload', () => {
}); });
distribution['getAvailableVersions'] = async () => []; distribution['getAvailableVersions'] = async () => [];
await expect(distribution['findPackageForDownload']('8')).rejects.toThrow( await expect(distribution['findPackageForDownload']('8')).rejects.toThrow(
/Could not find satisfied version for SemVer */ /No matching version found for SemVer */
); );
}); });
}); });
@@ -5,11 +5,13 @@ import {
} from '../../src/distributions/liberica/models'; } from '../../src/distributions/liberica/models';
import {HttpClient} from '@actions/http-client'; import {HttpClient} from '@actions/http-client';
import os from 'os'; import os from 'os';
import * as core from '@actions/core';
import manifestData from '../data/liberica.json'; import manifestData from '../data/liberica.json';
describe('getAvailableVersions', () => { describe('getAvailableVersions', () => {
let spyHttpClient: jest.SpyInstance; let spyHttpClient: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
beforeEach(() => { beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@@ -18,6 +20,10 @@ describe('getAvailableVersions', () => {
headers: {}, headers: {},
result: manifestData as LibericaVersion[] result: manifestData as LibericaVersion[]
}); });
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError.mockImplementation(() => {});
}); });
afterEach(() => { afterEach(() => {
@@ -209,7 +215,7 @@ describe('findPackageForDownload', () => {
it('should throw an error', async () => { it('should throw an error', async () => {
await expect(distribution['findPackageForDownload']('17')).rejects.toThrow( await expect(distribution['findPackageForDownload']('17')).rejects.toThrow(
/Could not find satisfied version for semver */ /No matching version found for SemVer/
); );
}); });
}); });
@@ -5,11 +5,13 @@ import {
} from '../../src/distributions/liberica/models'; } from '../../src/distributions/liberica/models';
import {HttpClient} from '@actions/http-client'; import {HttpClient} from '@actions/http-client';
import os from 'os'; import os from 'os';
import * as core from '@actions/core';
import manifestData from '../data/liberica-linux.json'; import manifestData from '../data/liberica-linux.json';
describe('getAvailableVersions', () => { describe('getAvailableVersions', () => {
let spyHttpClient: jest.SpyInstance; let spyHttpClient: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
beforeEach(() => { beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@@ -18,6 +20,10 @@ describe('getAvailableVersions', () => {
headers: {}, headers: {},
result: manifestData as LibericaVersion[] result: manifestData as LibericaVersion[]
}); });
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError.mockImplementation(() => {});
}); });
afterEach(() => { afterEach(() => {
@@ -209,7 +215,7 @@ describe('findPackageForDownload', () => {
it('should throw an error', async () => { it('should throw an error', async () => {
await expect(distribution['findPackageForDownload']('18')).rejects.toThrow( await expect(distribution['findPackageForDownload']('18')).rejects.toThrow(
/Could not find satisfied version for semver */ /No matching version found for SemVer/
); );
}); });
}); });
@@ -5,11 +5,13 @@ import {
} from '../../src/distributions/liberica/models'; } from '../../src/distributions/liberica/models';
import {HttpClient} from '@actions/http-client'; import {HttpClient} from '@actions/http-client';
import os from 'os'; import os from 'os';
import * as core from '@actions/core';
import manifestData from '../data/liberica-windows.json'; import manifestData from '../data/liberica-windows.json';
describe('getAvailableVersions', () => { describe('getAvailableVersions', () => {
let spyHttpClient: jest.SpyInstance; let spyHttpClient: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
beforeEach(() => { beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@@ -18,6 +20,9 @@ describe('getAvailableVersions', () => {
headers: {}, headers: {},
result: manifestData as LibericaVersion[] result: manifestData as LibericaVersion[]
}); });
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError.mockImplementation(() => {});
}); });
afterEach(() => { afterEach(() => {
@@ -209,7 +214,7 @@ describe('findPackageForDownload', () => {
it('should throw an error', async () => { it('should throw an error', async () => {
await expect(distribution['findPackageForDownload']('18')).rejects.toThrow( await expect(distribution['findPackageForDownload']('18')).rejects.toThrow(
/Could not find satisfied version for semver */ /No matching version found for SemVer/
); );
}); });
}); });
@@ -27,6 +27,7 @@ describe('setupJava', () => {
let spyFsReadDir: jest.SpyInstance; let spyFsReadDir: jest.SpyInstance;
let spyUtilsExtractJdkFile: jest.SpyInstance; let spyUtilsExtractJdkFile: jest.SpyInstance;
let spyPathResolve: jest.SpyInstance; let spyPathResolve: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
const expectedJdkFile = 'JavaLocalJdkFile'; const expectedJdkFile = 'JavaLocalJdkFile';
beforeEach(() => { beforeEach(() => {
@@ -93,6 +94,10 @@ describe('setupJava', () => {
// Spy on path methods // Spy on path methods
spyPathResolve = jest.spyOn(path, 'resolve'); spyPathResolve = jest.spyOn(path, 'resolve');
spyPathResolve.mockImplementation((path: string) => path); spyPathResolve.mockImplementation((path: string) => path);
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError.mockImplementation(() => {});
}); });
afterEach(() => { afterEach(() => {
@@ -214,7 +219,7 @@ describe('setupJava', () => {
); );
}); });
it('java is resolved from toolcache including Contents/Home on MacOS', async () => { it('java is resolved from toolcache including Contents/Home on macOS', async () => {
const inputs = { const inputs = {
version: actualJavaVersion, version: actualJavaVersion,
architecture: 'x86', architecture: 'x86',
@@ -257,7 +262,7 @@ describe('setupJava', () => {
}); });
}); });
it('java is unpacked from jdkfile including Contents/Home on MacOS', async () => { it('java is unpacked from jdkfile including Contents/Home on macOS', async () => {
const inputs = { const inputs = {
version: '11.0.289', version: '11.0.289',
architecture: 'x86', architecture: 'x86',
@@ -8,6 +8,7 @@ describe('findPackageForDownload', () => {
let distribution: MicrosoftDistributions; let distribution: MicrosoftDistributions;
let spyGetManifestFromRepo: jest.SpyInstance; let spyGetManifestFromRepo: jest.SpyInstance;
let spyDebug: jest.SpyInstance; let spyDebug: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
beforeEach(() => { beforeEach(() => {
distribution = new MicrosoftDistributions({ distribution = new MicrosoftDistributions({
@@ -26,6 +27,10 @@ describe('findPackageForDownload', () => {
spyDebug = jest.spyOn(core, 'debug'); spyDebug = jest.spyOn(core, 'debug');
spyDebug.mockImplementation(() => {}); spyDebug.mockImplementation(() => {});
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError.mockImplementation(() => {});
}); });
it.each([ it.each([
@@ -39,16 +44,21 @@ describe('findPackageForDownload', () => {
'21.0.0', '21.0.0',
'https://aka.ms/download-jdk/microsoft-jdk-21.0.0-{{OS_TYPE}}-x64.{{ARCHIVE_TYPE}}' 'https://aka.ms/download-jdk/microsoft-jdk-21.0.0-{{OS_TYPE}}-x64.{{ARCHIVE_TYPE}}'
], ],
[
'17.x',
'17.0.18',
'https://aka.ms/download-jdk/microsoft-jdk-17.0.18-{{OS_TYPE}}-x64.{{ARCHIVE_TYPE}}'
],
[
'17.0.7',
'17.0.7',
'https://aka.ms/download-jdk/microsoft-jdk-17.0.7-{{OS_TYPE}}-x64.{{ARCHIVE_TYPE}}'
],
[ [
'17.0.1', '17.0.1',
'17.0.1+12.1', '17.0.1+12.1',
'https://aka.ms/download-jdk/microsoft-jdk-17.0.1.12.1-{{OS_TYPE}}-x64.{{ARCHIVE_TYPE}}' 'https://aka.ms/download-jdk/microsoft-jdk-17.0.1.12.1-{{OS_TYPE}}-x64.{{ARCHIVE_TYPE}}'
], ],
[
'17.x',
'17.0.7',
'https://aka.ms/download-jdk/microsoft-jdk-17.0.7-{{OS_TYPE}}-x64.{{ARCHIVE_TYPE}}'
],
[ [
'16.0.x', '16.0.x',
'16.0.2+7.1', '16.0.2+7.1',
@@ -114,7 +124,7 @@ describe('findPackageForDownload', () => {
}); });
const result = await distro['findPackageForDownload'](version); const result = await distro['findPackageForDownload'](version);
const expectedUrl = `https://aka.ms/download-jdk/microsoft-jdk-17.0.7-macos-${distroArch}.tar.gz`; const expectedUrl = `https://aka.ms/download-jdk/microsoft-jdk-17.0.18-macos-${distroArch}.tar.gz`;
expect(result.url).toBe(expectedUrl); expect(result.url).toBe(expectedUrl);
} }
@@ -140,7 +150,7 @@ describe('findPackageForDownload', () => {
}); });
const result = await distro['findPackageForDownload'](version); const result = await distro['findPackageForDownload'](version);
const expectedUrl = `https://aka.ms/download-jdk/microsoft-jdk-17.0.7-linux-${distroArch}.tar.gz`; const expectedUrl = `https://aka.ms/download-jdk/microsoft-jdk-17.0.18-linux-${distroArch}.tar.gz`;
expect(result.url).toBe(expectedUrl); expect(result.url).toBe(expectedUrl);
} }
@@ -166,7 +176,7 @@ describe('findPackageForDownload', () => {
}); });
const result = await distro['findPackageForDownload'](version); const result = await distro['findPackageForDownload'](version);
const expectedUrl = `https://aka.ms/download-jdk/microsoft-jdk-17.0.7-windows-${distroArch}.zip`; const expectedUrl = `https://aka.ms/download-jdk/microsoft-jdk-17.0.18-windows-${distroArch}.zip`;
expect(result.url).toBe(expectedUrl); expect(result.url).toBe(expectedUrl);
} }
@@ -174,7 +184,7 @@ describe('findPackageForDownload', () => {
it('should throw an error', async () => { it('should throw an error', async () => {
await expect(distribution['findPackageForDownload']('8')).rejects.toThrow( await expect(distribution['findPackageForDownload']('8')).rejects.toThrow(
/Could not find satisfied version for SemVer */ /No matching version found for SemVer */
); );
}); });
}); });
@@ -8,6 +8,7 @@ describe('findPackageForDownload', () => {
let distribution: OracleDistribution; let distribution: OracleDistribution;
let spyDebug: jest.SpyInstance; let spyDebug: jest.SpyInstance;
let spyHttpClient: jest.SpyInstance; let spyHttpClient: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
beforeEach(() => { beforeEach(() => {
distribution = new OracleDistribution({ distribution = new OracleDistribution({
@@ -19,6 +20,10 @@ describe('findPackageForDownload', () => {
spyDebug = jest.spyOn(core, 'debug'); spyDebug = jest.spyOn(core, 'debug');
spyDebug.mockImplementation(() => {}); spyDebug.mockImplementation(() => {});
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError.mockImplementation(() => {});
}); });
it.each([ it.each([
@@ -1,12 +1,14 @@
import {HttpClient} from '@actions/http-client'; import {HttpClient} from '@actions/http-client';
import {SapMachineDistribution} from '../../src/distributions/sapmachine/installer'; import {SapMachineDistribution} from '../../src/distributions/sapmachine/installer';
import * as utils from '../../src/util'; import * as utils from '../../src/util';
import * as core from '@actions/core';
import manifestData from '../data/sapmachine.json'; import manifestData from '../data/sapmachine.json';
describe('getAvailableVersions', () => { describe('getAvailableVersions', () => {
let spyHttpClient: jest.SpyInstance; let spyHttpClient: jest.SpyInstance;
let spyUtilGetDownloadArchiveExtension: jest.SpyInstance; let spyUtilGetDownloadArchiveExtension: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
beforeEach(() => { beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@@ -21,6 +23,10 @@ describe('getAvailableVersions', () => {
'getDownloadArchiveExtension' 'getDownloadArchiveExtension'
); );
spyUtilGetDownloadArchiveExtension.mockReturnValue('tar.gz'); spyUtilGetDownloadArchiveExtension.mockReturnValue('tar.gz');
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError.mockImplementation(() => {});
}); });
afterEach(() => { afterEach(() => {
@@ -266,7 +272,7 @@ describe('getAvailableVersions', () => {
await expect( await expect(
distribution['findPackageForDownload'](normalizedVersion) distribution['findPackageForDownload'](normalizedVersion)
).rejects.toThrow( ).rejects.toThrow(
`Couldn't find any satisfied version for the specified java-version: "${normalizedVersion}" and architecture: "${arch}".` `No matching version found for SemVer '${normalizedVersion}'`
); );
} }
); );
@@ -4,9 +4,12 @@ import {JavaInstallerOptions} from '../../src/distributions/base-models';
import {SemeruDistribution} from '../../src/distributions/semeru/installer'; import {SemeruDistribution} from '../../src/distributions/semeru/installer';
import manifestData from '../data/semeru.json'; import manifestData from '../data/semeru.json';
import * as core from '@actions/core';
describe('getAvailableVersions', () => { describe('getAvailableVersions', () => {
let spyHttpClient: jest.SpyInstance; let spyHttpClient: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
let spyCoreWarning: jest.SpyInstance;
beforeEach(() => { beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@@ -15,6 +18,11 @@ describe('getAvailableVersions', () => {
headers: {}, headers: {},
result: [] result: []
}); });
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError.mockImplementation(() => {});
spyCoreWarning = jest.spyOn(core, 'warning');
spyCoreWarning.mockImplementation(() => {});
}); });
afterEach(() => { afterEach(() => {
@@ -77,22 +85,19 @@ describe('getAvailableVersions', () => {
); );
it('load available versions', async () => { it('load available versions', async () => {
const nextPageUrl =
'https://api.adoptopenjdk.net/v3/assets/version/%5B1.0,100.0%5D?page=1&page_size=20';
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
spyHttpClient spyHttpClient
.mockReturnValueOnce({ .mockReturnValueOnce({
statusCode: 200, statusCode: 200,
headers: {}, headers: {link: `<${nextPageUrl}>; rel="next"`},
result: manifestData as any result: manifestData as any
}) })
.mockReturnValueOnce({ .mockReturnValueOnce({
statusCode: 200, statusCode: 200,
headers: {}, headers: {},
result: manifestData as any result: manifestData as any
})
.mockReturnValueOnce({
statusCode: 200,
headers: {},
result: []
}); });
const distribution = new SemeruDistribution({ const distribution = new SemeruDistribution({
@@ -104,6 +109,31 @@ describe('getAvailableVersions', () => {
const availableVersions = await distribution['getAvailableVersions'](); const availableVersions = await distribution['getAvailableVersions']();
expect(availableVersions).not.toBeNull(); expect(availableVersions).not.toBeNull();
expect(availableVersions.length).toBe(manifestData.length * 2); expect(availableVersions.length).toBe(manifestData.length * 2);
expect(spyHttpClient).toHaveBeenNthCalledWith(2, nextPageUrl);
});
it('stops pagination after 1000 pages as a safeguard', async () => {
const nextPageUrl =
'https://api.adoptopenjdk.net/v3/assets/version/%5B1.0,100.0%5D?page=2&page_size=20';
spyHttpClient.mockReturnValue({
statusCode: 200,
headers: {link: `<${nextPageUrl}>; rel="next"`},
result: [{version_data: {semver: '17.0.1'}, binaries: []}] as any
});
const distribution = new SemeruDistribution({
version: '8',
architecture: 'x64',
packageType: 'jdk',
checkLatest: false
});
await distribution['getAvailableVersions']();
expect(spyHttpClient).toHaveBeenCalledTimes(1000);
expect(spyCoreWarning).toHaveBeenCalledWith(
expect.stringContaining('Reached pagination safeguard limit (1000 pages)')
);
}); });
it.each([ it.each([
@@ -152,7 +182,7 @@ describe('findPackageForDownload', () => {
distribution['getAvailableVersions'] = async () => manifestData as any; distribution['getAvailableVersions'] = async () => manifestData as any;
await expect( await expect(
distribution['findPackageForDownload']('9.0.8') distribution['findPackageForDownload']('9.0.8')
).rejects.toThrow(/Could not find satisfied version for SemVer */); ).rejects.toThrow(/No matching version found for SemVer */);
}); });
it('version is not found', async () => { it('version is not found', async () => {
@@ -164,7 +194,7 @@ describe('findPackageForDownload', () => {
}); });
distribution['getAvailableVersions'] = async () => manifestData as any; distribution['getAvailableVersions'] = async () => manifestData as any;
await expect(distribution['findPackageForDownload']('7.x')).rejects.toThrow( await expect(distribution['findPackageForDownload']('7.x')).rejects.toThrow(
/Could not find satisfied version for SemVer */ /No matching version found for SemVer */
); );
}); });
@@ -177,7 +207,7 @@ describe('findPackageForDownload', () => {
}); });
distribution['getAvailableVersions'] = async () => []; distribution['getAvailableVersions'] = async () => [];
await expect(distribution['findPackageForDownload']('8')).rejects.toThrow( await expect(distribution['findPackageForDownload']('8')).rejects.toThrow(
/Could not find satisfied version for SemVer */ /No matching version found for SemVer */
); );
}); });
@@ -7,9 +7,12 @@ import {
import {JavaInstallerOptions} from '../../src/distributions/base-models'; import {JavaInstallerOptions} from '../../src/distributions/base-models';
import manifestData from '../data/temurin.json'; import manifestData from '../data/temurin.json';
import * as core from '@actions/core';
describe('getAvailableVersions', () => { describe('getAvailableVersions', () => {
let spyHttpClient: jest.SpyInstance; let spyHttpClient: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
let spyCoreWarning: jest.SpyInstance;
beforeEach(() => { beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@@ -18,6 +21,11 @@ describe('getAvailableVersions', () => {
headers: {}, headers: {},
result: [] result: []
}); });
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError.mockImplementation(() => {});
spyCoreWarning = jest.spyOn(core, 'warning');
spyCoreWarning.mockImplementation(() => {});
}); });
afterEach(() => { afterEach(() => {
@@ -88,22 +96,19 @@ describe('getAvailableVersions', () => {
); );
it('load available versions', async () => { it('load available versions', async () => {
const nextPageUrl =
'https://api.adoptium.net/v3/assets/version/%5B1.0,100.0%5D?page=1&page_size=20';
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
spyHttpClient spyHttpClient
.mockReturnValueOnce({ .mockReturnValueOnce({
statusCode: 200, statusCode: 200,
headers: {}, headers: {link: `<${nextPageUrl}>; rel="next"`},
result: manifestData as any result: manifestData as any
}) })
.mockReturnValueOnce({ .mockReturnValueOnce({
statusCode: 200, statusCode: 200,
headers: {}, headers: {},
result: manifestData as any result: manifestData as any
})
.mockReturnValueOnce({
statusCode: 200,
headers: {},
result: []
}); });
const distribution = new TemurinDistribution( const distribution = new TemurinDistribution(
@@ -118,6 +123,34 @@ describe('getAvailableVersions', () => {
const availableVersions = await distribution['getAvailableVersions'](); const availableVersions = await distribution['getAvailableVersions']();
expect(availableVersions).not.toBeNull(); expect(availableVersions).not.toBeNull();
expect(availableVersions.length).toBe(manifestData.length * 2); expect(availableVersions.length).toBe(manifestData.length * 2);
expect(spyHttpClient).toHaveBeenNthCalledWith(2, nextPageUrl);
});
it('stops pagination after 1000 pages as a safeguard', async () => {
const nextPageUrl =
'https://api.adoptium.net/v3/assets/version/%5B1.0,100.0%5D?page=2&page_size=20';
spyHttpClient.mockReturnValue({
statusCode: 200,
headers: {link: `<${nextPageUrl}>; rel="next"`},
result: [{version_data: {semver: '17.0.1'}, binaries: []}] as any
});
const distribution = new TemurinDistribution(
{
version: '8',
architecture: 'x64',
packageType: 'jdk',
checkLatest: false
},
TemurinImplementation.Hotspot
);
await distribution['getAvailableVersions']();
expect(spyHttpClient).toHaveBeenCalledTimes(1000);
expect(spyCoreWarning).toHaveBeenCalledWith(
expect.stringContaining('Reached pagination safeguard limit (1000 pages)')
);
}); });
it.each([ it.each([
@@ -213,7 +246,7 @@ describe('findPackageForDownload', () => {
distribution['getAvailableVersions'] = async () => manifestData as any; distribution['getAvailableVersions'] = async () => manifestData as any;
await expect( await expect(
distribution['findPackageForDownload']('9.0.8') distribution['findPackageForDownload']('9.0.8')
).rejects.toThrow(/Could not find satisfied version for SemVer */); ).rejects.toThrow(/No matching version found for SemVer */);
}); });
it('version is not found', async () => { it('version is not found', async () => {
@@ -228,7 +261,7 @@ describe('findPackageForDownload', () => {
); );
distribution['getAvailableVersions'] = async () => manifestData as any; distribution['getAvailableVersions'] = async () => manifestData as any;
await expect(distribution['findPackageForDownload']('7.x')).rejects.toThrow( await expect(distribution['findPackageForDownload']('7.x')).rejects.toThrow(
/Could not find satisfied version for SemVer */ /No matching version found for SemVer */
); );
}); });
@@ -244,7 +277,7 @@ describe('findPackageForDownload', () => {
); );
distribution['getAvailableVersions'] = async () => []; distribution['getAvailableVersions'] = async () => [];
await expect(distribution['findPackageForDownload']('8')).rejects.toThrow( await expect(distribution['findPackageForDownload']('8')).rejects.toThrow(
/Could not find satisfied version for SemVer */ /No matching version found for SemVer */
); );
}); });
}); });
@@ -3,12 +3,14 @@ import {ZuluDistribution} from '../../src/distributions/zulu/installer';
import {IZuluVersions} from '../../src/distributions/zulu/models'; import {IZuluVersions} from '../../src/distributions/zulu/models';
import * as utils from '../../src/util'; import * as utils from '../../src/util';
import os from 'os'; import os from 'os';
import * as core from '@actions/core';
import manifestData from '../data/zulu-releases-default.json'; import manifestData from '../data/zulu-releases-default.json';
describe('getAvailableVersions', () => { describe('getAvailableVersions', () => {
let spyHttpClient: jest.SpyInstance; let spyHttpClient: jest.SpyInstance;
let spyUtilGetDownloadArchiveExtension: jest.SpyInstance; let spyUtilGetDownloadArchiveExtension: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
beforeEach(() => { beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@@ -23,6 +25,10 @@ describe('getAvailableVersions', () => {
'getDownloadArchiveExtension' 'getDownloadArchiveExtension'
); );
spyUtilGetDownloadArchiveExtension.mockReturnValue('tar.gz'); spyUtilGetDownloadArchiveExtension.mockReturnValue('tar.gz');
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError.mockImplementation(() => {});
}); });
afterEach(() => { afterEach(() => {
@@ -225,6 +231,6 @@ describe('findPackageForDownload', () => {
distribution['getAvailableVersions'] = async () => manifestData; distribution['getAvailableVersions'] = async () => manifestData;
await expect( await expect(
distribution['findPackageForDownload'](distribution['version']) distribution['findPackageForDownload'](distribution['version'])
).rejects.toThrow(/Could not find satisfied version for semver */); ).rejects.toThrow(/No matching version found for SemVer/);
}); });
}); });
@@ -4,12 +4,14 @@ import {ZuluDistribution} from '../../src/distributions/zulu/installer';
import {IZuluVersions} from '../../src/distributions/zulu/models'; import {IZuluVersions} from '../../src/distributions/zulu/models';
import * as utils from '../../src/util'; import * as utils from '../../src/util';
import os from 'os'; import os from 'os';
import * as core from '@actions/core';
import manifestData from '../data/zulu-linux.json'; import manifestData from '../data/zulu-linux.json';
describe('getAvailableVersions', () => { describe('getAvailableVersions', () => {
let spyHttpClient: jest.SpyInstance; let spyHttpClient: jest.SpyInstance;
let spyUtilGetDownloadArchiveExtension: jest.SpyInstance; let spyUtilGetDownloadArchiveExtension: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
beforeEach(() => { beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@@ -24,6 +26,10 @@ describe('getAvailableVersions', () => {
'getDownloadArchiveExtension' 'getDownloadArchiveExtension'
); );
spyUtilGetDownloadArchiveExtension.mockReturnValue('zip'); spyUtilGetDownloadArchiveExtension.mockReturnValue('zip');
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError.mockImplementation(() => {});
}); });
afterEach(() => { afterEach(() => {
@@ -228,6 +234,6 @@ describe('findPackageForDownload', () => {
distribution['getAvailableVersions'] = async () => manifestData; distribution['getAvailableVersions'] = async () => manifestData;
await expect( await expect(
distribution['findPackageForDownload'](distribution['version']) distribution['findPackageForDownload'](distribution['version'])
).rejects.toThrow(/Could not find satisfied version for semver */); ).rejects.toThrow(/No matching version found for SemVer/);
}); });
}); });
@@ -4,12 +4,14 @@ import {ZuluDistribution} from '../../src/distributions/zulu/installer';
import {IZuluVersions} from '../../src/distributions/zulu/models'; import {IZuluVersions} from '../../src/distributions/zulu/models';
import * as utils from '../../src/util'; import * as utils from '../../src/util';
import os from 'os'; import os from 'os';
import * as core from '@actions/core';
import manifestData from '../data/zulu-windows.json'; import manifestData from '../data/zulu-windows.json';
describe('getAvailableVersions', () => { describe('getAvailableVersions', () => {
let spyHttpClient: jest.SpyInstance; let spyHttpClient: jest.SpyInstance;
let spyUtilGetDownloadArchiveExtension: jest.SpyInstance; let spyUtilGetDownloadArchiveExtension: jest.SpyInstance;
let spyCoreError: jest.SpyInstance;
beforeEach(() => { beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
@@ -24,6 +26,10 @@ describe('getAvailableVersions', () => {
'getDownloadArchiveExtension' 'getDownloadArchiveExtension'
); );
spyUtilGetDownloadArchiveExtension.mockReturnValue('zip'); spyUtilGetDownloadArchiveExtension.mockReturnValue('zip');
// Mock core.error to suppress error logs
spyCoreError = jest.spyOn(core, 'error');
spyCoreError.mockImplementation(() => {});
}); });
afterEach(() => { afterEach(() => {
@@ -226,6 +232,6 @@ describe('findPackageForDownload', () => {
distribution['getAvailableVersions'] = async () => manifestData; distribution['getAvailableVersions'] = async () => manifestData;
await expect( await expect(
distribution['findPackageForDownload'](distribution['version']) distribution['findPackageForDownload'](distribution['version'])
).rejects.toThrow(/Could not find satisfied version for semver */); ).rejects.toThrow(/No matching version found for SemVer/);
}); });
}); });
+80 -2
View File
@@ -4,10 +4,12 @@ import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import { import {
convertVersionToSemver, convertVersionToSemver,
getNextPageUrlFromLinkHeader,
getVersionFromFileContent, getVersionFromFileContent,
isVersionSatisfies, isVersionSatisfies,
isCacheFeatureAvailable, isCacheFeatureAvailable,
isGhes isGhes,
validatePaginationUrl
} from '../src/util'; } from '../src/util';
jest.mock('@actions/cache'); jest.mock('@actions/cache');
@@ -27,7 +29,11 @@ describe('isVersionSatisfies', () => {
['2.5.1+3', '2.5.1+3', true], ['2.5.1+3', '2.5.1+3', true],
['2.5.1+3', '2.5.1+2', false], ['2.5.1+3', '2.5.1+2', false],
['15.0.0+14', '15.0.0+14.1.202003190635', false], ['15.0.0+14', '15.0.0+14.1.202003190635', false],
['15.0.0+14.1.202003190635', '15.0.0+14.1.202003190635', true] ['15.0.0+14.1.202003190635', '15.0.0+14.1.202003190635', true],
// 4-segment versions (e.g. JetBrains Runtime '17.0.8.1+1080.1') are not
// valid semver — they should be rejected, not throw.
['25.0.3+480.61', '17.0.8.1+1080.1', false],
['17', '17.0.8.1+1080.1', false]
])( ])(
'%s, %s -> %s', '%s, %s -> %s',
(inputRange: string, inputVersion: string, expected: boolean) => { (inputRange: string, inputVersion: string, expected: boolean) => {
@@ -85,6 +91,78 @@ describe('convertVersionToSemver', () => {
}); });
}); });
describe('getNextPageUrlFromLinkHeader', () => {
it.each([
[
{
link: '<https://api.adoptium.net/v3/info/release_versions?page=1&page_size=10>; rel="next"'
},
'https://api.adoptium.net/v3/info/release_versions?page=1&page_size=10'
],
[
{
Link: '<https://example.com/last?page=5>; rel="last", <https://example.com/next?page=2>; rel="next"'
},
'https://example.com/next?page=2'
],
[
{
link: '<https://api.adoptium.net/v3/versions?page=3>; type="application/json"; rel="next"'
},
'https://api.adoptium.net/v3/versions?page=3'
],
[{link: '<https://example.com/last?page=5>; rel="last"'}, null],
[{link: '<https://example.com/page?p=2>; rel="nextsomething"'}, null],
[undefined, null]
])('returns %s -> %s', (headers, expected) => {
expect(getNextPageUrlFromLinkHeader(headers)).toBe(expected);
});
});
describe('validatePaginationUrl', () => {
it('accepts URL with matching origin', () => {
expect(
validatePaginationUrl(
'https://api.adoptium.net/v3/assets?page=2',
'https://api.adoptium.net'
)
).toBe(true);
});
it('rejects URL with different host', () => {
expect(
validatePaginationUrl(
'https://evil.example.com/steal?data=1',
'https://api.adoptium.net'
)
).toBe(false);
});
it('rejects URL with different protocol', () => {
expect(
validatePaginationUrl(
'http://api.adoptium.net/v3/assets?page=2',
'https://api.adoptium.net'
)
).toBe(false);
});
it('returns false for invalid URL', () => {
expect(validatePaginationUrl('not-a-url', 'https://api.adoptium.net')).toBe(
false
);
});
it('accepts URL with explicit default port', () => {
expect(
validatePaginationUrl(
'https://api.adoptium.net:443/v3/assets?page=2',
'https://api.adoptium.net'
)
).toBe(true);
});
});
describe('getVersionFromFileContent', () => { describe('getVersionFromFileContent', () => {
describe('.sdkmanrc', () => { describe('.sdkmanrc', () => {
it.each([ it.each([
+7 -3
View File
@@ -5,8 +5,10 @@ author: 'GitHub'
inputs: inputs:
java-version: java-version:
description: 'The Java version to set up. Takes a whole or semver Java version. See examples of supported syntax in README file' description: 'The Java version to set up. Takes a whole or semver Java version. See examples of supported syntax in README file'
required: false
java-version-file: java-version-file:
description: 'The path to the `.java-version` file. See examples of supported syntax in README file' description: 'The path to a file containing the Java version to set up (.java-version, .tool-versions, .sdkmanrc). Used when java-version is not set. See examples of supported syntax in README file'
required: false
distribution: distribution:
description: 'Java distribution. See the list of supported distributions in README file' description: 'Java distribution. See the list of supported distributions in README file'
required: true required: true
@@ -49,9 +51,9 @@ inputs:
gpg-private-key: gpg-private-key:
description: 'GPG private key to import. Default is empty string.' description: 'GPG private key to import. Default is empty string.'
required: false required: false
default: ''
gpg-passphrase: gpg-passphrase:
description: 'Environment variable name for the GPG private key passphrase. Default is description: 'Environment variable name for the GPG private key passphrase. Defaults to GPG_PASSPHRASE when gpg-private-key is set; ignored otherwise.'
$GPG_PASSPHRASE.'
required: false required: false
cache: cache:
description: 'Name of the build platform to cache dependencies. It can be "maven", "gradle" or "sbt".' description: 'Name of the build platform to cache dependencies. It can be "maven", "gradle" or "sbt".'
@@ -61,9 +63,11 @@ inputs:
required: false required: false
job-status: job-status:
description: 'Workaround to pass job status to post job step. This variable is not intended for manual setting' description: 'Workaround to pass job status to post job step. This variable is not intended for manual setting'
required: false
default: ${{ job.status }} default: ${{ job.status }}
token: token:
description: The token used to authenticate when fetching version manifests hosted on github.com, such as for the Microsoft Build of OpenJDK. When running this action on github.com, the default value is sufficient. When running on GHES, you can pass a personal access token for github.com if you are experiencing rate limiting. description: The token used to authenticate when fetching version manifests hosted on github.com, such as for the Microsoft Build of OpenJDK. When running this action on github.com, the default value is sufficient. When running on GHES, you can pass a personal access token for github.com if you are experiencing rate limiting.
required: false
default: ${{ github.server_url == 'https://github.com' && github.token || '' }} default: ${{ github.server_url == 'https://github.com' && github.token || '' }}
mvn-toolchain-id: mvn-toolchain-id:
description: 'Name of Maven Toolchain ID if the default name of "${distribution}_${java-version}" is not wanted. See examples of supported syntax in Advanced Usage file' description: 'Name of Maven Toolchain ID if the default name of "${distribution}_${java-version}" is not wanted. See examples of supported syntax in Advanced Usage file'
+20431 -19231
View File
File diff suppressed because one or more lines are too long
+34773 -37318
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -34,7 +34,7 @@ Requiring a default version will break users that are pinned to `@main` as they
`setup-java` should be structured in such a way that will allow the open source community to easily add support for extra distributions. `setup-java` should be structured in such a way that will allow the open source community to easily add support for extra distributions.
Existing code will be restructured so that distribution specific code will be easily separated. Currently the core download logic is in a single file, `installer.ts`. This file will be split up and abstracted out so that there will be no vendor specified logic. Each distribution will have it's own files under `src/distributions` that will contain the core setup logic for a specific distribution. Existing code will be restructured so that distribution specific code will be easily separated. Currently the core download logic is in a single file, `installer.ts`. This file will be split up and abstracted out so that there will be no vendor specified logic. Each distribution will have its own files under `src/distributions` that will contain the core setup logic for a specific distribution.
```yaml ```yaml
∟ src/ ∟ src/
+1 -1
View File
@@ -16,4 +16,4 @@ This folder includes ADRs for the setup-java action. ADRs are proposed in the fo
--- ---
- More information about ADRs can be found [here](https://github.com/joelparkerhenderson/architecture_decision_record). - See [more information about ADRs](https://github.com/joelparkerhenderson/architecture_decision_record).
+60 -19
View File
@@ -10,8 +10,10 @@
- [Alibaba Dragonwell](#Alibaba-Dragonwell) - [Alibaba Dragonwell](#Alibaba-Dragonwell)
- [SapMachine](#SapMachine) - [SapMachine](#SapMachine)
- [GraalVM](#GraalVM) - [GraalVM](#GraalVM)
- [GraalVM Community](#GraalVM-Community)
- [JetBrains](#JetBrains) - [JetBrains](#JetBrains)
- [Installing custom Java package type](#Installing-custom-Java-package-type) - [Installing custom Java package type](#Installing-custom-Java-package-type)
- [JavaFX Maven project](#JavaFX-Maven-project)
- [Installing custom Java architecture](#Installing-custom-Java-architecture) - [Installing custom Java architecture](#Installing-custom-Java-architecture)
- [Installing custom Java distribution from local file](#Installing-Java-from-local-file) - [Installing custom Java distribution from local file](#Installing-Java-from-local-file)
- [Testing against different Java distributions](#Testing-against-different-Java-distributions) - [Testing against different Java distributions](#Testing-against-different-Java-distributions)
@@ -36,7 +38,7 @@ steps:
with: with:
distribution: 'temurin' distribution: 'temurin'
java-version: '21' java-version: '21'
- run: java -cp java HelloWorldApp - run: java --version
``` ```
### Adopt ### Adopt
@@ -49,7 +51,7 @@ steps:
with: with:
distribution: 'adopt-hotspot' distribution: 'adopt-hotspot'
java-version: '11' java-version: '11'
- run: java -cp java HelloWorldApp - run: java --version
``` ```
### Zulu ### Zulu
@@ -62,7 +64,7 @@ steps:
distribution: 'zulu' distribution: 'zulu'
java-version: '21' java-version: '21'
java-package: jdk # optional (jdk, jre, jdk+fx or jre+fx) - defaults to jdk java-package: jdk # optional (jdk, jre, jdk+fx or jre+fx) - defaults to jdk
- run: java -cp java HelloWorldApp - run: java --version
``` ```
### Liberica ### Liberica
@@ -75,7 +77,7 @@ steps:
distribution: 'liberica' distribution: 'liberica'
java-version: '21' java-version: '21'
java-package: jdk # optional (jdk, jre, jdk+fx or jre+fx) - defaults to jdk java-package: jdk # optional (jdk, jre, jdk+fx or jre+fx) - defaults to jdk
- run: java -cp java HelloWorldApp - run: java --version
``` ```
### Microsoft ### Microsoft
@@ -87,7 +89,7 @@ steps:
with: with:
distribution: 'microsoft' distribution: 'microsoft'
java-version: '21' java-version: '21'
- run: java -cp java HelloWorldApp - run: java --version
``` ```
### Using Microsoft distribution on GHES ### Using Microsoft distribution on GHES
@@ -116,7 +118,7 @@ steps:
with: with:
distribution: 'corretto' distribution: 'corretto'
java-version: '21' java-version: '21'
- run: java -cp java HelloWorldApp - run: java --version
``` ```
### Oracle ### Oracle
@@ -129,7 +131,7 @@ steps:
with: with:
distribution: 'oracle' distribution: 'oracle'
java-version: '21' java-version: '21'
- run: java -cp java HelloWorldApp - run: java --version
``` ```
### Alibaba Dragonwell ### Alibaba Dragonwell
@@ -142,7 +144,7 @@ steps:
with: with:
distribution: 'dragonwell' distribution: 'dragonwell'
java-version: '8' java-version: '8'
- run: java -cp java HelloWorldApp - run: java --version
``` ```
### SapMachine ### SapMachine
@@ -154,7 +156,7 @@ steps:
with: with:
distribution: 'sapmachine' distribution: 'sapmachine'
java-version: '21' java-version: '21'
- run: java -cp java HelloWorldApp - run: java --version
``` ```
### GraalVM ### GraalVM
@@ -167,6 +169,21 @@ steps:
with: with:
distribution: 'graalvm' distribution: 'graalvm'
java-version: '21' java-version: '21'
- run: |
java --version
native-image --version
```
### GraalVM Community
**NOTE:** GraalVM Community is available for stable JDK 17 and later releases.
```yaml
steps:
- uses: actions/checkout@v6
- uses: actions/setup-java@v5
with:
distribution: 'graalvm-community'
java-version: '21'
- run: | - run: |
java -cp java HelloWorldApp java -cp java HelloWorldApp
native-image -cp java HelloWorldApp native-image -cp java HelloWorldApp
@@ -176,7 +193,7 @@ steps:
**NOTE:** JetBrains is only available for LTS versions on 11 or later (11, 17, 21, etc.). **NOTE:** JetBrains is only available for LTS versions on 11 or later (11, 17, 21, etc.).
Not all minor LTS versions are guarenteed to be available, since JetBrains considers what to ship IntelliJ IDEA with, most commonly on JDK 11. Not all minor LTS versions are guaranteed to be available, since JetBrains considers what to ship IntelliJ IDEA with, most commonly on JDK 11.
For example, `11.0.24` is not available but `11.0.16` is. For example, `11.0.24` is not available but `11.0.16` is.
```yaml ```yaml
@@ -186,7 +203,7 @@ steps:
with: with:
distribution: 'jetbrains' distribution: 'jetbrains'
java-version: '11' java-version: '11'
- run: java -cp java HelloWorldApp - run: java --version
``` ```
The JetBrains installer uses the GitHub API to fetch the latest version. If you believe your project is going to be running into rate limits, you can provide a The JetBrains installer uses the GitHub API to fetch the latest version. If you believe your project is going to be running into rate limits, you can provide a
@@ -202,7 +219,7 @@ steps:
java-package: 'jdk' # optional (jdk, jre, jdk+jcef, jre+jcef, jdk+ft, or jre+ft) - defaults to jdk java-package: 'jdk' # optional (jdk, jre, jdk+jcef, jre+jcef, jdk+ft, or jre+ft) - defaults to jdk
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: java -cp java HelloWorldApp - run: java --version
``` ```
You can specify your package type (as shown in the [releases page](https://github.com/JetBrains/JetBrainsRuntime/releases/)) in the `java-package` parameter. You can specify your package type (as shown in the [releases page](https://github.com/JetBrains/JetBrainsRuntime/releases/)) in the `java-package` parameter.
@@ -225,7 +242,31 @@ steps:
distribution: '<distribution>' distribution: '<distribution>'
java-version: '11' java-version: '11'
java-package: jdk # optional (jdk or jre) - defaults to jdk java-package: jdk # optional (jdk or jre) - defaults to jdk
- run: java -cp java HelloWorldApp - run: java --version
```
### JavaFX Maven project
For JavaFX projects that use Maven, use `jdk+fx` (or `jre+fx`) as the `java-package` value together with a distribution that supports it (e.g. `zulu` or `liberica`). Then include the [`javafx-maven-plugin`](https://openjfx.io/openjfx-docs/#maven) in your `pom.xml` as described in the [Getting Started with JavaFX](https://openjfx.io/openjfx-docs/#maven) guide.
```yaml
steps:
- uses: actions/checkout@v6
- uses: actions/setup-java@v5
with:
distribution: 'zulu'
java-version: '21'
java-package: jdk+fx
cache: maven
- name: Build with Maven
run: mvn --no-transfer-progress compile
```
To run the JavaFX application in CI:
```yaml
- name: Run with Maven
run: mvn --no-transfer-progress javafx:run
``` ```
## Installing custom Java architecture ## Installing custom Java architecture
@@ -238,7 +279,7 @@ steps:
distribution: '<distribution>' distribution: '<distribution>'
java-version: '11' java-version: '11'
architecture: x86 # optional - default value derived from the runner machine architecture: x86 # optional - default value derived from the runner machine
- run: java -cp java HelloWorldApp - run: java --version
``` ```
## Installing Java from local file ## Installing Java from local file
@@ -256,7 +297,7 @@ steps:
java-version: '11.0.0' java-version: '11.0.0'
architecture: x64 architecture: x64
- run: java -cp java HelloWorldApp - run: java --version
``` ```
If your use-case requires a custom distribution (in the example, alpine-linux is used) or a version that is not provided by setup-java and you want to always install the latest version during runtime, then you can use the following code to auto-download the latest JDK, determine the semver needed for setup-java, and setup-java will take care of the installation and caching on the VM: If your use-case requires a custom distribution (in the example, alpine-linux is used) or a version that is not provided by setup-java and you want to always install the latest version during runtime, then you can use the following code to auto-download the latest JDK, determine the semver needed for setup-java, and setup-java will take care of the installation and caching on the VM:
@@ -281,7 +322,7 @@ If your use-case requires a custom distribution (in the example, alpine-linux is
jdkFile: ${{ runner.temp }}/java_package.tar.gz jdkFile: ${{ runner.temp }}/java_package.tar.gz
java-version: {{ steps.fetch_latest_jdk.outputs.java_version }} java-version: {{ steps.fetch_latest_jdk.outputs.java_version }}
architecture: x64 architecture: x64
- run: java -cp java HelloWorldApp - run: java --version
``` ```
## Testing against different Java distributions ## Testing against different Java distributions
@@ -302,7 +343,7 @@ jobs:
with: with:
distribution: ${{ matrix.distribution }} distribution: ${{ matrix.distribution }}
java-version: ${{ matrix.java }} java-version: ${{ matrix.java }}
- run: java -cp java HelloWorldApp - run: java --version
``` ```
#### Testing against different platforms #### Testing against different platforms
@@ -322,7 +363,7 @@ jobs:
with: with:
distribution: 'temurin' distribution: 'temurin'
java-version: ${{ matrix.java }} java-version: ${{ matrix.java }}
- run: java -cp java HelloWorldApp - run: java --version
``` ```
## Publishing using Apache Maven ## Publishing using Apache Maven
@@ -580,7 +621,7 @@ steps:
distribution: 'temurin' distribution: 'temurin'
java-version: '11' java-version: '11'
mvn-toolchain-id: 'some_other_id' mvn-toolchain-id: 'some_other_id'
- run: java -cp java HelloWorldApp - run: java --version
``` ```
In case you install multiple versions of Java at once you can use the same syntax as used in `java-versions`. Please note that you have to declare an ID for all Java versions that will be installed or the `mvn-toolchain-id` instruction will be skipped wholesale due to mapping ambiguities. In case you install multiple versions of Java at once you can use the same syntax as used in `java-versions`. Please note that you have to declare an ID for all Java versions that will be installed or the `mvn-toolchain-id` instruction will be skipped wholesale due to mapping ambiguities.
+4 -4
View File
@@ -6,13 +6,13 @@ We have prepared a short guide so that the process of making your contribution i
## How can I contribute... ## How can I contribute...
* [Contribute Documentation:green_book:](#contribute-documentation) * [:green_book: Contribute Documentation](#contribute-documentation)
* [Contribute Code :computer:](#contribute-code) * [:computer: Contribute Code](#contribute-code)
* [Provide Support on Issues:pencil:](#provide-support-on-issues) * [:pencil: Provide Support on Issues](#provide-support-on-issues)
* [Review Pull Requests:mag:](#review-pull-requests) * [:mag: Review Pull Requests](#review-pull-requests)
## Contribute documentation ## Contribute documentation
+2662 -1483
View File
File diff suppressed because it is too large Load Diff
+18 -18
View File
@@ -1,6 +1,6 @@
{ {
"name": "setup-java", "name": "setup-java",
"version": "5.2.0", "version": "5.3.0",
"private": true, "private": true,
"description": "setup java action", "description": "setup java action",
"main": "dist/setup/index.js", "main": "dist/setup/index.js",
@@ -29,31 +29,31 @@
"author": "GitHub", "author": "GitHub",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/cache": "^5.0.1", "@actions/cache": "^5.1.0",
"@actions/core": "^1.10.0", "@actions/core": "^2.0.3",
"@actions/exec": "^1.0.4", "@actions/exec": "^2.0.0",
"@actions/glob": "^0.5.0", "@actions/glob": "^0.5.1",
"@actions/http-client": "^2.2.3", "@actions/http-client": "^3.0.2",
"@actions/io": "^1.0.2", "@actions/io": "^2.0.0",
"@actions/tool-cache": "^2.0.1", "@actions/tool-cache": "^3.0.1",
"semver": "^7.6.0", "semver": "^7.6.0",
"xmlbuilder2": "^2.4.0" "xmlbuilder2": "^4.0.3"
}, },
"devDependencies": { "devDependencies": {
"@types/jest": "^29.5.14", "@types/jest": "^30.0.0",
"@types/node": "^24.1.0", "@types/node": "^26.0.0",
"@types/semver": "^7.5.8", "@types/semver": "^7.5.8",
"@typescript-eslint/eslint-plugin": "^8.35.1", "@typescript-eslint/eslint-plugin": "^8.48.0",
"@typescript-eslint/parser": "^8.35.1", "@typescript-eslint/parser": "^8.61.1",
"@vercel/ncc": "^0.38.1", "@vercel/ncc": "^0.44.0",
"eslint": "^8.57.0", "eslint": "^8.57.0",
"eslint-config-prettier": "^8.6.0", "eslint-config-prettier": "^10.1.8",
"eslint-plugin-jest": "^29.0.1", "eslint-plugin-jest": "^29.0.1",
"eslint-plugin-node": "^11.1.0", "eslint-plugin-node": "^11.1.0",
"jest": "^29.7.0", "jest": "^30.4.2",
"jest-circus": "^29.7.0", "jest-circus": "^30.4.2",
"prettier": "^3.6.2", "prettier": "^3.6.2",
"ts-jest": "^29.3.0", "ts-jest": "^29.4.11",
"typescript": "^5.3.3" "typescript": "^5.3.3"
}, },
"bugs": { "bugs": {
+14 -3
View File
@@ -23,9 +23,12 @@ interface PackageManager {
const supportedPackageManager: PackageManager[] = [ const supportedPackageManager: PackageManager[] = [
{ {
id: 'maven', id: 'maven',
path: [join(os.homedir(), '.m2', 'repository')], path: [
join(os.homedir(), '.m2', 'repository'),
join(os.homedir(), '.m2', 'wrapper', 'dists')
],
// https://github.com/actions/cache/blob/0638051e9af2c23d10bb70fa9beffcad6cff9ce3/examples.md#java---maven // https://github.com/actions/cache/blob/0638051e9af2c23d10bb70fa9beffcad6cff9ce3/examples.md#java---maven
pattern: ['**/pom.xml'] pattern: ['**/pom.xml', '**/.mvn/wrapper/maven-wrapper.properties']
}, },
{ {
id: 'gradle', id: 'gradle',
@@ -146,7 +149,15 @@ export async function save(id: string) {
return; return;
} }
try { try {
await cache.saveCache(packageManager.path, primaryKey); const cacheId = await cache.saveCache(packageManager.path, primaryKey);
if (cacheId === -1) {
// saveCache returns -1 without throwing when the cache was not saved,
// e.g. a reserve collision or a read-only token (fork PR). @actions/cache
// has already logged the reason at the appropriate severity, so just
// trace it instead of misreporting that the cache was saved.
core.debug(`Cache was not saved for the key: ${primaryKey}`);
return;
}
core.info(`Cache saved with the key: ${primaryKey}`); core.info(`Cache saved with the key: ${primaryKey}`);
} catch (error) { } catch (error) {
const err = error as Error; const err = error as Error;
+98 -26
View File
@@ -14,10 +14,14 @@ import {
} from '../base-models'; } from '../base-models';
import { import {
extractJdkFile, extractJdkFile,
getNextPageUrlFromLinkHeader,
getDownloadArchiveExtension, getDownloadArchiveExtension,
isVersionSatisfies, isVersionSatisfies,
renameWinArchive renameWinArchive,
MAX_PAGINATION_PAGES,
validatePaginationUrl
} from '../../util'; } from '../../util';
import {TemurinDistribution, TemurinImplementation} from '../temurin/installer';
export enum AdoptImplementation { export enum AdoptImplementation {
Hotspot = 'Hotspot', Hotspot = 'Hotspot',
@@ -25,15 +29,72 @@ export enum AdoptImplementation {
} }
export class AdoptDistribution extends JavaBase { export class AdoptDistribution extends JavaBase {
private readonly temurinDistribution: TemurinDistribution | null;
constructor( constructor(
installerOptions: JavaInstallerOptions, installerOptions: JavaInstallerOptions,
private readonly jvmImpl: AdoptImplementation private readonly jvmImpl: AdoptImplementation,
temurinDistribution: TemurinDistribution | null = null
) { ) {
super(`Adopt-${jvmImpl}`, installerOptions); super(`Adopt-${jvmImpl}`, installerOptions);
if (
temurinDistribution !== null &&
jvmImpl !== AdoptImplementation.Hotspot
) {
throw new Error('Only Hotspot JVM is supported by Temurin.');
}
// Only use the temurin repo for Hotspot JVMs
this.temurinDistribution =
temurinDistribution ??
(jvmImpl === AdoptImplementation.Hotspot
? new TemurinDistribution(
installerOptions,
TemurinImplementation.Hotspot
)
: null);
} }
protected async findPackageForDownload( protected async findPackageForDownload(
version: string version: string
): Promise<JavaDownloadRelease> {
if (this.jvmImpl === AdoptImplementation.Hotspot) {
core.notice(
"AdoptOpenJDK has moved to Eclipse Temurin https://github.com/actions/setup-java#supported-distributions please consider changing to the 'temurin' distribution type in your setup-java configuration."
);
}
if (
this.jvmImpl === AdoptImplementation.Hotspot &&
this.temurinDistribution !== null
) {
try {
return await this.temurinDistribution.findPackageForDownload(version);
} catch (error) {
// Log the failure but always fall back to legacy AdoptOpenJDK for resilience
const errorMessage =
error instanceof Error ? error.message : String(error);
if (error instanceof Error && error.name === 'VersionNotFoundError') {
core.notice(
'The JVM you are looking for could not be found in the Temurin repository, this likely indicates ' +
'that you are using an out of date version of Java, consider updating and moving to using the Temurin distribution type in setup-java.'
);
} else {
// Log other errors for debugging but gracefully fall back
core.debug(
`Temurin lookup failed: ${errorMessage}. Falling back to AdoptOpenJDK API.`
);
}
}
}
// failed to find a Temurin version, so fall back to AdoptOpenJDK
return this.findPackageForDownloadOldAdoptOpenJdk(version);
}
private async findPackageForDownloadOldAdoptOpenJdk(
version: string
): Promise<JavaDownloadRelease> { ): Promise<JavaDownloadRelease> {
const availableVersionsRaw = await this.getAvailableVersions(); const availableVersionsRaw = await this.getAvailableVersions();
const availableVersionsWithBinaries = availableVersionsRaw const availableVersionsWithBinaries = availableVersionsRaw
@@ -54,15 +115,10 @@ export class AdoptDistribution extends JavaBase {
const resolvedFullVersion = const resolvedFullVersion =
satisfiedVersions.length > 0 ? satisfiedVersions[0] : null; satisfiedVersions.length > 0 ? satisfiedVersions[0] : null;
if (!resolvedFullVersion) { if (!resolvedFullVersion) {
const availableOptions = availableVersionsWithBinaries const availableVersionStrings = availableVersionsWithBinaries.map(
.map(item => item.version) item => item.version
.join(', ');
const availableOptionsMessage = availableOptions
? `\nAvailable versions: ${availableOptions}`
: '';
throw new Error(
`Could not find satisfied version for SemVer '${version}'. ${availableOptionsMessage}`
); );
throw this.createVersionNotFoundError(version, availableVersionStrings);
} }
return resolvedFullVersion; return resolvedFullVersion;
@@ -130,30 +186,46 @@ export class AdoptDistribution extends JavaBase {
`jvm_impl=${this.jvmImpl.toLowerCase()}` `jvm_impl=${this.jvmImpl.toLowerCase()}`
].join('&'); ].join('&');
// need to iterate through all pages to retrieve the list of all versions const requestArguments = `${baseRequestArguments}&page_size=20&page=0`;
// Adopt API doesn't provide way to retrieve the count of pages to iterate so infinity loop let availableVersionsUrl: string | null =
let page_index = 0; `https://api.adoptopenjdk.net/v3/assets/version/${versionRange}?${requestArguments}`;
const availableVersions: IAdoptAvailableVersions[] = []; const availableVersions: IAdoptAvailableVersions[] = [];
while (true) { let pageCount = 0;
const requestArguments = `${baseRequestArguments}&page_size=20&page=${page_index}`; if (core.isDebug()) {
const availableVersionsUrl = `https://api.adoptopenjdk.net/v3/assets/version/${versionRange}?${requestArguments}`; core.debug(`Gathering available versions from '${availableVersionsUrl}'`);
if (core.isDebug() && page_index === 0) {
// url is identical except page_index so print it once for debug
core.debug(
`Gathering available versions from '${availableVersionsUrl}'`
);
} }
const paginationPage = ( while (availableVersionsUrl) {
await this.http.getJson<IAdoptAvailableVersions[]>(availableVersionsUrl) pageCount++;
).result; const response =
await this.http.getJson<IAdoptAvailableVersions[]>(
availableVersionsUrl
);
const paginationPage = response.result;
const nextUrl = getNextPageUrlFromLinkHeader(response.headers);
if (
nextUrl &&
!validatePaginationUrl(nextUrl, 'https://api.adoptopenjdk.net')
) {
core.warning(
`Ignoring pagination link with unexpected origin: ${nextUrl}`
);
availableVersionsUrl = null;
} else {
availableVersionsUrl = nextUrl;
}
if (paginationPage === null || paginationPage.length === 0) { if (paginationPage === null || paginationPage.length === 0) {
// break infinity loop because we have reached end of pagination
break; break;
} }
availableVersions.push(...paginationPage); availableVersions.push(...paginationPage);
page_index++;
if (pageCount >= MAX_PAGINATION_PAGES) {
core.warning(
`Reached pagination safeguard limit (${MAX_PAGINATION_PAGES} pages) while listing Adopt releases.`
);
break;
}
} }
if (core.isDebug()) { if (core.isDebug()) {
+38
View File
@@ -259,6 +259,44 @@ export abstract class JavaBase {
}; };
} }
protected createVersionNotFoundError(
versionOrRange: string,
availableVersions?: string[],
additionalContext?: string
): Error {
const parts = [
`No matching version found for SemVer '${versionOrRange}'.`,
`Distribution: ${this.distribution}`,
`Package type: ${this.packageType}`,
`Architecture: ${this.architecture}`
];
// Add additional context if provided (e.g., platform/OS info)
if (additionalContext) {
parts.push(additionalContext);
}
if (availableVersions && availableVersions.length > 0) {
const maxVersionsToShow = core.isDebug() ? availableVersions.length : 50;
const versionsToShow = availableVersions.slice(0, maxVersionsToShow);
const truncated = availableVersions.length > maxVersionsToShow;
parts.push(
`Available versions: ${versionsToShow.join(', ')}${truncated ? ', ...' : ''}`
);
if (truncated) {
parts.push(
`(showing first ${maxVersionsToShow} of ${availableVersions.length} versions, enable debug mode to see all)`
);
}
}
const error = new Error(parts.join('\n'));
error.name = 'VersionNotFoundError';
return error;
}
protected setJavaDefault(version: string, toolPath: string) { protected setJavaDefault(version: string, toolPath: string) {
const majorVersion = version.split('.')[0]; const majorVersion = version.split('.')[0];
core.exportVariable('JAVA_HOME', toolPath); core.exportVariable('JAVA_HOME', toolPath);
+3 -8
View File
@@ -75,15 +75,10 @@ export class CorrettoDistribution extends JavaBase {
const resolvedVersion = const resolvedVersion =
matchingVersions.length > 0 ? matchingVersions[0] : null; matchingVersions.length > 0 ? matchingVersions[0] : null;
if (!resolvedVersion) { if (!resolvedVersion) {
const availableOptions = availableVersions const availableVersionStrings = availableVersions.map(
.map(item => item.version) item => item.version
.join(', ');
const availableOptionsMessage = availableOptions
? `\nAvailable versions: ${availableOptions}`
: '';
throw new Error(
`Could not find satisfied version for SemVer '${version}'. ${availableOptionsMessage}`
); );
throw this.createVersionNotFoundError(version, availableVersionStrings);
} }
return resolvedVersion; return resolvedVersion;
} }
+7 -1
View File
@@ -11,7 +11,10 @@ import {CorrettoDistribution} from './corretto/installer';
import {OracleDistribution} from './oracle/installer'; import {OracleDistribution} from './oracle/installer';
import {DragonwellDistribution} from './dragonwell/installer'; import {DragonwellDistribution} from './dragonwell/installer';
import {SapMachineDistribution} from './sapmachine/installer'; import {SapMachineDistribution} from './sapmachine/installer';
import {GraalVMDistribution} from './graalvm/installer'; import {
GraalVMCommunityDistribution,
GraalVMDistribution
} from './graalvm/installer';
import {JetBrainsDistribution} from './jetbrains/installer'; import {JetBrainsDistribution} from './jetbrains/installer';
enum JavaDistribution { enum JavaDistribution {
@@ -29,6 +32,7 @@ enum JavaDistribution {
Dragonwell = 'dragonwell', Dragonwell = 'dragonwell',
SapMachine = 'sapmachine', SapMachine = 'sapmachine',
GraalVM = 'graalvm', GraalVM = 'graalvm',
GraalVMCommunity = 'graalvm-community',
JetBrains = 'jetbrains' JetBrains = 'jetbrains'
} }
@@ -74,6 +78,8 @@ export function getJavaDistribution(
return new SapMachineDistribution(installerOptions); return new SapMachineDistribution(installerOptions);
case JavaDistribution.GraalVM: case JavaDistribution.GraalVM:
return new GraalVMDistribution(installerOptions); return new GraalVMDistribution(installerOptions);
case JavaDistribution.GraalVMCommunity:
return new GraalVMCommunityDistribution(installerOptions);
case JavaDistribution.JetBrains: case JavaDistribution.JetBrains:
return new JetBrainsDistribution(installerOptions); return new JetBrainsDistribution(installerOptions);
default: default:
+3 -2
View File
@@ -51,9 +51,10 @@ export class DragonwellDistribution extends JavaBase {
}); });
if (!matchedVersions.length) { if (!matchedVersions.length) {
throw new Error( const availableVersionStrings = availableVersions.map(
`Couldn't find any satisfied version for the specified java-version: "${version}" and architecture: "${this.architecture}".` item => item.jdk_version
); );
throw this.createVersionNotFoundError(version, availableVersionStrings);
} }
const resolvedVersion = matchedVersions[0]; const resolvedVersion = matchedVersions[0];
+221 -38
View File
@@ -2,6 +2,7 @@ import * as core from '@actions/core';
import * as tc from '@actions/tool-cache'; import * as tc from '@actions/tool-cache';
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
import semver from 'semver';
import {JavaBase} from '../base-installer'; import {JavaBase} from '../base-installer';
import {HttpCodes} from '@actions/http-client'; import {HttpCodes} from '@actions/http-client';
import {GraalVMEAVersion} from './models'; import {GraalVMEAVersion} from './models';
@@ -11,13 +12,26 @@ import {
JavaInstallerResults JavaInstallerResults
} from '../base-models'; } from '../base-models';
import { import {
convertVersionToSemver,
extractJdkFile, extractJdkFile,
getDownloadArchiveExtension, getDownloadArchiveExtension,
getGitHubHttpHeaders, getGitHubHttpHeaders,
renameWinArchive getNextPageUrlFromLinkHeader,
isVersionSatisfies,
MAX_PAGINATION_PAGES,
renameWinArchive,
validatePaginationUrl
} from '../../util'; } from '../../util';
const GRAALVM_DL_BASE = 'https://download.oracle.com/graalvm'; const GRAALVM_DL_BASE = 'https://download.oracle.com/graalvm';
const GRAALVM_DOWNLOAD_URL = 'https://www.graalvm.org/downloads/';
const GRAALVM_COMMUNITY_RELEASES_URL =
'https://api.github.com/repos/graalvm/graalvm-ce-builds/releases?per_page=100';
const GRAALVM_COMMUNITY_RELEASES_PAGE_ORIGIN = 'https://api.github.com';
const GRAALVM_COMMUNITY_DOWNLOAD_URL =
'https://github.com/graalvm/graalvm-ce-builds/releases';
const GRAALVM_COMMUNITY_ASSET_PREFIX = 'graalvm-community-jdk-';
const GRAALVM_COMMUNITY_VERSION_PATTERN = /^\d+(?:\.\d+)*$/;
const IS_WINDOWS = process.platform === 'win32'; const IS_WINDOWS = process.platform === 'win32';
const GRAALVM_PLATFORM = IS_WINDOWS ? 'windows' : process.platform; const GRAALVM_PLATFORM = IS_WINDOWS ? 'windows' : process.platform;
const GRAALVM_MIN_VERSION = 17; const GRAALVM_MIN_VERSION = 17;
@@ -25,9 +39,23 @@ const SUPPORTED_ARCHITECTURES = ['x64', 'aarch64'] as const;
type SupportedArchitecture = (typeof SUPPORTED_ARCHITECTURES)[number]; type SupportedArchitecture = (typeof SUPPORTED_ARCHITECTURES)[number];
type OsVersions = 'linux' | 'macos' | 'windows'; type OsVersions = 'linux' | 'macos' | 'windows';
interface GraalVMCommunityAsset {
name: string;
browser_download_url: string;
}
interface GraalVMCommunityRelease {
draft: boolean;
prerelease: boolean;
assets: GraalVMCommunityAsset[];
}
export class GraalVMDistribution extends JavaBase { export class GraalVMDistribution extends JavaBase {
constructor(installerOptions: JavaInstallerOptions) { constructor(
super('GraalVM', installerOptions); installerOptions: JavaInstallerOptions,
distributionName = 'GraalVM'
) {
super(distributionName, installerOptions);
} }
protected async downloadTool( protected async downloadTool(
@@ -84,40 +112,14 @@ export class GraalVMDistribution extends JavaBase {
protected async findPackageForDownload( protected async findPackageForDownload(
range: string range: string
): Promise<JavaDownloadRelease> { ): Promise<JavaDownloadRelease> {
// Add input validation this.validateVersionRange(range);
if (!range || typeof range !== 'string') { const arch = this.getSupportedArchitecture();
throw new Error('Version range is required and must be a string');
}
const arch = this.distributionArchitecture();
if (!SUPPORTED_ARCHITECTURES.includes(arch as SupportedArchitecture)) {
throw new Error(
`Unsupported architecture: ${this.architecture}. Supported architectures are: ${SUPPORTED_ARCHITECTURES.join(', ')}`
);
}
if (!this.stable) { if (!this.stable) {
return this.findEABuildDownloadUrl(`${range}-ea`); return this.findEABuildDownloadUrl(`${range}-ea`);
} }
if (this.packageType !== 'jdk') { const {platform, extension, major} = this.validateStableBuildRequest(range);
throw new Error('GraalVM provides only the `jdk` package type');
}
const platform = this.getPlatform();
const extension = getDownloadArchiveExtension();
const major = range.includes('.') ? range.split('.')[0] : range;
const majorVersion = parseInt(major);
if (isNaN(majorVersion)) {
throw new Error(`Invalid version format: ${range}`);
}
if (majorVersion < GRAALVM_MIN_VERSION) {
throw new Error(
`GraalVM is only supported for JDK ${GRAALVM_MIN_VERSION} and later. Requested version: ${major}`
);
}
const fileUrl = this.constructFileUrl( const fileUrl = this.constructFileUrl(
range, range,
@@ -133,6 +135,56 @@ export class GraalVMDistribution extends JavaBase {
return {url: fileUrl, version: range}; return {url: fileUrl, version: range};
} }
protected validateVersionRange(range: string): void {
if (!range || typeof range !== 'string') {
throw new Error('Version range is required and must be a string');
}
}
protected getSupportedArchitecture(): SupportedArchitecture {
const arch = this.distributionArchitecture();
if (!SUPPORTED_ARCHITECTURES.includes(arch as SupportedArchitecture)) {
throw new Error(
`Unsupported architecture: ${this.architecture}. Supported architectures are: ${SUPPORTED_ARCHITECTURES.join(', ')}`
);
}
return arch as SupportedArchitecture;
}
protected validateStableBuildRequest(range: string): {
platform: OsVersions;
extension: string;
major: string;
} {
if (this.packageType !== 'jdk') {
throw new Error(
`${this.distribution} provides only the \`jdk\` package type`
);
}
const platform = this.getPlatform();
const extension = getDownloadArchiveExtension();
const major = range.includes('.') ? range.split('.')[0] : range;
const majorVersion = parseInt(major);
if (isNaN(majorVersion)) {
throw new Error(`Invalid version format: ${range}`);
}
if (majorVersion < GRAALVM_MIN_VERSION) {
throw new Error(
`${this.distribution} is only supported for JDK ${GRAALVM_MIN_VERSION} and later. Requested version: ${major}`
);
}
return {
platform,
major,
extension
};
}
private constructFileUrl( private constructFileUrl(
range: string, range: string,
major: string, major: string,
@@ -149,9 +201,10 @@ export class GraalVMDistribution extends JavaBase {
const statusCode = response.message.statusCode; const statusCode = response.message.statusCode;
if (statusCode === HttpCodes.NotFound) { if (statusCode === HttpCodes.NotFound) {
throw new Error( // Create the standard error with additional hint about checking the download URL
`Could not find GraalVM for SemVer ${range}. Please check if this version is available at ${GRAALVM_DL_BASE}` const error = this.createVersionNotFoundError(range);
); error.message += `\nPlease check if this version is available at ${GRAALVM_DOWNLOAD_URL} . Pick a version from the list.`;
throw error;
} }
if ( if (
@@ -180,10 +233,12 @@ export class GraalVMDistribution extends JavaBase {
const latestVersion = versions.find(v => v.latest); const latestVersion = versions.find(v => v.latest);
if (!latestVersion) { if (!latestVersion) {
core.error( const availableVersions = versions.map(v => v.version);
`Available versions: ${versions.map(v => v.version).join(', ')}` throw this.createVersionNotFoundError(
javaEaVersion,
availableVersions,
'Note: No EA build is marked as latest for this version.'
); );
throw new Error(`Unable to find latest version for '${javaEaVersion}'`);
} }
core.debug(`Latest version found: ${latestVersion.version}`); core.debug(`Latest version found: ${latestVersion.version}`);
@@ -276,3 +331,131 @@ export class GraalVMDistribution extends JavaBase {
return result; return result;
} }
} }
export class GraalVMCommunityDistribution extends GraalVMDistribution {
constructor(installerOptions: JavaInstallerOptions) {
super(installerOptions, 'GraalVM Community');
}
protected get toolcacheFolderName(): string {
return `Java_GraalVM_Community_${this.packageType}`;
}
protected async findPackageForDownload(
range: string
): Promise<JavaDownloadRelease> {
this.validateVersionRange(range);
if (!this.stable) {
throw new Error('GraalVM Community does not provide early access builds');
}
const arch = this.getSupportedArchitecture();
const {platform, extension} = this.validateStableBuildRequest(range);
// GraalVM Community asset names embed the platform, architecture and
// archive type, e.g. `graalvm-community-jdk-21.0.2_linux-x64_bin.tar.gz`.
const assetSuffix = `_${platform}-${arch}_bin.${extension}`;
const availableVersions = await this.getAvailableVersions(assetSuffix);
const satisfiedVersion = availableVersions
.filter(item => isVersionSatisfies(range, item.version))
.sort((a, b) => -semver.compareBuild(a.version, b.version))[0];
if (!satisfiedVersion) {
const error = this.createVersionNotFoundError(
range,
availableVersions.map(item => item.version),
`Platform: ${platform}`
);
error.message += `\nPlease check if this version is available at ${GRAALVM_COMMUNITY_DOWNLOAD_URL}.`;
throw error;
}
return satisfiedVersion;
}
private async getAvailableVersions(
assetSuffix: string
): Promise<JavaDownloadRelease[]> {
const headers = getGitHubHttpHeaders();
const versions = new Map<string, JavaDownloadRelease>();
let releasesUrl: string | null = GRAALVM_COMMUNITY_RELEASES_URL;
for (
let pageIndex = 0;
releasesUrl && pageIndex < MAX_PAGINATION_PAGES;
pageIndex++
) {
const response = await this.http.getJson<GraalVMCommunityRelease[]>(
releasesUrl,
headers
);
const releases = Array.isArray(response.result) ? response.result : [];
if (releases.length === 0) {
break;
}
for (const release of releases) {
if (release.draft || release.prerelease) {
continue;
}
for (const asset of release.assets ?? []) {
const version = this.extractAssetVersion(asset.name, assetSuffix);
if (version) {
versions.set(version, {
version,
url: asset.browser_download_url
});
}
}
}
releasesUrl = this.getNextReleasesUrl(response.headers);
}
return [...versions.values()];
}
// Returns the GraalVM JDK version encoded in a release asset name when it
// matches the requested platform/architecture/archive suffix, otherwise null.
private extractAssetVersion(
assetName: string,
assetSuffix: string
): string | null {
if (
!assetName.startsWith(GRAALVM_COMMUNITY_ASSET_PREFIX) ||
!assetName.endsWith(assetSuffix)
) {
return null;
}
const rawVersion = assetName.slice(
GRAALVM_COMMUNITY_ASSET_PREFIX.length,
-assetSuffix.length
);
if (!GRAALVM_COMMUNITY_VERSION_PATTERN.test(rawVersion)) {
return null;
}
return convertVersionToSemver(rawVersion);
}
private getNextReleasesUrl(
headers: Record<string, string | string[] | undefined>
): string | null {
const nextUrl = getNextPageUrlFromLinkHeader(headers);
if (
nextUrl &&
!validatePaginationUrl(nextUrl, GRAALVM_COMMUNITY_RELEASES_PAGE_ORIGIN)
) {
core.warning(
`Ignoring pagination link with unexpected origin: ${nextUrl}`
);
return null;
}
return nextUrl;
}
}
+3 -8
View File
@@ -44,15 +44,10 @@ export class JetBrainsDistribution extends JavaBase {
const resolvedFullVersion = const resolvedFullVersion =
satisfiedVersions.length > 0 ? satisfiedVersions[0] : null; satisfiedVersions.length > 0 ? satisfiedVersions[0] : null;
if (!resolvedFullVersion) { if (!resolvedFullVersion) {
const availableOptions = versionsRaw const availableVersionStrings = versionsRaw.map(
.map(item => `${item.tag_name} (${item.semver}+${item.build})`) item => `${item.tag_name} (${item.semver}+${item.build})`
.join(', ');
const availableOptionsMessage = availableOptions
? `\nAvailable versions: ${availableOptions}`
: '';
throw new Error(
`Could not find satisfied version for SemVer '${range}'. ${availableOptionsMessage}`
); );
throw this.createVersionNotFoundError(range, availableVersionStrings);
} }
return resolvedFullVersion; return resolvedFullVersion;
+3 -8
View File
@@ -69,15 +69,10 @@ export class LibericaDistributions extends JavaBase {
.sort((a, b) => -semver.compareBuild(a.version, b.version))[0]; .sort((a, b) => -semver.compareBuild(a.version, b.version))[0];
if (!satisfiedVersion) { if (!satisfiedVersion) {
const availableOptions = availableVersions const availableVersionStrings = availableVersions.map(
.map(item => item.version) item => item.version
.join(', ');
const availableOptionsMessage = availableOptions
? `\nAvailable versions: ${availableOptions}`
: '';
throw new Error(
`Could not find satisfied version for semver ${range}. ${availableOptionsMessage}`
); );
throw this.createVersionNotFoundError(range, availableVersionStrings);
} }
return satisfiedVersion; return satisfiedVersion;
+2 -5
View File
@@ -76,11 +76,8 @@ export class MicrosoftDistributions extends JavaBase {
const foundRelease = await tc.findFromManifest(range, true, manifest, arch); const foundRelease = await tc.findFromManifest(range, true, manifest, arch);
if (!foundRelease) { if (!foundRelease) {
throw new Error( const availableVersionStrings = manifest.map(item => item.version);
`Could not find satisfied version for SemVer ${range}.\nAvailable versions: ${manifest throw this.createVersionNotFoundError(range, availableVersionStrings);
.map(item => item.version)
.join(', ')}`
);
} }
return { return {
@@ -171,6 +171,49 @@
} }
] ]
}, },
{
"version": "17.0.18",
"stable": true,
"release_url": "https://aka.ms/download-jdk",
"files": [
{
"filename": "microsoft-jdk-17.0.18-macos-x64.tar.gz",
"arch": "x64",
"platform": "darwin",
"download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-macos-x64.tar.gz"
},
{
"filename": "microsoft-jdk-17.0.18-linux-x64.tar.gz",
"arch": "x64",
"platform": "linux",
"download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-linux-x64.tar.gz"
},
{
"filename": "microsoft-jdk-17.0.18-windows-x64.zip",
"arch": "x64",
"platform": "win32",
"download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-windows-x64.zip"
},
{
"filename": "microsoft-jdk-17.0.18-macos-aarch64.tar.gz",
"arch": "aarch64",
"platform": "darwin",
"download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-macos-aarch64.tar.gz"
},
{
"filename": "microsoft-jdk-17.0.18-linux-aarch64.tar.gz",
"arch": "aarch64",
"platform": "linux",
"download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-linux-aarch64.tar.gz"
},
{
"filename": "microsoft-jdk-17.0.18-windows-aarch64.zip",
"arch": "aarch64",
"platform": "win32",
"download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-windows-aarch64.zip"
}
]
},
{ {
"version": "17.0.10", "version": "17.0.10",
"stable": true, "stable": true,
@@ -180,7 +223,7 @@
"filename": "microsoft-jdk-17.0.10-macos-x64.tar.gz", "filename": "microsoft-jdk-17.0.10-macos-x64.tar.gz",
"arch": "x64", "arch": "x64",
"platform": "darwin", "platform": "darwin",
"download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.7-macos-x64.tar.gz" "download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.10-macos-x64.tar.gz"
}, },
{ {
"filename": "microsoft-jdk-17.0.10-linux-x64.tar.gz", "filename": "microsoft-jdk-17.0.10-linux-x64.tar.gz",
+1 -1
View File
@@ -112,7 +112,7 @@ export class OracleDistribution extends JavaBase {
} }
} }
throw new Error(`Could not find Oracle JDK for SemVer ${range}`); throw this.createVersionNotFoundError(range);
} }
public getPlatform(platform: NodeJS.Platform = process.platform): OsVersions { public getPlatform(platform: NodeJS.Platform = process.platform): OsVersions {
+3 -2
View File
@@ -49,9 +49,10 @@ export class SapMachineDistribution extends JavaBase {
}); });
if (!matchedVersions.length) { if (!matchedVersions.length) {
throw new Error( const availableVersionStrings = availableVersions.map(
`Couldn't find any satisfied version for the specified java-version: "${version}" and architecture: "${this.architecture}".` item => item.version
); );
throw this.createVersionNotFoundError(version, availableVersionStrings);
} }
const resolvedVersion = matchedVersions[0]; const resolvedVersion = matchedVersions[0];
+44 -25
View File
@@ -7,9 +7,12 @@ import {
import semver from 'semver'; import semver from 'semver';
import { import {
extractJdkFile, extractJdkFile,
getNextPageUrlFromLinkHeader,
getDownloadArchiveExtension, getDownloadArchiveExtension,
isVersionSatisfies, isVersionSatisfies,
renameWinArchive renameWinArchive,
MAX_PAGINATION_PAGES,
validatePaginationUrl
} from '../../util'; } from '../../util';
import * as core from '@actions/core'; import * as core from '@actions/core';
import * as tc from '@actions/tool-cache'; import * as tc from '@actions/tool-cache';
@@ -79,14 +82,16 @@ export class SemeruDistribution extends JavaBase {
const resolvedFullVersion = const resolvedFullVersion =
satisfiedVersions.length > 0 ? satisfiedVersions[0] : null; satisfiedVersions.length > 0 ? satisfiedVersions[0] : null;
if (!resolvedFullVersion) { if (!resolvedFullVersion) {
const availableOptions = availableVersionsWithBinaries const availableVersionStrings = availableVersionsWithBinaries.map(
.map(item => item.version) item => item.version
.join(', '); );
const availableOptionsMessage = availableOptions // Include platform context to help users understand OS-specific version availability
? `\nAvailable versions: ${availableOptions}` // IBM Semeru builds are OS-specific, so platform info aids in troubleshooting
: ''; const platformContext = `Platform: ${process.platform}`;
throw new Error( throw this.createVersionNotFoundError(
`Could not find satisfied version for SemVer version '${version}' for your current OS version for ${this.architecture} architecture ${availableOptionsMessage}` version,
availableVersionStrings,
platformContext
); );
} }
@@ -153,32 +158,46 @@ export class SemeruDistribution extends JavaBase {
`jvm_impl=openj9` `jvm_impl=openj9`
].join('&'); ].join('&');
// need to iterate through all pages to retrieve the list of all versions const requestArguments = `${baseRequestArguments}&page_size=20&page=0`;
// Adoptium API doesn't provide way to retrieve the count of pages to iterate so infinity loop let availableVersionsUrl: string | null =
let page_index = 0; `https://api.adoptopenjdk.net/v3/assets/version/${versionRange}?${requestArguments}`;
const availableVersions: ISemeruAvailableVersions[] = []; const availableVersions: ISemeruAvailableVersions[] = [];
while (true) { let pageCount = 0;
const requestArguments = `${baseRequestArguments}&page_size=20&page=${page_index}`; if (core.isDebug()) {
const availableVersionsUrl = `https://api.adoptopenjdk.net/v3/assets/version/${versionRange}?${requestArguments}`; core.debug(`Gathering available versions from '${availableVersionsUrl}'`);
if (core.isDebug() && page_index === 0) {
// url is identical except page_index so print it once for debug
core.debug(
`Gathering available versions from '${availableVersionsUrl}'`
);
} }
const paginationPage = ( while (availableVersionsUrl) {
pageCount++;
const response =
await this.http.getJson<ISemeruAvailableVersions[]>( await this.http.getJson<ISemeruAvailableVersions[]>(
availableVersionsUrl availableVersionsUrl
) );
).result; const paginationPage = response.result;
const nextUrl = getNextPageUrlFromLinkHeader(response.headers);
if (
nextUrl &&
!validatePaginationUrl(nextUrl, 'https://api.adoptopenjdk.net')
) {
core.warning(
`Ignoring pagination link with unexpected origin: ${nextUrl}`
);
availableVersionsUrl = null;
} else {
availableVersionsUrl = nextUrl;
}
if (paginationPage === null || paginationPage.length === 0) { if (paginationPage === null || paginationPage.length === 0) {
// break infinity loop because we have reached end of pagination
break; break;
} }
availableVersions.push(...paginationPage); availableVersions.push(...paginationPage);
page_index++;
if (pageCount >= MAX_PAGINATION_PAGES) {
core.warning(
`Reached pagination safeguard limit (${MAX_PAGINATION_PAGES} pages) while listing Semeru releases.`
);
break;
}
} }
if (core.isDebug()) { if (core.isDebug()) {
+47 -26
View File
@@ -14,9 +14,12 @@ import {
} from '../base-models'; } from '../base-models';
import { import {
extractJdkFile, extractJdkFile,
getNextPageUrlFromLinkHeader,
getDownloadArchiveExtension, getDownloadArchiveExtension,
isVersionSatisfies, isVersionSatisfies,
renameWinArchive renameWinArchive,
MAX_PAGINATION_PAGES,
validatePaginationUrl
} from '../../util'; } from '../../util';
export enum TemurinImplementation { export enum TemurinImplementation {
@@ -31,7 +34,10 @@ export class TemurinDistribution extends JavaBase {
super(`Temurin-${jvmImpl}`, installerOptions); super(`Temurin-${jvmImpl}`, installerOptions);
} }
protected async findPackageForDownload( /**
* @internal For cross-distribution reuse only. Not intended as a public API.
*/
public async findPackageForDownload(
version: string version: string
): Promise<JavaDownloadRelease> { ): Promise<JavaDownloadRelease> {
const availableVersionsRaw = await this.getAvailableVersions(); const availableVersionsRaw = await this.getAvailableVersions();
@@ -57,15 +63,10 @@ export class TemurinDistribution extends JavaBase {
const resolvedFullVersion = const resolvedFullVersion =
satisfiedVersions.length > 0 ? satisfiedVersions[0] : null; satisfiedVersions.length > 0 ? satisfiedVersions[0] : null;
if (!resolvedFullVersion) { if (!resolvedFullVersion) {
const availableOptions = availableVersionsWithBinaries const availableVersionStrings = availableVersionsWithBinaries.map(
.map(item => item.version) item => item.version
.join(', ');
const availableOptionsMessage = availableOptions
? `\nAvailable versions: ${availableOptions}`
: '';
throw new Error(
`Could not find satisfied version for SemVer '${version}'. ${availableOptionsMessage}`
); );
throw this.createVersionNotFoundError(version, availableVersionStrings);
} }
return resolvedFullVersion; return resolvedFullVersion;
@@ -128,32 +129,47 @@ export class TemurinDistribution extends JavaBase {
`jvm_impl=${this.jvmImpl.toLowerCase()}` `jvm_impl=${this.jvmImpl.toLowerCase()}`
].join('&'); ].join('&');
// need to iterate through all pages to retrieve the list of all versions const requestArguments = `${baseRequestArguments}&page_size=20&page=0`;
// Adoptium API doesn't provide way to retrieve the count of pages to iterate so infinity loop let availableVersionsUrl: string | null =
let page_index = 0; `https://api.adoptium.net/v3/assets/version/${versionRange}?${requestArguments}`;
const availableVersions: ITemurinAvailableVersions[] = []; const availableVersions: ITemurinAvailableVersions[] = [];
while (true) { let pageCount = 0;
const requestArguments = `${baseRequestArguments}&page_size=20&page=${page_index}`; if (core.isDebug()) {
const availableVersionsUrl = `https://api.adoptium.net/v3/assets/version/${versionRange}?${requestArguments}`; core.debug(`Gathering available versions from '${availableVersionsUrl}'`);
if (core.isDebug() && page_index === 0) {
// url is identical except page_index so print it once for debug
core.debug(
`Gathering available versions from '${availableVersionsUrl}'`
);
} }
const paginationPage = ( while (availableVersionsUrl) {
pageCount++;
const response =
await this.http.getJson<ITemurinAvailableVersions[]>( await this.http.getJson<ITemurinAvailableVersions[]>(
availableVersionsUrl availableVersionsUrl
) );
).result; const paginationPage = response.result;
const nextUrl = getNextPageUrlFromLinkHeader(response.headers);
if (
nextUrl &&
!validatePaginationUrl(nextUrl, 'https://api.adoptium.net')
) {
core.warning(
`Ignoring pagination link with unexpected origin: ${nextUrl}`
);
availableVersionsUrl = null;
} else {
availableVersionsUrl = nextUrl;
}
if (paginationPage === null || paginationPage.length === 0) { if (paginationPage === null || paginationPage.length === 0) {
// break infinity loop because we have reached end of pagination
break; break;
} }
availableVersions.push(...paginationPage); availableVersions.push(...paginationPage);
page_index++;
if (pageCount >= MAX_PAGINATION_PAGES) {
core.warning(
`Reached pagination safeguard limit (${MAX_PAGINATION_PAGES} pages) while listing Temurin releases.`
);
break;
}
} }
if (core.isDebug()) { if (core.isDebug()) {
@@ -176,6 +192,11 @@ export class TemurinDistribution extends JavaBase {
return 'mac'; return 'mac';
case 'win32': case 'win32':
return 'windows'; return 'windows';
case 'linux':
if (fs.existsSync('/etc/alpine-release')) {
return 'alpine-linux';
}
return 'linux';
default: default:
return process.platform; return process.platform;
} }
+3 -8
View File
@@ -57,15 +57,10 @@ export class ZuluDistribution extends JavaBase {
const resolvedFullVersion = const resolvedFullVersion =
satisfiedVersions.length > 0 ? satisfiedVersions[0] : null; satisfiedVersions.length > 0 ? satisfiedVersions[0] : null;
if (!resolvedFullVersion) { if (!resolvedFullVersion) {
const availableOptions = availableVersions const availableVersionStrings = availableVersions.map(
.map(item => item.version) item => item.version
.join(', ');
const availableOptionsMessage = availableOptions
? `\nAvailable versions: ${availableOptions}`
: '';
throw new Error(
`Could not find satisfied version for semver ${version}. ${availableOptionsMessage}`
); );
throw this.createVersionNotFoundError(version, availableVersionStrings);
} }
return resolvedFullVersion; return resolvedFullVersion;
+57
View File
@@ -55,6 +55,14 @@ export function getDownloadArchiveExtension() {
} }
export function isVersionSatisfies(range: string, version: string): boolean { export function isVersionSatisfies(range: string, version: string): boolean {
// Some distributions (e.g. JetBrains Runtime) publish 4-segment versions
// like '17.0.8.1+1080.1' that semver rejects. If the candidate version
// isn't valid semver, it can't match — bail out rather than letting
// compareBuild / satisfies throw.
if (!semver.valid(version)) {
return false;
}
if (semver.valid(range)) { if (semver.valid(range)) {
// if full version with build digit is provided as a range (such as '1.2.3+4') // if full version with build digit is provided as a range (such as '1.2.3+4')
// we should check for exact equal via compareBuild // we should check for exact equal via compareBuild
@@ -201,6 +209,55 @@ export function getGitHubHttpHeaders(): OutgoingHttpHeaders {
return headers; return headers;
} }
export const MAX_PAGINATION_PAGES = 1000;
export function getNextPageUrlFromLinkHeader(
headers?: Record<string, string | string[] | undefined>
): string | null {
if (!headers) {
return null;
}
const linkHeader = headers.link ?? headers.Link;
if (!linkHeader) {
return null;
}
const normalizedLinkHeader = Array.isArray(linkHeader)
? linkHeader.join(',')
: linkHeader;
// Split into individual link-values and find the one with rel="next"
// RFC 8288 allows rel to appear anywhere among the parameters
const linkValues = normalizedLinkHeader.split(/,(?=\s*<)/);
for (const linkValue of linkValues) {
const urlMatch = linkValue.match(/<([^>]+)>/);
if (!urlMatch) continue;
const params = linkValue.slice(urlMatch[0].length);
// Use word boundary to match "next" as a standalone relation type
// RFC 8288 allows space-separated relation types like rel="next prev"
if (/;\s*rel="?[^"]*\bnext\b/i.test(params)) {
return urlMatch[1];
}
}
return null;
}
export function validatePaginationUrl(
url: string,
allowedOrigin: string
): boolean {
try {
const parsed = new URL(url);
const allowed = new URL(allowedOrigin);
return parsed.origin === allowed.origin;
} catch {
return false;
}
}
// Rename archive to add extension because after downloading // Rename archive to add extension because after downloading
// archive does not contain extension type and it leads to some issues // archive does not contain extension type and it leads to some issues
// on Windows runners without PowerShell Core. // on Windows runners without PowerShell Core.