mirror of
https://github.com/actions/setup-java.git
synced 2026-06-22 15:59:41 +00:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 85aca0f605 | |||
| 5866e121b4 | |||
| 2872526dc6 | |||
| bb8b13a4a5 | |||
| 957ad8b43e | |||
| ce7f9ce621 | |||
| 6c68e0ac74 | |||
| 6e9017e125 | |||
| baa1691374 | |||
| bc52a13212 | |||
| c9b6aee07e | |||
| f300429fba | |||
| ad2b38190b | |||
| b24df5bba5 | |||
| 43120bc3c3 | |||
| ad9d6a6320 | |||
| 039af37997 | |||
| 1756ab6acd | |||
| 662bb59f48 | |||
| 1071fc12d6 | |||
| 576b821f29 | |||
| 307d3a25a0 | |||
| b622de1dfa | |||
| c76542e033 | |||
| 0756542bc5 |
@@ -10,5 +10,9 @@ on:
|
||||
|
||||
jobs:
|
||||
call-codeQL-analysis:
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
name: CodeQL analysis
|
||||
uses: actions/reusable-workflows/.github/workflows/codeql-analysis.yml@main
|
||||
|
||||
@@ -86,6 +86,32 @@ jobs:
|
||||
run: bash __tests__/verify-java.sh "${{ matrix.version }}" "${{ steps.setup-java.outputs.path }}"
|
||||
shell: bash
|
||||
|
||||
setup-java-alpine-linux:
|
||||
name: ${{ matrix.distribution }} ${{ matrix.version }} (jdk-x64) - alpine-linux - ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
container:
|
||||
image: alpine:latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
distribution: ['temurin', 'sapmachine']
|
||||
version: ['21', '17']
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
- name: Install bash
|
||||
run: apk add --no-cache bash
|
||||
- name: setup-java
|
||||
uses: ./
|
||||
id: setup-java
|
||||
with:
|
||||
java-version: ${{ matrix.version }}
|
||||
distribution: ${{ matrix.distribution }}
|
||||
- name: Verify Java
|
||||
run: bash __tests__/verify-java.sh "${{ matrix.version }}" "${{ steps.setup-java.outputs.path }}"
|
||||
shell: bash
|
||||
|
||||
setup-java-major-minor-versions:
|
||||
name: ${{ matrix.distribution }} ${{ matrix.version }} (jdk-x64) - ${{ matrix.os }}
|
||||
needs: setup-java-major-versions
|
||||
|
||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: "@actions/cache"
|
||||
version: 5.0.5
|
||||
version: 5.1.0
|
||||
type: npm
|
||||
summary: Actions cache lib
|
||||
homepage: https://github.com/actions/toolkit/tree/main/packages/cache
|
||||
|
||||
Generated
+11
@@ -0,0 +1,11 @@
|
||||
---
|
||||
name: "@nodable/entities"
|
||||
version: 2.2.0
|
||||
type: npm
|
||||
summary: Entity parser for XML, HTML, External entites with security and NCR control
|
||||
homepage:
|
||||
license: mit
|
||||
licenses:
|
||||
- sources: README.md
|
||||
text: MIT
|
||||
notices: []
|
||||
Generated
+33
@@ -0,0 +1,33 @@
|
||||
---
|
||||
name: anynum
|
||||
version: 1.0.0
|
||||
type: npm
|
||||
summary: Normalize all Unicode decimal digits (Devanagari, Arabic, Thai, etc.) to
|
||||
ASCII numerals. Zero dependencies, performance-first.
|
||||
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.
|
||||
notices: []
|
||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: debug
|
||||
version: 4.3.4
|
||||
version: 4.4.3
|
||||
type: npm
|
||||
summary: Lightweight debugging utility for Node.js and the browser
|
||||
homepage:
|
||||
|
||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: fast-xml-builder
|
||||
version: 1.1.4
|
||||
version: 1.2.0
|
||||
type: npm
|
||||
summary: Build XML from JSON without C/C++ based libraries
|
||||
homepage:
|
||||
|
||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: fast-xml-parser
|
||||
version: 5.5.10
|
||||
version: 5.8.0
|
||||
type: npm
|
||||
summary: Validate XML, Parse XML, Build XML without C/C++ based libraries
|
||||
homepage:
|
||||
|
||||
Generated
+2
-2
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: ms
|
||||
version: 2.1.2
|
||||
version: 2.1.3
|
||||
type: npm
|
||||
summary: Tiny millisecond conversion utility
|
||||
homepage:
|
||||
@@ -10,7 +10,7 @@ licenses:
|
||||
text: |
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Zeit, Inc.
|
||||
Copyright (c) 2020 Vercel, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: path-expression-matcher
|
||||
version: 1.4.0
|
||||
version: 1.5.0
|
||||
type: npm
|
||||
summary: Efficient path tracking and pattern matching for XML/JSON parsers
|
||||
homepage: https://github.com/NaturalIntelligence/path-expression-matcher#readme
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: semver
|
||||
version: 7.7.1
|
||||
version: 7.8.4
|
||||
type: npm
|
||||
summary: The semantic version parser used by npm.
|
||||
homepage:
|
||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: strnum
|
||||
version: 2.2.3
|
||||
version: 2.4.0
|
||||
type: npm
|
||||
summary: Parse String to Number based on configuration
|
||||
homepage:
|
||||
|
||||
Generated
+12
@@ -0,0 +1,12 @@
|
||||
---
|
||||
name: xml-naming
|
||||
version: 0.1.0
|
||||
type: npm
|
||||
summary: Validates XML name productions — Name, NCName, QName, NMToken, NMTokens —
|
||||
for XML 1.0 and 1.1
|
||||
homepage:
|
||||
license: mit
|
||||
licenses:
|
||||
- sources: README.md
|
||||
text: MIT
|
||||
notices: []
|
||||
@@ -105,21 +105,21 @@ The `java-version` input supports an exact version or a version range using [Sem
|
||||
|
||||
#### Supported distributions
|
||||
Currently, the following distributions are supported:
|
||||
| Keyword | Distribution | Official site | License
|
||||
|-|-|-|-|
|
||||
| `temurin` | Eclipse Temurin | [Link](https://adoptium.net/) | [Link](https://adoptium.net/about.html)
|
||||
| `zulu` | Azul Zulu OpenJDK | [Link](https://www.azul.com/downloads/zulu-community/?package=jdk) | [Link](https://www.azul.com/products/zulu-and-zulu-enterprise/zulu-terms-of-use/) |
|
||||
| `adopt` or `adopt-hotspot` | AdoptOpenJDK Hotspot | [Link](https://adoptopenjdk.net/) | [Link](https://adoptopenjdk.net/about.html) |
|
||||
| `adopt-openj9` | AdoptOpenJDK OpenJ9 | [Link](https://adoptopenjdk.net/) | [Link](https://adoptopenjdk.net/about.html) |
|
||||
| `liberica` | Liberica JDK | [Link](https://bell-sw.com/) | [Link](https://bell-sw.com/liberica_eula/) |
|
||||
| `microsoft` | Microsoft Build of OpenJDK | [Link](https://www.microsoft.com/openjdk) | [Link](https://docs.microsoft.com/java/openjdk/faq)
|
||||
| `corretto` | Amazon Corretto Build of OpenJDK | [Link](https://aws.amazon.com/corretto/) | [Link](https://aws.amazon.com/corretto/faqs/)
|
||||
| `semeru` | IBM Semeru Runtime Open Edition | [Link](https://developer.ibm.com/languages/java/semeru-runtimes/downloads/) | [Link](https://openjdk.java.net/legal/gplv2+ce.html) |
|
||||
| `oracle` | Oracle JDK | [Link](https://www.oracle.com/java/technologies/downloads/) | [Link](https://java.com/freeuselicense)
|
||||
| `dragonwell` | Alibaba Dragonwell JDK | [Link](https://dragonwell-jdk.io/) | [Link](https://www.aliyun.com/product/dragonwell/)
|
||||
| `sapmachine` | SAP SapMachine JDK/JRE | [Link](https://sapmachine.io/) | [Link](https://github.com/SAP/SapMachine/blob/sapmachine/LICENSE)
|
||||
| `graalvm` | Oracle GraalVM | [Link](https://www.graalvm.org/) | [Link](https://www.oracle.com/downloads/licenses/graal-free-license.html)
|
||||
| `jetbrains` | JetBrains Runtime | [Link](https://github.com/JetBrains/JetBrainsRuntime/) | [Link](https://github.com/JetBrains/JetBrainsRuntime/blob/main/LICENSE)
|
||||
| Keyword | Distribution / Official site | License
|
||||
|-|-|-|
|
||||
| `temurin` | [Eclipse Temurin](https://adoptium.net/) | [`temurin` license](https://adoptium.net/about.html)
|
||||
| `zulu` | [Azul Zulu OpenJDK](https://www.azul.com/downloads/zulu-community/?package=jdk) | [`zulu` license](https://www.azul.com/products/zulu-and-zulu-enterprise/zulu-terms-of-use/) |
|
||||
| `adopt` or `adopt-hotspot` | [AdoptOpenJDK Hotspot](https://adoptopenjdk.net/) | [`adopt-hotspot` license](https://adoptopenjdk.net/about.html) |
|
||||
| `adopt-openj9` | [AdoptOpenJDK OpenJ9](https://adoptopenjdk.net/) | [`adopt-openj9` license](https://adoptopenjdk.net/about.html) |
|
||||
| `liberica` | [Liberica JDK](https://bell-sw.com/) | [`liberica` license](https://bell-sw.com/liberica_eula/) |
|
||||
| `microsoft` | [Microsoft Build of OpenJDK](https://www.microsoft.com/openjdk) | [`microsoft` license](https://docs.microsoft.com/java/openjdk/faq)
|
||||
| `corretto` | [Amazon Corretto Build of OpenJDK](https://aws.amazon.com/corretto/) | [`corretto` license](https://aws.amazon.com/corretto/faqs/)
|
||||
| `semeru` | [IBM Semeru Runtime Open Edition](https://developer.ibm.com/languages/java/semeru-runtimes/downloads/) | [`semeru` license](https://openjdk.java.net/legal/gplv2+ce.html) |
|
||||
| `oracle` | [Oracle JDK](https://www.oracle.com/java/technologies/downloads/) | [`oracle` license](https://java.com/freeuselicense)
|
||||
| `dragonwell` | [Alibaba Dragonwell JDK](https://dragonwell-jdk.io/) | [`dragonwell` license](https://www.aliyun.com/product/dragonwell/)
|
||||
| `sapmachine` | [SAP SapMachine JDK/JRE](https://sapmachine.io/) | [`sapmachine` license](https://github.com/SAP/SapMachine/blob/sapmachine/LICENSE)
|
||||
| `graalvm` | [Oracle GraalVM](https://www.graalvm.org/) | [`graalvm` license](https://www.oracle.com/downloads/licenses/graal-free-license.html)
|
||||
| `jetbrains` | [JetBrains Runtime](https://github.com/JetBrains/JetBrainsRuntime/) | [`jetbrains` license](https://github.com/JetBrains/JetBrainsRuntime/blob/main/LICENSE)
|
||||
|
||||
**NOTE:** The different distributors can provide discrepant list of available versions / supported configurations. Please refer to the official documentation to see the list of supported versions.
|
||||
|
||||
@@ -129,11 +129,15 @@ Currently, the following distributions are supported:
|
||||
|
||||
**NOTE:** To comply with the GraalVM Free Terms and Conditions (GFTC) license, it is recommended to use GraalVM JDK 17 version 17.0.12, as this is the only version of GraalVM JDK 17 available under the GFTC license. Additionally, it is encouraged to consider upgrading to GraalVM JDK 21, which offers the latest features and improvements.
|
||||
|
||||
**NOTE:** Oracle JDK 17 licensing varies by patch level. As shown on the [JDK 17 Archive](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html) (versions up to 17.0.12 are under the [NFTC](https://www.oracle.com/downloads/licenses/no-fee-license.html) license) and the [JDK 17.0.13+ Archive](https://www.oracle.com/java/technologies/javase/jdk17-0-13-later-archive-downloads.html) (versions 17.0.13 and later are under the [OTN](https://www.oracle.com/downloads/licenses/javase-license1.html) license). To stay on the free NFTC license, use `distribution: 'oracle'` with `java-version: '17.0.12'` (or earlier) instead of the floating `'17'`. Alternatively, upgrade to Oracle JDK 21+, which remains under the NFTC license.
|
||||
|
||||
**NOTE:** On Ubuntu runners, commands executed via `sudo` do not inherit the `JAVA_HOME` and `PATH` set by `setup-java` and will fall back to the runner image's system-default JDK.
|
||||
|
||||
### Caching packages dependencies
|
||||
The action has a built-in functionality for caching and restoring dependencies. It uses [toolkit/cache](https://github.com/actions/toolkit/tree/main/packages/cache) under hood for caching dependencies but requires less configuration settings. Supported package managers are gradle, maven and sbt. The format of the used cache key is `setup-java-${{ platform }}-${{ packageManager }}-${{ fileHash }}`, where the hash is based on the following files:
|
||||
|
||||
- gradle: `**/*.gradle*`, `**/gradle-wrapper.properties`, `buildSrc/**/Versions.kt`, `buildSrc/**/Dependencies.kt`, `gradle/*.versions.toml`, and `**/versions.properties`
|
||||
- maven: `**/pom.xml`
|
||||
- maven: `**/pom.xml` and `**/.mvn/wrapper/maven-wrapper.properties`
|
||||
- sbt: all sbt build definition files `**/*.sbt`, `**/project/build.properties`, `**/project/**.scala`, `**/project/**.sbt`
|
||||
|
||||
When the option `cache-dependency-path` is specified, the hash is based on the matching file. This option supports wildcards and a list of file names, and is especially useful for monorepos.
|
||||
@@ -214,7 +218,7 @@ In the basic examples above, the `check-latest` flag defaults to `false`. When s
|
||||
|
||||
If `check-latest` is set to `true`, the action first checks if the cached version is the latest one. If the locally cached version is not the most up-to-date, the latest version of Java will be downloaded. Set `check-latest` to `true` if you want the most up-to-date version of Java to always be used. Setting `check-latest` to `true` has performance implications as downloading versions of Java is slower than using cached versions.
|
||||
|
||||
For Java distributions that are not cached on Hosted images, `check-latest` always behaves as `true` and downloads Java on-flight. Check out [Hosted Tool Cache](docs/advanced-usage.md#Hosted-Tool-Cache) for more details about pre-cached Java versions.
|
||||
For Java distributions that are not cached on Hosted images, `check-latest` always behaves as `true` and downloads Java on the fly. Check out [Hosted Tool Cache](docs/advanced-usage.md#Hosted-Tool-Cache) for more details about pre-cached Java versions.
|
||||
|
||||
|
||||
```yaml
|
||||
@@ -278,6 +282,7 @@ In the example above multiple JDKs are installed for the same job. The result af
|
||||
- [Alibaba Dragonwell](docs/advanced-usage.md#Alibaba-Dragonwell)
|
||||
- [SapMachine](docs/advanced-usage.md#SapMachine)
|
||||
- [GraalVM](docs/advanced-usage.md#GraalVM)
|
||||
- [JetBrains](docs/advanced-usage.md#JetBrains)
|
||||
- [Installing custom Java package type](docs/advanced-usage.md#Installing-custom-Java-package-type)
|
||||
- [Installing custom Java architecture](docs/advanced-usage.md#Installing-custom-Java-architecture)
|
||||
- [Installing custom Java distribution from local file](docs/advanced-usage.md#Installing-Java-from-local-file)
|
||||
|
||||
+47
-7
@@ -17,6 +17,7 @@ describe('dependency cache', () => {
|
||||
let spyWarning: jest.SpyInstance<void, Parameters<typeof core.warning>>;
|
||||
let spyDebug: jest.SpyInstance<void, Parameters<typeof core.debug>>;
|
||||
let spySaveState: jest.SpyInstance<void, Parameters<typeof core.saveState>>;
|
||||
let spyCoreError: jest.SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
workspace = mkdtempSync(join(tmpdir(), 'setup-java-cache-'));
|
||||
@@ -51,6 +52,10 @@ describe('dependency cache', () => {
|
||||
|
||||
spySaveState = jest.spyOn(core, 'saveState');
|
||||
spySaveState.mockImplementation(() => null);
|
||||
|
||||
// Mock core.error to suppress error logs
|
||||
spyCoreError = jest.spyOn(core, 'error');
|
||||
spyCoreError.mockImplementation(() => {});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -58,6 +63,10 @@ describe('dependency cache', () => {
|
||||
process.env['GITHUB_WORKSPACE'] = ORIGINAL_GITHUB_WORKSPACE;
|
||||
process.env['RUNNER_OS'] = ORIGINAL_RUNNER_OS;
|
||||
resetState();
|
||||
|
||||
jest.resetAllMocks();
|
||||
jest.clearAllMocks();
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('restore', () => {
|
||||
@@ -87,19 +96,48 @@ describe('dependency cache', () => {
|
||||
});
|
||||
|
||||
describe('for maven', () => {
|
||||
it('throws error if no pom.xml found', async () => {
|
||||
it('throws error if no pom.xml or maven-wrapper.properties found', async () => {
|
||||
await expect(restore('maven', '')).rejects.toThrow(
|
||||
`No file in ${projectRoot(
|
||||
workspace
|
||||
)} matched to [**/pom.xml], make sure you have checked out the target repository`
|
||||
)} matched to [**/pom.xml,**/.mvn/wrapper/maven-wrapper.properties], make sure you have checked out the target repository`
|
||||
);
|
||||
});
|
||||
it('downloads cache', async () => {
|
||||
it('downloads cache based on pom.xml', async () => {
|
||||
createFile(join(workspace, 'pom.xml'));
|
||||
|
||||
await restore('maven', '');
|
||||
expect(spyCacheRestore).toHaveBeenCalled();
|
||||
expect(spyGlobHashFiles).toHaveBeenCalledWith('**/pom.xml');
|
||||
expect(spyCacheRestore).toHaveBeenCalledWith(
|
||||
[
|
||||
join(os.homedir(), '.m2', 'repository'),
|
||||
join(os.homedir(), '.m2', 'wrapper', 'dists')
|
||||
],
|
||||
expect.any(String)
|
||||
);
|
||||
expect(spyGlobHashFiles).toHaveBeenCalledWith(
|
||||
'**/pom.xml\n**/.mvn/wrapper/maven-wrapper.properties'
|
||||
);
|
||||
expect(spyWarning).not.toHaveBeenCalled();
|
||||
expect(spyInfo).toHaveBeenCalledWith('maven cache is not found');
|
||||
});
|
||||
it('downloads cache based on maven-wrapper.properties', async () => {
|
||||
createDirectory(join(workspace, '.mvn'));
|
||||
createDirectory(join(workspace, '.mvn', 'wrapper'));
|
||||
createFile(
|
||||
join(workspace, '.mvn', 'wrapper', 'maven-wrapper.properties')
|
||||
);
|
||||
|
||||
await restore('maven', '');
|
||||
expect(spyCacheRestore).toHaveBeenCalledWith(
|
||||
[
|
||||
join(os.homedir(), '.m2', 'repository'),
|
||||
join(os.homedir(), '.m2', 'wrapper', 'dists')
|
||||
],
|
||||
expect.any(String)
|
||||
);
|
||||
expect(spyGlobHashFiles).toHaveBeenCalledWith(
|
||||
'**/pom.xml\n**/.mvn/wrapper/maven-wrapper.properties'
|
||||
);
|
||||
expect(spyWarning).not.toHaveBeenCalled();
|
||||
expect(spyInfo).toHaveBeenCalledWith('maven cache is not found');
|
||||
});
|
||||
@@ -282,10 +320,12 @@ describe('dependency cache', () => {
|
||||
await save('maven');
|
||||
expect(spyCacheSave).toHaveBeenCalled();
|
||||
expect(spyWarning).not.toHaveBeenCalled();
|
||||
expect(spyInfo).toHaveBeenCalled();
|
||||
expect(spyInfo).toHaveBeenCalledWith(
|
||||
expect(spyInfo).not.toHaveBeenCalledWith(
|
||||
expect.stringMatching(/^Cache saved with the key:.*/)
|
||||
);
|
||||
expect(spyDebug).toHaveBeenCalledWith(
|
||||
expect.stringMatching(/^Cache was not saved for the key:.*/)
|
||||
);
|
||||
});
|
||||
|
||||
it('saves with error from toolkit, should fail workflow', async () => {
|
||||
|
||||
@@ -11,22 +11,35 @@ describe('cleanup', () => {
|
||||
Parameters<typeof cache.saveCache>
|
||||
>;
|
||||
let spyJobStatusSuccess: jest.SpyInstance;
|
||||
let spyCoreError: jest.SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
spyWarning = jest.spyOn(core, 'warning');
|
||||
spyWarning.mockImplementation(() => null);
|
||||
|
||||
spyInfo = jest.spyOn(core, 'info');
|
||||
spyInfo.mockImplementation(() => null);
|
||||
|
||||
spyCacheSave = jest.spyOn(cache, 'saveCache');
|
||||
|
||||
spyJobStatusSuccess = jest.spyOn(util, 'isJobStatusSuccess');
|
||||
spyJobStatusSuccess.mockReturnValue(true);
|
||||
|
||||
// Mock core.error to suppress error logs
|
||||
spyCoreError = jest.spyOn(core, 'error');
|
||||
spyCoreError.mockImplementation(() => {});
|
||||
|
||||
createStateForSuccessfulRestore();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
resetState();
|
||||
jest.resetAllMocks();
|
||||
jest.clearAllMocks();
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('does not fail nor warn even when the save process throws a ReserveCacheError', async () => {
|
||||
it('does not warn/fail even when the save process throws a ReserveCacheError', async () => {
|
||||
spyCacheSave.mockImplementation((paths: string[], key: string) =>
|
||||
Promise.reject(
|
||||
new cache.ReserveCacheError(
|
||||
|
||||
@@ -79,6 +79,49 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "17.0.18",
|
||||
"stable": true,
|
||||
"release_url": "https://aka.ms/download-jdk",
|
||||
"files": [
|
||||
{
|
||||
"filename": "microsoft-jdk-17.0.18-macos-x64.tar.gz",
|
||||
"arch": "x64",
|
||||
"platform": "darwin",
|
||||
"download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-macos-x64.tar.gz"
|
||||
},
|
||||
{
|
||||
"filename": "microsoft-jdk-17.0.18-linux-x64.tar.gz",
|
||||
"arch": "x64",
|
||||
"platform": "linux",
|
||||
"download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-linux-x64.tar.gz"
|
||||
},
|
||||
{
|
||||
"filename": "microsoft-jdk-17.0.18-windows-x64.zip",
|
||||
"arch": "x64",
|
||||
"platform": "win32",
|
||||
"download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-windows-x64.zip"
|
||||
},
|
||||
{
|
||||
"filename": "microsoft-jdk-17.0.18-macos-aarch64.tar.gz",
|
||||
"arch": "aarch64",
|
||||
"platform": "darwin",
|
||||
"download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-macos-aarch64.tar.gz"
|
||||
},
|
||||
{
|
||||
"filename": "microsoft-jdk-17.0.18-linux-aarch64.tar.gz",
|
||||
"arch": "aarch64",
|
||||
"platform": "linux",
|
||||
"download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-linux-aarch64.tar.gz"
|
||||
},
|
||||
{
|
||||
"filename": "microsoft-jdk-17.0.18-windows-aarch64.zip",
|
||||
"arch": "aarch64",
|
||||
"platform": "win32",
|
||||
"download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-windows-aarch64.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "17.0.7",
|
||||
"stable": true,
|
||||
|
||||
@@ -247,7 +247,7 @@
|
||||
{
|
||||
"id": 12446,
|
||||
"url": "https://cdn.azul.com/zulu/bin/zulu17.48.15-ca-jdk17.0.10-windows_aarch64.zip",
|
||||
"name": "zulu17.48.15-ca-jdk17.0.10-win_aarhc4.zip",
|
||||
"name": "zulu17.48.15-ca-jdk17.0.10-win_aarch4.zip",
|
||||
"zulu_version": [17, 48, 15, 0],
|
||||
"jdk_version": [17, 0, 10, 7]
|
||||
}
|
||||
|
||||
@@ -4,14 +4,18 @@ import {
|
||||
AdoptDistribution,
|
||||
AdoptImplementation
|
||||
} from '../../src/distributions/adopt/installer';
|
||||
import {TemurinDistribution} from '../../src/distributions/temurin/installer';
|
||||
import {JavaInstallerOptions} from '../../src/distributions/base-models';
|
||||
|
||||
import os from 'os';
|
||||
|
||||
import manifestData from '../data/adopt.json';
|
||||
import * as core from '@actions/core';
|
||||
|
||||
describe('getAvailableVersions', () => {
|
||||
let spyHttpClient: jest.SpyInstance;
|
||||
let spyCoreError: jest.SpyInstance;
|
||||
let spyCoreWarning: jest.SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
|
||||
@@ -20,6 +24,12 @@ describe('getAvailableVersions', () => {
|
||||
headers: {},
|
||||
result: []
|
||||
});
|
||||
|
||||
// Mock core.error to suppress error logs
|
||||
spyCoreError = jest.spyOn(core, 'error');
|
||||
spyCoreError.mockImplementation(() => {});
|
||||
spyCoreWarning = jest.spyOn(core, 'warning');
|
||||
spyCoreWarning.mockImplementation(() => {});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -130,22 +140,19 @@ describe('getAvailableVersions', () => {
|
||||
);
|
||||
|
||||
it('load available versions', async () => {
|
||||
const nextPageUrl =
|
||||
'https://api.adoptopenjdk.net/v3/assets/version/%5B1.0,100.0%5D?page=1&page_size=20';
|
||||
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
|
||||
spyHttpClient
|
||||
.mockReturnValueOnce({
|
||||
statusCode: 200,
|
||||
headers: {},
|
||||
headers: {link: `<${nextPageUrl}>; rel="next"`},
|
||||
result: manifestData as any
|
||||
})
|
||||
.mockReturnValueOnce({
|
||||
statusCode: 200,
|
||||
headers: {},
|
||||
result: manifestData as any
|
||||
})
|
||||
.mockReturnValueOnce({
|
||||
statusCode: 200,
|
||||
headers: {},
|
||||
result: []
|
||||
});
|
||||
|
||||
const distribution = new AdoptDistribution(
|
||||
@@ -160,6 +167,34 @@ describe('getAvailableVersions', () => {
|
||||
const availableVersions = await distribution['getAvailableVersions']();
|
||||
expect(availableVersions).not.toBeNull();
|
||||
expect(availableVersions.length).toBe(manifestData.length * 2);
|
||||
expect(spyHttpClient).toHaveBeenNthCalledWith(2, nextPageUrl);
|
||||
});
|
||||
|
||||
it('stops pagination after 1000 pages as a safeguard', async () => {
|
||||
const nextPageUrl =
|
||||
'https://api.adoptopenjdk.net/v3/assets/version/%5B1.0,100.0%5D?page=2&page_size=20';
|
||||
spyHttpClient.mockReturnValue({
|
||||
statusCode: 200,
|
||||
headers: {link: `<${nextPageUrl}>; rel="next"`},
|
||||
result: [{version_data: {semver: '17.0.1'}, binaries: []}] as any
|
||||
});
|
||||
|
||||
const distribution = new AdoptDistribution(
|
||||
{
|
||||
version: '11',
|
||||
architecture: 'x64',
|
||||
packageType: 'jdk',
|
||||
checkLatest: false
|
||||
},
|
||||
AdoptImplementation.Hotspot
|
||||
);
|
||||
|
||||
await distribution['getAvailableVersions']();
|
||||
|
||||
expect(spyHttpClient).toHaveBeenCalledTimes(1000);
|
||||
expect(spyCoreWarning).toHaveBeenCalledWith(
|
||||
expect.stringContaining('Reached pagination safeguard limit (1000 pages)')
|
||||
);
|
||||
});
|
||||
|
||||
it.each([
|
||||
@@ -222,6 +257,38 @@ describe('getAvailableVersions', () => {
|
||||
});
|
||||
|
||||
describe('findPackageForDownload', () => {
|
||||
it('returns Temurin result and does not query Adopt API when Temurin succeeds', async () => {
|
||||
const temurinRelease = {
|
||||
version: '11.0.31+11',
|
||||
url: 'https://example.test/temurin-11.tar.gz'
|
||||
};
|
||||
const temurinFindPackageForDownload = jest
|
||||
.fn()
|
||||
.mockResolvedValue(temurinRelease);
|
||||
const temurinDistribution = {
|
||||
findPackageForDownload: temurinFindPackageForDownload
|
||||
} as unknown as TemurinDistribution;
|
||||
|
||||
const distribution = new AdoptDistribution(
|
||||
{
|
||||
version: '11',
|
||||
architecture: 'x64',
|
||||
packageType: 'jdk',
|
||||
checkLatest: false
|
||||
},
|
||||
AdoptImplementation.Hotspot,
|
||||
temurinDistribution
|
||||
);
|
||||
const adoptLookupSpy = jest.fn();
|
||||
distribution['getAvailableVersions'] = adoptLookupSpy;
|
||||
|
||||
const resolvedVersion = await distribution['findPackageForDownload']('11');
|
||||
|
||||
expect(resolvedVersion).toEqual(temurinRelease);
|
||||
expect(temurinFindPackageForDownload).toHaveBeenCalledWith('11');
|
||||
expect(adoptLookupSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it.each([
|
||||
['9', '9.0.7+10'],
|
||||
['15', '15.0.2+7'],
|
||||
@@ -244,6 +311,11 @@ describe('findPackageForDownload', () => {
|
||||
},
|
||||
AdoptImplementation.Hotspot
|
||||
);
|
||||
// Mock Temurin to fail so fallback to AdoptOpenJDK is tested
|
||||
distribution['temurinDistribution']!['findPackageForDownload'] =
|
||||
async () => {
|
||||
throw new Error('No matching version found for SemVer');
|
||||
};
|
||||
distribution['getAvailableVersions'] = async () => manifestData as any;
|
||||
const resolvedVersion = await distribution['findPackageForDownload'](input);
|
||||
expect(resolvedVersion.version).toBe(expected);
|
||||
@@ -259,10 +331,15 @@ describe('findPackageForDownload', () => {
|
||||
},
|
||||
AdoptImplementation.Hotspot
|
||||
);
|
||||
// Mock Temurin to fail so fallback to AdoptOpenJDK is tested
|
||||
distribution['temurinDistribution']!['findPackageForDownload'] =
|
||||
async () => {
|
||||
throw new Error('No matching version found for SemVer');
|
||||
};
|
||||
distribution['getAvailableVersions'] = async () => manifestData as any;
|
||||
await expect(
|
||||
distribution['findPackageForDownload']('9.0.8')
|
||||
).rejects.toThrow(/Could not find satisfied version for SemVer */);
|
||||
).rejects.toThrow(/No matching version found for SemVer */);
|
||||
});
|
||||
|
||||
it('version is not found', async () => {
|
||||
@@ -275,9 +352,14 @@ describe('findPackageForDownload', () => {
|
||||
},
|
||||
AdoptImplementation.Hotspot
|
||||
);
|
||||
// Mock Temurin to fail so fallback to AdoptOpenJDK is tested
|
||||
distribution['temurinDistribution']!['findPackageForDownload'] =
|
||||
async () => {
|
||||
throw new Error('No matching version found for SemVer');
|
||||
};
|
||||
distribution['getAvailableVersions'] = async () => manifestData as any;
|
||||
await expect(distribution['findPackageForDownload']('7.x')).rejects.toThrow(
|
||||
/Could not find satisfied version for SemVer */
|
||||
/No matching version found for SemVer */
|
||||
);
|
||||
});
|
||||
|
||||
@@ -291,9 +373,14 @@ describe('findPackageForDownload', () => {
|
||||
},
|
||||
AdoptImplementation.Hotspot
|
||||
);
|
||||
// Mock Temurin to fail so fallback to AdoptOpenJDK is tested
|
||||
distribution['temurinDistribution']!['findPackageForDownload'] =
|
||||
async () => {
|
||||
throw new Error('No matching version found for SemVer');
|
||||
};
|
||||
distribution['getAvailableVersions'] = async () => [];
|
||||
await expect(distribution['findPackageForDownload']('11')).rejects.toThrow(
|
||||
/Could not find satisfied version for SemVer */
|
||||
/No matching version found for SemVer */
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -38,7 +38,7 @@ class EmptyJavaBase extends JavaBase {
|
||||
): Promise<JavaDownloadRelease> {
|
||||
const availableVersion = '11.0.9';
|
||||
if (!semver.satisfies(availableVersion, range)) {
|
||||
throw new Error('Available version not found');
|
||||
throw this.createVersionNotFoundError(range, [availableVersion]);
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -248,6 +248,7 @@ describe('setupJava', () => {
|
||||
let spyCoreExportVariable: jest.SpyInstance;
|
||||
let spyCoreAddPath: jest.SpyInstance;
|
||||
let spyCoreSetOutput: jest.SpyInstance;
|
||||
let spyCoreError: jest.SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
spyGetToolcachePath = jest.spyOn(util, 'getToolcachePath');
|
||||
@@ -287,6 +288,10 @@ describe('setupJava', () => {
|
||||
spyCoreSetOutput = jest.spyOn(core, 'setOutput');
|
||||
spyCoreSetOutput.mockImplementation(() => undefined);
|
||||
|
||||
// Mock core.error to suppress error logs
|
||||
spyCoreError = jest.spyOn(core, 'error');
|
||||
spyCoreError.mockImplementation(() => undefined);
|
||||
|
||||
jest.spyOn(os, 'arch').mockReturnValue('x86' as ReturnType<typeof os.arch>);
|
||||
});
|
||||
|
||||
@@ -530,19 +535,16 @@ describe('setupJava', () => {
|
||||
checkLatest: false
|
||||
}
|
||||
]
|
||||
])(
|
||||
'should throw an error for Available version not found for %s',
|
||||
async input => {
|
||||
])('should throw an error for version not found for %s', async input => {
|
||||
mockJavaBase = new EmptyJavaBase(input);
|
||||
await expect(mockJavaBase.setupJava()).rejects.toThrow(
|
||||
'Available version not found'
|
||||
`No matching version found for SemVer '${input.version}'`
|
||||
);
|
||||
expect(spyTcFindAllVersions).toHaveBeenCalled();
|
||||
expect(spyCoreAddPath).not.toHaveBeenCalled();
|
||||
expect(spyCoreExportVariable).not.toHaveBeenCalled();
|
||||
expect(spyCoreSetOutput).not.toHaveBeenCalled();
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('normalizeVersion', () => {
|
||||
@@ -570,6 +572,97 @@ describe('normalizeVersion', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('createVersionNotFoundError', () => {
|
||||
it('should include all required fields in error message without available versions', () => {
|
||||
const mockJavaBase = new EmptyJavaBase({
|
||||
version: '17.0.5',
|
||||
architecture: 'x64',
|
||||
packageType: 'jdk',
|
||||
checkLatest: false
|
||||
});
|
||||
|
||||
const error = (mockJavaBase as any).createVersionNotFoundError('17.0.5');
|
||||
|
||||
expect(error.message).toContain(
|
||||
"No matching version found for SemVer '17.0.5'"
|
||||
);
|
||||
expect(error.message).toContain('Distribution: Empty');
|
||||
expect(error.message).toContain('Package type: jdk');
|
||||
expect(error.message).toContain('Architecture: x64');
|
||||
});
|
||||
|
||||
it('should include available versions when provided', () => {
|
||||
const mockJavaBase = new EmptyJavaBase({
|
||||
version: '17.0.5',
|
||||
architecture: 'x64',
|
||||
packageType: 'jdk',
|
||||
checkLatest: false
|
||||
});
|
||||
|
||||
const availableVersions = ['11.0.1', '11.0.2', '17.0.1', '17.0.2'];
|
||||
const error = (mockJavaBase as any).createVersionNotFoundError(
|
||||
'17.0.5',
|
||||
availableVersions
|
||||
);
|
||||
|
||||
expect(error.message).toContain(
|
||||
"No matching version found for SemVer '17.0.5'"
|
||||
);
|
||||
expect(error.message).toContain('Distribution: Empty');
|
||||
expect(error.message).toContain('Package type: jdk');
|
||||
expect(error.message).toContain('Architecture: x64');
|
||||
expect(error.message).toContain(
|
||||
'Available versions: 11.0.1, 11.0.2, 17.0.1, 17.0.2'
|
||||
);
|
||||
});
|
||||
|
||||
it('should truncate available versions when there are many', () => {
|
||||
const mockJavaBase = new EmptyJavaBase({
|
||||
version: '17.0.5',
|
||||
architecture: 'x64',
|
||||
packageType: 'jdk',
|
||||
checkLatest: false
|
||||
});
|
||||
|
||||
// Create 60 versions to test truncation
|
||||
const availableVersions = Array.from({length: 60}, (_, i) => `11.0.${i}`);
|
||||
const error = (mockJavaBase as any).createVersionNotFoundError(
|
||||
'17.0.5',
|
||||
availableVersions
|
||||
);
|
||||
|
||||
expect(error.message).toContain('Available versions:');
|
||||
expect(error.message).toContain('...');
|
||||
expect(error.message).toContain('(showing first 50 of 60 versions');
|
||||
});
|
||||
|
||||
it('should include additional context when provided', () => {
|
||||
const mockJavaBase = new EmptyJavaBase({
|
||||
version: '17.0.5',
|
||||
architecture: 'x64',
|
||||
packageType: 'jdk',
|
||||
checkLatest: false
|
||||
});
|
||||
|
||||
const availableVersions = ['11.0.1', '11.0.2'];
|
||||
const additionalContext = 'Platform: linux';
|
||||
const error = (mockJavaBase as any).createVersionNotFoundError(
|
||||
'17.0.5',
|
||||
availableVersions,
|
||||
additionalContext
|
||||
);
|
||||
|
||||
expect(error.message).toContain(
|
||||
"No matching version found for SemVer '17.0.5'"
|
||||
);
|
||||
expect(error.message).toContain('Distribution: Empty');
|
||||
expect(error.message).toContain('Package type: jdk');
|
||||
expect(error.message).toContain('Architecture: x64');
|
||||
expect(error.message).toContain('Platform: linux');
|
||||
expect(error.message).toContain('Available versions: 11.0.1, 11.0.2');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getToolcacheVersionName', () => {
|
||||
const DummyJavaBase = JavaBase as any;
|
||||
|
||||
|
||||
@@ -4,13 +4,14 @@ import {JavaInstallerOptions} from '../../src/distributions/base-models';
|
||||
import {CorrettoDistribution} from '../../src/distributions/corretto/installer';
|
||||
import * as util from '../../src/util';
|
||||
import os from 'os';
|
||||
import {isGeneratorFunction} from 'util/types';
|
||||
import * as core from '@actions/core';
|
||||
|
||||
import manifestData from '../data/corretto.json';
|
||||
|
||||
describe('getAvailableVersions', () => {
|
||||
let spyHttpClient: jest.SpyInstance;
|
||||
let spyGetDownloadArchiveExtension: jest.SpyInstance;
|
||||
let spyCoreError: jest.SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
|
||||
@@ -23,6 +24,10 @@ describe('getAvailableVersions', () => {
|
||||
util,
|
||||
'getDownloadArchiveExtension'
|
||||
);
|
||||
|
||||
// Mock core.error to suppress error logs
|
||||
spyCoreError = jest.spyOn(core, 'error');
|
||||
spyCoreError.mockImplementation(() => {});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -198,7 +203,7 @@ describe('getAvailableVersions', () => {
|
||||
|
||||
await expect(
|
||||
distribution['findPackageForDownload'](version)
|
||||
).rejects.toThrow("Could not find satisfied version for SemVer '4'");
|
||||
).rejects.toThrow("No matching version found for SemVer '4'");
|
||||
});
|
||||
|
||||
it.each([
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import {HttpClient} from '@actions/http-client';
|
||||
import {DragonwellDistribution} from '../../src/distributions/dragonwell/installer';
|
||||
import * as utils from '../../src/util';
|
||||
import * as core from '@actions/core';
|
||||
|
||||
import manifestData from '../data/dragonwell.json';
|
||||
|
||||
describe('getAvailableVersions', () => {
|
||||
let spyHttpClient: jest.SpyInstance;
|
||||
let spyUtilGetDownloadArchiveExtension: jest.SpyInstance;
|
||||
let spyCoreError: jest.SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
|
||||
@@ -21,6 +23,10 @@ describe('getAvailableVersions', () => {
|
||||
'getDownloadArchiveExtension'
|
||||
);
|
||||
spyUtilGetDownloadArchiveExtension.mockReturnValue('tar.gz');
|
||||
|
||||
// Mock core.error to suppress error logs
|
||||
spyCoreError = jest.spyOn(core, 'error');
|
||||
spyCoreError.mockImplementation(() => {});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -232,7 +238,7 @@ describe('getAvailableVersions', () => {
|
||||
await expect(
|
||||
distribution['findPackageForDownload'](jdkVersion)
|
||||
).rejects.toThrow(
|
||||
`Couldn't find any satisfied version for the specified java-version: "${jdkVersion}" and architecture: "${arch}".`
|
||||
`No matching version found for SemVer '${jdkVersion}'`
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -42,6 +42,7 @@ beforeAll(() => {
|
||||
describe('GraalVMDistribution', () => {
|
||||
let distribution: GraalVMDistribution;
|
||||
let mockHttpClient: jest.Mocked<http.HttpClient>;
|
||||
let spyCoreError: jest.SpyInstance;
|
||||
|
||||
const defaultOptions: JavaInstallerOptions = {
|
||||
version: '17',
|
||||
@@ -59,6 +60,10 @@ describe('GraalVMDistribution', () => {
|
||||
(distribution as any).http = mockHttpClient;
|
||||
|
||||
(util.getDownloadArchiveExtension as jest.Mock).mockReturnValue('tar.gz');
|
||||
|
||||
// Mock core.error to suppress error logs
|
||||
spyCoreError = jest.spyOn(core, 'error');
|
||||
spyCoreError.mockImplementation(() => {});
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
@@ -348,11 +353,19 @@ describe('GraalVMDistribution', () => {
|
||||
} as http.HttpClientResponse;
|
||||
mockHttpClient.head.mockResolvedValue(mockResponse);
|
||||
|
||||
// Verify the error is thrown with the expected message
|
||||
await expect(
|
||||
(distribution as any).findPackageForDownload('17.0.99')
|
||||
).rejects.toThrow(
|
||||
'Could not find GraalVM for SemVer 17.0.99. Please check if this version is available at https://download.oracle.com/graalvm'
|
||||
);
|
||||
).rejects.toThrow("No matching version found for SemVer '17.0.99'");
|
||||
// Verify distribution info is included
|
||||
await expect(
|
||||
(distribution as any).findPackageForDownload('17.0.99')
|
||||
).rejects.toThrow('GraalVM');
|
||||
|
||||
// Verify the hint about checking the base URL is included
|
||||
await expect(
|
||||
(distribution as any).findPackageForDownload('17.0.99')
|
||||
).rejects.toThrow('https://www.graalvm.org/downloads/');
|
||||
});
|
||||
|
||||
it('should throw error for unauthorized access (401)', async () => {
|
||||
@@ -496,12 +509,19 @@ describe('GraalVMDistribution', () => {
|
||||
|
||||
await expect(
|
||||
(distribution as any).findPackageForDownload('23')
|
||||
).rejects.toThrow("Unable to find latest version for '23-ea'");
|
||||
).rejects.toThrow("No matching version found for SemVer '23-ea'");
|
||||
|
||||
// Verify error logging
|
||||
expect(core.error).toHaveBeenCalledWith(
|
||||
'Available versions: 23-ea-20240716'
|
||||
await expect(
|
||||
(distribution as any).findPackageForDownload('23')
|
||||
).rejects.toThrow(
|
||||
'Note: No EA build is marked as latest for this version.'
|
||||
);
|
||||
|
||||
await expect(
|
||||
(distribution as any).findPackageForDownload('23')
|
||||
).rejects.toThrow('23-ea-20240716');
|
||||
|
||||
// Verify error logging - removed as we now use the helper method which doesn't call core.error
|
||||
});
|
||||
|
||||
it('should throw error when no matching file for architecture in EA build', async () => {
|
||||
@@ -708,11 +728,19 @@ describe('GraalVMDistribution', () => {
|
||||
|
||||
await expect(
|
||||
(distribution as any).findEABuildDownloadUrl('23-ea')
|
||||
).rejects.toThrow("Unable to find latest version for '23-ea'");
|
||||
).rejects.toThrow("No matching version found for SemVer '23-ea'");
|
||||
|
||||
expect(core.error).toHaveBeenCalledWith(
|
||||
'Available versions: 23-ea-20240716, 23-ea-20240709'
|
||||
await expect(
|
||||
(distribution as any).findEABuildDownloadUrl('23-ea')
|
||||
).rejects.toThrow(
|
||||
'Note: No EA build is marked as latest for this version.'
|
||||
);
|
||||
|
||||
await expect(
|
||||
(distribution as any).findEABuildDownloadUrl('23-ea')
|
||||
).rejects.toThrow('23-ea-20240716');
|
||||
|
||||
// Verify error logging - removed as we now use the helper method which doesn't call core.error
|
||||
});
|
||||
|
||||
it('should throw error when no matching file for architecture', async () => {
|
||||
|
||||
@@ -4,9 +4,11 @@ import {JetBrainsDistribution} from '../../src/distributions/jetbrains/installer
|
||||
|
||||
import manifestData from '../data/jetbrains.json';
|
||||
import os from 'os';
|
||||
import * as core from '@actions/core';
|
||||
|
||||
describe('getAvailableVersions', () => {
|
||||
let spyHttpClient: jest.SpyInstance;
|
||||
let spyCoreError: jest.SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
|
||||
@@ -15,6 +17,10 @@ describe('getAvailableVersions', () => {
|
||||
headers: {},
|
||||
result: []
|
||||
});
|
||||
|
||||
// Mock core.error to suppress error logs
|
||||
spyCoreError = jest.spyOn(core, 'error');
|
||||
spyCoreError.mockImplementation(() => {});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -98,7 +104,7 @@ describe('findPackageForDownload', () => {
|
||||
});
|
||||
distribution['getAvailableVersions'] = async () => manifestData as any;
|
||||
await expect(distribution['findPackageForDownload']('8.x')).rejects.toThrow(
|
||||
/Could not find satisfied version for SemVer */
|
||||
/No matching version found for SemVer */
|
||||
);
|
||||
});
|
||||
|
||||
@@ -111,7 +117,7 @@ describe('findPackageForDownload', () => {
|
||||
});
|
||||
distribution['getAvailableVersions'] = async () => [];
|
||||
await expect(distribution['findPackageForDownload']('8')).rejects.toThrow(
|
||||
/Could not find satisfied version for SemVer */
|
||||
/No matching version found for SemVer */
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,11 +5,13 @@ import {
|
||||
} from '../../src/distributions/liberica/models';
|
||||
import {HttpClient} from '@actions/http-client';
|
||||
import os from 'os';
|
||||
import * as core from '@actions/core';
|
||||
|
||||
import manifestData from '../data/liberica.json';
|
||||
|
||||
describe('getAvailableVersions', () => {
|
||||
let spyHttpClient: jest.SpyInstance;
|
||||
let spyCoreError: jest.SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
|
||||
@@ -18,6 +20,10 @@ describe('getAvailableVersions', () => {
|
||||
headers: {},
|
||||
result: manifestData as LibericaVersion[]
|
||||
});
|
||||
|
||||
// Mock core.error to suppress error logs
|
||||
spyCoreError = jest.spyOn(core, 'error');
|
||||
spyCoreError.mockImplementation(() => {});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -209,7 +215,7 @@ describe('findPackageForDownload', () => {
|
||||
|
||||
it('should throw an error', async () => {
|
||||
await expect(distribution['findPackageForDownload']('17')).rejects.toThrow(
|
||||
/Could not find satisfied version for semver */
|
||||
/No matching version found for SemVer/
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,11 +5,13 @@ import {
|
||||
} from '../../src/distributions/liberica/models';
|
||||
import {HttpClient} from '@actions/http-client';
|
||||
import os from 'os';
|
||||
import * as core from '@actions/core';
|
||||
|
||||
import manifestData from '../data/liberica-linux.json';
|
||||
|
||||
describe('getAvailableVersions', () => {
|
||||
let spyHttpClient: jest.SpyInstance;
|
||||
let spyCoreError: jest.SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
|
||||
@@ -18,6 +20,10 @@ describe('getAvailableVersions', () => {
|
||||
headers: {},
|
||||
result: manifestData as LibericaVersion[]
|
||||
});
|
||||
|
||||
// Mock core.error to suppress error logs
|
||||
spyCoreError = jest.spyOn(core, 'error');
|
||||
spyCoreError.mockImplementation(() => {});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -209,7 +215,7 @@ describe('findPackageForDownload', () => {
|
||||
|
||||
it('should throw an error', async () => {
|
||||
await expect(distribution['findPackageForDownload']('18')).rejects.toThrow(
|
||||
/Could not find satisfied version for semver */
|
||||
/No matching version found for SemVer/
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,11 +5,13 @@ import {
|
||||
} from '../../src/distributions/liberica/models';
|
||||
import {HttpClient} from '@actions/http-client';
|
||||
import os from 'os';
|
||||
import * as core from '@actions/core';
|
||||
|
||||
import manifestData from '../data/liberica-windows.json';
|
||||
|
||||
describe('getAvailableVersions', () => {
|
||||
let spyHttpClient: jest.SpyInstance;
|
||||
let spyCoreError: jest.SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
|
||||
@@ -18,6 +20,9 @@ describe('getAvailableVersions', () => {
|
||||
headers: {},
|
||||
result: manifestData as LibericaVersion[]
|
||||
});
|
||||
// Mock core.error to suppress error logs
|
||||
spyCoreError = jest.spyOn(core, 'error');
|
||||
spyCoreError.mockImplementation(() => {});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -209,7 +214,7 @@ describe('findPackageForDownload', () => {
|
||||
|
||||
it('should throw an error', async () => {
|
||||
await expect(distribution['findPackageForDownload']('18')).rejects.toThrow(
|
||||
/Could not find satisfied version for semver */
|
||||
/No matching version found for SemVer/
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -27,6 +27,7 @@ describe('setupJava', () => {
|
||||
let spyFsReadDir: jest.SpyInstance;
|
||||
let spyUtilsExtractJdkFile: jest.SpyInstance;
|
||||
let spyPathResolve: jest.SpyInstance;
|
||||
let spyCoreError: jest.SpyInstance;
|
||||
const expectedJdkFile = 'JavaLocalJdkFile';
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -93,6 +94,10 @@ describe('setupJava', () => {
|
||||
// Spy on path methods
|
||||
spyPathResolve = jest.spyOn(path, 'resolve');
|
||||
spyPathResolve.mockImplementation((path: string) => path);
|
||||
|
||||
// Mock core.error to suppress error logs
|
||||
spyCoreError = jest.spyOn(core, 'error');
|
||||
spyCoreError.mockImplementation(() => {});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -214,7 +219,7 @@ describe('setupJava', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('java is resolved from toolcache including Contents/Home on MacOS', async () => {
|
||||
it('java is resolved from toolcache including Contents/Home on macOS', async () => {
|
||||
const inputs = {
|
||||
version: actualJavaVersion,
|
||||
architecture: 'x86',
|
||||
@@ -257,7 +262,7 @@ describe('setupJava', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('java is unpacked from jdkfile including Contents/Home on MacOS', async () => {
|
||||
it('java is unpacked from jdkfile including Contents/Home on macOS', async () => {
|
||||
const inputs = {
|
||||
version: '11.0.289',
|
||||
architecture: 'x86',
|
||||
|
||||
@@ -8,6 +8,7 @@ describe('findPackageForDownload', () => {
|
||||
let distribution: MicrosoftDistributions;
|
||||
let spyGetManifestFromRepo: jest.SpyInstance;
|
||||
let spyDebug: jest.SpyInstance;
|
||||
let spyCoreError: jest.SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
distribution = new MicrosoftDistributions({
|
||||
@@ -26,6 +27,10 @@ describe('findPackageForDownload', () => {
|
||||
|
||||
spyDebug = jest.spyOn(core, 'debug');
|
||||
spyDebug.mockImplementation(() => {});
|
||||
|
||||
// Mock core.error to suppress error logs
|
||||
spyCoreError = jest.spyOn(core, 'error');
|
||||
spyCoreError.mockImplementation(() => {});
|
||||
});
|
||||
|
||||
it.each([
|
||||
@@ -39,16 +44,21 @@ describe('findPackageForDownload', () => {
|
||||
'21.0.0',
|
||||
'https://aka.ms/download-jdk/microsoft-jdk-21.0.0-{{OS_TYPE}}-x64.{{ARCHIVE_TYPE}}'
|
||||
],
|
||||
[
|
||||
'17.x',
|
||||
'17.0.18',
|
||||
'https://aka.ms/download-jdk/microsoft-jdk-17.0.18-{{OS_TYPE}}-x64.{{ARCHIVE_TYPE}}'
|
||||
],
|
||||
[
|
||||
'17.0.7',
|
||||
'17.0.7',
|
||||
'https://aka.ms/download-jdk/microsoft-jdk-17.0.7-{{OS_TYPE}}-x64.{{ARCHIVE_TYPE}}'
|
||||
],
|
||||
[
|
||||
'17.0.1',
|
||||
'17.0.1+12.1',
|
||||
'https://aka.ms/download-jdk/microsoft-jdk-17.0.1.12.1-{{OS_TYPE}}-x64.{{ARCHIVE_TYPE}}'
|
||||
],
|
||||
[
|
||||
'17.x',
|
||||
'17.0.7',
|
||||
'https://aka.ms/download-jdk/microsoft-jdk-17.0.7-{{OS_TYPE}}-x64.{{ARCHIVE_TYPE}}'
|
||||
],
|
||||
[
|
||||
'16.0.x',
|
||||
'16.0.2+7.1',
|
||||
@@ -114,7 +124,7 @@ describe('findPackageForDownload', () => {
|
||||
});
|
||||
|
||||
const result = await distro['findPackageForDownload'](version);
|
||||
const expectedUrl = `https://aka.ms/download-jdk/microsoft-jdk-17.0.7-macos-${distroArch}.tar.gz`;
|
||||
const expectedUrl = `https://aka.ms/download-jdk/microsoft-jdk-17.0.18-macos-${distroArch}.tar.gz`;
|
||||
|
||||
expect(result.url).toBe(expectedUrl);
|
||||
}
|
||||
@@ -140,7 +150,7 @@ describe('findPackageForDownload', () => {
|
||||
});
|
||||
|
||||
const result = await distro['findPackageForDownload'](version);
|
||||
const expectedUrl = `https://aka.ms/download-jdk/microsoft-jdk-17.0.7-linux-${distroArch}.tar.gz`;
|
||||
const expectedUrl = `https://aka.ms/download-jdk/microsoft-jdk-17.0.18-linux-${distroArch}.tar.gz`;
|
||||
|
||||
expect(result.url).toBe(expectedUrl);
|
||||
}
|
||||
@@ -166,7 +176,7 @@ describe('findPackageForDownload', () => {
|
||||
});
|
||||
|
||||
const result = await distro['findPackageForDownload'](version);
|
||||
const expectedUrl = `https://aka.ms/download-jdk/microsoft-jdk-17.0.7-windows-${distroArch}.zip`;
|
||||
const expectedUrl = `https://aka.ms/download-jdk/microsoft-jdk-17.0.18-windows-${distroArch}.zip`;
|
||||
|
||||
expect(result.url).toBe(expectedUrl);
|
||||
}
|
||||
@@ -174,7 +184,7 @@ describe('findPackageForDownload', () => {
|
||||
|
||||
it('should throw an error', async () => {
|
||||
await expect(distribution['findPackageForDownload']('8')).rejects.toThrow(
|
||||
/Could not find satisfied version for SemVer */
|
||||
/No matching version found for SemVer */
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,6 +8,7 @@ describe('findPackageForDownload', () => {
|
||||
let distribution: OracleDistribution;
|
||||
let spyDebug: jest.SpyInstance;
|
||||
let spyHttpClient: jest.SpyInstance;
|
||||
let spyCoreError: jest.SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
distribution = new OracleDistribution({
|
||||
@@ -19,6 +20,10 @@ describe('findPackageForDownload', () => {
|
||||
|
||||
spyDebug = jest.spyOn(core, 'debug');
|
||||
spyDebug.mockImplementation(() => {});
|
||||
|
||||
// Mock core.error to suppress error logs
|
||||
spyCoreError = jest.spyOn(core, 'error');
|
||||
spyCoreError.mockImplementation(() => {});
|
||||
});
|
||||
|
||||
it.each([
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import {HttpClient} from '@actions/http-client';
|
||||
import {SapMachineDistribution} from '../../src/distributions/sapmachine/installer';
|
||||
import * as utils from '../../src/util';
|
||||
import * as core from '@actions/core';
|
||||
|
||||
import manifestData from '../data/sapmachine.json';
|
||||
|
||||
describe('getAvailableVersions', () => {
|
||||
let spyHttpClient: jest.SpyInstance;
|
||||
let spyUtilGetDownloadArchiveExtension: jest.SpyInstance;
|
||||
let spyCoreError: jest.SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
|
||||
@@ -21,6 +23,10 @@ describe('getAvailableVersions', () => {
|
||||
'getDownloadArchiveExtension'
|
||||
);
|
||||
spyUtilGetDownloadArchiveExtension.mockReturnValue('tar.gz');
|
||||
|
||||
// Mock core.error to suppress error logs
|
||||
spyCoreError = jest.spyOn(core, 'error');
|
||||
spyCoreError.mockImplementation(() => {});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -266,7 +272,7 @@ describe('getAvailableVersions', () => {
|
||||
await expect(
|
||||
distribution['findPackageForDownload'](normalizedVersion)
|
||||
).rejects.toThrow(
|
||||
`Couldn't find any satisfied version for the specified java-version: "${normalizedVersion}" and architecture: "${arch}".`
|
||||
`No matching version found for SemVer '${normalizedVersion}'`
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -4,9 +4,12 @@ import {JavaInstallerOptions} from '../../src/distributions/base-models';
|
||||
import {SemeruDistribution} from '../../src/distributions/semeru/installer';
|
||||
|
||||
import manifestData from '../data/semeru.json';
|
||||
import * as core from '@actions/core';
|
||||
|
||||
describe('getAvailableVersions', () => {
|
||||
let spyHttpClient: jest.SpyInstance;
|
||||
let spyCoreError: jest.SpyInstance;
|
||||
let spyCoreWarning: jest.SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
|
||||
@@ -15,6 +18,11 @@ describe('getAvailableVersions', () => {
|
||||
headers: {},
|
||||
result: []
|
||||
});
|
||||
// Mock core.error to suppress error logs
|
||||
spyCoreError = jest.spyOn(core, 'error');
|
||||
spyCoreError.mockImplementation(() => {});
|
||||
spyCoreWarning = jest.spyOn(core, 'warning');
|
||||
spyCoreWarning.mockImplementation(() => {});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -77,22 +85,19 @@ describe('getAvailableVersions', () => {
|
||||
);
|
||||
|
||||
it('load available versions', async () => {
|
||||
const nextPageUrl =
|
||||
'https://api.adoptopenjdk.net/v3/assets/version/%5B1.0,100.0%5D?page=1&page_size=20';
|
||||
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
|
||||
spyHttpClient
|
||||
.mockReturnValueOnce({
|
||||
statusCode: 200,
|
||||
headers: {},
|
||||
headers: {link: `<${nextPageUrl}>; rel="next"`},
|
||||
result: manifestData as any
|
||||
})
|
||||
.mockReturnValueOnce({
|
||||
statusCode: 200,
|
||||
headers: {},
|
||||
result: manifestData as any
|
||||
})
|
||||
.mockReturnValueOnce({
|
||||
statusCode: 200,
|
||||
headers: {},
|
||||
result: []
|
||||
});
|
||||
|
||||
const distribution = new SemeruDistribution({
|
||||
@@ -104,6 +109,31 @@ describe('getAvailableVersions', () => {
|
||||
const availableVersions = await distribution['getAvailableVersions']();
|
||||
expect(availableVersions).not.toBeNull();
|
||||
expect(availableVersions.length).toBe(manifestData.length * 2);
|
||||
expect(spyHttpClient).toHaveBeenNthCalledWith(2, nextPageUrl);
|
||||
});
|
||||
|
||||
it('stops pagination after 1000 pages as a safeguard', async () => {
|
||||
const nextPageUrl =
|
||||
'https://api.adoptopenjdk.net/v3/assets/version/%5B1.0,100.0%5D?page=2&page_size=20';
|
||||
spyHttpClient.mockReturnValue({
|
||||
statusCode: 200,
|
||||
headers: {link: `<${nextPageUrl}>; rel="next"`},
|
||||
result: [{version_data: {semver: '17.0.1'}, binaries: []}] as any
|
||||
});
|
||||
|
||||
const distribution = new SemeruDistribution({
|
||||
version: '8',
|
||||
architecture: 'x64',
|
||||
packageType: 'jdk',
|
||||
checkLatest: false
|
||||
});
|
||||
|
||||
await distribution['getAvailableVersions']();
|
||||
|
||||
expect(spyHttpClient).toHaveBeenCalledTimes(1000);
|
||||
expect(spyCoreWarning).toHaveBeenCalledWith(
|
||||
expect.stringContaining('Reached pagination safeguard limit (1000 pages)')
|
||||
);
|
||||
});
|
||||
|
||||
it.each([
|
||||
@@ -152,7 +182,7 @@ describe('findPackageForDownload', () => {
|
||||
distribution['getAvailableVersions'] = async () => manifestData as any;
|
||||
await expect(
|
||||
distribution['findPackageForDownload']('9.0.8')
|
||||
).rejects.toThrow(/Could not find satisfied version for SemVer */);
|
||||
).rejects.toThrow(/No matching version found for SemVer */);
|
||||
});
|
||||
|
||||
it('version is not found', async () => {
|
||||
@@ -164,7 +194,7 @@ describe('findPackageForDownload', () => {
|
||||
});
|
||||
distribution['getAvailableVersions'] = async () => manifestData as any;
|
||||
await expect(distribution['findPackageForDownload']('7.x')).rejects.toThrow(
|
||||
/Could not find satisfied version for SemVer */
|
||||
/No matching version found for SemVer */
|
||||
);
|
||||
});
|
||||
|
||||
@@ -177,7 +207,7 @@ describe('findPackageForDownload', () => {
|
||||
});
|
||||
distribution['getAvailableVersions'] = async () => [];
|
||||
await expect(distribution['findPackageForDownload']('8')).rejects.toThrow(
|
||||
/Could not find satisfied version for SemVer */
|
||||
/No matching version found for SemVer */
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -7,9 +7,12 @@ import {
|
||||
import {JavaInstallerOptions} from '../../src/distributions/base-models';
|
||||
|
||||
import manifestData from '../data/temurin.json';
|
||||
import * as core from '@actions/core';
|
||||
|
||||
describe('getAvailableVersions', () => {
|
||||
let spyHttpClient: jest.SpyInstance;
|
||||
let spyCoreError: jest.SpyInstance;
|
||||
let spyCoreWarning: jest.SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
|
||||
@@ -18,6 +21,11 @@ describe('getAvailableVersions', () => {
|
||||
headers: {},
|
||||
result: []
|
||||
});
|
||||
// Mock core.error to suppress error logs
|
||||
spyCoreError = jest.spyOn(core, 'error');
|
||||
spyCoreError.mockImplementation(() => {});
|
||||
spyCoreWarning = jest.spyOn(core, 'warning');
|
||||
spyCoreWarning.mockImplementation(() => {});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -88,22 +96,19 @@ describe('getAvailableVersions', () => {
|
||||
);
|
||||
|
||||
it('load available versions', async () => {
|
||||
const nextPageUrl =
|
||||
'https://api.adoptium.net/v3/assets/version/%5B1.0,100.0%5D?page=1&page_size=20';
|
||||
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
|
||||
spyHttpClient
|
||||
.mockReturnValueOnce({
|
||||
statusCode: 200,
|
||||
headers: {},
|
||||
headers: {link: `<${nextPageUrl}>; rel="next"`},
|
||||
result: manifestData as any
|
||||
})
|
||||
.mockReturnValueOnce({
|
||||
statusCode: 200,
|
||||
headers: {},
|
||||
result: manifestData as any
|
||||
})
|
||||
.mockReturnValueOnce({
|
||||
statusCode: 200,
|
||||
headers: {},
|
||||
result: []
|
||||
});
|
||||
|
||||
const distribution = new TemurinDistribution(
|
||||
@@ -118,6 +123,34 @@ describe('getAvailableVersions', () => {
|
||||
const availableVersions = await distribution['getAvailableVersions']();
|
||||
expect(availableVersions).not.toBeNull();
|
||||
expect(availableVersions.length).toBe(manifestData.length * 2);
|
||||
expect(spyHttpClient).toHaveBeenNthCalledWith(2, nextPageUrl);
|
||||
});
|
||||
|
||||
it('stops pagination after 1000 pages as a safeguard', async () => {
|
||||
const nextPageUrl =
|
||||
'https://api.adoptium.net/v3/assets/version/%5B1.0,100.0%5D?page=2&page_size=20';
|
||||
spyHttpClient.mockReturnValue({
|
||||
statusCode: 200,
|
||||
headers: {link: `<${nextPageUrl}>; rel="next"`},
|
||||
result: [{version_data: {semver: '17.0.1'}, binaries: []}] as any
|
||||
});
|
||||
|
||||
const distribution = new TemurinDistribution(
|
||||
{
|
||||
version: '8',
|
||||
architecture: 'x64',
|
||||
packageType: 'jdk',
|
||||
checkLatest: false
|
||||
},
|
||||
TemurinImplementation.Hotspot
|
||||
);
|
||||
|
||||
await distribution['getAvailableVersions']();
|
||||
|
||||
expect(spyHttpClient).toHaveBeenCalledTimes(1000);
|
||||
expect(spyCoreWarning).toHaveBeenCalledWith(
|
||||
expect.stringContaining('Reached pagination safeguard limit (1000 pages)')
|
||||
);
|
||||
});
|
||||
|
||||
it.each([
|
||||
@@ -213,7 +246,7 @@ describe('findPackageForDownload', () => {
|
||||
distribution['getAvailableVersions'] = async () => manifestData as any;
|
||||
await expect(
|
||||
distribution['findPackageForDownload']('9.0.8')
|
||||
).rejects.toThrow(/Could not find satisfied version for SemVer */);
|
||||
).rejects.toThrow(/No matching version found for SemVer */);
|
||||
});
|
||||
|
||||
it('version is not found', async () => {
|
||||
@@ -228,7 +261,7 @@ describe('findPackageForDownload', () => {
|
||||
);
|
||||
distribution['getAvailableVersions'] = async () => manifestData as any;
|
||||
await expect(distribution['findPackageForDownload']('7.x')).rejects.toThrow(
|
||||
/Could not find satisfied version for SemVer */
|
||||
/No matching version found for SemVer */
|
||||
);
|
||||
});
|
||||
|
||||
@@ -244,7 +277,7 @@ describe('findPackageForDownload', () => {
|
||||
);
|
||||
distribution['getAvailableVersions'] = async () => [];
|
||||
await expect(distribution['findPackageForDownload']('8')).rejects.toThrow(
|
||||
/Could not find satisfied version for SemVer */
|
||||
/No matching version found for SemVer */
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,12 +3,14 @@ import {ZuluDistribution} from '../../src/distributions/zulu/installer';
|
||||
import {IZuluVersions} from '../../src/distributions/zulu/models';
|
||||
import * as utils from '../../src/util';
|
||||
import os from 'os';
|
||||
import * as core from '@actions/core';
|
||||
|
||||
import manifestData from '../data/zulu-releases-default.json';
|
||||
|
||||
describe('getAvailableVersions', () => {
|
||||
let spyHttpClient: jest.SpyInstance;
|
||||
let spyUtilGetDownloadArchiveExtension: jest.SpyInstance;
|
||||
let spyCoreError: jest.SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
|
||||
@@ -23,6 +25,10 @@ describe('getAvailableVersions', () => {
|
||||
'getDownloadArchiveExtension'
|
||||
);
|
||||
spyUtilGetDownloadArchiveExtension.mockReturnValue('tar.gz');
|
||||
|
||||
// Mock core.error to suppress error logs
|
||||
spyCoreError = jest.spyOn(core, 'error');
|
||||
spyCoreError.mockImplementation(() => {});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -225,6 +231,6 @@ describe('findPackageForDownload', () => {
|
||||
distribution['getAvailableVersions'] = async () => manifestData;
|
||||
await expect(
|
||||
distribution['findPackageForDownload'](distribution['version'])
|
||||
).rejects.toThrow(/Could not find satisfied version for semver */);
|
||||
).rejects.toThrow(/No matching version found for SemVer/);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,12 +4,14 @@ import {ZuluDistribution} from '../../src/distributions/zulu/installer';
|
||||
import {IZuluVersions} from '../../src/distributions/zulu/models';
|
||||
import * as utils from '../../src/util';
|
||||
import os from 'os';
|
||||
import * as core from '@actions/core';
|
||||
|
||||
import manifestData from '../data/zulu-linux.json';
|
||||
|
||||
describe('getAvailableVersions', () => {
|
||||
let spyHttpClient: jest.SpyInstance;
|
||||
let spyUtilGetDownloadArchiveExtension: jest.SpyInstance;
|
||||
let spyCoreError: jest.SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
|
||||
@@ -24,6 +26,10 @@ describe('getAvailableVersions', () => {
|
||||
'getDownloadArchiveExtension'
|
||||
);
|
||||
spyUtilGetDownloadArchiveExtension.mockReturnValue('zip');
|
||||
|
||||
// Mock core.error to suppress error logs
|
||||
spyCoreError = jest.spyOn(core, 'error');
|
||||
spyCoreError.mockImplementation(() => {});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -228,6 +234,6 @@ describe('findPackageForDownload', () => {
|
||||
distribution['getAvailableVersions'] = async () => manifestData;
|
||||
await expect(
|
||||
distribution['findPackageForDownload'](distribution['version'])
|
||||
).rejects.toThrow(/Could not find satisfied version for semver */);
|
||||
).rejects.toThrow(/No matching version found for SemVer/);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,12 +4,14 @@ import {ZuluDistribution} from '../../src/distributions/zulu/installer';
|
||||
import {IZuluVersions} from '../../src/distributions/zulu/models';
|
||||
import * as utils from '../../src/util';
|
||||
import os from 'os';
|
||||
import * as core from '@actions/core';
|
||||
|
||||
import manifestData from '../data/zulu-windows.json';
|
||||
|
||||
describe('getAvailableVersions', () => {
|
||||
let spyHttpClient: jest.SpyInstance;
|
||||
let spyUtilGetDownloadArchiveExtension: jest.SpyInstance;
|
||||
let spyCoreError: jest.SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
|
||||
@@ -24,6 +26,10 @@ describe('getAvailableVersions', () => {
|
||||
'getDownloadArchiveExtension'
|
||||
);
|
||||
spyUtilGetDownloadArchiveExtension.mockReturnValue('zip');
|
||||
|
||||
// Mock core.error to suppress error logs
|
||||
spyCoreError = jest.spyOn(core, 'error');
|
||||
spyCoreError.mockImplementation(() => {});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -226,6 +232,6 @@ describe('findPackageForDownload', () => {
|
||||
distribution['getAvailableVersions'] = async () => manifestData;
|
||||
await expect(
|
||||
distribution['findPackageForDownload'](distribution['version'])
|
||||
).rejects.toThrow(/Could not find satisfied version for semver */);
|
||||
).rejects.toThrow(/No matching version found for SemVer/);
|
||||
});
|
||||
});
|
||||
|
||||
+80
-2
@@ -4,10 +4,12 @@ import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import {
|
||||
convertVersionToSemver,
|
||||
getNextPageUrlFromLinkHeader,
|
||||
getVersionFromFileContent,
|
||||
isVersionSatisfies,
|
||||
isCacheFeatureAvailable,
|
||||
isGhes
|
||||
isGhes,
|
||||
validatePaginationUrl
|
||||
} from '../src/util';
|
||||
|
||||
jest.mock('@actions/cache');
|
||||
@@ -27,7 +29,11 @@ describe('isVersionSatisfies', () => {
|
||||
['2.5.1+3', '2.5.1+3', true],
|
||||
['2.5.1+3', '2.5.1+2', false],
|
||||
['15.0.0+14', '15.0.0+14.1.202003190635', false],
|
||||
['15.0.0+14.1.202003190635', '15.0.0+14.1.202003190635', true]
|
||||
['15.0.0+14.1.202003190635', '15.0.0+14.1.202003190635', true],
|
||||
// 4-segment versions (e.g. JetBrains Runtime '17.0.8.1+1080.1') are not
|
||||
// valid semver — they should be rejected, not throw.
|
||||
['25.0.3+480.61', '17.0.8.1+1080.1', false],
|
||||
['17', '17.0.8.1+1080.1', false]
|
||||
])(
|
||||
'%s, %s -> %s',
|
||||
(inputRange: string, inputVersion: string, expected: boolean) => {
|
||||
@@ -85,6 +91,78 @@ describe('convertVersionToSemver', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('getNextPageUrlFromLinkHeader', () => {
|
||||
it.each([
|
||||
[
|
||||
{
|
||||
link: '<https://api.adoptium.net/v3/info/release_versions?page=1&page_size=10>; rel="next"'
|
||||
},
|
||||
'https://api.adoptium.net/v3/info/release_versions?page=1&page_size=10'
|
||||
],
|
||||
[
|
||||
{
|
||||
Link: '<https://example.com/last?page=5>; rel="last", <https://example.com/next?page=2>; rel="next"'
|
||||
},
|
||||
'https://example.com/next?page=2'
|
||||
],
|
||||
[
|
||||
{
|
||||
link: '<https://api.adoptium.net/v3/versions?page=3>; type="application/json"; rel="next"'
|
||||
},
|
||||
'https://api.adoptium.net/v3/versions?page=3'
|
||||
],
|
||||
[{link: '<https://example.com/last?page=5>; rel="last"'}, null],
|
||||
[{link: '<https://example.com/page?p=2>; rel="nextsomething"'}, null],
|
||||
[undefined, null]
|
||||
])('returns %s -> %s', (headers, expected) => {
|
||||
expect(getNextPageUrlFromLinkHeader(headers)).toBe(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('validatePaginationUrl', () => {
|
||||
it('accepts URL with matching origin', () => {
|
||||
expect(
|
||||
validatePaginationUrl(
|
||||
'https://api.adoptium.net/v3/assets?page=2',
|
||||
'https://api.adoptium.net'
|
||||
)
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('rejects URL with different host', () => {
|
||||
expect(
|
||||
validatePaginationUrl(
|
||||
'https://evil.example.com/steal?data=1',
|
||||
'https://api.adoptium.net'
|
||||
)
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('rejects URL with different protocol', () => {
|
||||
expect(
|
||||
validatePaginationUrl(
|
||||
'http://api.adoptium.net/v3/assets?page=2',
|
||||
'https://api.adoptium.net'
|
||||
)
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false for invalid URL', () => {
|
||||
expect(validatePaginationUrl('not-a-url', 'https://api.adoptium.net')).toBe(
|
||||
false
|
||||
);
|
||||
});
|
||||
|
||||
it('accepts URL with explicit default port', () => {
|
||||
expect(
|
||||
validatePaginationUrl(
|
||||
'https://api.adoptium.net:443/v3/assets?page=2',
|
||||
'https://api.adoptium.net'
|
||||
)
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getVersionFromFileContent', () => {
|
||||
describe('.sdkmanrc', () => {
|
||||
it.each([
|
||||
|
||||
+7
-3
@@ -5,8 +5,10 @@ author: 'GitHub'
|
||||
inputs:
|
||||
java-version:
|
||||
description: 'The Java version to set up. Takes a whole or semver Java version. See examples of supported syntax in README file'
|
||||
required: false
|
||||
java-version-file:
|
||||
description: 'The path to the `.java-version` file. See examples of supported syntax in README file'
|
||||
description: 'The path to a file containing the Java version to set up (.java-version, .tool-versions, .sdkmanrc). Used when java-version is not set. See examples of supported syntax in README file'
|
||||
required: false
|
||||
distribution:
|
||||
description: 'Java distribution. See the list of supported distributions in README file'
|
||||
required: true
|
||||
@@ -49,9 +51,9 @@ inputs:
|
||||
gpg-private-key:
|
||||
description: 'GPG private key to import. Default is empty string.'
|
||||
required: false
|
||||
default: ''
|
||||
gpg-passphrase:
|
||||
description: 'Environment variable name for the GPG private key passphrase. Default is
|
||||
$GPG_PASSPHRASE.'
|
||||
description: 'Environment variable name for the GPG private key passphrase. Defaults to GPG_PASSPHRASE when gpg-private-key is set; ignored otherwise.'
|
||||
required: false
|
||||
cache:
|
||||
description: 'Name of the build platform to cache dependencies. It can be "maven", "gradle" or "sbt".'
|
||||
@@ -61,9 +63,11 @@ inputs:
|
||||
required: false
|
||||
job-status:
|
||||
description: 'Workaround to pass job status to post job step. This variable is not intended for manual setting'
|
||||
required: false
|
||||
default: ${{ job.status }}
|
||||
token:
|
||||
description: The token used to authenticate when fetching version manifests hosted on github.com, such as for the Microsoft Build of OpenJDK. When running this action on github.com, the default value is sufficient. When running on GHES, you can pass a personal access token for github.com if you are experiencing rate limiting.
|
||||
required: false
|
||||
default: ${{ github.server_url == 'https://github.com' && github.token || '' }}
|
||||
mvn-toolchain-id:
|
||||
description: 'Name of Maven Toolchain ID if the default name of "${distribution}_${java-version}" is not wanted. See examples of supported syntax in Advanced Usage file'
|
||||
|
||||
Vendored
+2595
-2230
File diff suppressed because one or more lines are too long
Vendored
+3596
-3159
File diff suppressed because one or more lines are too long
@@ -34,7 +34,7 @@ Requiring a default version will break users that are pinned to `@main` as they
|
||||
|
||||
`setup-java` should be structured in such a way that will allow the open source community to easily add support for extra distributions.
|
||||
|
||||
Existing code will be restructured so that distribution specific code will be easily separated. Currently the core download logic is in a single file, `installer.ts`. This file will be split up and abstracted out so that there will be no vendor specified logic. Each distribution will have it's own files under `src/distributions` that will contain the core setup logic for a specific distribution.
|
||||
Existing code will be restructured so that distribution specific code will be easily separated. Currently the core download logic is in a single file, `installer.ts`. This file will be split up and abstracted out so that there will be no vendor specified logic. Each distribution will have its own files under `src/distributions` that will contain the core setup logic for a specific distribution.
|
||||
|
||||
```yaml
|
||||
∟ src/
|
||||
|
||||
+1
-1
@@ -16,4 +16,4 @@ This folder includes ADRs for the setup-java action. ADRs are proposed in the fo
|
||||
|
||||
---
|
||||
|
||||
- More information about ADRs can be found [here](https://github.com/joelparkerhenderson/architecture_decision_record).
|
||||
- See [more information about ADRs](https://github.com/joelparkerhenderson/architecture_decision_record).
|
||||
@@ -176,7 +176,7 @@ steps:
|
||||
|
||||
**NOTE:** JetBrains is only available for LTS versions on 11 or later (11, 17, 21, etc.).
|
||||
|
||||
Not all minor LTS versions are guarenteed to be available, since JetBrains considers what to ship IntelliJ IDEA with, most commonly on JDK 11.
|
||||
Not all minor LTS versions are guaranteed to be available, since JetBrains considers what to ship IntelliJ IDEA with, most commonly on JDK 11.
|
||||
For example, `11.0.24` is not available but `11.0.16` is.
|
||||
|
||||
```yaml
|
||||
|
||||
Generated
+2522
-1314
File diff suppressed because it is too large
Load Diff
+11
-11
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "setup-java",
|
||||
"version": "5.2.0",
|
||||
"version": "5.3.0",
|
||||
"private": true,
|
||||
"description": "setup java action",
|
||||
"main": "dist/setup/index.js",
|
||||
@@ -29,7 +29,7 @@
|
||||
"author": "GitHub",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/cache": "^5.0.5",
|
||||
"@actions/cache": "^5.1.0",
|
||||
"@actions/core": "^2.0.3",
|
||||
"@actions/exec": "^2.0.0",
|
||||
"@actions/glob": "^0.5.1",
|
||||
@@ -40,20 +40,20 @@
|
||||
"xmlbuilder2": "^4.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^29.5.14",
|
||||
"@types/node": "^24.1.0",
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/node": "^25.9.3",
|
||||
"@types/semver": "^7.5.8",
|
||||
"@typescript-eslint/eslint-plugin": "^8.35.1",
|
||||
"@typescript-eslint/parser": "^8.35.1",
|
||||
"@vercel/ncc": "^0.38.1",
|
||||
"@typescript-eslint/eslint-plugin": "^8.48.0",
|
||||
"@typescript-eslint/parser": "^8.61.1",
|
||||
"@vercel/ncc": "^0.44.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-prettier": "^8.6.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-jest": "^29.0.1",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"jest": "^29.7.0",
|
||||
"jest-circus": "^29.7.0",
|
||||
"jest": "^30.4.2",
|
||||
"jest-circus": "^30.4.2",
|
||||
"prettier": "^3.6.2",
|
||||
"ts-jest": "^29.3.0",
|
||||
"ts-jest": "^29.4.11",
|
||||
"typescript": "^5.3.3"
|
||||
},
|
||||
"bugs": {
|
||||
|
||||
+14
-3
@@ -23,9 +23,12 @@ interface PackageManager {
|
||||
const supportedPackageManager: PackageManager[] = [
|
||||
{
|
||||
id: 'maven',
|
||||
path: [join(os.homedir(), '.m2', 'repository')],
|
||||
path: [
|
||||
join(os.homedir(), '.m2', 'repository'),
|
||||
join(os.homedir(), '.m2', 'wrapper', 'dists')
|
||||
],
|
||||
// https://github.com/actions/cache/blob/0638051e9af2c23d10bb70fa9beffcad6cff9ce3/examples.md#java---maven
|
||||
pattern: ['**/pom.xml']
|
||||
pattern: ['**/pom.xml', '**/.mvn/wrapper/maven-wrapper.properties']
|
||||
},
|
||||
{
|
||||
id: 'gradle',
|
||||
@@ -146,7 +149,15 @@ export async function save(id: string) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await cache.saveCache(packageManager.path, primaryKey);
|
||||
const cacheId = await cache.saveCache(packageManager.path, primaryKey);
|
||||
if (cacheId === -1) {
|
||||
// saveCache returns -1 without throwing when the cache was not saved,
|
||||
// e.g. a reserve collision or a read-only token (fork PR). @actions/cache
|
||||
// has already logged the reason at the appropriate severity, so just
|
||||
// trace it instead of misreporting that the cache was saved.
|
||||
core.debug(`Cache was not saved for the key: ${primaryKey}`);
|
||||
return;
|
||||
}
|
||||
core.info(`Cache saved with the key: ${primaryKey}`);
|
||||
} catch (error) {
|
||||
const err = error as Error;
|
||||
|
||||
@@ -14,10 +14,14 @@ import {
|
||||
} from '../base-models';
|
||||
import {
|
||||
extractJdkFile,
|
||||
getNextPageUrlFromLinkHeader,
|
||||
getDownloadArchiveExtension,
|
||||
isVersionSatisfies,
|
||||
renameWinArchive
|
||||
renameWinArchive,
|
||||
MAX_PAGINATION_PAGES,
|
||||
validatePaginationUrl
|
||||
} from '../../util';
|
||||
import {TemurinDistribution, TemurinImplementation} from '../temurin/installer';
|
||||
|
||||
export enum AdoptImplementation {
|
||||
Hotspot = 'Hotspot',
|
||||
@@ -25,15 +29,72 @@ export enum AdoptImplementation {
|
||||
}
|
||||
|
||||
export class AdoptDistribution extends JavaBase {
|
||||
private readonly temurinDistribution: TemurinDistribution | null;
|
||||
|
||||
constructor(
|
||||
installerOptions: JavaInstallerOptions,
|
||||
private readonly jvmImpl: AdoptImplementation
|
||||
private readonly jvmImpl: AdoptImplementation,
|
||||
temurinDistribution: TemurinDistribution | null = null
|
||||
) {
|
||||
super(`Adopt-${jvmImpl}`, installerOptions);
|
||||
|
||||
if (
|
||||
temurinDistribution !== null &&
|
||||
jvmImpl !== AdoptImplementation.Hotspot
|
||||
) {
|
||||
throw new Error('Only Hotspot JVM is supported by Temurin.');
|
||||
}
|
||||
|
||||
// Only use the temurin repo for Hotspot JVMs
|
||||
this.temurinDistribution =
|
||||
temurinDistribution ??
|
||||
(jvmImpl === AdoptImplementation.Hotspot
|
||||
? new TemurinDistribution(
|
||||
installerOptions,
|
||||
TemurinImplementation.Hotspot
|
||||
)
|
||||
: null);
|
||||
}
|
||||
|
||||
protected async findPackageForDownload(
|
||||
version: string
|
||||
): Promise<JavaDownloadRelease> {
|
||||
if (this.jvmImpl === AdoptImplementation.Hotspot) {
|
||||
core.notice(
|
||||
"AdoptOpenJDK has moved to Eclipse Temurin https://github.com/actions/setup-java#supported-distributions please consider changing to the 'temurin' distribution type in your setup-java configuration."
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
this.jvmImpl === AdoptImplementation.Hotspot &&
|
||||
this.temurinDistribution !== null
|
||||
) {
|
||||
try {
|
||||
return await this.temurinDistribution.findPackageForDownload(version);
|
||||
} catch (error) {
|
||||
// Log the failure but always fall back to legacy AdoptOpenJDK for resilience
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : String(error);
|
||||
if (error instanceof Error && error.name === 'VersionNotFoundError') {
|
||||
core.notice(
|
||||
'The JVM you are looking for could not be found in the Temurin repository, this likely indicates ' +
|
||||
'that you are using an out of date version of Java, consider updating and moving to using the Temurin distribution type in setup-java.'
|
||||
);
|
||||
} else {
|
||||
// Log other errors for debugging but gracefully fall back
|
||||
core.debug(
|
||||
`Temurin lookup failed: ${errorMessage}. Falling back to AdoptOpenJDK API.`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// failed to find a Temurin version, so fall back to AdoptOpenJDK
|
||||
return this.findPackageForDownloadOldAdoptOpenJdk(version);
|
||||
}
|
||||
|
||||
private async findPackageForDownloadOldAdoptOpenJdk(
|
||||
version: string
|
||||
): Promise<JavaDownloadRelease> {
|
||||
const availableVersionsRaw = await this.getAvailableVersions();
|
||||
const availableVersionsWithBinaries = availableVersionsRaw
|
||||
@@ -54,15 +115,10 @@ export class AdoptDistribution extends JavaBase {
|
||||
const resolvedFullVersion =
|
||||
satisfiedVersions.length > 0 ? satisfiedVersions[0] : null;
|
||||
if (!resolvedFullVersion) {
|
||||
const availableOptions = availableVersionsWithBinaries
|
||||
.map(item => item.version)
|
||||
.join(', ');
|
||||
const availableOptionsMessage = availableOptions
|
||||
? `\nAvailable versions: ${availableOptions}`
|
||||
: '';
|
||||
throw new Error(
|
||||
`Could not find satisfied version for SemVer '${version}'. ${availableOptionsMessage}`
|
||||
const availableVersionStrings = availableVersionsWithBinaries.map(
|
||||
item => item.version
|
||||
);
|
||||
throw this.createVersionNotFoundError(version, availableVersionStrings);
|
||||
}
|
||||
|
||||
return resolvedFullVersion;
|
||||
@@ -130,30 +186,46 @@ export class AdoptDistribution extends JavaBase {
|
||||
`jvm_impl=${this.jvmImpl.toLowerCase()}`
|
||||
].join('&');
|
||||
|
||||
// need to iterate through all pages to retrieve the list of all versions
|
||||
// Adopt API doesn't provide way to retrieve the count of pages to iterate so infinity loop
|
||||
let page_index = 0;
|
||||
const requestArguments = `${baseRequestArguments}&page_size=20&page=0`;
|
||||
let availableVersionsUrl: string | null =
|
||||
`https://api.adoptopenjdk.net/v3/assets/version/${versionRange}?${requestArguments}`;
|
||||
const availableVersions: IAdoptAvailableVersions[] = [];
|
||||
while (true) {
|
||||
const requestArguments = `${baseRequestArguments}&page_size=20&page=${page_index}`;
|
||||
const availableVersionsUrl = `https://api.adoptopenjdk.net/v3/assets/version/${versionRange}?${requestArguments}`;
|
||||
if (core.isDebug() && page_index === 0) {
|
||||
// url is identical except page_index so print it once for debug
|
||||
core.debug(
|
||||
`Gathering available versions from '${availableVersionsUrl}'`
|
||||
);
|
||||
let pageCount = 0;
|
||||
if (core.isDebug()) {
|
||||
core.debug(`Gathering available versions from '${availableVersionsUrl}'`);
|
||||
}
|
||||
|
||||
const paginationPage = (
|
||||
await this.http.getJson<IAdoptAvailableVersions[]>(availableVersionsUrl)
|
||||
).result;
|
||||
while (availableVersionsUrl) {
|
||||
pageCount++;
|
||||
const response =
|
||||
await this.http.getJson<IAdoptAvailableVersions[]>(
|
||||
availableVersionsUrl
|
||||
);
|
||||
const paginationPage = response.result;
|
||||
const nextUrl = getNextPageUrlFromLinkHeader(response.headers);
|
||||
if (
|
||||
nextUrl &&
|
||||
!validatePaginationUrl(nextUrl, 'https://api.adoptopenjdk.net')
|
||||
) {
|
||||
core.warning(
|
||||
`Ignoring pagination link with unexpected origin: ${nextUrl}`
|
||||
);
|
||||
availableVersionsUrl = null;
|
||||
} else {
|
||||
availableVersionsUrl = nextUrl;
|
||||
}
|
||||
if (paginationPage === null || paginationPage.length === 0) {
|
||||
// break infinity loop because we have reached end of pagination
|
||||
break;
|
||||
}
|
||||
|
||||
availableVersions.push(...paginationPage);
|
||||
page_index++;
|
||||
|
||||
if (pageCount >= MAX_PAGINATION_PAGES) {
|
||||
core.warning(
|
||||
`Reached pagination safeguard limit (${MAX_PAGINATION_PAGES} pages) while listing Adopt releases.`
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (core.isDebug()) {
|
||||
|
||||
@@ -259,6 +259,44 @@ export abstract class JavaBase {
|
||||
};
|
||||
}
|
||||
|
||||
protected createVersionNotFoundError(
|
||||
versionOrRange: string,
|
||||
availableVersions?: string[],
|
||||
additionalContext?: string
|
||||
): Error {
|
||||
const parts = [
|
||||
`No matching version found for SemVer '${versionOrRange}'.`,
|
||||
`Distribution: ${this.distribution}`,
|
||||
`Package type: ${this.packageType}`,
|
||||
`Architecture: ${this.architecture}`
|
||||
];
|
||||
|
||||
// Add additional context if provided (e.g., platform/OS info)
|
||||
if (additionalContext) {
|
||||
parts.push(additionalContext);
|
||||
}
|
||||
|
||||
if (availableVersions && availableVersions.length > 0) {
|
||||
const maxVersionsToShow = core.isDebug() ? availableVersions.length : 50;
|
||||
const versionsToShow = availableVersions.slice(0, maxVersionsToShow);
|
||||
const truncated = availableVersions.length > maxVersionsToShow;
|
||||
|
||||
parts.push(
|
||||
`Available versions: ${versionsToShow.join(', ')}${truncated ? ', ...' : ''}`
|
||||
);
|
||||
|
||||
if (truncated) {
|
||||
parts.push(
|
||||
`(showing first ${maxVersionsToShow} of ${availableVersions.length} versions, enable debug mode to see all)`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const error = new Error(parts.join('\n'));
|
||||
error.name = 'VersionNotFoundError';
|
||||
return error;
|
||||
}
|
||||
|
||||
protected setJavaDefault(version: string, toolPath: string) {
|
||||
const majorVersion = version.split('.')[0];
|
||||
core.exportVariable('JAVA_HOME', toolPath);
|
||||
|
||||
@@ -75,15 +75,10 @@ export class CorrettoDistribution extends JavaBase {
|
||||
const resolvedVersion =
|
||||
matchingVersions.length > 0 ? matchingVersions[0] : null;
|
||||
if (!resolvedVersion) {
|
||||
const availableOptions = availableVersions
|
||||
.map(item => item.version)
|
||||
.join(', ');
|
||||
const availableOptionsMessage = availableOptions
|
||||
? `\nAvailable versions: ${availableOptions}`
|
||||
: '';
|
||||
throw new Error(
|
||||
`Could not find satisfied version for SemVer '${version}'. ${availableOptionsMessage}`
|
||||
const availableVersionStrings = availableVersions.map(
|
||||
item => item.version
|
||||
);
|
||||
throw this.createVersionNotFoundError(version, availableVersionStrings);
|
||||
}
|
||||
return resolvedVersion;
|
||||
}
|
||||
|
||||
@@ -51,9 +51,10 @@ export class DragonwellDistribution extends JavaBase {
|
||||
});
|
||||
|
||||
if (!matchedVersions.length) {
|
||||
throw new Error(
|
||||
`Couldn't find any satisfied version for the specified java-version: "${version}" and architecture: "${this.architecture}".`
|
||||
const availableVersionStrings = availableVersions.map(
|
||||
item => item.jdk_version
|
||||
);
|
||||
throw this.createVersionNotFoundError(version, availableVersionStrings);
|
||||
}
|
||||
|
||||
const resolvedVersion = matchedVersions[0];
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
} from '../../util';
|
||||
|
||||
const GRAALVM_DL_BASE = 'https://download.oracle.com/graalvm';
|
||||
const GRAALVM_DOWNLOAD_URL = 'https://www.graalvm.org/downloads/';
|
||||
const IS_WINDOWS = process.platform === 'win32';
|
||||
const GRAALVM_PLATFORM = IS_WINDOWS ? 'windows' : process.platform;
|
||||
const GRAALVM_MIN_VERSION = 17;
|
||||
@@ -149,9 +150,10 @@ export class GraalVMDistribution extends JavaBase {
|
||||
const statusCode = response.message.statusCode;
|
||||
|
||||
if (statusCode === HttpCodes.NotFound) {
|
||||
throw new Error(
|
||||
`Could not find GraalVM for SemVer ${range}. Please check if this version is available at ${GRAALVM_DL_BASE}`
|
||||
);
|
||||
// Create the standard error with additional hint about checking the download URL
|
||||
const error = this.createVersionNotFoundError(range);
|
||||
error.message += `\nPlease check if this version is available at ${GRAALVM_DOWNLOAD_URL} . Pick a version from the list.`;
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (
|
||||
@@ -180,10 +182,12 @@ export class GraalVMDistribution extends JavaBase {
|
||||
|
||||
const latestVersion = versions.find(v => v.latest);
|
||||
if (!latestVersion) {
|
||||
core.error(
|
||||
`Available versions: ${versions.map(v => v.version).join(', ')}`
|
||||
const availableVersions = versions.map(v => v.version);
|
||||
throw this.createVersionNotFoundError(
|
||||
javaEaVersion,
|
||||
availableVersions,
|
||||
'Note: No EA build is marked as latest for this version.'
|
||||
);
|
||||
throw new Error(`Unable to find latest version for '${javaEaVersion}'`);
|
||||
}
|
||||
|
||||
core.debug(`Latest version found: ${latestVersion.version}`);
|
||||
|
||||
@@ -44,15 +44,10 @@ export class JetBrainsDistribution extends JavaBase {
|
||||
const resolvedFullVersion =
|
||||
satisfiedVersions.length > 0 ? satisfiedVersions[0] : null;
|
||||
if (!resolvedFullVersion) {
|
||||
const availableOptions = versionsRaw
|
||||
.map(item => `${item.tag_name} (${item.semver}+${item.build})`)
|
||||
.join(', ');
|
||||
const availableOptionsMessage = availableOptions
|
||||
? `\nAvailable versions: ${availableOptions}`
|
||||
: '';
|
||||
throw new Error(
|
||||
`Could not find satisfied version for SemVer '${range}'. ${availableOptionsMessage}`
|
||||
const availableVersionStrings = versionsRaw.map(
|
||||
item => `${item.tag_name} (${item.semver}+${item.build})`
|
||||
);
|
||||
throw this.createVersionNotFoundError(range, availableVersionStrings);
|
||||
}
|
||||
|
||||
return resolvedFullVersion;
|
||||
|
||||
@@ -69,15 +69,10 @@ export class LibericaDistributions extends JavaBase {
|
||||
.sort((a, b) => -semver.compareBuild(a.version, b.version))[0];
|
||||
|
||||
if (!satisfiedVersion) {
|
||||
const availableOptions = availableVersions
|
||||
.map(item => item.version)
|
||||
.join(', ');
|
||||
const availableOptionsMessage = availableOptions
|
||||
? `\nAvailable versions: ${availableOptions}`
|
||||
: '';
|
||||
throw new Error(
|
||||
`Could not find satisfied version for semver ${range}. ${availableOptionsMessage}`
|
||||
const availableVersionStrings = availableVersions.map(
|
||||
item => item.version
|
||||
);
|
||||
throw this.createVersionNotFoundError(range, availableVersionStrings);
|
||||
}
|
||||
|
||||
return satisfiedVersion;
|
||||
|
||||
@@ -76,11 +76,8 @@ export class MicrosoftDistributions extends JavaBase {
|
||||
const foundRelease = await tc.findFromManifest(range, true, manifest, arch);
|
||||
|
||||
if (!foundRelease) {
|
||||
throw new Error(
|
||||
`Could not find satisfied version for SemVer ${range}.\nAvailable versions: ${manifest
|
||||
.map(item => item.version)
|
||||
.join(', ')}`
|
||||
);
|
||||
const availableVersionStrings = manifest.map(item => item.version);
|
||||
throw this.createVersionNotFoundError(range, availableVersionStrings);
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -171,6 +171,49 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "17.0.18",
|
||||
"stable": true,
|
||||
"release_url": "https://aka.ms/download-jdk",
|
||||
"files": [
|
||||
{
|
||||
"filename": "microsoft-jdk-17.0.18-macos-x64.tar.gz",
|
||||
"arch": "x64",
|
||||
"platform": "darwin",
|
||||
"download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-macos-x64.tar.gz"
|
||||
},
|
||||
{
|
||||
"filename": "microsoft-jdk-17.0.18-linux-x64.tar.gz",
|
||||
"arch": "x64",
|
||||
"platform": "linux",
|
||||
"download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-linux-x64.tar.gz"
|
||||
},
|
||||
{
|
||||
"filename": "microsoft-jdk-17.0.18-windows-x64.zip",
|
||||
"arch": "x64",
|
||||
"platform": "win32",
|
||||
"download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-windows-x64.zip"
|
||||
},
|
||||
{
|
||||
"filename": "microsoft-jdk-17.0.18-macos-aarch64.tar.gz",
|
||||
"arch": "aarch64",
|
||||
"platform": "darwin",
|
||||
"download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-macos-aarch64.tar.gz"
|
||||
},
|
||||
{
|
||||
"filename": "microsoft-jdk-17.0.18-linux-aarch64.tar.gz",
|
||||
"arch": "aarch64",
|
||||
"platform": "linux",
|
||||
"download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-linux-aarch64.tar.gz"
|
||||
},
|
||||
{
|
||||
"filename": "microsoft-jdk-17.0.18-windows-aarch64.zip",
|
||||
"arch": "aarch64",
|
||||
"platform": "win32",
|
||||
"download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.18-windows-aarch64.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "17.0.10",
|
||||
"stable": true,
|
||||
@@ -180,7 +223,7 @@
|
||||
"filename": "microsoft-jdk-17.0.10-macos-x64.tar.gz",
|
||||
"arch": "x64",
|
||||
"platform": "darwin",
|
||||
"download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.7-macos-x64.tar.gz"
|
||||
"download_url": "https://aka.ms/download-jdk/microsoft-jdk-17.0.10-macos-x64.tar.gz"
|
||||
},
|
||||
{
|
||||
"filename": "microsoft-jdk-17.0.10-linux-x64.tar.gz",
|
||||
|
||||
@@ -112,7 +112,7 @@ export class OracleDistribution extends JavaBase {
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`Could not find Oracle JDK for SemVer ${range}`);
|
||||
throw this.createVersionNotFoundError(range);
|
||||
}
|
||||
|
||||
public getPlatform(platform: NodeJS.Platform = process.platform): OsVersions {
|
||||
|
||||
@@ -49,9 +49,10 @@ export class SapMachineDistribution extends JavaBase {
|
||||
});
|
||||
|
||||
if (!matchedVersions.length) {
|
||||
throw new Error(
|
||||
`Couldn't find any satisfied version for the specified java-version: "${version}" and architecture: "${this.architecture}".`
|
||||
const availableVersionStrings = availableVersions.map(
|
||||
item => item.version
|
||||
);
|
||||
throw this.createVersionNotFoundError(version, availableVersionStrings);
|
||||
}
|
||||
|
||||
const resolvedVersion = matchedVersions[0];
|
||||
|
||||
@@ -7,9 +7,12 @@ import {
|
||||
import semver from 'semver';
|
||||
import {
|
||||
extractJdkFile,
|
||||
getNextPageUrlFromLinkHeader,
|
||||
getDownloadArchiveExtension,
|
||||
isVersionSatisfies,
|
||||
renameWinArchive
|
||||
renameWinArchive,
|
||||
MAX_PAGINATION_PAGES,
|
||||
validatePaginationUrl
|
||||
} from '../../util';
|
||||
import * as core from '@actions/core';
|
||||
import * as tc from '@actions/tool-cache';
|
||||
@@ -79,14 +82,16 @@ export class SemeruDistribution extends JavaBase {
|
||||
const resolvedFullVersion =
|
||||
satisfiedVersions.length > 0 ? satisfiedVersions[0] : null;
|
||||
if (!resolvedFullVersion) {
|
||||
const availableOptions = availableVersionsWithBinaries
|
||||
.map(item => item.version)
|
||||
.join(', ');
|
||||
const availableOptionsMessage = availableOptions
|
||||
? `\nAvailable versions: ${availableOptions}`
|
||||
: '';
|
||||
throw new Error(
|
||||
`Could not find satisfied version for SemVer version '${version}' for your current OS version for ${this.architecture} architecture ${availableOptionsMessage}`
|
||||
const availableVersionStrings = availableVersionsWithBinaries.map(
|
||||
item => item.version
|
||||
);
|
||||
// Include platform context to help users understand OS-specific version availability
|
||||
// IBM Semeru builds are OS-specific, so platform info aids in troubleshooting
|
||||
const platformContext = `Platform: ${process.platform}`;
|
||||
throw this.createVersionNotFoundError(
|
||||
version,
|
||||
availableVersionStrings,
|
||||
platformContext
|
||||
);
|
||||
}
|
||||
|
||||
@@ -153,32 +158,46 @@ export class SemeruDistribution extends JavaBase {
|
||||
`jvm_impl=openj9`
|
||||
].join('&');
|
||||
|
||||
// need to iterate through all pages to retrieve the list of all versions
|
||||
// Adoptium API doesn't provide way to retrieve the count of pages to iterate so infinity loop
|
||||
let page_index = 0;
|
||||
const requestArguments = `${baseRequestArguments}&page_size=20&page=0`;
|
||||
let availableVersionsUrl: string | null =
|
||||
`https://api.adoptopenjdk.net/v3/assets/version/${versionRange}?${requestArguments}`;
|
||||
const availableVersions: ISemeruAvailableVersions[] = [];
|
||||
while (true) {
|
||||
const requestArguments = `${baseRequestArguments}&page_size=20&page=${page_index}`;
|
||||
const availableVersionsUrl = `https://api.adoptopenjdk.net/v3/assets/version/${versionRange}?${requestArguments}`;
|
||||
if (core.isDebug() && page_index === 0) {
|
||||
// url is identical except page_index so print it once for debug
|
||||
core.debug(
|
||||
`Gathering available versions from '${availableVersionsUrl}'`
|
||||
);
|
||||
let pageCount = 0;
|
||||
if (core.isDebug()) {
|
||||
core.debug(`Gathering available versions from '${availableVersionsUrl}'`);
|
||||
}
|
||||
|
||||
const paginationPage = (
|
||||
while (availableVersionsUrl) {
|
||||
pageCount++;
|
||||
const response =
|
||||
await this.http.getJson<ISemeruAvailableVersions[]>(
|
||||
availableVersionsUrl
|
||||
)
|
||||
).result;
|
||||
);
|
||||
const paginationPage = response.result;
|
||||
const nextUrl = getNextPageUrlFromLinkHeader(response.headers);
|
||||
if (
|
||||
nextUrl &&
|
||||
!validatePaginationUrl(nextUrl, 'https://api.adoptopenjdk.net')
|
||||
) {
|
||||
core.warning(
|
||||
`Ignoring pagination link with unexpected origin: ${nextUrl}`
|
||||
);
|
||||
availableVersionsUrl = null;
|
||||
} else {
|
||||
availableVersionsUrl = nextUrl;
|
||||
}
|
||||
if (paginationPage === null || paginationPage.length === 0) {
|
||||
// break infinity loop because we have reached end of pagination
|
||||
break;
|
||||
}
|
||||
|
||||
availableVersions.push(...paginationPage);
|
||||
page_index++;
|
||||
|
||||
if (pageCount >= MAX_PAGINATION_PAGES) {
|
||||
core.warning(
|
||||
`Reached pagination safeguard limit (${MAX_PAGINATION_PAGES} pages) while listing Semeru releases.`
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (core.isDebug()) {
|
||||
|
||||
@@ -14,9 +14,12 @@ import {
|
||||
} from '../base-models';
|
||||
import {
|
||||
extractJdkFile,
|
||||
getNextPageUrlFromLinkHeader,
|
||||
getDownloadArchiveExtension,
|
||||
isVersionSatisfies,
|
||||
renameWinArchive
|
||||
renameWinArchive,
|
||||
MAX_PAGINATION_PAGES,
|
||||
validatePaginationUrl
|
||||
} from '../../util';
|
||||
|
||||
export enum TemurinImplementation {
|
||||
@@ -31,7 +34,10 @@ export class TemurinDistribution extends JavaBase {
|
||||
super(`Temurin-${jvmImpl}`, installerOptions);
|
||||
}
|
||||
|
||||
protected async findPackageForDownload(
|
||||
/**
|
||||
* @internal For cross-distribution reuse only. Not intended as a public API.
|
||||
*/
|
||||
public async findPackageForDownload(
|
||||
version: string
|
||||
): Promise<JavaDownloadRelease> {
|
||||
const availableVersionsRaw = await this.getAvailableVersions();
|
||||
@@ -57,15 +63,10 @@ export class TemurinDistribution extends JavaBase {
|
||||
const resolvedFullVersion =
|
||||
satisfiedVersions.length > 0 ? satisfiedVersions[0] : null;
|
||||
if (!resolvedFullVersion) {
|
||||
const availableOptions = availableVersionsWithBinaries
|
||||
.map(item => item.version)
|
||||
.join(', ');
|
||||
const availableOptionsMessage = availableOptions
|
||||
? `\nAvailable versions: ${availableOptions}`
|
||||
: '';
|
||||
throw new Error(
|
||||
`Could not find satisfied version for SemVer '${version}'. ${availableOptionsMessage}`
|
||||
const availableVersionStrings = availableVersionsWithBinaries.map(
|
||||
item => item.version
|
||||
);
|
||||
throw this.createVersionNotFoundError(version, availableVersionStrings);
|
||||
}
|
||||
|
||||
return resolvedFullVersion;
|
||||
@@ -128,32 +129,47 @@ export class TemurinDistribution extends JavaBase {
|
||||
`jvm_impl=${this.jvmImpl.toLowerCase()}`
|
||||
].join('&');
|
||||
|
||||
// need to iterate through all pages to retrieve the list of all versions
|
||||
// Adoptium API doesn't provide way to retrieve the count of pages to iterate so infinity loop
|
||||
let page_index = 0;
|
||||
const requestArguments = `${baseRequestArguments}&page_size=20&page=0`;
|
||||
let availableVersionsUrl: string | null =
|
||||
`https://api.adoptium.net/v3/assets/version/${versionRange}?${requestArguments}`;
|
||||
const availableVersions: ITemurinAvailableVersions[] = [];
|
||||
while (true) {
|
||||
const requestArguments = `${baseRequestArguments}&page_size=20&page=${page_index}`;
|
||||
const availableVersionsUrl = `https://api.adoptium.net/v3/assets/version/${versionRange}?${requestArguments}`;
|
||||
if (core.isDebug() && page_index === 0) {
|
||||
// url is identical except page_index so print it once for debug
|
||||
core.debug(
|
||||
`Gathering available versions from '${availableVersionsUrl}'`
|
||||
);
|
||||
let pageCount = 0;
|
||||
if (core.isDebug()) {
|
||||
core.debug(`Gathering available versions from '${availableVersionsUrl}'`);
|
||||
}
|
||||
|
||||
const paginationPage = (
|
||||
while (availableVersionsUrl) {
|
||||
pageCount++;
|
||||
const response =
|
||||
await this.http.getJson<ITemurinAvailableVersions[]>(
|
||||
availableVersionsUrl
|
||||
)
|
||||
).result;
|
||||
);
|
||||
const paginationPage = response.result;
|
||||
const nextUrl = getNextPageUrlFromLinkHeader(response.headers);
|
||||
if (
|
||||
nextUrl &&
|
||||
!validatePaginationUrl(nextUrl, 'https://api.adoptium.net')
|
||||
) {
|
||||
core.warning(
|
||||
`Ignoring pagination link with unexpected origin: ${nextUrl}`
|
||||
);
|
||||
availableVersionsUrl = null;
|
||||
} else {
|
||||
availableVersionsUrl = nextUrl;
|
||||
}
|
||||
|
||||
if (paginationPage === null || paginationPage.length === 0) {
|
||||
// break infinity loop because we have reached end of pagination
|
||||
break;
|
||||
}
|
||||
|
||||
availableVersions.push(...paginationPage);
|
||||
page_index++;
|
||||
|
||||
if (pageCount >= MAX_PAGINATION_PAGES) {
|
||||
core.warning(
|
||||
`Reached pagination safeguard limit (${MAX_PAGINATION_PAGES} pages) while listing Temurin releases.`
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (core.isDebug()) {
|
||||
@@ -176,6 +192,11 @@ export class TemurinDistribution extends JavaBase {
|
||||
return 'mac';
|
||||
case 'win32':
|
||||
return 'windows';
|
||||
case 'linux':
|
||||
if (fs.existsSync('/etc/alpine-release')) {
|
||||
return 'alpine-linux';
|
||||
}
|
||||
return 'linux';
|
||||
default:
|
||||
return process.platform;
|
||||
}
|
||||
|
||||
@@ -57,15 +57,10 @@ export class ZuluDistribution extends JavaBase {
|
||||
const resolvedFullVersion =
|
||||
satisfiedVersions.length > 0 ? satisfiedVersions[0] : null;
|
||||
if (!resolvedFullVersion) {
|
||||
const availableOptions = availableVersions
|
||||
.map(item => item.version)
|
||||
.join(', ');
|
||||
const availableOptionsMessage = availableOptions
|
||||
? `\nAvailable versions: ${availableOptions}`
|
||||
: '';
|
||||
throw new Error(
|
||||
`Could not find satisfied version for semver ${version}. ${availableOptionsMessage}`
|
||||
const availableVersionStrings = availableVersions.map(
|
||||
item => item.version
|
||||
);
|
||||
throw this.createVersionNotFoundError(version, availableVersionStrings);
|
||||
}
|
||||
|
||||
return resolvedFullVersion;
|
||||
|
||||
+57
@@ -55,6 +55,14 @@ export function getDownloadArchiveExtension() {
|
||||
}
|
||||
|
||||
export function isVersionSatisfies(range: string, version: string): boolean {
|
||||
// Some distributions (e.g. JetBrains Runtime) publish 4-segment versions
|
||||
// like '17.0.8.1+1080.1' that semver rejects. If the candidate version
|
||||
// isn't valid semver, it can't match — bail out rather than letting
|
||||
// compareBuild / satisfies throw.
|
||||
if (!semver.valid(version)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (semver.valid(range)) {
|
||||
// if full version with build digit is provided as a range (such as '1.2.3+4')
|
||||
// we should check for exact equal via compareBuild
|
||||
@@ -201,6 +209,55 @@ export function getGitHubHttpHeaders(): OutgoingHttpHeaders {
|
||||
return headers;
|
||||
}
|
||||
|
||||
export const MAX_PAGINATION_PAGES = 1000;
|
||||
|
||||
export function getNextPageUrlFromLinkHeader(
|
||||
headers?: Record<string, string | string[] | undefined>
|
||||
): string | null {
|
||||
if (!headers) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const linkHeader = headers.link ?? headers.Link;
|
||||
if (!linkHeader) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const normalizedLinkHeader = Array.isArray(linkHeader)
|
||||
? linkHeader.join(',')
|
||||
: linkHeader;
|
||||
|
||||
// Split into individual link-values and find the one with rel="next"
|
||||
// RFC 8288 allows rel to appear anywhere among the parameters
|
||||
const linkValues = normalizedLinkHeader.split(/,(?=\s*<)/);
|
||||
for (const linkValue of linkValues) {
|
||||
const urlMatch = linkValue.match(/<([^>]+)>/);
|
||||
if (!urlMatch) continue;
|
||||
|
||||
const params = linkValue.slice(urlMatch[0].length);
|
||||
// Use word boundary to match "next" as a standalone relation type
|
||||
// RFC 8288 allows space-separated relation types like rel="next prev"
|
||||
if (/;\s*rel="?[^"]*\bnext\b/i.test(params)) {
|
||||
return urlMatch[1];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function validatePaginationUrl(
|
||||
url: string,
|
||||
allowedOrigin: string
|
||||
): boolean {
|
||||
try {
|
||||
const parsed = new URL(url);
|
||||
const allowed = new URL(allowedOrigin);
|
||||
return parsed.origin === allowed.origin;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Rename archive to add extension because after downloading
|
||||
// archive does not contain extension type and it leads to some issues
|
||||
// on Windows runners without PowerShell Core.
|
||||
|
||||
Reference in New Issue
Block a user