Compare commits

...

17 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
7761ca7f37 Initial plan 2026-07-29 01:51:03 +00:00
Bruno Borges
382d4b753d Fix caching when wrapper distributions are absent (#1151)
* Fix missing wrapper cache distributions

Skip optional Maven and Gradle wrapper cache saves when their distribution paths do not exist, while allowing the main dependency cache to save.

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

Copilot-Session: a43181c5-548d-4293-be58-b76c03cece79

* Use resolved paths for wrapper cache saves

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

Copilot-Session: a43181c5-548d-4293-be58-b76c03cece79

* Rebuild action distributions

Regenerate the setup and cleanup bundles after updating additional cache saves to use resolved paths.

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

Copilot-Session: a43181c5-548d-4293-be58-b76c03cece79

---------

Copilot-Session: a43181c5-548d-4293-be58-b76c03cece79
2026-07-28 19:14:06 -04:00
Bruno Borges
24d1ce4c2b Document Java package compatibility (#1152)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: de5ff500-7ba1-4b07-9805-cfc4036d6155
2026-07-28 18:47:14 -04:00
Copilot
1c3b3d28f0 Support Temurin JDKs with JMOD files (#1149)
* Initial plan

* Add Temurin JMOD installation support

* Rebuild action bundles

* Use java-package for Temurin JMODs

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

Copilot-Session: e7d8c581-2d14-4ccc-aeca-afc0f3b0c2bc

* Fix Temurin JMOD test paths on Windows

Use platform-aware path construction for the JMOD copy and cache assertions so the Windows test expects backslash-normalized paths.

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

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Bruno Borges <brborges@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: e7d8c581-2d14-4ccc-aeca-afc0f3b0c2bc
2026-07-28 18:39:15 -04:00
Copilot
0b0bd25927 Add OpenJDK distribution (#1147)
* Initial plan

* Add OpenJDK distribution

* Support archived OpenJDK release formats

* Handle legacy OpenJDK URL layout

* Resolve legacy OpenJDK build metadata

* Rename OpenJDK distribution to oracle-openjdk

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

Copilot-Session: 2c93ae0c-bbf5-40f5-bf6e-40168d0e267f

* Make OpenJDK tests platform independent

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

Copilot-Session: 2c93ae0c-bbf5-40f5-bf6e-40168d0e267f

* Document Oracle OpenJDK early access builds

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

Copilot-Session: 2c93ae0c-bbf5-40f5-bf6e-40168d0e267f

* Clarify Oracle OpenJDK security note

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

Copilot-Session: 2c93ae0c-bbf5-40f5-bf6e-40168d0e267f

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Bruno Borges <brborges@microsoft.com>
Copilot-Session: 2c93ae0c-bbf5-40f5-bf6e-40168d0e267f
2026-07-28 15:55:33 -04:00
Copilot
089b010dc8 Add force-download option for reproducible JDK builds (#1148)
* Initial plan

* Add force-download input

* Build force-download action bundles

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Bruno Borges <brborges@microsoft.com>
2026-07-28 14:43:47 -04:00
Copilot
e07d36bbdd Set GRAALVM_HOME for GraalVM distributions (#1146)
* Initial plan

* Set GRAALVM_HOME for GraalVM distributions

* Rebuild setup action bundle

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-07-27 22:27:24 -04:00
Copilot
69304e5bab Remediate npm audit findings and rebuild distributions (#1145)
* Pin patched brace-expansion release

* Rebuild action bundles

* Refresh licensed npm cache records

* Restore compatible brace expansion versions

* Restore transitive dependency license records

* Fix brace-expansion GHSA-mh99-v99m-4gvg vulnerability via npm overrides

* Update licensed dependency records to fix CI license check

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-07-27 21:57:35 -04:00
Bruno Borges
f75542ba2b Fix formatting issues in README.md (#1144) 2026-07-27 16:11:12 -04:00
Markus Hoffrogge
c59dceb0cd chore(deps): fix npm audited vulnerabilities (#1140) 2026-07-27 14:34:04 -04:00
dependabot[bot]
8f48118d89 chore(deps-dev): bump typescript from 6.0.3 to 7.0.2 (#1137)
Bumps [typescript](https://github.com/microsoft/TypeScript) from 6.0.3 to 7.0.2.
- [Release notes](https://github.com/microsoft/TypeScript/releases)
- [Commits](https://github.com/microsoft/TypeScript/commits)

---
updated-dependencies:
- dependency-name: typescript
  dependency-version: 7.0.2
  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 <brborges@microsoft.com>
2026-07-27 13:45:11 -04:00
dependabot[bot]
c79143eaae chore(deps-dev): bump lint-staged from 17.0.8 to 17.2.0 (#1136)
Bumps [lint-staged](https://github.com/lint-staged/lint-staged) from 17.0.8 to 17.2.0.
- [Release notes](https://github.com/lint-staged/lint-staged/releases)
- [Changelog](https://github.com/lint-staged/lint-staged/blob/main/CHANGELOG.md)
- [Commits](https://github.com/lint-staged/lint-staged/compare/v17.0.8...v17.2.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Bruno Borges <brborges@microsoft.com>
2026-07-27 13:44:06 -04:00
dependabot[bot]
77c695c0d0 chore(deps-dev): bump @typescript-eslint/parser from 8.64.0 to 8.65.0 (#1138)
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 8.64.0 to 8.65.0.
- [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.65.0/packages/parser)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Bruno Borges <brborges@microsoft.com>
2026-07-27 13:42:04 -04:00
dependabot[bot]
7b26641a55 chore(deps): bump fast-xml-parser from 5.9.3 to 5.10.1 (#1142)
Bumps [fast-xml-parser](https://github.com/NaturalIntelligence/fast-xml-parser) from 5.9.3 to 5.10.1.
- [Release notes](https://github.com/NaturalIntelligence/fast-xml-parser/releases)
- [Changelog](https://github.com/NaturalIntelligence/fast-xml-parser/blob/master/CHANGELOG.md)
- [Commits](https://github.com/NaturalIntelligence/fast-xml-parser/compare/v5.9.3...v5.10.1)

---
updated-dependencies:
- dependency-name: fast-xml-parser
  dependency-version: 5.10.1
  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 <brborges@microsoft.com>
2026-07-27 13:38:57 -04:00
dependabot[bot]
e08df439e0 chore(deps): bump actions/setup-python from 6 to 7 (#1143)
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 6 to 7.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/setup-python
  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-07-27 13:38:27 -04:00
dependabot[bot]
cd3b6000e4 chore(deps-dev): bump @typescript-eslint/eslint-plugin (#1135)
Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 8.63.0 to 8.64.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.64.0/packages/eslint-plugin)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-27 13:11:27 -04:00
Bruno Borges
c3d7ccbf81 Clarify credential environment variable inputs (#1134)
* Clarify credential environment variable inputs

Rename credential-related inputs to make their environment-variable semantics explicit while preserving deprecated aliases with migration warnings.

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

Copilot-Session: 70a3daa8-dbc9-4eb0-a57b-df198a459315

* Potential fix for pull request finding

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

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-07-17 20:10:58 -04:00
55 changed files with 8232 additions and 12487 deletions

View File

@@ -38,9 +38,9 @@ jobs:
distribution: 'adopt'
java-version: '11'
server-id: maven
server-username: MAVEN_USERNAME
server-password: MAVEN_CENTRAL_TOKEN
gpg-passphrase: MAVEN_GPG_PASSPHRASE
server-username-env-var: MAVEN_USERNAME
server-password-env-var: MAVEN_CENTRAL_TOKEN
gpg-passphrase-env-var: MAVEN_GPG_PASSPHRASE
- name: Validate settings.xml
run: |
$xmlPath = Join-Path $HOME ".m2" "settings.xml"
@@ -93,9 +93,9 @@ jobs:
distribution: 'adopt'
java-version: '11'
server-id: maven
server-username: MAVEN_USERNAME
server-password: MAVEN_CENTRAL_TOKEN
gpg-passphrase: MAVEN_GPG_PASSPHRASE
server-username-env-var: MAVEN_USERNAME
server-password-env-var: MAVEN_CENTRAL_TOKEN
gpg-passphrase-env-var: MAVEN_GPG_PASSPHRASE
- name: Validate settings.xml is overwritten
run: |
$xmlPath = Join-Path $HOME ".m2" "settings.xml"
@@ -131,10 +131,10 @@ jobs:
distribution: 'adopt'
java-version: '11'
server-id: maven
server-username: MAVEN_USERNAME
server-password: MAVEN_CENTRAL_TOKEN
server-username-env-var: MAVEN_USERNAME
server-password-env-var: MAVEN_CENTRAL_TOKEN
overwrite-settings: false
gpg-passphrase: MAVEN_GPG_PASSPHRASE
gpg-passphrase-env-var: MAVEN_GPG_PASSPHRASE
- name: Validate that settings.xml is not overwritten
run: |
$xmlPath = Join-Path $HOME ".m2" "settings.xml"
@@ -164,9 +164,9 @@ jobs:
distribution: 'adopt'
java-version: '11'
server-id: maven
server-username: MAVEN_USERNAME
server-password: MAVEN_CENTRAL_TOKEN
gpg-passphrase: MAVEN_GPG_PASSPHRASE
server-username-env-var: MAVEN_USERNAME
server-password-env-var: MAVEN_CENTRAL_TOKEN
gpg-passphrase-env-var: MAVEN_GPG_PASSPHRASE
settings-path: ${{ runner.temp }}
- name: Validate settings.xml location
run: |

View File

@@ -28,7 +28,7 @@ jobs:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@v6
uses: actions/setup-python@v7
with:
python-version: '3.x'

View File

@@ -1,20 +0,0 @@
---
name: "@actions/glob"
version: 0.6.1
type: npm
summary: Actions glob lib
homepage: https://github.com/actions/toolkit/tree/main/packages/glob
license: mit
licenses:
- sources: LICENSE.md
text: |-
The MIT License (MIT)
Copyright 2019 GitHub
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
notices: []

View File

@@ -1,6 +1,6 @@
---
name: "@azure/abort-controller"
version: 2.1.2
version: 2.2.0
type: npm
summary: Microsoft Azure SDK for JavaScript - Aborter
homepage: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/abort-controller/README.md
@@ -8,9 +8,9 @@ license: mit
licenses:
- sources: LICENSE
text: |
The MIT License (MIT)
Copyright (c) Microsoft Corporation.
Copyright (c) 2020 Microsoft
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
@@ -22,7 +22,7 @@ licenses:
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
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

View File

@@ -1,10 +1,10 @@
---
name: "@azure/core-auth"
version: 1.10.1
version: 1.11.0
type: npm
summary: Provides low-level interfaces and helper methods for authentication in Azure
SDK
homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-auth/README.md
homepage: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/core-auth/README.md
license: mit
licenses:
- sources: LICENSE

View File

@@ -1,6 +1,6 @@
---
name: "@azure/core-client"
version: 1.10.2
version: 1.11.0
type: npm
summary: Core library for interfacing with AutoRest generated code
homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-client/

View File

@@ -1,9 +1,9 @@
---
name: "@azure/core-http-compat"
version: 2.4.0
version: 2.5.0
type: npm
summary: Core HTTP Compatibility Library to bridge the gap between Core V1 & V2 packages.
homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-compat/
homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-http-compat/
license: mit
licenses:
- sources: LICENSE

View File

@@ -1,6 +1,6 @@
---
name: "@azure/core-paging"
version: 1.6.2
version: 1.7.0
type: npm
summary: Core types for paging async iterable iterators
homepage: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/core-paging/README.md
@@ -8,9 +8,9 @@ license: mit
licenses:
- sources: LICENSE
text: |
The MIT License (MIT)
Copyright (c) Microsoft Corporation.
Copyright (c) 2020 Microsoft
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
@@ -22,7 +22,7 @@ licenses:
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
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

View File

@@ -1,6 +1,6 @@
---
name: "@azure/core-rest-pipeline"
version: 1.24.0
version: 1.25.0
type: npm
summary: Isomorphic client library for making HTTP requests in node.js and browser.
homepage: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/core-rest-pipeline/README.md

View File

@@ -1,6 +1,6 @@
---
name: "@azure/core-tracing"
version: 1.3.1
version: 1.4.0
type: npm
summary: Provides low-level interfaces and helper methods for tracing in Azure SDK
homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-tracing/README.md

View File

@@ -1,6 +1,6 @@
---
name: "@azure/core-util"
version: 1.13.1
version: 1.14.0
type: npm
summary: Core library for shared utility methods
homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-util/

View File

@@ -1,9 +1,9 @@
---
name: "@azure/core-xml"
version: 1.5.1
version: 1.6.0
type: npm
summary: Core library for interacting with XML payloads
homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-xml/
homepage: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/core-xml/README.md
license: mit
licenses:
- sources: LICENSE

View File

@@ -1,6 +1,6 @@
---
name: "@azure/logger"
version: 1.3.0
version: 1.4.0
type: npm
summary: Microsoft Azure SDK for JavaScript - Logger
homepage: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/logger/README.md

View File

@@ -1,6 +1,6 @@
---
name: "@nodable/entities"
version: 2.2.0
version: 3.0.0
type: npm
summary: Entity parser for XML, HTML, External entites with security and NCR control
homepage:

View File

@@ -1,6 +1,6 @@
---
name: "@typespec/ts-http-runtime"
version: 0.3.6
version: 0.3.7
type: npm
summary: Isomorphic client library for making HTTP requests in node.js and browser.
homepage: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/ts-http-runtime/README.md

View File

@@ -1,55 +0,0 @@
---
name: balanced-match
version: 1.0.2
type: npm
summary: Match balanced character pairs, like "{" and "}"
homepage: https://github.com/juliangruber/balanced-match
license: mit
licenses:
- sources: LICENSE.md
text: |
(MIT)
Copyright (c) 2013 Julian Gruber &lt;julian@juliangruber.com&gt;
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
- sources: README.md
text: |-
(MIT)
Copyright (c) 2013 Julian Gruber &lt;julian@juliangruber.com&gt;
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: []

View File

@@ -4,7 +4,7 @@ version: 4.0.4
type: npm
summary: Match balanced character pairs, like "{" and "}"
homepage:
license: other
license: mit
licenses:
- sources: LICENSE.md
text: |

View File

@@ -1,55 +0,0 @@
---
name: brace-expansion
version: 1.1.15
type: npm
summary: Brace expansion as known from sh/bash
homepage: https://github.com/juliangruber/brace-expansion
license: mit
licenses:
- sources: LICENSE
text: |
MIT License
Copyright (c) 2013 Julian Gruber <julian@juliangruber.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
- sources: README.md
text: |-
(MIT)
Copyright (c) 2013 Julian Gruber &lt;julian@juliangruber.com&gt;
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: []

View File

@@ -1,10 +1,10 @@
---
name: brace-expansion
version: 5.0.7
version: 5.0.8
type: npm
summary: Brace expansion as known from sh/bash
homepage:
license: other
license: mit
licenses:
- sources: LICENSE
text: |

View File

@@ -1,31 +0,0 @@
---
name: concat-map
version: 0.0.1
type: npm
summary: concatenative mapdashery
homepage: https://github.com/substack/node-concat-map#readme
license: other
licenses:
- sources: LICENSE
text: |
This software is released under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- sources: README.markdown
text: MIT
notices: []

View File

@@ -1,6 +1,6 @@
---
name: fast-xml-builder
version: 1.2.1
version: 1.3.0
type: npm
summary: Build XML from JSON without C/C++ based libraries
homepage:

View File

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

View File

@@ -1,6 +1,6 @@
---
name: is-unsafe
version: 1.0.1
version: 2.0.0
type: npm
summary: Zero-dependency, DOM-free, pure predicate for detecting unsafe strings across
HTML, XML, SVG, SQL, SHELL, and REGEX contexts

View File

@@ -1,26 +0,0 @@
---
name: minimatch
version: 3.1.5
type: npm
summary: a glob matcher in javascript
homepage:
license: isc
licenses:
- sources: LICENSE
text: |
The ISC License
Copyright (c) Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
notices: []

View File

@@ -1,6 +1,6 @@
---
name: minimatch
version: 10.2.5
version: 10.2.6
type: npm
summary: a glob matcher in javascript
homepage:

View File

@@ -1,6 +1,6 @@
---
name: path-expression-matcher
version: 1.6.1
version: 1.6.2
type: npm
summary: Efficient path tracking and pattern matching for XML/JSON parsers
homepage: https://github.com/NaturalIntelligence/path-expression-matcher#readme

View File

@@ -1,6 +1,6 @@
---
name: undici
version: 6.27.0
version: 6.28.0
type: npm
summary: An HTTP/1.1 client, written from scratch for Node.js
homepage: https://undici.nodejs.org

View File

@@ -1,12 +1,35 @@
---
name: xml-naming
version: 0.1.0
version: 0.3.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: LICENSE
text: |
MIT License
Copyright (c) 2026 Natural Intelligence
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
- sources: README.md
text: MIT
notices: []

View File

@@ -23,11 +23,13 @@ This action allows you to work with Java and Scala projects.
> [!NOTE]
> V6 is still in development (`main` branch) and is not yet recommended for production workflows.
- **Migrated to ESM** to enable support for the latest `@actions/*` package versions. This is an internal implementation change only. No changes are required to your workflow configuration, and the action's behavior is unchanged. Existing workflows continue to work as before.
- **Migrated to ESM** to enable support for the latest `@actions/*` package versions. This is an internal implementation change.
## Breaking changes in V6
- **The GPG passphrase is now passed to the Maven GPG Plugin through an environment variable (`gpg.passphraseEnvName`) instead of the deprecated `gpg.passphrase` server in `settings.xml`.** The `gpg-passphrase` input and its default (`GPG_PASSPHRASE`) are unchanged, so if you already set that environment variable in your build step your workflow keeps working. However, this now requires `maven-gpg-plugin` **3.2.0 or newer**; older versions do not honor `gpg.passphraseEnvName` and, because the `gpg.passphrase` server is no longer written, will not pick up the passphrase. Upgrade the plugin to 3.2.0+.
- **Renamed inputs that accept environment-variable names** to make it clear that their values are not credentials. Replace `server-username`, `server-password`, and `gpg-passphrase` with `server-username-env-var`, `server-password-env-var`, and `gpg-passphrase-env-var`, respectively. The old names remain as deprecated aliases and emit a warning when used.
- **The GPG passphrase is now passed to the Maven GPG Plugin through an environment variable (`gpg.passphraseEnvName`) instead of the deprecated `gpg.passphrase` server in `settings.xml`.** Set the environment variable name with `gpg-passphrase-env-var`, which defaults to `GPG_PASSPHRASE`. This requires `maven-gpg-plugin` **3.2.0 or newer**; older versions do not honor `gpg.passphraseEnvName` and, because the `gpg.passphrase` server is no longer written, will not pick up the passphrase. Upgrade the plugin to 3.2.0+.
See [GPG](docs/advanced-usage.md#gpg) for details.
@@ -40,56 +42,58 @@ For more details, see the full release notes on the [releases page](https://git
## 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.
- `java-version-file`: The path to a file containing java version. Supported file types are `.java-version`, `.tool-versions`, and `.sdkmanrc`. See more details in [about .java-version-file](docs/advanced-usage.md#Java-version-file).
- `java-version-file`: The path to a file containing java version. Supported file types are `.java-version`, `.tool-versions`, and `.sdkmanrc`. See more details in [about .java-version-file](docs/advanced-usage.md#Java-version-file).
- `distribution`: Java [distribution](#supported-distributions). Required unless `java-version-file` points to `.sdkmanrc` with a recognized distribution suffix (for example `java=21.0.5-tem`).
- `distribution`: Java [distribution](#supported-distributions). Required unless `java-version-file` points to `.sdkmanrc` with a recognized distribution suffix (for example `java=21.0.5-tem`).
- `java-package`: The packaging variant of the chosen distribution. Possible values: `jdk`, `jre`, `jdk+fx`, `jre+fx`. For Azul Zulu, `jdk+crac` and `jre+crac` are also supported. Default value: `jdk`.
- `java-package`: The packaging variant of the chosen distribution. Possible values: `jdk`, `jre`, `jdk+fx`, `jre+fx`. For Azul Zulu, `jdk+crac` and `jre+crac` are also supported. For Eclipse Temurin 24 and later, `jdk+jmods` includes the separately packaged JMOD files. Default value: `jdk`.
- `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.
- `jdk-file`: If a use-case requires a custom distribution setup-java uses the compressed JDK from the location pointed by this input and will take care of the installation and caching on the VM. Note: `distribution` must be set to 'jdkfile' (case-sensitive; all lowercase) when using this option. (The camelCase `jdkFile` input is still accepted as a deprecated alias and may be removed in a future release.)
- `jdk-file`: If a use-case requires a custom distribution setup-java uses the compressed JDK from the location pointed by this input and will take care of the installation and caching on the VM. Note: `distribution` must be set to 'jdkfile' (case-sensitive; all lowercase) when using this option. (The camelCase `jdkFile` input is still accepted as a deprecated alias and may be removed in a future release.)
- `check-latest`: Setting this option makes the action to check for the latest available version for the version spec.
- `check-latest`: Setting this option makes the action to check for the latest available version for the version spec.
- `set-default`: Set to `false` to install a JDK without making it the default. When `false`, `JAVA_HOME` and `PATH` are not updated, but `JAVA_HOME_<major>_<arch>` is still set so the JDK remains discoverable. Default value: `true`. See [Installing JDK without setting as default](docs/advanced-usage.md#Installing-JDK-without-setting-as-default) for more details.
- `force-download`: Set to `true` to always download Java and replace any matching version in the tool cache. This can help make builds reproducible when a runner image has modified a pre-installed JDK, such as its `cacerts` file. Default value: `false`.
- `problem-matcher`: Set to `false` to disable Java problem matcher annotations (compiler diagnostics and uncaught exceptions). Default value: `true`. See [Java problem matcher](docs/advanced-usage.md#java-problem-matcher-compiler-annotations) for details and annotation limits.
- `set-default`: Set to `false` to install a JDK without making it the default. When `false`, `JAVA_HOME` and `PATH` are not updated, but `JAVA_HOME_<major>_<arch>` is still set so the JDK remains discoverable. Default value: `true`. See [Installing JDK without setting as default](docs/advanced-usage.md#Installing-JDK-without-setting-as-default) for more details.
- `verify-signature`: Verifies downloaded Java package signatures when supported by the selected distribution. Currently supported for `temurin` and `microsoft`. If set to `true` for unsupported distributions, the action fails.
- `problem-matcher`: Set to `false` to disable Java problem matcher annotations (compiler diagnostics and uncaught exceptions). Default value: `true`. See [Java problem matcher](docs/advanced-usage.md#java-problem-matcher-compiler-annotations) for details and annotation limits.
- `verify-signature-public-key`: ASCII-armored GPG public key used to verify the downloaded package signature. Overrides the default bundled key for the selected distribution.
- `verify-signature`: Verifies downloaded Java package signatures when supported by the selected distribution. Currently supported for `temurin` and `microsoft`. If set to `true` for unsupported distributions, the action fails.
- `token`: The token used to authenticate when fetching version manifests hosted on GitHub.com. Defaults to `${{ github.token }}` when running on GitHub.com; defaults to an empty string on GitHub Enterprise Server. On GHES, provide a GitHub.com personal access token if manifest requests are rate-limited. See [Using Microsoft distribution on GHES](docs/advanced-usage.md#using-microsoft-distribution-on-ghes) for more details.
- `verify-signature-public-key`: ASCII-armored GPG public key used to verify the downloaded package signature. Overrides the default bundled key for the selected distribution.
- `cache`: Quick [setup caching](#caching-packages-dependencies) for the dependencies managed through one of the predefined package managers. It can be one of "maven", "gradle" or "sbt".
- `token`: The token used to authenticate when fetching version manifests hosted on GitHub.com. Defaults to `${{ github.token }}` when running on GitHub.com; defaults to an empty string on GitHub Enterprise Server. On GHES, provide a GitHub.com personal access token if manifest requests are rate-limited. See [Using Microsoft distribution on GHES](docs/advanced-usage.md#using-microsoft-distribution-on-ghes) for more details.
- `cache-dependency-path`: The path to a dependency file: pom.xml, build.gradle, build.sbt, etc. This option can be used with the `cache` option. If this option is omitted, the action searches for the dependency file in the entire repository. This option supports wildcards and a list of file names for caching multiple dependencies.
- `cache`: Quick [setup caching](#caching-packages-dependencies) for the dependencies managed through one of the predefined package managers. It can be one of "maven", "gradle" or "sbt".
- `cache-dependency-path`: The path to a dependency file: pom.xml, build.gradle, build.sbt, etc. This option can be used with the `cache` option. If this option is omitted, the action searches for the dependency file in the entire repository. This option supports wildcards and a list of file names for caching multiple dependencies.
#### Maven options
The action has a bunch of inputs to generate maven's [settings.xml](https://maven.apache.org/settings.html) on the fly and pass the values to Apache Maven GPG Plugin as well as Apache Maven Toolchains. See [advanced usage](docs/advanced-usage.md) for more.
- `overwrite-settings`: By default action overwrites the settings.xml. In order to skip generation of file if it exists, set this to `false`.
- `overwrite-settings`: By default action overwrites the settings.xml. In order to skip generation of file if it exists, set this to `false`.
- `server-id`: ID of the distributionManagement repository in the pom.xml file. Default is `github`.
- `server-id`: ID of the distributionManagement repository in the pom.xml file. Default is `github`.
- `server-username`: Environment variable name for the username for authentication to the Apache Maven repository. Default is GITHUB\_ACTOR.
- `server-username-env-var`: Environment variable name for the username for authentication to the Apache Maven repository. Default is GITHUB\_ACTOR.
- `server-password`: Environment variable name for password or token for authentication to the Apache Maven repository. Default is GITHUB\_TOKEN.
- `server-password-env-var`: Environment variable name for password or token for authentication to the Apache Maven repository. Default is GITHUB\_TOKEN.
- `settings-path`: Maven related setting to point to the directory where the settings.xml file will be written. Default is \~/.m2.
- `settings-path`: Maven related setting to point to the directory where the settings.xml file will be written. Default is \~/.m2.
- `gpg-private-key`: GPG private key to import. Default is empty string.
- `gpg-private-key`: GPG private key to import. Default is empty string.
- `gpg-passphrase`: Environment variable name for the GPG private key passphrase. Default is GPG\_PASSPHRASE.
- `gpg-passphrase-env-var`: Environment variable name for the GPG private key passphrase. Default is GPG\_PASSPHRASE.
- `mvn-toolchain-id`: Name of Maven Toolchain ID if the default name of `${distribution}_${java-version}` is not wanted.
- `mvn-toolchain-id`: Name of Maven Toolchain ID if the default name of `${distribution}_${java-version}` is not wanted.
- `mvn-toolchain-vendor`: Name of Maven Toolchain Vendor if the default name of `${distribution}` is not wanted.
- `mvn-toolchain-vendor`: Name of Maven Toolchain Vendor if the default name of `${distribution}` is not wanted.
- `show-download-progress`: Set to `true` to keep Maven artifact download and transfer progress in build logs. Default value: `false`. By default, the action adds `-ntp` (`--no-transfer-progress`) to `MAVEN_ARGS`. This input has no effect on non-Maven builds. See [Maven transfer progress](docs/advanced-usage.md#maven-transfer-progress-download-logs) for more details.
- `show-download-progress`: Set to `true` to keep Maven artifact download and transfer progress in build logs. Default value: `false`. By default, the action adds `-ntp` (`--no-transfer-progress`) to `MAVEN_ARGS`. This input has no effect on non-Maven builds. See [Maven transfer progress](docs/advanced-usage.md#maven-transfer-progress-download-logs) for more details.
### Basic Configuration
@@ -144,6 +148,7 @@ Currently, the following distributions are supported:
| `corretto` | [Amazon Corretto Build of OpenJDK](https://aws.amazon.com/corretto/) | [`corretto` license](https://aws.amazon.com/corretto/faqs/)
| `semeru` | [IBM Semeru Runtime Open Edition](https://developer.ibm.com/languages/java/semeru-runtimes/downloads/) | [`semeru` license](https://openjdk.java.net/legal/gplv2+ce.html) |
| `oracle` | [Oracle JDK](https://www.oracle.com/java/technologies/downloads/) | [`oracle` license](https://java.com/freeuselicense)
| `oracle-openjdk` | [Oracle OpenJDK](https://jdk.java.net/) | [`oracle-openjdk` license](https://openjdk.org/legal/gplv2+ce.html)
| `dragonwell` | [Alibaba Dragonwell JDK](https://dragonwell-jdk.io/) | [`dragonwell` license](https://www.aliyun.com/product/dragonwell/)
| `sapmachine` | [SAP SapMachine JDK/JRE](https://sapmachine.io/) | [`sapmachine` license](https://github.com/SAP/SapMachine/blob/sapmachine/LICENSE)
| `graalvm` | [Oracle GraalVM](https://www.graalvm.org/) | [`graalvm` license](https://www.oracle.com/downloads/licenses/graal-free-license.html)
@@ -155,6 +160,7 @@ Currently, the following distributions are supported:
> [!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/).
> - Oracle OpenJDK builds are created and hosted by Oracle. After a limited number of releases, Oracle archives these builds and no longer provides security updates. To continue receiving security patches, users must move to Oracle JDK or choose a different vendor.
> - For Azul Zulu OpenJDK, architecture `arm64` is mapped to `aarch64` when querying the Azul Metadata API.
> - To comply with the GraalVM Free Terms and Conditions (GFTC) license, it is recommended to use GraalVM JDK 17 version 17.0.12, as this is the only version of GraalVM JDK 17 available under the GFTC license. Additionally, it is encouraged to consider upgrading to GraalVM JDK 21, which offers the latest features and improvements.
> - GraalVM Community is available as `distribution: 'graalvm-community'` for stable JDK 17 and later releases published on GitHub.

View File

@@ -270,4 +270,55 @@ describe('auth tests', () => {
expectedSettings
);
});
it('uses deprecated input aliases and warns', () => {
const mockGetInput = core.getInput as jest.MockedFunction<
typeof core.getInput
>;
const mockWarning = core.warning as jest.MockedFunction<
typeof core.warning
>;
mockGetInput.mockImplementation(name =>
name === 'server-username' ? 'LEGACY_USERNAME' : ''
);
expect(
auth.getInputWithDeprecatedAlias(
'server-username-env-var',
'server-username',
'GITHUB_ACTOR'
)
).toBe('LEGACY_USERNAME');
expect(mockWarning).toHaveBeenCalledWith(
"The 'server-username' input is deprecated and may be removed in a future release. Please use 'server-username-env-var' instead."
);
mockGetInput.mockReset();
mockWarning.mockReset();
});
it('prefers the replacement input over its deprecated alias', () => {
const mockGetInput = core.getInput as jest.MockedFunction<
typeof core.getInput
>;
mockGetInput.mockImplementation(name => {
const inputs: Record<string, string> = {
'server-password-env-var': 'NEW_PASSWORD',
'server-password': 'LEGACY_PASSWORD'
};
return inputs[name] || '';
});
expect(
auth.getInputWithDeprecatedAlias(
'server-password-env-var',
'server-password',
'GITHUB_TOKEN'
)
).toBe('NEW_PASSWORD');
expect(core.warning).toHaveBeenCalled();
mockGetInput.mockReset();
(core.warning as jest.Mock).mockReset();
});
});

View File

@@ -458,11 +458,16 @@ describe('dependency cache', () => {
});
describe('save', () => {
let spyCacheSave: any;
let spyGlobCreate: jest.Mock;
beforeEach(() => {
spyCacheSave = (cache.saveCache as any).mockImplementation(
(paths: string[], key: string) => Promise.resolve(0)
);
spyGlobCreate = glob.create as jest.Mock;
spyGlobCreate.mockResolvedValue({
glob: jest.fn(() => Promise.resolve(['wrapper-path']))
});
spyWarning.mockImplementation(() => null);
});
@@ -543,7 +548,7 @@ describe('dependency cache', () => {
await save('maven');
expect(spyCacheSave).toHaveBeenCalledWith(
[join(os.homedir(), '.m2', 'wrapper', 'dists')],
['wrapper-path'],
'setup-java-maven-wrapper-key'
);
expect(spyWarning).not.toHaveBeenCalled();
@@ -572,6 +577,11 @@ describe('dependency cache', () => {
});
it('does not fail the post step when the wrapper distribution path is missing', async () => {
createFile(join(workspace, 'pom.xml'));
createDirectory(join(workspace, '.mvn'));
createDirectory(join(workspace, '.mvn', 'wrapper'));
createFile(
join(workspace, '.mvn', 'wrapper', 'maven-wrapper.properties')
);
(core.getState as jest.Mock<any>).mockImplementation((name: any) => {
switch (name) {
case 'cache-primary-key':
@@ -584,17 +594,19 @@ describe('dependency cache', () => {
return '';
}
});
spyCacheSave.mockImplementation((paths: string[]) =>
paths.includes(join(os.homedir(), '.m2', 'wrapper', 'dists'))
? Promise.reject(
new cache.ValidationError(
'Path Validation Error: Path(s) specified in the action for caching do(es) not exist'
)
)
: Promise.resolve(0)
);
spyGlobCreate.mockResolvedValue({
glob: jest.fn(() => Promise.resolve([]))
});
await expect(save('maven')).resolves.toBeUndefined();
expect(spyCacheSave).not.toHaveBeenCalledWith(
[join(os.homedir(), '.m2', 'wrapper', 'dists')],
expect.any(String)
);
expect(spyCacheSave).toHaveBeenCalledWith(
[join(os.homedir(), '.m2', 'repository')],
'setup-java-cache-primary-key'
);
expect(spyWarning).not.toHaveBeenCalled();
});
});
@@ -666,7 +678,7 @@ describe('dependency cache', () => {
await save('gradle');
expect(spyCacheSave).toHaveBeenCalledWith(
[join(os.homedir(), '.gradle', 'wrapper')],
['wrapper-path'],
'setup-java-gradle-wrapper-key'
);
expect(spyWarning).not.toHaveBeenCalled();
@@ -693,6 +705,36 @@ describe('dependency cache', () => {
expect.any(String)
);
});
it('does not fail the post step when the wrapper distribution path is missing', async () => {
createFile(join(workspace, 'build.gradle'));
createFile(join(workspace, 'gradle-wrapper.properties'));
(core.getState as jest.Mock<any>).mockImplementation((name: any) => {
switch (name) {
case 'cache-primary-key':
return 'setup-java-cache-primary-key';
case 'cache-matched-key':
return 'setup-java-cache-matched-key';
case 'cache-primary-key-gradle-wrapper':
return 'setup-java-gradle-wrapper-key';
default:
return '';
}
});
spyGlobCreate.mockResolvedValue({
glob: jest.fn(() => Promise.resolve([]))
});
await expect(save('gradle')).resolves.toBeUndefined();
expect(spyCacheSave).not.toHaveBeenCalledWith(
[join(os.homedir(), '.gradle', 'wrapper')],
expect.any(String)
);
expect(spyCacheSave).toHaveBeenCalledWith(
[join(os.homedir(), '.gradle', 'caches')],
'setup-java-cache-primary-key'
);
expect(spyWarning).not.toHaveBeenCalled();
});
});
describe('for sbt', () => {
it('uploads cache even if no build.sbt found', async () => {

View File

@@ -443,6 +443,35 @@ describe('setupJava', () => {
);
});
it('should download java when force-download is enabled, even if the version is cached', async () => {
mockJavaBase = new EmptyJavaBase({
version: actualJavaVersion,
architecture: 'x86',
packageType: 'jdk',
checkLatest: false,
forceDownload: true
});
const findInToolcache = jest.fn(() => ({
version: actualJavaVersion,
path: javaPathInstalled
}));
mockJavaBase['findInToolcache'] = findInToolcache;
await expect(mockJavaBase.setupJava()).resolves.toEqual({
version: actualJavaVersion,
path: javaPathInstalled
});
expect(findInToolcache).not.toHaveBeenCalled();
expect(spyCoreInfo).toHaveBeenCalledWith('Trying to download...');
expect(spyCoreInfo).toHaveBeenCalledWith(
`Java ${actualJavaVersion} was downloaded`
);
expect(spyCoreInfo).not.toHaveBeenCalledWith(
`Resolved Java ${actualJavaVersion} from tool-cache`
);
});
it.each([
[
{

View File

@@ -0,0 +1,16 @@
import {getJavaDistribution} from '../../src/distributions/distribution-factory.js';
describe('getJavaDistribution', () => {
it("rejects java-package 'jdk+jmods' for non-Temurin distributions", () => {
expect(() =>
getJavaDistribution('zulu', {
version: '25',
architecture: 'x64',
packageType: 'jdk+jmods',
checkLatest: false
})
).toThrow(
"java-package 'jdk+jmods' is only supported for distribution 'temurin'."
);
});
});

View File

@@ -166,6 +166,29 @@ describe('GraalVMDistribution', () => {
});
});
describe('setJavaDefault', () => {
it('should set GRAALVM_HOME for Oracle GraalVM', () => {
(distribution as any).setJavaDefault('17.0.5', '/cached/java/path');
expect(core.exportVariable).toHaveBeenCalledWith(
'GRAALVM_HOME',
'/cached/java/path'
);
});
it('should set GRAALVM_HOME for GraalVM Community', () => {
(communityDistribution as any).setJavaDefault(
'17.0.5',
'/cached/java/path'
);
expect(core.exportVariable).toHaveBeenCalledWith(
'GRAALVM_HOME',
'/cached/java/path'
);
});
});
describe('downloadTool', () => {
const javaRelease = {
version: '17.0.5',

View File

@@ -208,6 +208,29 @@ describe('setupJava', () => {
);
});
it('java is unpacked from jdkfile when force-download is enabled', async () => {
const inputs = {
version: actualJavaVersion,
architecture: 'x86',
packageType: 'jdk',
checkLatest: false,
forceDownload: true
};
mockJavaBase = new LocalDistribution(inputs, expectedJdkFile);
await expect(mockJavaBase.setupJava()).resolves.toEqual({
version: actualJavaVersion,
path: javaPath
});
expect(spyGetToolcachePath).not.toHaveBeenCalled();
expect(spyUtilsExtractJdkFile).toHaveBeenCalledWith(expectedJdkFile);
expect(spyTcCacheDir).toHaveBeenCalled();
expect(spyCoreInfo).not.toHaveBeenCalledWith(
`Resolved Java ${actualJavaVersion} from tool-cache`
);
});
it("java is resolved from toolcache, jdkfile doesn't exist", async () => {
const inputs = {
version: actualJavaVersion,

View File

@@ -0,0 +1,216 @@
import {afterEach, beforeEach, describe, expect, it, jest} from '@jest/globals';
import {HttpClient} from '@actions/http-client';
jest.unstable_mockModule('@actions/core', () => ({
info: jest.fn(),
warning: jest.fn(),
debug: jest.fn(),
error: jest.fn(),
notice: jest.fn(),
setFailed: jest.fn(),
setOutput: jest.fn(),
getInput: jest.fn(),
getBooleanInput: jest.fn(),
getMultilineInput: jest.fn(),
addPath: jest.fn(),
exportVariable: jest.fn(),
saveState: jest.fn(),
getState: jest.fn(),
setSecret: jest.fn(),
isDebug: jest.fn(() => false),
startGroup: jest.fn(),
endGroup: jest.fn(),
group: jest.fn((_name: string, fn: () => Promise<unknown>) => fn()),
toPlatformPath: jest.fn((value: string) => value),
toWin32Path: jest.fn((value: string) => value),
toPosixPath: jest.fn((value: string) => value)
}));
const {OpenJdkDistribution} =
await import('../../src/distributions/openjdk/installer.js');
const {getJavaDistribution} =
await import('../../src/distributions/distribution-factory.js');
const homePage = `
<a href="/26/">JDK 26</a>
<a href="/27/">JDK
27</a>
`;
const currentPage = `
<a href="https://download.java.net/java/GA/jdk26.0.2/hash/10/GPL/openjdk-26.0.2_linux-x64_bin.tar.gz">tar.gz</a>
<a href="https://download.java.net/java/GA/jdk26.0.2/hash/10/GPL/openjdk-26.0.2_linux-aarch64_bin.tar.gz">tar.gz</a>
`;
const earlyAccessPage = `
<a href="https://download.java.net/java/early_access/jdk27/32/GPL/openjdk-27-ea+32_linux-x64_bin.tar.gz">tar.gz</a>
`;
const archivePage = `
<a href="https://download.java.net/java/GA/jdk26.0.1/hash/8/GPL/openjdk-26.0.1_linux-x64_bin.tar.gz">tar.gz</a>
<a href="https://download.java.net/java/GA/jdk25/hash/36/GPL/openjdk-25_linux-x64_bin.tar.gz">tar.gz</a>
<a href="https://download.java.net/java/GA/jdk18.0.1.1/hash/2/GPL/openjdk-18.0.1.1_linux-x64_bin.tar.gz">tar.gz</a>
<th>9.0.4 (build 9.0.4+11)</th>
<a href="https://download.java.net/java/GA/jdk9/9.0.4/binaries/openjdk-9.0.4_linux-x64_bin.tar.gz">tar.gz</a>
`;
function createDistribution(
version = '26',
architecture = 'x64',
packageType = 'jdk',
useFixturePlatform = true
) {
const distribution = new OpenJdkDistribution({
version,
architecture,
packageType,
checkLatest: false
});
if (useFixturePlatform) {
distribution['getPlatform'] = jest.fn(() => 'linux');
}
return distribution;
}
describe('OpenJdkDistribution', () => {
let getSpy: jest.SpiedFunction<HttpClient['get']>;
beforeEach(() => {
getSpy = jest
.spyOn(HttpClient.prototype, 'get')
.mockImplementation(async url => {
const pages: Record<string, string> = {
'https://jdk.java.net/': homePage,
'https://jdk.java.net/26/': currentPage,
'https://jdk.java.net/27/': earlyAccessPage,
'https://jdk.java.net/archive/': archivePage
};
return {
readBody: async () => pages[url] ?? ''
} as Awaited<ReturnType<HttpClient['get']>>;
});
});
afterEach(() => {
jest.restoreAllMocks();
});
it('resolves the newest matching GA release', async () => {
const result = await createDistribution()['findPackageForDownload']('26');
expect(result).toEqual({
version: '26.0.2+10',
url: 'https://download.java.net/java/GA/jdk26.0.2/hash/10/GPL/openjdk-26.0.2_linux-x64_bin.tar.gz'
});
});
it('resolves an archived GA release', async () => {
const result =
await createDistribution('26.0.1')['findPackageForDownload']('26.0.1');
expect(result.version).toBe('26.0.1+8');
expect(result.url).toContain('/openjdk-26.0.1_linux-x64_bin.tar.gz');
});
it('resolves an exact GA build', async () => {
const result =
await createDistribution('26.0.2+10')['findPackageForDownload'](
'26.0.2+10'
);
expect(result.version).toBe('26.0.2+10');
});
it('resolves an exact build from a legacy archive heading', async () => {
const result =
await createDistribution('9.0.4+11')['findPackageForDownload'](
'9.0.4+11'
);
expect(result.version).toBe('9.0.4+11');
expect(result.url).toContain('/binaries/openjdk-9.0.4_linux-x64_bin');
});
it('resolves a four-field Java version', async () => {
const result =
await createDistribution('18.0.1.1')['findPackageForDownload'](
'18.0.1+1'
);
expect(result.version).toBe('18.0.1+1');
expect(result.url).toContain('/openjdk-18.0.1.1_linux-x64_bin.tar.gz');
});
it('resolves an early-access release without requesting the archive', async () => {
const result =
await createDistribution('27-ea')['findPackageForDownload']('27');
expect(result).toEqual({
version: '27.0.0+32',
url: 'https://download.java.net/java/early_access/jdk27/32/GPL/openjdk-27-ea+32_linux-x64_bin.tar.gz'
});
expect(getSpy).not.toHaveBeenCalledWith('https://jdk.java.net/archive/');
});
it('reports available versions when no release matches', async () => {
await expect(
createDistribution()['findPackageForDownload']('24')
).rejects.toThrow(
"No matching version found for SemVer '24'.\nDistribution: Oracle OpenJDK"
);
});
it.each([
['jre', 'Oracle OpenJDK provides only the `jdk` package type'],
['jdk+fx', 'Oracle OpenJDK provides only the `jdk` package type']
])('rejects the %s package type', async (packageType, message) => {
await expect(
createDistribution('26', 'x64', packageType)['findPackageForDownload'](
'26'
)
).rejects.toThrow(message);
});
it('rejects unsupported architectures', async () => {
await expect(
createDistribution('26', 'x86')['findPackageForDownload']('26')
).rejects.toThrow('Unsupported architecture: x86');
});
it('maps supported platforms', () => {
const distribution = createDistribution('26', 'x64', 'jdk', false);
expect(distribution['getPlatform']('linux')).toBe('linux');
expect(distribution['getPlatform']('darwin')).toBe('macos');
expect(distribution['getPlatform']('win32')).toBe('windows');
expect(() => distribution['getPlatform']('freebsd')).toThrow(
"Platform 'freebsd' is not supported"
);
});
it('parses legacy platform names and archive formats', () => {
const distribution = createDistribution();
const macRelease = distribution['parseReleases'](
'<a href="https://download.java.net/java/GA/jdk16/hash/7/GPL/openjdk-16_osx-x64_bin.tar.gz">tar.gz</a>',
'macos',
'x64'
);
const windowsRelease = distribution['parseReleases'](
'<a href="https://download.java.net/java/GA/jdk10/hash/13/openjdk-10.0.2_windows-x64_bin.tar.gz">tar.gz</a>',
'windows',
'x64'
);
expect(macRelease[0].version).toBe('16.0.0+7');
expect(windowsRelease[0].version).toBe('10.0.2+13');
expect(windowsRelease[0].url.endsWith('.tar.gz')).toBe(true);
});
it('is registered in the distribution factory', () => {
const distribution = getJavaDistribution('oracle-openjdk', {
version: '26',
architecture: 'x64',
packageType: 'jdk',
checkLatest: false
});
expect(distribution).toBeInstanceOf(OpenJdkDistribution);
});
});

View File

@@ -13,6 +13,7 @@ import type {TemurinImplementation as TemurinImplementationType} from '../../src
import {HttpClient} from '@actions/http-client';
import fs from 'fs';
import os from 'os';
import path from 'path';
import manifestData from '../data/temurin.json' with {type: 'json'};
@@ -119,6 +120,16 @@ describe('getAvailableVersions', () => {
TemurinImplementation.Hotspot,
'os=mac&architecture=x64&image_type=jdk&release_type=ga&jvm_impl=hotspot&page_size=20&page=0'
],
[
{
version: '25',
architecture: 'x64',
packageType: 'jdk+jmods',
checkLatest: false
},
TemurinImplementation.Hotspot,
'os=mac&architecture=x64&image_type=jdk&release_type=ga&jvm_impl=hotspot&page_size=20&page=0'
],
[
{
version: '16',
@@ -169,6 +180,27 @@ describe('getAvailableVersions', () => {
}
);
it('requests the JMOD image type', async () => {
const distribution = new TemurinDistribution(
{
version: '25',
architecture: 'x64',
packageType: 'jdk+jmods',
checkLatest: false
},
TemurinImplementation.Hotspot
);
distribution['getPlatformOption'] = () => 'linux';
await distribution['getAvailableVersions']('jmods');
expect(spyHttpClient).toHaveBeenCalledWith(
expect.stringContaining(
'os=linux&architecture=x64&image_type=jmods&release_type=ga'
)
);
});
it('load available versions', async () => {
const nextPageUrl =
'https://api.adoptium.net/v3/assets/version/%5B1.0,100.0%5D?page=1&page_size=20';
@@ -229,7 +261,12 @@ describe('getAvailableVersions', () => {
it.each([
[TemurinImplementation.Hotspot, 'jdk', 'Java_Temurin-Hotspot_jdk'],
[TemurinImplementation.Hotspot, 'jre', 'Java_Temurin-Hotspot_jre']
[TemurinImplementation.Hotspot, 'jre', 'Java_Temurin-Hotspot_jre'],
[
TemurinImplementation.Hotspot,
'jdk+jmods',
'Java_Temurin-Hotspot_jdk+jmods'
]
])(
'find right toolchain folder',
(
@@ -386,6 +423,7 @@ describe('downloadTool', () => {
let spyCacheDir: any;
let spyReadDirSync: any;
let spyRenameWinArchive: any;
let spyCopySync: any;
beforeEach(() => {
spyDownloadTool = tc.downloadTool as jest.Mock;
@@ -400,6 +438,8 @@ describe('downloadTool', () => {
spyReadDirSync.mockReturnValue(['jdk-17'] as any);
spyRenameWinArchive = util.renameWinArchive as jest.Mock;
spyRenameWinArchive.mockReturnValue('/tmp/jdk.tar.gz.zip');
spyCopySync = jest.spyOn(fs, 'cpSync');
spyCopySync.mockImplementation(() => undefined);
});
afterEach(() => {
@@ -433,6 +473,60 @@ describe('downloadTool', () => {
);
});
it('downloads and adds matching JMODs to the JDK', async () => {
spyDownloadTool
.mockResolvedValueOnce('/tmp/jdk.tar.gz')
.mockResolvedValueOnce('/tmp/jmods.tar.gz');
spyExtractJdkFile
.mockResolvedValueOnce('/tmp/extracted')
.mockResolvedValueOnce('/tmp/extracted-jmods');
spyReadDirSync
.mockReturnValueOnce(['jdk-25'] as any)
.mockReturnValueOnce(['jdk-25-jmods'] as any);
jest.spyOn(fs, 'existsSync').mockReturnValue(false);
const distribution = new TemurinDistribution(
{
version: '25',
architecture: 'x64',
packageType: 'jdk+jmods',
checkLatest: false
},
TemurinImplementation.Hotspot
);
distribution['resolvePackage'] = jest.fn().mockResolvedValue({
version: '25.0.3+9',
url: 'https://example.com/jmods.tar.gz'
});
await distribution['downloadTool']({
version: '25.0.3+9',
url: 'https://example.com/jdk.tar.gz'
});
expect(distribution['resolvePackage']).toHaveBeenCalledWith(
'25.0.3+9',
'jmods'
);
expect(spyDownloadTool).toHaveBeenNthCalledWith(
2,
'https://example.com/jmods.tar.gz'
);
expect(spyCopySync).toHaveBeenCalledWith(
path.join('/tmp/extracted-jmods', 'jdk-25-jmods'),
process.platform === 'darwin'
? path.join('/tmp/extracted', 'jdk-25', 'Contents', 'Home', 'jmods')
: path.join('/tmp/extracted', 'jdk-25', 'jmods'),
{recursive: true}
);
expect(spyCacheDir).toHaveBeenCalledWith(
path.join('/tmp/extracted', 'jdk-25'),
'Java_Temurin-Hotspot_jdk+jmods',
'25.0.3-9',
'x64'
);
});
it('fails when signature is missing and verification is enabled', async () => {
const distribution = new TemurinDistribution(
{

View File

@@ -13,7 +13,7 @@ inputs:
description: 'Java distribution. See the list of supported distributions in README file. This input is required except when java-version-file points to .sdkmanrc with a recognized distribution suffix (e.g., java=21.0.5-tem).'
required: false
java-package:
description: 'The package type (jdk, jre, jdk+fx, jre+fx, jdk+crac, jre+crac)'
description: 'The package type (jdk, jre, jdk+fx, jre+fx, jdk+crac, jre+crac, jdk+jmods)'
required: false
default: 'jdk'
architecture:
@@ -30,6 +30,10 @@ inputs:
description: 'Set this option if you want the action to check for the latest available version that satisfies the version spec'
required: false
default: false
force-download:
description: 'Set this option to always download Java and replace any matching version in the tool cache'
required: false
default: false
set-default:
description: 'Set this option to false if you want to install a JDK but not make it the default. When false, JAVA_HOME and PATH are not updated, but JAVA_HOME_<major>_<arch> is still set.'
required: false
@@ -46,16 +50,20 @@ inputs:
file. Default is `github`'
required: false
default: 'github'
server-username:
server-username-env-var:
description: 'Environment variable name for the username for authentication
to the Apache Maven repository. Default is $GITHUB_ACTOR'
required: false
default: 'GITHUB_ACTOR'
server-password:
server-username:
description: 'Deprecated alias for server-username-env-var'
required: false
server-password-env-var:
description: 'Environment variable name for password or token for
authentication to the Apache Maven repository. Default is $GITHUB_TOKEN'
required: false
default: 'GITHUB_TOKEN'
server-password:
description: 'Deprecated alias for server-password-env-var'
required: false
settings-path:
description: 'Path to where the settings.xml file will be written. Default is ~/.m2.'
required: false
@@ -67,8 +75,11 @@ inputs:
description: 'GPG private key to import. Default is empty string.'
required: false
default: ''
gpg-passphrase-env-var:
description: 'Environment variable name for the GPG private key passphrase. Defaults to GPG_PASSPHRASE when gpg-private-key is set.'
required: false
gpg-passphrase:
description: 'Environment variable name for the GPG private key passphrase. Defaults to GPG_PASSPHRASE when gpg-private-key is set; ignored otherwise.'
description: 'Deprecated alias for gpg-passphrase-env-var'
required: false
cache:
description: 'Name of the build platform to cache dependencies. It can be "maven", "gradle" or "sbt".'

8517
dist/cleanup/index.js vendored

File diff suppressed because it is too large Load Diff

8901
dist/setup/index.js vendored

File diff suppressed because it is too large Load Diff

View File

@@ -15,6 +15,7 @@
- [JetBrains](#JetBrains)
- [Tencent Kona](#Tencent-Kona)
- [Installing custom Java package type](#Installing-custom-Java-package-type)
- [Package compatibility](#Package-compatibility)
- [JavaFX Maven project](#JavaFX-Maven-project)
- [Ensuring the Maven cache is complete (plugin dependencies)](#ensuring-the-maven-cache-is-complete-plugin-dependencies)
- [Installing custom Java architecture](#Installing-custom-Java-architecture)
@@ -44,6 +45,7 @@ steps:
with:
distribution: 'temurin'
java-version: '25'
java-package: 'jdk+jmods' # optional, includes JMOD files with JDK 24 and later
- run: java --version
```
@@ -154,6 +156,21 @@ steps:
- run: java --version
```
### Oracle OpenJDK
Oracle OpenJDK builds are created and hosted by Oracle under GPLv2+CE. To install the latest early-access build for a feature release, append `-ea` to the Java version:
```yaml
steps:
- uses: actions/checkout@v7
- uses: actions/setup-java@v6
with:
distribution: 'oracle-openjdk'
java-version: '27-ea'
- run: java --version
```
Using `27` without the `-ea` suffix selects a stable (GA) release. Oracle archives OpenJDK builds after a limited number of releases and no longer provides security updates for them. To continue receiving security patches, move to Oracle JDK or choose a different vendor.
### Alibaba Dragonwell
**NOTE:** Alibaba Dragonwell only provides jdk.
@@ -266,14 +283,59 @@ steps:
```
## Installing custom Java package type
The `java-package` input selects the vendor artifact to install. It defaults to
`jdk`. Package availability is a combination of distribution, Java version,
operating system, and architecture; a package listed below can still be absent
for a particular platform or patch release. Unless a fixed version range is
called out, `setup-java` queries the distribution's catalog and installs the
newest artifact matching `java-version`.
The package types have these meanings:
- `jdk` and `jre` select a development kit or runtime image, respectively.
- `+fx` selects a vendor bundle that includes JavaFX.
- `+crac` selects an Azul Zulu build with CRaC support.
- `+jmods` installs the Temurin JDK and adds its separately published JMOD
archive when the JDK does not already contain a `jmods` directory.
- `+jcef` and `+ft` select JetBrains Runtime bundles with JCEF or FreeType.
### Package compatibility
| Distribution | Supported `java-package` values | Version support and important details |
| --- | --- | --- |
| `temurin` | `jdk`, `jre`, `jdk+jmods` | `jdk` and `jre` follow the Adoptium catalog. `jdk+jmods` is available for Java 24 and later and resolves both artifacts at the exact same Java version. |
| `adopt`, `adopt-hotspot` | `jdk`, `jre` | HotSpot requests check Temurin first, then fall back to the archived AdoptOpenJDK catalog (Java 8 through 16). Migrate to `temurin` for supported releases. |
| `adopt-openj9` | `jdk`, `jre` | Uses the archived AdoptOpenJDK OpenJ9 catalog, which ended at Java 16. Migrate to `semeru`. Some historical JRE/platform combinations were not published. |
| `zulu` | `jdk`, `jre`, `jdk+fx`, `jre+fx`, `jdk+crac`, `jre+crac` | Standard JDK builds go back to Java 6; JRE and JavaFX bundles start at Java 8. The vendor catalog has gaps among older non-LTS releases. CRaC bundles start at Java 17 and have more limited OS and architecture availability. |
| `liberica` | `jdk`, `jre`, `jdk+fx`, `jre+fx` | Standard JDK builds go back to Java 8 in the supported action catalog; JRE and JavaFX "full" bundles also start at Java 8. Exact versions follow BellSoft's catalog for the requested platform. |
| `liberica-nik` | `jdk`, `jdk+fx` | `java-version` selects the embedded JDK version, not the NIK/GraalVM release number. BellSoft currently publishes matching standard and JavaFX "full" bundles for JDK 11 and later, with gaps between feature releases. Other values are not meaningful: they resolve to the standard bundle. |
| `microsoft` | `jdk` | Stable builds only. The bundled manifest contains Java 11, 16, 17, 21, and 25 releases; platform availability varies by release. |
| `semeru` | `jdk`, `jre` | Stable OpenJ9 builds only. IBM publishes both image types for the supported release lines (currently 8, 11, 17, 21, and 25), subject to platform availability. |
| `corretto` | `jdk`, `jre` | Accepts major versions only. JDK availability follows Amazon's platform catalog. For the operating systems directly selected by `setup-java`, JRE downloads are limited to Java 8 on Windows; Linux and macOS use `jdk`. |
| `oracle` | `jdk` | Stable Oracle JDK 17 and later only. |
| `oracle-openjdk` | `jdk` | Installs the GA or early-access JDK builds currently listed or archived on `jdk.java.net`; use a `-ea` version such as `27-ea` for early access. |
| `dragonwell` | `jdk` | Stable builds only. The current vendor catalog provides Java 8, 11, 17, 21, and 25. |
| `sapmachine` | `jdk`, `jre` | Follows the SapMachine catalog. Both editions are represented from Java 10 onward, but individual versions and platforms can differ. |
| `graalvm` | `jdk` | Stable Oracle GraalVM for JDK 17 and later only. |
| `graalvm-community` | `jdk` | Stable GraalVM Community releases for JDK 17 and later only. |
| `jetbrains` | `jdk`, `jre`, `jdk+jcef`, `jre+jcef`, `jdk+ft`, `jre+ft` | JetBrains publishes selected LTS-based releases rather than every OpenJDK patch. JDK/JRE and JCEF bundles start with the Java 11 release family; FreeType bundles start with Java 17. Exact package, LTS family, patch, OS, and architecture availability is determined from release assets. |
| `kona` | `jdk` | Stable Java 8, 11, 17, 21, and 25 releases only. |
| `jdkfile` | `jdk` (recommended) | The package contents and version are supplied by `jdk-file`; `setup-java` does not validate them. `java-package` only separates the local archive's tool-cache entry, so use `jdk` unless separate cache namespaces are required. |
Values outside this table are unsupported even when a distribution forwards the
value to its vendor API instead of rejecting it immediately. In that case, the
action normally fails with a version-not-found error because no matching
artifact exists.
```yaml
steps:
- uses: actions/checkout@v7
- uses: actions/setup-java@v6
with:
distribution: '<distribution>'
java-version: '25'
java-package: jdk # optional (jdk or jre) - defaults to jdk
distribution: 'semeru'
java-version: '21'
java-package: jre
- run: java --version
```
@@ -469,7 +531,7 @@ In this example, `JAVA_HOME` and `java` on `PATH` point to Java 17, while Java 2
If your use-case requires a custom distribution or a version that is not provided by setup-java, you can download it manually and setup-java will take care of the installation and caching on the VM:
> [!NOTE]
> This approach also lets you use builds that setup-java does not provide directly, such as **Early Access (EA)** or other unreleased JDK builds (for example, an upcoming feature release or a Loom/Valhalla preview build). Download the desired archive in a prior step and point `jdk-file` at it; setup-java will extract, install, and cache it just like a supported distribution. When targeting multiple architectures, select the correct binary per architecture in your workflow (for example, with a build matrix).
> This approach also lets you use builds that setup-java does not provide directly, such as unreleased Loom/Valhalla preview builds or early-access builds not exposed by a supported distribution. Download the desired archive in a prior step and point `jdk-file` at it; setup-java will extract, install, and cache it just like a supported distribution. When targeting multiple architectures, select the correct binary per architecture in your workflow (for example, with a build matrix).
```yaml
steps:
@@ -486,23 +548,6 @@ steps:
- run: java --version
```
For example, to use an **Early Access** build from [jdk.java.net](https://jdk.java.net/), download the archive for your runner OS/architecture and install it via `distribution: 'jdkfile'` (example below assumes Linux x64):
```yaml
steps:
- run: |
download_url="https://download.java.net/java/early_access/jdk25/36/GPL/openjdk-25-ea+36_linux-x64_bin.tar.gz"
wget -O $RUNNER_TEMP/java_package.tar.gz $download_url
- uses: actions/setup-java@v6
with:
distribution: 'jdkfile'
jdk-file: ${{ runner.temp }}/java_package.tar.gz
java-version: '25.0.0-ea.36'
architecture: x64
- run: java --version
```
If your use-case requires a custom distribution (in the example, alpine-linux is used) or a version that is not provided by setup-java and you want to always install the latest version during runtime, then you can use the following code to auto-download the latest JDK, determine the semver needed for setup-java, and setup-java will take care of the installation and caching on the VM:
```yaml
@@ -598,8 +643,8 @@ jobs:
distribution: 'temurin'
java-version: '11'
server-id: maven # Value of the distributionManagement/repository/id field of the pom.xml
server-username: MAVEN_USERNAME # env variable for username in deploy
server-password: MAVEN_CENTRAL_TOKEN # env variable for token in deploy
server-username-env-var: MAVEN_USERNAME # env variable for username in deploy
server-password-env-var: MAVEN_CENTRAL_TOKEN # env variable for token in deploy
- name: Publish to Apache Maven Central
run: mvn deploy -Dgpg.signer=bc # requires maven-gpg-plugin >= 3.2.0 (bc signer support)
@@ -660,9 +705,9 @@ See the help docs on [Publishing a Package](https://help.github.com/en/github/ma
#### Legacy / alternative: let setup-java import the key
If you prefer signing with the `gpg` executable (for example because you are using `maven-gpg-plugin` older than 3.2.0), you can let setup-java import the key instead by providing the `gpg-private-key` and `gpg-passphrase` inputs. The private key is written to a file in the runner's temp directory, imported into the GPG keychain, and the file is promptly removed before proceeding with the rest of the setup process. A cleanup step removes the imported private key from the GPG keychain after the job completes regardless of the job status. This ensures that the private key is no longer accessible on self-hosted runners and cannot "leak" between jobs (hosted runners are always clean instances).
If you prefer signing with the `gpg` executable (for example because you are using `maven-gpg-plugin` older than 3.2.0), you can let setup-java import the key instead by providing the `gpg-private-key` and `gpg-passphrase-env-var` inputs. The private key is written to a file in the runner's temp directory, imported into the GPG keychain, and the file is promptly removed before proceeding with the rest of the setup process. A cleanup step removes the imported private key from the GPG keychain after the job completes regardless of the job status. This ensures that the private key is no longer accessible on self-hosted runners and cannot "leak" between jobs (hosted runners are always clean instances).
setup-java imports the key independently of the plugin version, but the generated passphrase profile described below uses `gpg.passphraseEnvName`, which requires `maven-gpg-plugin` 3.2.0 or newer. Since `gpg-passphrase` defaults to `GPG_PASSPHRASE`, setup-java writes that profile unless you override the input to `MAVEN_GPG_PASSPHRASE`.
setup-java imports the key independently of the plugin version, but the generated passphrase profile described below uses `gpg.passphraseEnvName`, which requires `maven-gpg-plugin` 3.2.0 or newer. Since `gpg-passphrase-env-var` defaults to `GPG_PASSPHRASE`, setup-java writes that profile unless you override the input to `MAVEN_GPG_PASSPHRASE`.
```yaml
- name: Set up Apache Maven Central
@@ -671,10 +716,10 @@ setup-java imports the key independently of the plugin version, but the generate
distribution: 'temurin'
java-version: '11'
server-id: maven # Value of the distributionManagement/repository/id field of the pom.xml
server-username: MAVEN_USERNAME # env variable for username in deploy
server-password: MAVEN_CENTRAL_TOKEN # env variable for token in deploy
server-username-env-var: MAVEN_USERNAME # env variable for username in deploy
server-password-env-var: MAVEN_CENTRAL_TOKEN # env variable for token in deploy
gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} # Value of the GPG private key to import
gpg-passphrase: MAVEN_GPG_PASSPHRASE # env variable for GPG private key passphrase
gpg-passphrase-env-var: MAVEN_GPG_PASSPHRASE # env variable for GPG private key passphrase
- name: Publish to Apache Maven Central
run: mvn deploy
@@ -684,10 +729,10 @@ setup-java imports the key independently of the plugin version, but the generate
MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }}
```
The `gpg-passphrase` input is the **name of the environment variable** that holds the passphrase (not the passphrase itself). It defaults to `GPG_PASSPHRASE`. The [Maven GPG Plugin](https://maven.apache.org/plugins/maven-gpg-plugin/) reads the passphrase from the environment variable named by its `gpg.passphraseEnvName` property, whose own default is `MAVEN_GPG_PASSPHRASE`.
The `gpg-passphrase-env-var` input is the **name of the environment variable** that holds the passphrase (not the passphrase itself). It defaults to `GPG_PASSPHRASE`. The [Maven GPG Plugin](https://maven.apache.org/plugins/maven-gpg-plugin/) reads the passphrase from the environment variable named by its `gpg.passphraseEnvName` property, whose own default is `MAVEN_GPG_PASSPHRASE`.
- If `gpg-passphrase` is `MAVEN_GPG_PASSPHRASE`, the plugin already reads that variable by default, so setup-java writes nothing extra to `settings.xml`.
- Otherwise (including the default `GPG_PASSPHRASE`), setup-java configures `gpg.passphraseEnvName` through an active profile in the generated `settings.xml` so the plugin reads the passphrase from that variable. For the default `gpg-passphrase: GPG_PASSPHRASE`:
- If `gpg-passphrase-env-var` is `MAVEN_GPG_PASSPHRASE`, the plugin already reads that variable by default, so setup-java writes nothing extra to `settings.xml`.
- Otherwise (including the default `GPG_PASSPHRASE`), setup-java configures `gpg.passphraseEnvName` through an active profile in the generated `settings.xml` so the plugin reads the passphrase from that variable. For the default `gpg-passphrase-env-var: GPG_PASSPHRASE`:
```xml
<profiles>
@@ -703,7 +748,7 @@ The `gpg-passphrase` input is the **name of the environment variable** that hold
</activeProfiles>
```
> **Note:** Earlier versions of setup-java wrote a `gpg.passphrase` server to `settings.xml`. That mechanism is deprecated by the Maven GPG Plugin and fails when its `bestPractices` mode is enabled, so setup-java now relies on `gpg.passphraseEnvName` instead. The `gpg-passphrase` input and its `GPG_PASSPHRASE` default are unchanged, so existing workflows that set the `GPG_PASSPHRASE` environment variable keep working.
> **Note:** Earlier versions of setup-java wrote a `gpg.passphrase` server to `settings.xml`. That mechanism is deprecated by the Maven GPG Plugin and fails when its `bestPractices` mode is enabled, so setup-java now relies on `gpg.passphraseEnvName` instead. Set the environment variable name with `gpg-passphrase-env-var`, which defaults to `GPG_PASSPHRASE`.
> **Compatibility note:** Reading the passphrase from an environment variable (`gpg.passphraseEnvName`) requires `maven-gpg-plugin` 3.2.0 or newer. Older versions do not honor this property and will not pick up the passphrase, because setup-java no longer writes the deprecated `gpg.passphrase` server to `settings.xml`. If you are pinned to `maven-gpg-plugin` older than 3.2.0, upgrade to 3.2.0+.

1859
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -57,8 +57,8 @@
"@jest/globals": "^30.4.1",
"@types/node": "^26.1.1",
"@types/semver": "^7.7.0",
"@typescript-eslint/eslint-plugin": "^8.62.0",
"@typescript-eslint/parser": "^8.62.0",
"@typescript-eslint/eslint-plugin": "^8.64.0",
"@typescript-eslint/parser": "^8.65.0",
"@vercel/ncc": "^0.44.0",
"eslint": "^10.7.0",
"eslint-config-prettier": "^10.1.8",
@@ -67,7 +67,7 @@
"globals": "^17.7.0",
"husky": "^9.1.7",
"jest": "^30.4.2",
"lint-staged": "^17.0.8",
"lint-staged": "^17.2.0",
"prettier": "^3.9.5",
"ts-jest": "^29.4.11",
"typescript": "^6.0.3"
@@ -75,5 +75,12 @@
"bugs": {
"url": "https://github.com/actions/setup-java/issues"
},
"homepage": "https://github.com/actions/setup-java#readme"
"homepage": "https://github.com/actions/setup-java#readme",
"overrides": {
"@actions/cache": {
"@actions/glob": "0.7.0"
},
"glob": "^11.1.0",
"test-exclude": "^7.0.2"
}
}

View File

@@ -12,8 +12,16 @@ import {getBooleanInput} from './util.js';
export async function configureAuthentication() {
const id = core.getInput(constants.INPUT_SERVER_ID);
const username = core.getInput(constants.INPUT_SERVER_USERNAME);
const password = core.getInput(constants.INPUT_SERVER_PASSWORD);
const usernameEnvVar = getInputWithDeprecatedAlias(
constants.INPUT_SERVER_USERNAME_ENV_VAR,
constants.INPUT_SERVER_USERNAME_DEPRECATED,
constants.INPUT_DEFAULT_SERVER_USERNAME
);
const passwordEnvVar = getInputWithDeprecatedAlias(
constants.INPUT_SERVER_PASSWORD_ENV_VAR,
constants.INPUT_SERVER_PASSWORD_DEPRECATED,
constants.INPUT_DEFAULT_SERVER_PASSWORD
);
const settingsDirectory =
core.getInput(constants.INPUT_SETTINGS_PATH) ||
path.join(os.homedir(), constants.M2_DIR);
@@ -24,9 +32,11 @@ export async function configureAuthentication() {
const gpgPrivateKey =
core.getInput(constants.INPUT_GPG_PRIVATE_KEY) ||
constants.INPUT_DEFAULT_GPG_PRIVATE_KEY;
const gpgPassphrase =
core.getInput(constants.INPUT_GPG_PASSPHRASE) ||
(gpgPrivateKey ? constants.INPUT_DEFAULT_GPG_PASSPHRASE : undefined);
const gpgPassphraseEnvVar = getInputWithDeprecatedAlias(
constants.INPUT_GPG_PASSPHRASE_ENV_VAR,
constants.INPUT_GPG_PASSPHRASE_DEPRECATED,
gpgPrivateKey ? constants.INPUT_DEFAULT_GPG_PASSPHRASE : undefined
);
if (gpgPrivateKey) {
core.setSecret(gpgPrivateKey);
@@ -34,11 +44,11 @@ export async function configureAuthentication() {
await createAuthenticationSettings(
id,
username,
password,
usernameEnvVar,
passwordEnvVar,
settingsDirectory,
overwriteSettings,
gpgPassphrase
gpgPassphraseEnvVar
);
if (gpgPrivateKey) {
@@ -48,13 +58,30 @@ export async function configureAuthentication() {
}
}
export function getInputWithDeprecatedAlias(
inputName: string,
deprecatedInputName: string,
defaultValue?: string
): string {
const value = core.getInput(inputName);
const deprecatedValue = core.getInput(deprecatedInputName);
if (deprecatedValue) {
core.warning(
`The '${deprecatedInputName}' input is deprecated and may be removed in a future release. Please use '${inputName}' instead.`
);
}
return value || deprecatedValue || defaultValue || '';
}
export async function createAuthenticationSettings(
id: string,
username: string,
password: string,
usernameEnvVar: string,
passwordEnvVar: string,
settingsDirectory: string,
overwriteSettings: boolean,
gpgPassphrase: string | undefined = undefined
gpgPassphraseEnvVar: string | undefined = undefined
) {
core.info(`Creating ${constants.MVN_SETTINGS_FILE} with server-id: ${id}`);
// when an alternate m2 location is specified use only that location (no .m2 directory)
@@ -62,7 +89,7 @@ export async function createAuthenticationSettings(
await io.mkdirP(settingsDirectory);
await write(
settingsDirectory,
generate(id, username, password, gpgPassphrase),
generate(id, usernameEnvVar, passwordEnvVar, gpgPassphraseEnvVar),
overwriteSettings
);
}
@@ -70,9 +97,9 @@ export async function createAuthenticationSettings(
// only exported for testing purposes
export function generate(
id: string,
username: string,
password: string,
gpgPassphrase?: string | undefined
usernameEnvVar: string,
passwordEnvVar: string,
gpgPassphraseEnvVar?: string | undefined
) {
const xmlObj: {[key: string]: any} = {
settings: {
@@ -85,8 +112,8 @@ export function generate(
server: [
{
id: id,
username: `\${env.${username}}`,
password: `\${env.${password}}`
username: `\${env.${usernameEnvVar}}`,
password: `\${env.${passwordEnvVar}}`
}
]
}
@@ -100,14 +127,14 @@ export function generate(
// are needed. Writing `gpg.passphrase` to settings.xml is deprecated and fails
// when the plugin's `bestPractices` mode is enabled.
if (
gpgPassphrase &&
gpgPassphrase !== constants.MAVEN_GPG_PASSPHRASE_DEFAULT_ENV
gpgPassphraseEnvVar &&
gpgPassphraseEnvVar !== constants.MAVEN_GPG_PASSPHRASE_DEFAULT_ENV
) {
xmlObj.settings.profiles = {
profile: {
id: constants.GPG_PASSPHRASE_PROFILE_ID,
properties: {
'gpg.passphraseEnvName': gpgPassphrase
'gpg.passphraseEnvName': gpgPassphraseEnvVar
}
}
};

View File

@@ -319,8 +319,20 @@ async function saveAdditionalCache(
);
return;
}
const globber = await glob.create(additionalCache.path.join('\n'), {
implicitDescendants: false
});
const cachePaths = await globber.glob();
if (cachePaths.length === 0) {
core.debug(
`${additionalCache.name} cache paths do not exist, not saving cache.`
);
return;
}
try {
const cacheId = await cache.saveCache(additionalCache.path, primaryKey);
const cacheId = await cache.saveCache(cachePaths, primaryKey);
if (cacheId === -1) {
core.debug(
`${additionalCache.name} cache was not saved for the key: ${primaryKey}`

View File

@@ -7,18 +7,24 @@ export const INPUT_DISTRIBUTION = 'distribution';
export const INPUT_JDK_FILE = 'jdk-file';
export const INPUT_JDK_FILE_DEPRECATED = 'jdkFile';
export const INPUT_CHECK_LATEST = 'check-latest';
export const INPUT_FORCE_DOWNLOAD = 'force-download';
export const INPUT_SET_DEFAULT = 'set-default';
export const INPUT_PROBLEM_MATCHER = 'problem-matcher';
export const INPUT_VERIFY_SIGNATURE = 'verify-signature';
export const INPUT_VERIFY_SIGNATURE_PUBLIC_KEY = 'verify-signature-public-key';
export const INPUT_SERVER_ID = 'server-id';
export const INPUT_SERVER_USERNAME = 'server-username';
export const INPUT_SERVER_PASSWORD = 'server-password';
export const INPUT_SERVER_USERNAME_ENV_VAR = 'server-username-env-var';
export const INPUT_SERVER_PASSWORD_ENV_VAR = 'server-password-env-var';
export const INPUT_SERVER_USERNAME_DEPRECATED = 'server-username';
export const INPUT_SERVER_PASSWORD_DEPRECATED = 'server-password';
export const INPUT_SETTINGS_PATH = 'settings-path';
export const INPUT_OVERWRITE_SETTINGS = 'overwrite-settings';
export const INPUT_GPG_PRIVATE_KEY = 'gpg-private-key';
export const INPUT_GPG_PASSPHRASE = 'gpg-passphrase';
export const INPUT_GPG_PASSPHRASE_ENV_VAR = 'gpg-passphrase-env-var';
export const INPUT_GPG_PASSPHRASE_DEPRECATED = 'gpg-passphrase';
export const INPUT_DEFAULT_SERVER_USERNAME = 'GITHUB_ACTOR';
export const INPUT_DEFAULT_SERVER_PASSWORD = 'GITHUB_TOKEN';
export const INPUT_DEFAULT_GPG_PRIVATE_KEY = undefined;
export const INPUT_DEFAULT_GPG_PASSPHRASE = 'GPG_PASSPHRASE';

View File

@@ -25,6 +25,7 @@ export abstract class JavaBase {
protected stable: boolean;
protected latest: boolean;
protected checkLatest: boolean;
protected forceDownload: boolean;
protected setDefault: boolean;
protected verifySignature: boolean;
protected verifySignaturePublicKey: string | undefined;
@@ -46,6 +47,7 @@ export abstract class JavaBase {
this.architecture = installerOptions.architecture || os.arch();
this.packageType = installerOptions.packageType;
this.checkLatest = installerOptions.checkLatest;
this.forceDownload = installerOptions.forceDownload ?? false;
this.setDefault =
installerOptions.setDefault !== undefined
? installerOptions.setDefault
@@ -68,7 +70,7 @@ export abstract class JavaBase {
);
}
let foundJava = this.findInToolcache();
let foundJava = this.forceDownload ? null : this.findInToolcache();
if (foundJava && !this.checkLatest && !this.latest) {
core.info(`Resolved Java ${foundJava.version} from tool-cache`);
} else {
@@ -91,7 +93,10 @@ export abstract class JavaBase {
}
const javaRelease = await this.findPackageForDownload(this.version);
core.info(`Resolved latest version as ${javaRelease.version}`);
if (foundJava?.version === javaRelease.version) {
if (
!this.forceDownload &&
foundJava?.version === javaRelease.version
) {
core.info(`Resolved Java ${foundJava.version} from tool-cache`);
} else {
core.info('Trying to download...');

View File

@@ -3,6 +3,7 @@ export interface JavaInstallerOptions {
architecture: string;
packageType: string;
checkLatest: boolean;
forceDownload?: boolean;
setDefault?: boolean;
verifySignature?: boolean;
verifySignaturePublicKey?: string;

View File

@@ -21,6 +21,7 @@ import {
} from './graalvm/installer.js';
import {JetBrainsDistribution} from './jetbrains/installer.js';
import {KonaDistribution} from './kona/installer.js';
import {OpenJdkDistribution} from './openjdk/installer.js';
enum JavaDistribution {
Adopt = 'adopt',
@@ -40,7 +41,8 @@ enum JavaDistribution {
GraalVM = 'graalvm',
GraalVMCommunity = 'graalvm-community',
JetBrains = 'jetbrains',
Kona = 'kona'
Kona = 'kona',
OracleOpenJdk = 'oracle-openjdk'
}
export function getJavaDistribution(
@@ -48,6 +50,15 @@ export function getJavaDistribution(
installerOptions: JavaInstallerOptions,
jdkFile?: string
): JavaBase | null {
if (
installerOptions.packageType === 'jdk+jmods' &&
distributionName !== JavaDistribution.Temurin
) {
throw new Error(
"java-package 'jdk+jmods' is only supported for distribution 'temurin'."
);
}
switch (distributionName) {
case JavaDistribution.JdkFile:
return new LocalDistribution(installerOptions, jdkFile);
@@ -93,6 +104,8 @@ export function getJavaDistribution(
return new JetBrainsDistribution(installerOptions);
case JavaDistribution.Kona:
return new KonaDistribution(installerOptions);
case JavaDistribution.OracleOpenJdk:
return new OpenJdkDistribution(installerOptions);
default:
return null;
}

View File

@@ -110,6 +110,11 @@ export class GraalVMDistribution extends JavaBase {
}
}
protected setJavaDefault(version: string, toolPath: string): void {
super.setJavaDefault(version, toolPath);
core.exportVariable('GRAALVM_HOME', toolPath);
}
protected async findPackageForDownload(
range: string
): Promise<JavaDownloadRelease> {

View File

@@ -28,7 +28,7 @@ export class LocalDistribution extends JavaBase {
);
}
let foundJava = this.findInToolcache();
let foundJava = this.forceDownload ? null : this.findInToolcache();
if (foundJava) {
core.info(`Resolved Java ${foundJava.version} from tool-cache`);

View File

@@ -0,0 +1,181 @@
import * as core from '@actions/core';
import * as tc from '@actions/tool-cache';
import fs from 'fs';
import path from 'path';
import semver from 'semver';
import {JavaBase} from '../base-installer.js';
import {
JavaDownloadRelease,
JavaInstallerOptions,
JavaInstallerResults
} from '../base-models.js';
import {
convertVersionToSemver,
extractJdkFile,
isVersionSatisfies,
renameWinArchive
} from '../../util.js';
const OPENJDK_BASE_URL = 'https://jdk.java.net';
export class OpenJdkDistribution extends JavaBase {
constructor(installerOptions: JavaInstallerOptions) {
super('Oracle OpenJDK', installerOptions);
}
protected async findPackageForDownload(
range: string
): Promise<JavaDownloadRelease> {
if (this.packageType !== 'jdk') {
throw new Error('Oracle OpenJDK provides only the `jdk` package type');
}
const arch = this.distributionArchitecture();
if (!['x64', 'aarch64'].includes(arch)) {
throw new Error(`Unsupported architecture: ${this.architecture}`);
}
const platform = this.getPlatform();
const releases = await this.getAvailableVersions(platform, arch);
const matchingReleases = releases
.filter(release => isVersionSatisfies(range, release.version))
.sort((left, right) => -semver.compareBuild(left.version, right.version));
if (!matchingReleases.length) {
throw this.createVersionNotFoundError(
range,
releases.map(release => release.version),
`Platform: ${platform}`
);
}
return matchingReleases[0];
}
protected async downloadTool(
javaRelease: JavaDownloadRelease
): Promise<JavaInstallerResults> {
core.info(
`Downloading Java ${javaRelease.version} (${this.distribution}) from ${javaRelease.url} ...`
);
let javaArchivePath = await tc.downloadTool(javaRelease.url);
core.info(`Extracting Java archive...`);
const extension = javaRelease.url.endsWith('.zip') ? 'zip' : 'tar.gz';
if (extension === 'zip') {
javaArchivePath = renameWinArchive(javaArchivePath);
}
const extractedJavaPath = await extractJdkFile(javaArchivePath, extension);
const archiveName = fs.readdirSync(extractedJavaPath)[0];
const archivePath = path.join(extractedJavaPath, archiveName);
const javaPath = await tc.cacheDir(
archivePath,
this.toolcacheFolderName,
this.getToolcacheVersionName(javaRelease.version),
this.architecture
);
return {version: javaRelease.version, path: javaPath};
}
private async getAvailableVersions(
platform: string,
arch: string
): Promise<JavaDownloadRelease[]> {
const homePage = await this.fetchPage(`${OPENJDK_BASE_URL}/`);
const releasePageUrls = Array.from(
homePage.matchAll(/href="\/(\d+)\/">JDK\s+\d+/g),
match => `${OPENJDK_BASE_URL}/${match[1]}/`
);
const pages = await Promise.all(
releasePageUrls.map(url => this.fetchPage(url))
);
if (this.stable) {
pages.push(await this.fetchPage(`${OPENJDK_BASE_URL}/archive/`));
}
const releases = pages.flatMap(page =>
this.parseReleases(page, platform, arch)
);
return releases.filter(
release => release.url.includes('/early_access/') !== this.stable
);
}
private async fetchPage(url: string): Promise<string> {
const response = await this.http.get(url);
return response.readBody();
}
private parseReleases(
html: string,
platform: string,
arch: string
): JavaDownloadRelease[] {
const platformPattern = platform === 'macos' ? '(?:macos|osx)' : platform;
const extensionPattern =
platform === 'windows' ? '(?:zip|tar\\.gz)' : 'tar\\.gz';
const pattern = new RegExp(
`href="(https://download\\.java\\.net/[^"]+/openjdk-([^"_]+)_${platformPattern}-${arch}_bin\\.${extensionPattern})"`,
'g'
);
return Array.from(html.matchAll(pattern), match => {
const url = match[1];
const build =
url.match(/\/(\d+)\/(?:GPL\/)?openjdk-/)?.[1] ??
this.findBuildInArchiveHeading(html, match.index, match[2]);
return {
version: this.toSemver(match[2], build),
url
};
});
}
private findBuildInArchiveHeading(
html: string,
assetIndex: number,
version: string
): string | undefined {
const headings = Array.from(
html.slice(0, assetIndex).matchAll(/\(build\s+([^)]+)\)/g)
);
const headingVersion = headings.at(-1)?.[1];
if (!headingVersion) {
return undefined;
}
const [javaVersion, build] = headingVersion.split('+');
return javaVersion === version ? build : undefined;
}
private toSemver(version: string, urlBuild?: string): string {
const [javaVersion, filenameBuild] = version.replace('-ea', '').split('+');
const versionParts = javaVersion.split('.');
const normalizedVersion = convertVersionToSemver(
versionParts.length === 1 ? `${javaVersion}.0.0` : javaVersion
);
const build =
filenameBuild ?? (versionParts.length <= 3 ? urlBuild : undefined);
return build ? `${normalizedVersion}+${build}` : normalizedVersion;
}
private getPlatform(platform: NodeJS.Platform = process.platform): string {
switch (platform) {
case 'darwin':
return 'macos';
case 'linux':
return 'linux';
case 'win32':
return 'windows';
default:
throw new Error(
`Platform '${platform}' is not supported. Supported platforms: 'linux', 'macos', 'windows'`
);
}
}
}

View File

@@ -9,6 +9,7 @@ import * as gpg from '../../gpg.js';
import {ADOPTIUM_PUBLIC_KEY} from './adoptium-key.js';
import {JavaBase} from '../base-installer.js';
import {ITemurinAvailableVersions} from './models.js';
import {MACOS_JAVA_CONTENT_POSTFIX} from '../../constants.js';
import {
JavaDownloadRelease,
JavaInstallerOptions,
@@ -31,11 +32,14 @@ export enum TemurinImplementation {
}
export class TemurinDistribution extends JavaBase {
private readonly includeJmods: boolean;
constructor(
installerOptions: JavaInstallerOptions,
private readonly jvmImpl: TemurinImplementation
) {
super(`Temurin-${jvmImpl}`, installerOptions);
this.includeJmods = this.packageType === 'jdk+jmods';
}
/**
@@ -44,7 +48,17 @@ export class TemurinDistribution extends JavaBase {
public async findPackageForDownload(
version: string
): Promise<JavaDownloadRelease> {
const availableVersionsRaw = await this.getAvailableVersions();
return this.resolvePackage(
version,
this.includeJmods ? 'jdk' : this.packageType
);
}
private async resolvePackage(
version: string,
imageType: string
): Promise<JavaDownloadRelease> {
const availableVersionsRaw = await this.getAvailableVersions(imageType);
const availableVersionsWithBinaries = availableVersionsRaw
.filter(item => item.binaries.length > 0)
.map(item => {
@@ -83,30 +97,7 @@ export class TemurinDistribution extends JavaBase {
core.info(
`Downloading Java ${javaRelease.version} (${this.distribution}) from ${javaRelease.url} ...`
);
let javaArchivePath = await tc.downloadTool(javaRelease.url);
if (this.verifySignature) {
if (!javaRelease.signatureUrl) {
throw new Error(
`Input 'verify-signature' is enabled, but no signature URL was found for Temurin version ${javaRelease.version}.`
);
}
core.info(`Verifying Java package signature...`);
try {
await gpg.verifyPackageSignature(
javaArchivePath,
javaRelease.signatureUrl,
this.verifySignaturePublicKey ?? ADOPTIUM_PUBLIC_KEY
);
} catch (error) {
throw new Error(
`Failed to verify signature for Temurin version ${javaRelease.version} from ${javaRelease.signatureUrl}: ${
(error as Error).message
}`,
{cause: error}
);
}
}
let javaArchivePath = await this.downloadPackage(javaRelease);
core.info(`Extracting Java archive...`);
const extension = getDownloadArchiveExtension();
@@ -117,6 +108,13 @@ export class TemurinDistribution extends JavaBase {
const archiveName = fs.readdirSync(extractedJavaPath)[0];
const archivePath = path.join(extractedJavaPath, archiveName);
const javaHome =
process.platform === 'darwin'
? path.join(archivePath, MACOS_JAVA_CONTENT_POSTFIX)
: archivePath;
if (this.includeJmods && !fs.existsSync(path.join(javaHome, 'jmods'))) {
await this.installJmods(javaRelease.version, javaHome);
}
const version = this.getToolcacheVersionName(javaRelease.version);
const javaPath = await tc.cacheDir(
@@ -129,18 +127,64 @@ export class TemurinDistribution extends JavaBase {
return {version: javaRelease.version, path: javaPath};
}
protected get toolcacheFolderName(): string {
return super.toolcacheFolderName;
}
protected supportsSignatureVerification(): boolean {
return true;
}
private async getAvailableVersions(): Promise<ITemurinAvailableVersions[]> {
private async downloadPackage(release: JavaDownloadRelease): Promise<string> {
const archivePath = await tc.downloadTool(release.url);
if (this.verifySignature) {
if (!release.signatureUrl) {
throw new Error(
`Input 'verify-signature' is enabled, but no signature URL was found for Temurin version ${release.version}.`
);
}
core.info(`Verifying Java package signature...`);
try {
await gpg.verifyPackageSignature(
archivePath,
release.signatureUrl,
this.verifySignaturePublicKey ?? ADOPTIUM_PUBLIC_KEY
);
} catch (error) {
throw new Error(
`Failed to verify signature for Temurin version ${release.version} from ${release.signatureUrl}: ${
(error as Error).message
}`,
{cause: error}
);
}
}
return archivePath;
}
private async installJmods(version: string, javaHome: string): Promise<void> {
const jmodsRelease = await this.resolvePackage(version, 'jmods');
core.info(
`Downloading JMODs ${jmodsRelease.version} (${this.distribution}) from ${jmodsRelease.url} ...`
);
let jmodsArchivePath = await this.downloadPackage(jmodsRelease);
if (process.platform === 'win32') {
jmodsArchivePath = renameWinArchive(jmodsArchivePath);
}
const extractedJmodsPath = await extractJdkFile(
jmodsArchivePath,
getDownloadArchiveExtension()
);
const jmodsDirectory = path.join(
extractedJmodsPath,
fs.readdirSync(extractedJmodsPath)[0]
);
fs.cpSync(jmodsDirectory, path.join(javaHome, 'jmods'), {recursive: true});
}
private async getAvailableVersions(
imageType = this.includeJmods ? 'jdk' : this.packageType
): Promise<ITemurinAvailableVersions[]> {
const platform = this.getPlatformOption();
const arch = this.distributionArchitecture();
const imageType = this.packageType;
const versionRange = encodeURI('[1.0,100.0]'); // retrieve all available versions
const releaseType = this.stable ? 'ga' : 'ea';

View File

@@ -29,6 +29,10 @@ async function run() {
constants.INPUT_CACHE_DEPENDENCY_PATH
);
const checkLatest = getBooleanInput(constants.INPUT_CHECK_LATEST, false);
const forceDownload = getBooleanInput(
constants.INPUT_FORCE_DOWNLOAD,
false
);
const setDefault = getBooleanInput(constants.INPUT_SET_DEFAULT, true);
const verifySignature = getBooleanInput(
constants.INPUT_VERIFY_SIGNATURE,
@@ -83,6 +87,7 @@ async function run() {
architecture,
packageType,
checkLatest,
forceDownload,
setDefault,
verifySignature,
verifySignaturePublicKey,
@@ -102,6 +107,7 @@ async function run() {
architecture,
packageType,
checkLatest,
forceDownload,
setDefault,
verifySignature,
verifySignaturePublicKey,
@@ -159,6 +165,7 @@ async function installVersion(
architecture,
packageType,
checkLatest,
forceDownload,
setDefault,
verifySignature,
verifySignaturePublicKey,
@@ -169,6 +176,7 @@ async function installVersion(
architecture,
packageType,
checkLatest,
forceDownload,
setDefault,
verifySignature,
verifySignaturePublicKey,
@@ -212,6 +220,7 @@ interface installerInputsOptions {
architecture: string;
packageType: string;
checkLatest: boolean;
forceDownload: boolean;
setDefault: boolean;
verifySignature: boolean;
verifySignaturePublicKey: string | undefined;