Compare commits

...
14 Commits
Author SHA1 Message Date
MaksimZhukov 3bc31aaf88 Merge pull request #210 from dmitry-shibanov/v-dmshib/suppress-test-log-output
Suppress warning/debug/info output from tests
2021-08-23 14:47:51 +03:00
Dmitry Shibanov 30cd52e29b fix warning output in cleanup-java 2021-08-23 11:54:48 +03:00
Dmitry Shibanov 2e40ee8132 suppress tests log output 2021-08-23 11:31:06 +03:00
Maxim Lobanov c21fb9392d Update readme and test matrix (#209) 2021-08-23 11:09:55 +03:00
08e4e813b8 Introduce the dependency caching for Maven and Gradle (#193)
* implement a core logic to cache dependnecies

* integrate the cache logic to entry points

* add a user doc about the dependency cache feature

* reflect changes to the dist dir

* add a prefix to the cache key

https://github.com/actions/setup-java/pull/193/files#r669521434

* test: extract build.gradle to a file in __tests__ dir

* run the restore e2e test on the specified OS

* add an e2e test for maven

* fix the dependency among workflows

* stabilize the cache on the Windows in e2e test

* add .gitignore files to __tests__/cache directories

* try to run restore after the authentication

* use the key in state to save caches in the post process

* suggest users to run without daemon if fail to save Gradle cache on Windows

* add missing description in the README.md

* run clean-up tasks in serial

* Add validation for post step (#3)

* work on fixing cache post step

* fix tests

* Update src/cleanup-java.ts

Co-authored-by: Konrad Pabjan <konradpabjan@github.com>

* Update src/cache.ts

Co-authored-by: Konrad Pabjan <konradpabjan@github.com>

* style: put the name of input to the constants.ts

* format: run `npm run build` to reflect changes to the dist dir

* chore: update licensed files by `licensed cache`

it still has three errors as follows:
>* setup-java.npm.sax
>  filename: /Users/kengo/GitHub/setup-java/.licenses/npm/sax.dep.yml
>    - license needs review: other
>
>* setup-java.npm.tslib-1.14.1
>  filename: /Users/kengo/GitHub/setup-java/.licenses/npm/tslib-1.14.1.dep.yml
>    - license needs review: 0bsd
>
>* setup-java.npm.tslib-2.3.0
>  filename: /Users/kengo/GitHub/setup-java/.licenses/npm/tslib-2.3.0.dep.yml
>    - license needs review: 0bsd

* fix: rerun ncc on macOS with node v12

* build: follow the suggestion at PR page

https://github.com/actions/setup-java/pull/193#issuecomment-901839546

* fix: throw error in case of no package manager file found

Co-authored-by: Dmitry Shibanov <dmitry-shibanov@github.com>
Co-authored-by: Konrad Pabjan <konradpabjan@github.com>
2021-08-19 20:19:35 +03:00
Jochen SchalandaandMaxim Lobanov 4b1b3d4a82 Add support for Eclipse Temurin (#201)
* Add support for Adoptium OpenJDK

Refs https://github.com/actions/setup-java/issues/191

* Rename distribution to Eclipse Temurin

* Update end-to-end tests in GitHub workflows

* Exclude e2e tests for Temurin JREs for now

* fix version

* Update e2e-versions.yml

* Handle Eclipse Temurin version suffixes ("beta")

* Add test for new version suffix "beta"

* Add updated `index.js`

* fix an issue

Co-authored-by: Maxim Lobanov <maxim-lobanov@github.com>
2021-08-06 13:12:36 +03:00
MaksimZhukovandMaksimZhukov ad01d131cc Automate releasing new versions of the "setup-java" action (#182)
* Automate releasing new versions of the setup-java action

* Use permissions as a top-level key

Co-authored-by: MaksimZhukov <v-mazhuk@microsoft.com>
2021-05-27 17:28:08 +03:00
dependabot[bot] d9126d7df2 Bump hosted-git-info from 2.8.8 to 2.8.9 (#178)
Bumps [hosted-git-info](https://github.com/npm/hosted-git-info) from 2.8.8 to 2.8.9.
- [Release notes](https://github.com/npm/hosted-git-info/releases)
- [Changelog](https://github.com/npm/hosted-git-info/blob/v2.8.9/CHANGELOG.md)
- [Commits](https://github.com/npm/hosted-git-info/compare/v2.8.8...v2.8.9)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-17 16:38:14 +03:00
Marcono1234 53ac717e09 Improve README and advanced usage guide (#174) 2021-05-17 16:38:02 +03:00
Marcel cbc183b1c1 Added 'adopt-hotspot' and 'adopt-openj9' (#155)
* Added 'adopt-hotspot' and 'adopt-openj9'

* Fixed adopt toolchain folder
2021-05-17 16:33:21 +03:00
Dmitry Shibanov 0443912ed7 Fix typo in documentation "jdkfile" (#167) 2021-04-14 11:33:57 +03:00
Manuel 56b2808da7 Fix typo on distribution "jdkfile" (#163)
Its jdkfile and not "jdkFile", see https://github.com/actions/setup-java/blob/b53500dabc37db6cc1dcd35059bdcd85df25d140/src/distributions/distribution-factory.ts#L10
2021-04-12 20:14:22 +03:00
Dmitry Shibanov 00401c4488 add cron for e2e tests, twice a day (#162) 2021-04-12 11:08:05 +03:00
Nuh Koca 1e063f2878 Fix navigation issue of supported distributions (#153) 2021-04-05 17:59:08 +03:00
80 changed files with 126764 additions and 734 deletions
+113
View File
@@ -0,0 +1,113 @@
name: Validate cache
on:
push:
branches:
- main
- releases/*
paths-ignore:
- '**.md'
pull_request:
paths-ignore:
- '**.md'
defaults:
run:
shell: bash
jobs:
gradle-save:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, windows-latest, ubuntu-latest]
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Run setup-java with the cache for gradle
uses: ./
id: setup-java
with:
distribution: 'adopt'
java-version: '11'
cache: gradle
- name: Create files to cache
# Need to avoid using Gradle daemon to stabilize the save process on Windows
# https://github.com/actions/cache/issues/454#issuecomment-840493935
run: |
gradle downloadDependencies --no-daemon -p __tests__/cache/gradle
if [ ! -d ~/.gradle/caches ]; then
echo "::error::The ~/.gradle/caches directory does not exist unexpectedly"
exit 1
fi
gradle-restore:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, windows-latest, ubuntu-latest]
needs: gradle-save
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Run setup-java with the cache for gradle
uses: ./
id: setup-java
with:
distribution: 'adopt'
java-version: '11'
cache: gradle
- name: Confirm that ~/.gradle/caches directory has been made
run: |
if [ ! -d ~/.gradle/caches ]; then
echo "::error::The ~/.gradle/caches directory does not exist unexpectedly"
exit 1
fi
ls ~/.gradle/caches/
maven-save:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, windows-latest, ubuntu-latest]
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Run setup-java with the cache for maven
uses: ./
id: setup-java
with:
distribution: 'adopt'
java-version: '11'
cache: maven
- name: Create files to cache
run: |
mvn verify -f __tests__/cache/maven/pom.xml
if [ ! -d ~/.m2/repository ]; then
echo "::error::The ~/.m2/repository directory does not exist unexpectedly"
exit 1
fi
maven-restore:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, windows-latest, ubuntu-latest]
needs: maven-save
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Run setup-java with the cache for maven
uses: ./
id: setup-java
with:
distribution: 'adopt'
java-version: '11'
cache: maven
- name: Confirm that ~/.m2/repository directory has been made
run: |
if [ ! -d ~/.m2/repository ]; then
echo "::error::The ~/.m2/repository directory does not exist unexpectedly"
exit 1
fi
ls ~/.m2/repository
+38 -1
View File
@@ -83,4 +83,41 @@ jobs:
architecture: x64 architecture: x64
- name: Verify Java version - name: Verify Java version
run: bash __tests__/verify-java.sh "11.0" "${{ steps.setup-java.outputs.path }}" run: bash __tests__/verify-java.sh "11.0" "${{ steps.setup-java.outputs.path }}"
shell: bash shell: bash
setup-java-local-file-temurin:
name: Validate installation from local file Eclipse Temurin
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, windows-latest, ubuntu-latest]
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Download Eclipse Temurin file
run: |
if ($IsLinux) {
$downloadUrl = "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.12%2B7/OpenJDK11U-jdk_x64_linux_hotspot_11.0.12_7.tar.gz"
$localFilename = "java_package.tar.gz"
} elseif ($IsMacOS) {
$downloadUrl = "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.12%2B7/OpenJDK11U-jdk_x64_mac_hotspot_11.0.12_7.tar.gz"
$localFilename = "java_package.tar.gz"
} elseif ($IsWindows) {
$downloadUrl = "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.12%2B7/OpenJDK11U-jdk_x64_windows_hotspot_11.0.12_7.zip"
$localFilename = "java_package.zip"
}
echo "LocalFilename=$localFilename" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
(New-Object System.Net.WebClient).DownloadFile($downloadUrl, "$env:RUNNER_TEMP/$localFilename")
shell: pwsh
- name: setup-java
uses: ./
id: setup-java
with:
distribution: 'jdkfile'
jdkFile: ${{ runner.temp }}/${{ env.LocalFilename }}
java-version: '11.0.0-ea'
architecture: x64
- name: Verify Java version
run: bash __tests__/verify-java.sh "11.0.12" "${{ steps.setup-java.outputs.path }}"
shell: bash
+21 -26
View File
@@ -9,7 +9,9 @@ on:
pull_request: pull_request:
paths-ignore: paths-ignore:
- '**.md' - '**.md'
schedule:
- cron: '0 */12 * * *'
workflow_dispatch:
jobs: jobs:
setup-java-major-versions: setup-java-major-versions:
name: ${{ matrix.distribution }} ${{ matrix.version }} (jdk-x64) - ${{ matrix.os }} name: ${{ matrix.distribution }} ${{ matrix.version }} (jdk-x64) - ${{ matrix.os }}
@@ -18,8 +20,8 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
os: [macos-latest, windows-latest, ubuntu-latest] os: [macos-latest, windows-latest, ubuntu-latest]
distribution: ['adopt', 'zulu'] distribution: ['temurin', 'adopt', 'adopt-openj9', 'zulu'] # internally 'adopt-hotspot' is the same as 'adopt'
version: ['8', '11', '15'] version: ['8', '11', '16']
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v2
@@ -41,21 +43,11 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
os: [macos-latest, windows-latest, ubuntu-latest] os: [macos-latest, windows-latest, ubuntu-latest]
distribution: ['adopt', 'zulu'] distribution: ['temurin', 'zulu']
version: version:
- '11.0' - '11.0'
- '8.0.282' - '8.0.302'
- '11.0.2+7' - '16.0.2+7'
include:
- distribution: 'adopt'
version: '12.0.2+10.1'
os: macos-latest
- distribution: 'adopt'
version: '12.0.2+10.1'
os: windows-latest
- distribution: 'adopt'
version: '12.0.2+10.1'
os: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v2
@@ -77,7 +69,7 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
os: [macos-latest, windows-latest, ubuntu-latest] os: [macos-latest, windows-latest, ubuntu-latest]
distribution: ['adopt', 'zulu'] distribution: ['temurin', 'zulu']
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v2
@@ -91,7 +83,7 @@ jobs:
- name: Verify Java - name: Verify Java
run: bash __tests__/verify-java.sh "11" "${{ steps.setup-java.outputs.path }}" run: bash __tests__/verify-java.sh "11" "${{ steps.setup-java.outputs.path }}"
shell: bash shell: bash
setup-java-ea-versions-zulu: setup-java-ea-versions-zulu:
name: zulu ${{ matrix.version }} (jdk-x64) - ${{ matrix.os }} name: zulu ${{ matrix.version }} (jdk-x64) - ${{ matrix.os }}
needs: setup-java-major-minor-versions needs: setup-java-major-minor-versions
@@ -114,15 +106,15 @@ jobs:
run: bash __tests__/verify-java.sh "${{ matrix.version }}" "${{ steps.setup-java.outputs.path }}" run: bash __tests__/verify-java.sh "${{ matrix.version }}" "${{ steps.setup-java.outputs.path }}"
shell: bash shell: bash
setup-java-ea-versions-adopt: setup-java-ea-versions-temurin:
name: adopt ${{ matrix.version }} (jdk-x64) - ${{ matrix.os }} name: temurin ${{ matrix.version }} (jdk-x64) - ${{ matrix.os }}
needs: setup-java-major-minor-versions needs: setup-java-major-minor-versions
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [macos-latest, windows-latest, ubuntu-latest] os: [macos-latest, windows-latest, ubuntu-latest]
version: ['17-ea', '15.0.0-ea.14.1.202003160455'] version: ['17-ea']
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v2
@@ -131,7 +123,7 @@ jobs:
id: setup-java id: setup-java
with: with:
java-version: ${{ matrix.version }} java-version: ${{ matrix.version }}
distribution: adopt distribution: temurin
- name: Verify Java - name: Verify Java
run: bash __tests__/verify-java.sh "${{ matrix.version }}" "${{ steps.setup-java.outputs.path }}" run: bash __tests__/verify-java.sh "${{ matrix.version }}" "${{ steps.setup-java.outputs.path }}"
shell: bash shell: bash
@@ -144,10 +136,9 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
os: [macos-latest, windows-latest, ubuntu-latest] os: [macos-latest, windows-latest, ubuntu-latest]
distribution: ['adopt', 'zulu'] distribution: ['temurin', 'zulu']
java-package: ['jre'] java-package: ['jre']
version: version: ['16.0']
- '15.0'
include: include:
- distribution: 'zulu' - distribution: 'zulu'
java-package: jre+fx java-package: jre+fx
@@ -157,6 +148,10 @@ jobs:
java-package: jdk+fx java-package: jdk+fx
version: '8.0.242' version: '8.0.242'
os: ubuntu-latest os: ubuntu-latest
exclude:
# Eclipse Temurin currently doesn't publish JREs, only JDKs
- distribution: 'temurin'
java-package: 'jre'
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v2
@@ -194,4 +189,4 @@ jobs:
architecture: x86 architecture: x86
- name: Verify Java - name: Verify Java
run: bash __tests__/verify-java.sh "${{ matrix.version }}" "${{ steps.setup-java.outputs.path }}" run: bash __tests__/verify-java.sh "${{ matrix.version }}" "${{ steps.setup-java.outputs.path }}"
shell: bash shell: bash
@@ -0,0 +1,28 @@
name: Release new action version
on:
release:
types: [released]
workflow_dispatch:
inputs:
TAG_NAME:
description: 'Tag name that the major tag will point to'
required: true
env:
TAG_NAME: ${{ github.event.inputs.TAG_NAME || github.event.release.tag_name }}
permissions:
contents: write
jobs:
update_tag:
name: Update the major tag to include the ${{ github.event.inputs.TAG_NAME || github.event.release.tag_name }} changes
environment:
name: releaseNewActionVersion
runs-on: ubuntu-latest
steps:
- name: Update the ${{ env.TAG_NAME }} tag
id: update-major-tag
uses: actions/publish-action@v0.1.0
with:
source-tag: ${{ env.TAG_NAME }}
slack-webhook: ${{ secrets.SLACK_WEBHOOK }}
+1
View File
@@ -3,6 +3,7 @@ sources:
allowed: allowed:
- apache-2.0 - apache-2.0
- 0bsd
- bsd-2-clause - bsd-2-clause
- bsd-3-clause - bsd-3-clause
- isc - isc
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+44 -9
View File
@@ -11,22 +11,24 @@ This action provides the following functionality for GitHub Actions runners:
- Configuring runner for publishing using Gradle - Configuring runner for publishing using Gradle
- Configuring runner for using GPG private key - Configuring runner for using GPG private key
- Registering problem matchers for error output - Registering problem matchers for error output
- Caching dependencies managed by Apache Maven
- Caching dependencies managed by Gradle
## V2 vs V1 ## V2 vs V1
- V2 supports custom distributions and provides support for Zulu OpenJDK and Adopt OpenJDK out of the box. V1 supports only Zulu OpenJDK - V2 supports custom distributions and provides support for Zulu OpenJDK, Eclipse Temurin and Adopt OpenJDK out of the box. V1 supports only Zulu OpenJDK
- V2 requires you to specify distribution along with the version. V1 defaults to Zulu OpenJDK, only version input is required. Follow [the migration guide](docs/switching-to-v2.md) to switch from V1 to V2 - V2 requires you to specify distribution along with the version. V1 defaults to Zulu OpenJDK, only version input is required. Follow [the migration guide](docs/switching-to-v2.md) to switch from V1 to V2
## Usage ## Usage
Inputs `java-version` and `distribution` are mandatory. See [Supported distributions](../README.md#Supported-distributions) section for a list of available options. Inputs `java-version` and `distribution` are mandatory. See [Supported distributions](#supported-distributions) section for a list of available options.
### Basic ### Basic
**Adopt OpenJDK** **Eclipse Temurin**
```yaml ```yaml
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: actions/setup-java@v2 - uses: actions/setup-java@v2
with: with:
distribution: 'adopt' # See 'Supported distributions' for available options distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '11' java-version: '11'
- run: java -cp java HelloWorldApp - run: java -cp java HelloWorldApp
``` ```
@@ -44,19 +46,51 @@ steps:
#### Supported version syntax #### Supported version syntax
The `java-version` input supports an exact version or a version range using [SemVer](https://semver.org/) notation: The `java-version` input supports an exact version or a version range using [SemVer](https://semver.org/) notation:
- major versions: `8`, `11`, `15` - major versions: `8`, `11`, `16`
- more specific versions: `11.0`, `11.0.4`, `8.0.232`, `8.0.282+8` - more specific versions: `11.0`, `11.0.4`, `8.0.232`, `8.0.282+8`
- early access (EA) versions: `15-ea`, `15.0.0-ea`, `15.0.0-ea.2`, `15.0.0+2-ea` - early access (EA) versions: `15-ea`, `15.0.0-ea`, `15.0.0-ea.2`, `15.0.0+2-ea`
#### Supported distributions #### Supported distributions
Currently, the following distributions are supported: Currently, the following distributions are supported:
| Keyword | Distribution | Official site | License | | Keyword | Distribution | Official site | License
|-|-|-|-| |-|-|-|-|
| `temurin` | Eclipse Temurin | [Link](https://adoptium.net/) | [Link](https://adoptium.net/about.html)
| `zulu` | Zulu OpenJDK | [Link](https://www.azul.com/downloads/zulu-community/?package=jdk) | [Link](https://www.azul.com/products/zulu-and-zulu-enterprise/zulu-terms-of-use/) | | `zulu` | 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` | Adopt OpenJDK | [Link](https://adoptopenjdk.net/) | [Link](https://adoptopenjdk.net/about.html) | `adopt` or `adopt-hotspot` | Adopt OpenJDK Hotspot | [Link](https://adoptopenjdk.net/) | [Link](https://adoptopenjdk.net/about.html) |
| `adopt-openj9` | Adopt OpenJDK OpenJ9 | [Link](https://adoptopenjdk.net/) | [Link](https://adoptopenjdk.net/about.html)
**NOTE:** The different distributors can provide discrepant list of available versions / supported configurations. Please refer to the official documentation to see the list of supported versions. **NOTE:** The different distributors can provide discrepant list of available versions / supported configurations. Please refer to the official documentation to see the list of supported versions.
**NOTE:** Adopt OpenJDK got moved to Eclipse Temurin and won't be updated anymore. It is highly recommended to migrate workflows from `adopt` to `temurin` to keep receiving software and security updates. See more details in the [Good-bye AdoptOpenJDK post](https://blog.adoptopenjdk.net/2021/08/goodbye-adoptopenjdk-hello-adoptium/).
### Caching packages dependencies
The action has a built-in functionality for caching and restoring dependencies. It uses [actions/cache](https://github.com/actions/cache) under hood for caching dependencies but requires less configuration settings. Supported package managers are gradle and maven. The cache input is optional, and caching is turned off by default.
#### Caching gradle dependencies
```yaml
steps:
- uses: actions/checkout@v2
- uses: actions/setup-java@v2
with:
distribution: 'temurin'
java-version: '11'
cache: 'gradle'
- run: ./gradlew build
```
#### Caching maven dependencies
```yaml
steps:
- uses: actions/checkout@v2
- uses: actions/setup-java@v2
with:
distribution: 'temurin'
java-version: '11'
cache: 'maven'
- name: Build with Maven
run: mvn -B package --file pom.xml
```
### Check latest ### Check latest
In the basic examples above, the `check-latest` flag defaults to `false`. When set to `false`, the action tries to first resolve a version of Java from the local tool cache on the runner. If unable to find a specific version in the cache, the action will download a version of Java. Use the default or set `check-latest` to `false` if you prefer a faster more consistent setup experience that prioritizes trying to use the cached versions at the expense of newer versions sometimes being available for download. In the basic examples above, the `check-latest` flag defaults to `false`. When set to `false`, the action tries to first resolve a version of Java from the local tool cache on the runner. If unable to find a specific version in the cache, the action will download a version of Java. Use the default or set `check-latest` to `false` if you prefer a faster more consistent setup experience that prioritizes trying to use the cached versions at the expense of newer versions sometimes being available for download.
@@ -97,6 +131,7 @@ jobs:
### Advanced ### Advanced
- [Selecting a Java distribution](docs/advanced-usage.md#Selecting-a-Java-distribution) - [Selecting a Java distribution](docs/advanced-usage.md#Selecting-a-Java-distribution)
- [Eclipse Temurin](docs/advanced-usage.md#Eclipse-Temurin)
- [Adopt](docs/advanced-usage.md#Adopt) - [Adopt](docs/advanced-usage.md#Adopt)
- [Zulu](docs/advanced-usage.md#Zulu) - [Zulu](docs/advanced-usage.md#Zulu)
- [Installing custom Java package type](docs/advanced-usage.md#Installing-custom-Java-package-type) - [Installing custom Java package type](docs/advanced-usage.md#Installing-custom-Java-package-type)
@@ -110,8 +145,8 @@ jobs:
## License ## License
The scripts and documentation in this project are released under the [MIT License](LICENSE) The scripts and documentation in this project are released under the [MIT License](LICENSE).
## Contributions ## Contributions
Contributions are welcome! See [Contributor's Guide](docs/contributors.md) Contributions are welcome! See [Contributor's Guide](CONTRIBUTING.md)
+4
View File
@@ -1,6 +1,7 @@
import io = require('@actions/io'); import io = require('@actions/io');
import fs = require('fs'); import fs = require('fs');
import path = require('path'); import path = require('path');
import * as core from '@actions/core';
import os from 'os'; import os from 'os';
import * as auth from '../src/auth'; import * as auth from '../src/auth';
@@ -10,11 +11,14 @@ const settingsFile = path.join(m2Dir, auth.SETTINGS_FILE);
describe('auth tests', () => { describe('auth tests', () => {
let spyOSHomedir: jest.SpyInstance; let spyOSHomedir: jest.SpyInstance;
let spyInfo: jest.SpyInstance;
beforeEach(async () => { beforeEach(async () => {
await io.rmRF(m2Dir); await io.rmRF(m2Dir);
spyOSHomedir = jest.spyOn(os, 'homedir'); spyOSHomedir = jest.spyOn(os, 'homedir');
spyOSHomedir.mockReturnValue(__dirname); spyOSHomedir.mockReturnValue(__dirname);
spyInfo = jest.spyOn(core, 'info');
spyInfo.mockImplementation(() => null);
}, 300000); }, 300000);
afterAll(async () => { afterAll(async () => {
+245
View File
@@ -0,0 +1,245 @@
import { mkdtempSync } from 'fs';
import { tmpdir } from 'os';
import { join } from 'path';
import { restore, save } from '../src/cache';
import * as fs from 'fs';
import * as os from 'os';
import * as core from '@actions/core';
import * as cache from '@actions/cache';
describe('dependency cache', () => {
const ORIGINAL_RUNNER_OS = process.env['RUNNER_OS'];
const ORIGINAL_GITHUB_WORKSPACE = process.env['GITHUB_WORKSPACE'];
const ORIGINAL_CWD = process.cwd();
let workspace: string;
let spyInfo: jest.SpyInstance<void, Parameters<typeof core.info>>;
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>>;
beforeEach(() => {
workspace = mkdtempSync(join(tmpdir(), 'setup-java-cache-'));
switch (os.platform()) {
case 'darwin':
process.env['RUNNER_OS'] = 'macOS';
break;
case 'win32':
process.env['RUNNER_OS'] = 'Windows';
break;
case 'linux':
process.env['RUNNER_OS'] = 'Linux';
break;
default:
throw new Error(`unknown platform: ${os.platform()}`);
}
process.chdir(workspace);
// This hack is necessary because @actions/glob ignores files not in the GITHUB_WORKSPACE
// https://git.io/Jcxig
process.env['GITHUB_WORKSPACE'] = projectRoot(workspace);
});
beforeEach(() => {
spyInfo = jest.spyOn(core, 'info');
spyInfo.mockImplementation(() => null);
spyWarning = jest.spyOn(core, 'warning');
spyWarning.mockImplementation(() => null);
spyDebug = jest.spyOn(core, 'debug');
spyDebug.mockImplementation(() => null);
spySaveState = jest.spyOn(core, 'saveState');
spySaveState.mockImplementation(() => null);
});
afterEach(() => {
process.chdir(ORIGINAL_CWD);
process.env['GITHUB_WORKSPACE'] = ORIGINAL_GITHUB_WORKSPACE;
process.env['RUNNER_OS'] = ORIGINAL_RUNNER_OS;
resetState();
});
describe('restore', () => {
let spyCacheRestore: jest.SpyInstance<
ReturnType<typeof cache.restoreCache>,
Parameters<typeof cache.restoreCache>
>;
beforeEach(() => {
spyCacheRestore = jest
.spyOn(cache, 'restoreCache')
.mockImplementation((paths: string[], primaryKey: string) => Promise.resolve(undefined));
spyWarning.mockImplementation(() => null);
});
it('throws error if unsupported package manager specified', () => {
return expect(restore('ant')).rejects.toThrowError('unknown package manager specified: ant');
});
describe('for maven', () => {
it('throws error if no pom.xml found', async () => {
await expect(restore('maven')).rejects.toThrowError(
`No file in ${projectRoot(
workspace
)} matched to [**/pom.xml], make sure you have checked out the target repository`
);
});
it('downloads cache', async () => {
createFile(join(workspace, 'pom.xml'));
await restore('maven');
expect(spyCacheRestore).toBeCalled();
expect(spyWarning).not.toBeCalled();
expect(spyInfo).toBeCalledWith('maven cache is not found');
});
});
describe('for gradle', () => {
it('throws error if no build.gradle found', async () => {
await expect(restore('gradle')).rejects.toThrowError(
`No file in ${projectRoot(
workspace
)} matched to [**/*.gradle*,**/gradle-wrapper.properties], make sure you have checked out the target repository`
);
});
it('downloads cache based on build.gradle', async () => {
createFile(join(workspace, 'build.gradle'));
await restore('gradle');
expect(spyCacheRestore).toBeCalled();
expect(spyWarning).not.toBeCalled();
expect(spyInfo).toBeCalledWith('gradle cache is not found');
});
it('downloads cache based on build.gradle.kts', async () => {
createFile(join(workspace, 'build.gradle.kts'));
await restore('gradle');
expect(spyCacheRestore).toBeCalled();
expect(spyWarning).not.toBeCalled();
expect(spyInfo).toBeCalledWith('gradle cache is not found');
});
});
});
describe('save', () => {
let spyCacheSave: jest.SpyInstance<
ReturnType<typeof cache.saveCache>,
Parameters<typeof cache.saveCache>
>;
beforeEach(() => {
spyCacheSave = jest
.spyOn(cache, 'saveCache')
.mockImplementation((paths: string[], key: string) => Promise.resolve(0));
spyWarning.mockImplementation(() => null);
});
it('throws error if unsupported package manager specified', () => {
return expect(save('ant')).rejects.toThrowError('unknown package manager specified: ant');
});
describe('for maven', () => {
it('uploads cache even if no pom.xml found', async () => {
createStateForMissingBuildFile();
await save('maven');
expect(spyCacheSave).toBeCalled();
expect(spyWarning).not.toBeCalled();
});
it('does not upload cache if no restore run before', async () => {
createFile(join(workspace, 'pom.xml'));
await save('maven');
expect(spyCacheSave).not.toBeCalled();
expect(spyWarning).toBeCalledWith('Error retrieving key from state.');
});
it('uploads cache', async () => {
createFile(join(workspace, 'pom.xml'));
createStateForSuccessfulRestore();
await save('maven');
expect(spyCacheSave).toBeCalled();
expect(spyWarning).not.toBeCalled();
expect(spyInfo).toBeCalledWith(expect.stringMatching(/^Cache saved with the key:.*/));
});
});
describe('for gradle', () => {
it('uploads cache even if no build.gradle found', async () => {
createStateForMissingBuildFile();
await save('gradle');
expect(spyCacheSave).toBeCalled();
expect(spyWarning).not.toBeCalled();
});
it('does not upload cache if no restore run before', async () => {
createFile(join(workspace, 'build.gradle'));
await save('gradle');
expect(spyCacheSave).not.toBeCalled();
expect(spyWarning).toBeCalledWith('Error retrieving key from state.');
});
it('uploads cache based on build.gradle', async () => {
createFile(join(workspace, 'build.gradle'));
createStateForSuccessfulRestore();
await save('gradle');
expect(spyCacheSave).toBeCalled();
expect(spyWarning).not.toBeCalled();
expect(spyInfo).toBeCalledWith(expect.stringMatching(/^Cache saved with the key:.*/));
});
it('uploads cache based on build.gradle.kts', async () => {
createFile(join(workspace, 'build.gradle.kts'));
createStateForSuccessfulRestore();
await save('gradle');
expect(spyCacheSave).toBeCalled();
expect(spyWarning).not.toBeCalled();
expect(spyInfo).toBeCalledWith(expect.stringMatching(/^Cache saved with the key:.*/));
});
});
});
});
function resetState() {
jest.spyOn(core, 'getState').mockReset();
}
/**
* Create states to emulate a restore process without build file.
*/
function createStateForMissingBuildFile() {
jest.spyOn(core, 'getState').mockImplementation(name => {
switch (name) {
case 'cache-primary-key':
return 'setup-java-cache-';
default:
return '';
}
});
}
/**
* Create states to emulate a successful restore process.
*/
function createStateForSuccessfulRestore() {
jest.spyOn(core, 'getState').mockImplementation(name => {
switch (name) {
case 'cache-primary-key':
return 'setup-java-cache-primary-key';
case 'cache-matched-key':
return 'setup-java-cache-matched-key';
default:
return '';
}
});
}
function createFile(path: string) {
core.info(`created a file at ${path}`);
fs.writeFileSync(path, '');
}
function projectRoot(workspace: string): string {
if (os.platform() === 'darwin') {
return `/private${workspace}`;
} else {
return workspace;
}
}
+12
View File
@@ -0,0 +1,12 @@
.gradle
**/build/
!src/**/build/
# Ignore Gradle GUI config
gradle-app.setting
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
!gradle-wrapper.jar
# Cache of project
.gradletasknamecache
+17
View File
@@ -0,0 +1,17 @@
plugins {
id 'java'
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.codehaus.groovy:groovy:1.8.6'
}
tasks.register('downloadDependencies') {
doLast {
def total = configurations.compileClasspath.inject (0) { sum, file ->
sum + file.length()
}
println total
}
}
+11
View File
@@ -0,0 +1,11 @@
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
.mvn/wrapper/maven-wrapper.jar
+16
View File
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>io.github.actions</groupId>
<artifactId>setup-java-maven-example</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.7.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
+75
View File
@@ -0,0 +1,75 @@
import { run as cleanup } from '../src/cleanup-java';
import * as core from '@actions/core';
import * as cache from '@actions/cache';
import * as util from '../src/util';
describe('cleanup', () => {
let spyWarning: jest.SpyInstance<void, Parameters<typeof core.warning>>;
let spyInfo: jest.SpyInstance<void, Parameters<typeof core.info>>;
let spyCacheSave: jest.SpyInstance<
ReturnType<typeof cache.saveCache>,
Parameters<typeof cache.saveCache>
>;
let spyJobStatusSuccess: 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);
createStateForSuccessfulRestore();
});
afterEach(() => {
resetState();
});
it('does not fail nor warn even when the save provess throws a ReserveCacheError', async () => {
spyCacheSave.mockImplementation((paths: string[], key: string) =>
Promise.reject(
new cache.ReserveCacheError(
'Unable to reserve cache with key, another job may be creating this cache.'
)
)
);
jest.spyOn(core, 'getInput').mockImplementation((name: string) => {
return name === 'cache' ? 'gradle' : '';
});
await cleanup();
expect(spyCacheSave).toBeCalled();
expect(spyWarning).not.toBeCalled();
});
it('does not fail even though the save process throws error', async () => {
spyCacheSave.mockImplementation((paths: string[], key: string) =>
Promise.reject(new Error('Unexpected error'))
);
jest.spyOn(core, 'getInput').mockImplementation((name: string) => {
return name === 'cache' ? 'gradle' : '';
});
await cleanup();
expect(spyCacheSave).toBeCalled();
});
});
function resetState() {
jest.spyOn(core, 'getState').mockReset();
}
/**
* Create states to emulate a successful restore process.
*/
function createStateForSuccessfulRestore() {
jest.spyOn(core, 'getState').mockImplementation(name => {
switch (name) {
case 'cache-primary-key':
return 'setup-java-cache-primary-key';
case 'cache-matched-key':
return 'setup-java-cache-matched-key';
default:
return '';
}
});
}
File diff suppressed because it is too large Load Diff
+74 -40
View File
@@ -1,8 +1,6 @@
import { HttpClient } from '@actions/http-client'; import { HttpClient } from '@actions/http-client';
import * as semver from 'semver'; import { AdoptDistribution, AdoptImplementation } from '../../src/distributions/adopt/installer';
import { AdoptDistribution } from '../../src/distributions/adopt/installer';
import { JavaInstallerOptions } from '../../src/distributions/base-models'; import { JavaInstallerOptions } from '../../src/distributions/base-models';
let manifestData = require('../data/adopt.json') as []; let manifestData = require('../data/adopt.json') as [];
@@ -28,26 +26,54 @@ describe('getAvailableVersions', () => {
it.each([ it.each([
[ [
{ version: '11', architecture: 'x64', packageType: 'jdk', checkLatest: false }, { version: '11', architecture: 'x64', packageType: 'jdk', checkLatest: false },
'os=mac&architecture=x64&image_type=jdk&release_type=ga&page_size=20&page=0' AdoptImplementation.Hotspot,
'os=mac&architecture=x64&image_type=jdk&release_type=ga&jvm_impl=hotspot&page_size=20&page=0'
], ],
[ [
{ version: '11', architecture: 'x86', packageType: 'jdk', checkLatest: false }, { version: '11', architecture: 'x86', packageType: 'jdk', checkLatest: false },
'os=mac&architecture=x86&image_type=jdk&release_type=ga&page_size=20&page=0' AdoptImplementation.Hotspot,
'os=mac&architecture=x86&image_type=jdk&release_type=ga&jvm_impl=hotspot&page_size=20&page=0'
], ],
[ [
{ version: '11', architecture: 'x64', packageType: 'jre', checkLatest: false }, { version: '11', architecture: 'x64', packageType: 'jre', checkLatest: false },
'os=mac&architecture=x64&image_type=jre&release_type=ga&page_size=20&page=0' AdoptImplementation.Hotspot,
'os=mac&architecture=x64&image_type=jre&release_type=ga&jvm_impl=hotspot&page_size=20&page=0'
], ],
[ [
{ version: '11-ea', architecture: 'x64', packageType: 'jdk', checkLatest: false }, { version: '11-ea', architecture: 'x64', packageType: 'jdk', checkLatest: false },
'os=mac&architecture=x64&image_type=jdk&release_type=ea&page_size=20&page=0' AdoptImplementation.Hotspot,
'os=mac&architecture=x64&image_type=jdk&release_type=ea&jvm_impl=hotspot&page_size=20&page=0'
],
[
{ version: '11', architecture: 'x64', packageType: 'jdk', checkLatest: false },
AdoptImplementation.OpenJ9,
'os=mac&architecture=x64&image_type=jdk&release_type=ga&jvm_impl=openj9&page_size=20&page=0'
],
[
{ version: '11', architecture: 'x86', packageType: 'jdk', checkLatest: false },
AdoptImplementation.OpenJ9,
'os=mac&architecture=x86&image_type=jdk&release_type=ga&jvm_impl=openj9&page_size=20&page=0'
],
[
{ version: '11', architecture: 'x64', packageType: 'jre', checkLatest: false },
AdoptImplementation.OpenJ9,
'os=mac&architecture=x64&image_type=jre&release_type=ga&jvm_impl=openj9&page_size=20&page=0'
],
[
{ version: '11-ea', architecture: 'x64', packageType: 'jdk', checkLatest: false },
AdoptImplementation.OpenJ9,
'os=mac&architecture=x64&image_type=jdk&release_type=ea&jvm_impl=openj9&page_size=20&page=0'
] ]
])( ])(
'build correct url for %s', 'build correct url for %s',
async (installerOptions: JavaInstallerOptions, expectedParameters) => { async (
const distribution = new AdoptDistribution(installerOptions); installerOptions: JavaInstallerOptions,
impl: AdoptImplementation,
expectedParameters
) => {
const distribution = new AdoptDistribution(installerOptions, impl);
const baseUrl = 'https://api.adoptopenjdk.net/v3/assets/version/%5B1.0,100.0%5D'; const baseUrl = 'https://api.adoptopenjdk.net/v3/assets/version/%5B1.0,100.0%5D';
const expectedUrl = `${baseUrl}?project=jdk&vendor=adoptopenjdk&heap_size=normal&jvm_impl=hotspot&sort_method=DEFAULT&sort_order=DESC&${expectedParameters}`; const expectedUrl = `${baseUrl}?project=jdk&vendor=adoptopenjdk&heap_size=normal&sort_method=DEFAULT&sort_order=DESC&${expectedParameters}`;
distribution['getPlatformOption'] = () => 'mac'; distribution['getPlatformOption'] = () => 'mac';
await distribution['getAvailableVersions'](); await distribution['getAvailableVersions']();
@@ -76,16 +102,32 @@ describe('getAvailableVersions', () => {
result: [] result: []
}); });
const distribution = new AdoptDistribution({ const distribution = new AdoptDistribution(
version: '11', { version: '11', architecture: 'x64', packageType: 'jdk', checkLatest: false },
architecture: 'x64', AdoptImplementation.Hotspot
packageType: 'jdk', );
checkLatest: false
});
const availableVersions = await distribution['getAvailableVersions'](); const availableVersions = await distribution['getAvailableVersions']();
expect(availableVersions).not.toBeNull(); expect(availableVersions).not.toBeNull();
expect(availableVersions.length).toBe(manifestData.length * 2); expect(availableVersions.length).toBe(manifestData.length * 2);
}); });
it.each([
[AdoptImplementation.Hotspot, 'jdk', 'Java_Adopt_jdk'],
[AdoptImplementation.Hotspot, 'jre', 'Java_Adopt_jre'],
[AdoptImplementation.OpenJ9, 'jdk', 'Java_Adopt-OpenJ9_jdk'],
[AdoptImplementation.OpenJ9, 'jre', 'Java_Adopt-OpenJ9_jre']
])(
'find right toolchain folder',
(impl: AdoptImplementation, packageType: string, expected: string) => {
const distribution = new AdoptDistribution(
{ version: '11', architecture: 'x64', packageType: packageType, checkLatest: false },
impl
);
// @ts-ignore - because it is protected
expect(distribution.toolcacheFolderName).toBe(expected);
}
);
}); });
describe('findPackageForDownload', () => { describe('findPackageForDownload', () => {
@@ -102,24 +144,20 @@ describe('findPackageForDownload', () => {
['15.0.1+9', '15.0.1+9'], ['15.0.1+9', '15.0.1+9'],
['15.0.1+9.1', '15.0.1+9.1'] ['15.0.1+9.1', '15.0.1+9.1']
])('version is resolved correctly %s -> %s', async (input, expected) => { ])('version is resolved correctly %s -> %s', async (input, expected) => {
const distribution = new AdoptDistribution({ const distribution = new AdoptDistribution(
version: '11', { version: '11', architecture: 'x64', packageType: 'jdk', checkLatest: false },
architecture: 'x64', AdoptImplementation.Hotspot
packageType: 'jdk', );
checkLatest: false
});
distribution['getAvailableVersions'] = async () => manifestData; distribution['getAvailableVersions'] = async () => manifestData;
const resolvedVersion = await distribution['findPackageForDownload'](input); const resolvedVersion = await distribution['findPackageForDownload'](input);
expect(resolvedVersion.version).toBe(expected); expect(resolvedVersion.version).toBe(expected);
}); });
it('version is found but binaries list is empty', async () => { it('version is found but binaries list is empty', async () => {
const distribution = new AdoptDistribution({ const distribution = new AdoptDistribution(
version: '11', { version: '11', architecture: 'x64', packageType: 'jdk', checkLatest: false },
architecture: 'x64', AdoptImplementation.Hotspot
packageType: 'jdk', );
checkLatest: false
});
distribution['getAvailableVersions'] = async () => manifestData; distribution['getAvailableVersions'] = async () => manifestData;
await expect(distribution['findPackageForDownload']('9.0.8')).rejects.toThrowError( await expect(distribution['findPackageForDownload']('9.0.8')).rejects.toThrowError(
/Could not find satisfied version for SemVer */ /Could not find satisfied version for SemVer */
@@ -127,12 +165,10 @@ describe('findPackageForDownload', () => {
}); });
it('version is not found', async () => { it('version is not found', async () => {
const distribution = new AdoptDistribution({ const distribution = new AdoptDistribution(
version: '11', { version: '11', architecture: 'x64', packageType: 'jdk', checkLatest: false },
architecture: 'x64', AdoptImplementation.Hotspot
packageType: 'jdk', );
checkLatest: false
});
distribution['getAvailableVersions'] = async () => manifestData; distribution['getAvailableVersions'] = async () => manifestData;
await expect(distribution['findPackageForDownload']('7.x')).rejects.toThrowError( await expect(distribution['findPackageForDownload']('7.x')).rejects.toThrowError(
/Could not find satisfied version for SemVer */ /Could not find satisfied version for SemVer */
@@ -140,12 +176,10 @@ describe('findPackageForDownload', () => {
}); });
it('version list is empty', async () => { it('version list is empty', async () => {
const distribution = new AdoptDistribution({ const distribution = new AdoptDistribution(
version: '11', { version: '11', architecture: 'x64', packageType: 'jdk', checkLatest: false },
architecture: 'x64', AdoptImplementation.Hotspot
packageType: 'jdk', );
checkLatest: false
});
distribution['getAvailableVersions'] = async () => []; distribution['getAvailableVersions'] = async () => [];
await expect(distribution['findPackageForDownload']('11')).rejects.toThrowError( await expect(distribution['findPackageForDownload']('11')).rejects.toThrowError(
/Could not find satisfied version for SemVer */ /Could not find satisfied version for SemVer */
@@ -0,0 +1,164 @@
import { HttpClient } from '@actions/http-client';
import {
TemurinDistribution,
TemurinImplementation
} from '../../src/distributions/temurin/installer';
import { JavaInstallerOptions } from '../../src/distributions/base-models';
let manifestData = require('../data/temurin.json') as [];
describe('getAvailableVersions', () => {
let spyHttpClient: jest.SpyInstance;
beforeEach(() => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
spyHttpClient.mockReturnValue({
statusCode: 200,
headers: {},
result: []
});
});
afterEach(() => {
jest.resetAllMocks();
jest.clearAllMocks();
jest.restoreAllMocks();
});
it.each([
[
{ version: '16', architecture: 'x64', packageType: 'jdk', checkLatest: false },
TemurinImplementation.Hotspot,
'os=mac&architecture=x64&image_type=jdk&release_type=ga&jvm_impl=hotspot&page_size=20&page=0'
],
[
{ version: '16', architecture: 'x86', packageType: 'jdk', checkLatest: false },
TemurinImplementation.Hotspot,
'os=mac&architecture=x86&image_type=jdk&release_type=ga&jvm_impl=hotspot&page_size=20&page=0'
],
[
{ version: '16', architecture: 'x64', packageType: 'jre', checkLatest: false },
TemurinImplementation.Hotspot,
'os=mac&architecture=x64&image_type=jre&release_type=ga&jvm_impl=hotspot&page_size=20&page=0'
],
[
{ version: '16-ea', architecture: 'x64', packageType: 'jdk', checkLatest: false },
TemurinImplementation.Hotspot,
'os=mac&architecture=x64&image_type=jdk&release_type=ea&jvm_impl=hotspot&page_size=20&page=0'
]
])(
'build correct url for %s',
async (
installerOptions: JavaInstallerOptions,
impl: TemurinImplementation,
expectedParameters
) => {
const distribution = new TemurinDistribution(installerOptions, impl);
const baseUrl = 'https://api.adoptium.net/v3/assets/version/%5B1.0,100.0%5D';
const expectedUrl = `${baseUrl}?project=jdk&vendor=adoptium&heap_size=normal&sort_method=DEFAULT&sort_order=DESC&${expectedParameters}`;
distribution['getPlatformOption'] = () => 'mac';
await distribution['getAvailableVersions']();
expect(spyHttpClient.mock.calls).toHaveLength(1);
expect(spyHttpClient.mock.calls[0][0]).toBe(expectedUrl);
}
);
it('load available versions', async () => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson');
spyHttpClient
.mockReturnValueOnce({
statusCode: 200,
headers: {},
result: manifestData
})
.mockReturnValueOnce({
statusCode: 200,
headers: {},
result: manifestData
})
.mockReturnValueOnce({
statusCode: 200,
headers: {},
result: []
});
const distribution = new TemurinDistribution(
{ version: '8', architecture: 'x64', packageType: 'jdk', checkLatest: false },
TemurinImplementation.Hotspot
);
const availableVersions = await distribution['getAvailableVersions']();
expect(availableVersions).not.toBeNull();
expect(availableVersions.length).toBe(manifestData.length * 2);
});
it.each([
[TemurinImplementation.Hotspot, 'jdk', 'Java_Temurin-Hotspot_jdk'],
[TemurinImplementation.Hotspot, 'jre', 'Java_Temurin-Hotspot_jre']
])(
'find right toolchain folder',
(impl: TemurinImplementation, packageType: string, expected: string) => {
const distribution = new TemurinDistribution(
{ version: '8', architecture: 'x64', packageType: packageType, checkLatest: false },
impl
);
// @ts-ignore - because it is protected
expect(distribution.toolcacheFolderName).toBe(expected);
}
);
});
describe('findPackageForDownload', () => {
it.each([
['8', '8.0.302+8'],
['16', '16.0.2+7'],
['16.0', '16.0.2+7'],
['16.0.2', '16.0.2+7'],
['8.x', '8.0.302+8'],
['x', '16.0.2+7']
])('version is resolved correctly %s -> %s', async (input, expected) => {
const distribution = new TemurinDistribution(
{ version: '8', architecture: 'x64', packageType: 'jdk', checkLatest: false },
TemurinImplementation.Hotspot
);
distribution['getAvailableVersions'] = async () => manifestData;
const resolvedVersion = await distribution['findPackageForDownload'](input);
expect(resolvedVersion.version).toBe(expected);
});
it('version is found but binaries list is empty', async () => {
const distribution = new TemurinDistribution(
{ version: '9.0.8', architecture: 'x64', packageType: 'jdk', checkLatest: false },
TemurinImplementation.Hotspot
);
distribution['getAvailableVersions'] = async () => manifestData;
await expect(distribution['findPackageForDownload']('9.0.8')).rejects.toThrowError(
/Could not find satisfied version for SemVer */
);
});
it('version is not found', async () => {
const distribution = new TemurinDistribution(
{ version: '7.x', architecture: 'x64', packageType: 'jdk', checkLatest: false },
TemurinImplementation.Hotspot
);
distribution['getAvailableVersions'] = async () => manifestData;
await expect(distribution['findPackageForDownload']('7.x')).rejects.toThrowError(
/Could not find satisfied version for SemVer */
);
});
it('version list is empty', async () => {
const distribution = new TemurinDistribution(
{ version: '8', architecture: 'x64', packageType: 'jdk', checkLatest: false },
TemurinImplementation.Hotspot
);
distribution['getAvailableVersions'] = async () => [];
await expect(distribution['findPackageForDownload']('8')).rejects.toThrowError(
/Could not find satisfied version for SemVer */
);
});
});
+6
View File
@@ -53,6 +53,12 @@ inputs:
description: 'Environment variable name for the GPG private key passphrase. Default is description: 'Environment variable name for the GPG private key passphrase. Default is
$GPG_PASSPHRASE.' $GPG_PASSPHRASE.'
required: false required: false
cache:
description: 'Name of the build platform to cache dependencies. It can be "maven" or "gradle".'
required: false
job-status:
description: 'Workaround to pass job status to post job step. This variable is not intended for manual setting'
default: ${{ job.status }}
outputs: outputs:
distribution: distribution:
description: 'Distribution of Java that has been installed' description: 'Distribution of Java that has been installed'
+58281 -118
View File
File diff suppressed because one or more lines are too long
+57935 -459
View File
File diff suppressed because one or more lines are too long
+52 -40
View File
@@ -1,5 +1,6 @@
# Usage # Usage
- [Selecting a Java distribution](#Selecting-a-Java-distribution) - [Selecting a Java distribution](#Selecting-a-Java-distribution)
- [Eclipse Temurin](#Eclipse-Temurin)
- [Adopt](#Adopt) - [Adopt](#Adopt)
- [Zulu](#Zulu) - [Zulu](#Zulu)
- [Installing custom Java package type](#Installing-custom-Java-package-type) - [Installing custom Java package type](#Installing-custom-Java-package-type)
@@ -16,13 +17,26 @@ See [action.yml](../action.yml) for more details on task inputs.
## Selecting a Java distribution ## Selecting a Java distribution
Inputs `java-version` and `distribution` are mandatory and needs to be provided. See [Supported distributions](../README.md#Supported-distributions) for a list of available options. Inputs `java-version` and `distribution` are mandatory and needs to be provided. See [Supported distributions](../README.md#Supported-distributions) for a list of available options.
### Adopt ### Eclipse Temurin
```yaml ```yaml
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: actions/setup-java@v2 - uses: actions/setup-java@v2
with: with:
distribution: 'adopt' distribution: 'temurin'
java-version: '11'
- run: java -cp java HelloWorldApp
```
### Adopt
**NOTE:** Adopt OpenJDK got moved to Eclipse Temurin and won't be updated anymore. It is highly recommended to migrate workflows from `adopt` to `temurin` to keep receiving software and security updates. See more details in the [Good-bye AdoptOpenJDK post](https://blog.adoptopenjdk.net/2021/08/goodbye-adoptopenjdk-hello-adoptium/).
```yaml
steps:
- uses: actions/checkout@v2
- uses: actions/setup-java@v2
with:
distribution: 'adopt-hotspot'
java-version: '11' java-version: '11'
- run: java -cp java HelloWorldApp - run: java -cp java HelloWorldApp
``` ```
@@ -75,7 +89,7 @@ steps:
wget -O $RUNNER_TEMP/java_package.tar.gz $download_url wget -O $RUNNER_TEMP/java_package.tar.gz $download_url
- uses: actions/setup-java@v2 - uses: actions/setup-java@v2
with: with:
distribution: 'jdkFile' distribution: 'jdkfile'
jdkFile: ${{ runner.temp }}/java_package.tar.gz jdkFile: ${{ runner.temp }}/java_package.tar.gz
java-version: '11.0.0' java-version: '11.0.0'
architecture: x64 architecture: x64
@@ -91,8 +105,8 @@ jobs:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
strategy: strategy:
matrix: matrix:
distribution: [ 'zulu', 'adopt' ] distribution: [ 'zulu', 'temurin' ]
java: [ '8', '11', '13', '15' ] java: [ '8', '11' ]
name: Java ${{ matrix.Java }} (${{ matrix.distribution }}) sample name: Java ${{ matrix.Java }} (${{ matrix.distribution }}) sample
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@@ -119,7 +133,7 @@ jobs:
- name: Setup java - name: Setup java
uses: actions/setup-java@v2 uses: actions/setup-java@v2
with: with:
distribution: 'adopt' distribution: 'temurin'
java-version: ${{ matrix.java }} java-version: ${{ matrix.java }}
- run: java -cp java HelloWorldApp - run: java -cp java HelloWorldApp
``` ```
@@ -129,7 +143,6 @@ jobs:
```yaml ```yaml
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -151,7 +164,7 @@ jobs:
- name: Set up Apache Maven Central - name: Set up Apache Maven Central
uses: actions/setup-java@v2 uses: actions/setup-java@v2
with: # running setup-java again overwrites the settings.xml with: # running setup-java again overwrites the settings.xml
distribution: 'adopt' distribution: 'temurin'
java-version: '11' java-version: '11'
server-id: maven # Value of the distributionManagement/repository/id field of the pom.xml server-id: maven # Value of the distributionManagement/repository/id field of the pom.xml
server-username: MAVEN_USERNAME # env variable for username in deploy server-username: MAVEN_USERNAME # env variable for username in deploy
@@ -207,7 +220,7 @@ The two `settings.xml` files created from the above example look like the follow
</settings> </settings>
``` ```
***NOTE***: The `settings.xml` file is created in the Actions $HOME/.m2 directory. If you have an existing `settings.xml` file at that location, it will be overwritten. See below for using the `settings-path` to change your `settings.xml` file location. ***NOTE***: The `settings.xml` file is created in the Actions `$HOME/.m2` directory. If you have an existing `settings.xml` file at that location, it will be overwritten. See [below](#apache-maven-with-a-settings-path) for using the `settings-path` to change your `settings.xml` file location.
If you don't want to overwrite the `settings.xml` file, you can set `overwrite-settings: false` If you don't want to overwrite the `settings.xml` file, you can set `overwrite-settings: false`
@@ -234,6 +247,34 @@ If `gpg-private-key` input is provided, the private key will be written to a fil
See the help docs on [Publishing a Package](https://help.github.com/en/github/managing-packages-with-github-packages/configuring-apache-maven-for-use-with-github-packages#publishing-a-package) for more information on the `pom.xml` file. See the help docs on [Publishing a Package](https://help.github.com/en/github/managing-packages-with-github-packages/configuring-apache-maven-for-use-with-github-packages#publishing-a-package) for more information on the `pom.xml` file.
## Apache Maven with a settings path
When using an Actions self-hosted runner with multiple shared runners the default `$HOME` directory can be shared by a number runners at the same time which could overwrite existing settings file. Setting the `settings-path` variable allows you to choose a unique location for your settings file.
```yaml
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 11 for Shared Runner
uses: actions/setup-java@v2
with:
distribution: '<distribution>'
java-version: '11'
server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
settings-path: ${{ github.workspace }} # location for the settings.xml file
- name: Build with Maven
run: mvn -B package --file pom.xml
- name: Publish to GitHub Packages Apache Maven
run: mvn deploy -s $GITHUB_WORKSPACE/settings.xml
env:
GITHUB_TOKEN: ${{ github.token }}
```
## Publishing using Gradle ## Publishing using Gradle
```yaml ```yaml
jobs: jobs:
@@ -264,38 +305,9 @@ jobs:
See the help docs on [Publishing a Package with Gradle](https://help.github.com/en/github/managing-packages-with-github-packages/configuring-gradle-for-use-with-github-packages#example-using-gradle-groovy-for-a-single-package-in-a-repository) for more information on the `build.gradle` configuration file. See the help docs on [Publishing a Package with Gradle](https://help.github.com/en/github/managing-packages-with-github-packages/configuring-gradle-for-use-with-github-packages#example-using-gradle-groovy-for-a-single-package-in-a-repository) for more information on the `build.gradle` configuration file.
## Apache Maven with a settings path
When using an Actions self-hosted runner with multiple shared runners the default `$HOME` directory can be shared by a number runners at the same time which could overwrite existing settings file. Setting the `settings-path` variable allows you to choose a unique location for your settings file.
```yaml
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 11 for Shared Runner
uses: actions/setup-java@v2
with:
distribution: '<distribution>'
java-version: '11'
server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
settings-path: ${{ github.workspace }} # location for the settings.xml file
- name: Build with Maven
run: mvn -B package --file pom.xml
- name: Publish to GitHub Packages Apache Maven
run: mvn deploy -s $GITHUB_WORKSPACE/settings.xml
env:
GITHUB_TOKEN: ${{ github.token }}
```
## Hosted Tool Cache ## Hosted Tool Cache
GitHub Hosted Runners have a tool cache that comes with some Java versions pre-installed. This tool cache helps speed up runs and tool setup by not requiring any new downloads. There is an environment variable called `RUNNER_TOOL_CACHE` on each runner that describes the location of this tools cache and this is where you can find the pre-installed versions of Java. `setup-java` works by taking a specific version of Java in this tool cache and adding it to PATH if the version, architecture and distribution match. GitHub Hosted Runners have a tool cache that comes with some Java versions pre-installed. This tool cache helps speed up runs and tool setup by not requiring any new downloads. There is an environment variable called `RUNNER_TOOL_CACHE` on each runner that describes the location of this tools cache and this is where you can find the pre-installed versions of Java. `setup-java` works by taking a specific version of Java in this tool cache and adding it to PATH if the version, architecture and distribution match.
Currently, LTS versions of Adopt OpenJDK (`adopt`) are cached on the GitHub Hosted Runners. Currently, LTS versions of Adopt OpenJDK (`adopt`) are cached on the GitHub Hosted Runners.
The tools cache gets updated on a weekly basis. For information regarding locally cached versions of Java on GitHub hosted runners, check out [GitHub Actions Virtual Environments](https://github.com/actions/virtual-environments). The tools cache gets updated on a weekly basis. For information regarding locally cached versions of Java on GitHub hosted runners, check out [GitHub Actions Virtual Environments](https://github.com/actions/virtual-environments).
+2 -2
View File
@@ -16,7 +16,7 @@ steps:
**General recommendation** — configure CI with the same distribution that is used on your local dev machine. **General recommendation** — configure CI with the same distribution that is used on your local dev machine.
## Installing custom Java distribution from local file ## Installing custom Java distribution from local file
Since the `distribution` input is required in V2, you should specify it using `jdkFile` to continue installing Java from a local file on the runner Since the `distribution` input is required in V2, you should specify it using `jdkfile` to continue installing Java from a local file on the runner
```yaml ```yaml
steps: steps:
- run: | - run: |
@@ -24,7 +24,7 @@ steps:
wget -O $RUNNER_TEMP/java_package.tar.gz $download_url wget -O $RUNNER_TEMP/java_package.tar.gz $download_url
- uses: actions/setup-java@v2 - uses: actions/setup-java@v2
with: with:
distribution: 'jdkFile' distribution: 'jdkfile'
jdkFile: ${{ runner.temp }}/java_package.tar.gz jdkFile: ${{ runner.temp }}/java_package.tar.gz
java-version: '11.0.0' java-version: '11.0.0'
architecture: x64 architecture: x64
+6640 -29
View File
File diff suppressed because it is too large Load Diff
+2
View File
@@ -24,8 +24,10 @@
"author": "GitHub", "author": "GitHub",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/cache": "^1.0.7",
"@actions/core": "^1.2.6", "@actions/core": "^1.2.6",
"@actions/exec": "^1.0.4", "@actions/exec": "^1.0.4",
"@actions/glob": "^0.2.0",
"@actions/http-client": "^1.0.9", "@actions/http-client": "^1.0.9",
"@actions/io": "^1.0.2", "@actions/io": "^1.0.2",
"@actions/tool-cache": "^1.6.1", "@actions/tool-cache": "^1.6.1",
+134
View File
@@ -0,0 +1,134 @@
/**
* @fileoverview this file provides methods handling dependency cache
*/
import { join } from 'path';
import os from 'os';
import * as cache from '@actions/cache';
import * as core from '@actions/core';
import * as glob from '@actions/glob';
const STATE_CACHE_PRIMARY_KEY = 'cache-primary-key';
const CACHE_MATCHED_KEY = 'cache-matched-key';
const CACHE_KEY_PREFIX = 'setup-java';
interface PackageManager {
id: 'maven' | 'gradle';
/**
* Paths of the file that specify the files to cache.
*/
path: string[];
pattern: string[];
}
const supportedPackageManager: PackageManager[] = [
{
id: 'maven',
path: [join(os.homedir(), '.m2', 'repository')],
// https://github.com/actions/cache/blob/0638051e9af2c23d10bb70fa9beffcad6cff9ce3/examples.md#java---maven
pattern: ['**/pom.xml']
},
{
id: 'gradle',
path: [join(os.homedir(), '.gradle', 'caches'), join(os.homedir(), '.gradle', 'wrapper')],
// https://github.com/actions/cache/blob/0638051e9af2c23d10bb70fa9beffcad6cff9ce3/examples.md#java---gradle
pattern: ['**/*.gradle*', '**/gradle-wrapper.properties']
}
];
function findPackageManager(id: string): PackageManager {
const packageManager = supportedPackageManager.find(packageManager => packageManager.id === id);
if (packageManager === undefined) {
throw new Error(`unknown package manager specified: ${id}`);
}
return packageManager;
}
/**
* A function that generates a cache key to use.
* Format of the generated key will be "${{ platform }}-${{ id }}-${{ fileHash }}"".
* If there is no file matched to {@link PackageManager.path}, the generated key ends with a dash (-).
* @see {@link https://docs.github.com/en/actions/guides/caching-dependencies-to-speed-up-workflows#matching-a-cache-key|spec of cache key}
*/
async function computeCacheKey(packageManager: PackageManager) {
const hash = await glob.hashFiles(packageManager.pattern.join('\n'));
return `${CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${packageManager.id}-${hash}`;
}
/**
* Restore the dependency cache
* @param id ID of the package manager, should be "maven" or "gradle"
*/
export async function restore(id: string) {
const packageManager = findPackageManager(id);
const primaryKey = await computeCacheKey(packageManager);
core.debug(`primary key is ${primaryKey}`);
core.saveState(STATE_CACHE_PRIMARY_KEY, primaryKey);
if (primaryKey.endsWith('-')) {
throw new Error(
`No file in ${process.cwd()} matched to [${
packageManager.pattern
}], make sure you have checked out the target repository`
);
}
const matchedKey = await cache.restoreCache(packageManager.path, primaryKey, [
`${CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${id}`
]);
if (matchedKey) {
core.saveState(CACHE_MATCHED_KEY, matchedKey);
core.info(`Cache restored from key: ${matchedKey}`);
} else {
core.info(`${packageManager.id} cache is not found`);
}
}
/**
* Save the dependency cache
* @param id ID of the package manager, should be "maven" or "gradle"
*/
export async function save(id: string) {
const packageManager = findPackageManager(id);
const matchedKey = core.getState(CACHE_MATCHED_KEY);
// Inputs are re-evaluted before the post action, so we want the original key used for restore
const primaryKey = core.getState(STATE_CACHE_PRIMARY_KEY);
if (!primaryKey) {
core.warning('Error retrieving key from state.');
return;
} else if (matchedKey === primaryKey) {
// no change in target directories
core.info(`Cache hit occurred on the primary key ${primaryKey}, not saving cache.`);
return;
}
try {
await cache.saveCache(packageManager.path, primaryKey);
core.info(`Cache saved with the key: ${primaryKey}`);
} catch (error) {
if (error.name === cache.ReserveCacheError.name) {
core.info(error.message);
} else {
if (isProbablyGradleDaemonProblem(packageManager, error)) {
core.warning(
'Failed to save Gradle cache on Windows. If tar.exe reported "Permission denied", try to run Gradle with `--no-daemon` option. Refer to https://github.com/actions/cache/issues/454 for details.'
);
}
throw error;
}
}
}
/**
* @param packageManager the specified package manager by user
* @param error the error thrown by the saveCache
* @returns true if the given error seems related to the {@link https://github.com/actions/cache/issues/454|running Gradle Daemon issue}.
* @see {@link https://github.com/actions/cache/issues/454#issuecomment-840493935|why --no-daemon is necessary}
*/
function isProbablyGradleDaemonProblem(packageManager: PackageManager, error: Error) {
if (packageManager.id !== 'gradle' || process.env['RUNNER_OS'] !== 'Windows') {
return false;
}
const message = error.message || '';
return message.startsWith('Tar failed with error: ');
}
+41 -2
View File
@@ -1,8 +1,10 @@
import * as core from '@actions/core'; import * as core from '@actions/core';
import * as gpg from './gpg'; import * as gpg from './gpg';
import * as constants from './constants'; import * as constants from './constants';
import { isJobStatusSuccess } from './util';
import { save } from './cache';
async function run() { async function removePrivateKeyFromKeychain() {
if (core.getInput(constants.INPUT_GPG_PRIVATE_KEY, { required: false })) { if (core.getInput(constants.INPUT_GPG_PRIVATE_KEY, { required: false })) {
core.info('Removing private key from keychain'); core.info('Removing private key from keychain');
try { try {
@@ -14,4 +16,41 @@ async function run() {
} }
} }
run(); /**
* Check given input and run a save process for the specified package manager
* @returns Promise that will be resolved when the save process finishes
*/
async function saveCache() {
const jobStatus = isJobStatusSuccess();
const cache = core.getInput(constants.INPUT_CACHE);
return jobStatus && cache ? save(cache) : Promise.resolve();
}
/**
* The save process is best-effort, and it should not make the workflow fail
* even though this process throws an error.
* @param promise the promise to ignore error from
* @returns Promise that will ignore error reported by the given promise
*/
async function ignoreError(promise: Promise<void>) {
return new Promise(resolve => {
promise
.catch(error => {
core.warning(error);
resolve(void 0);
})
.then(resolve);
});
}
export async function run() {
await removePrivateKeyFromKeychain();
await ignoreError(saveCache());
}
if (require.main === module) {
run();
} else {
// https://nodejs.org/api/modules.html#modules_accessing_the_main_module
core.info('the script is loaded as a module, so skipping the execution');
}
+3
View File
@@ -16,4 +16,7 @@ export const INPUT_GPG_PASSPHRASE = 'gpg-passphrase';
export const INPUT_DEFAULT_GPG_PRIVATE_KEY = undefined; export const INPUT_DEFAULT_GPG_PRIVATE_KEY = undefined;
export const INPUT_DEFAULT_GPG_PASSPHRASE = 'GPG_PASSPHRASE'; export const INPUT_DEFAULT_GPG_PASSPHRASE = 'GPG_PASSPHRASE';
export const INPUT_CACHE = 'cache';
export const INPUT_JOB_STATUS = 'job-status';
export const STATE_GPG_PRIVATE_KEY_FINGERPRINT = 'gpg-private-key-fingerprint'; export const STATE_GPG_PRIVATE_KEY_FINGERPRINT = 'gpg-private-key-fingerprint';
+22 -6
View File
@@ -7,13 +7,20 @@ import semver from 'semver';
import { JavaBase } from '../base-installer'; import { JavaBase } from '../base-installer';
import { IAdoptAvailableVersions } from './models'; import { IAdoptAvailableVersions } from './models';
import { JavaInstallerOptions, JavaDownloadRelease, JavaInstallerResults } from '../base-models'; import { JavaDownloadRelease, JavaInstallerOptions, JavaInstallerResults } from '../base-models';
import { MACOS_JAVA_CONTENT_POSTFIX } from '../../constants';
import { extractJdkFile, getDownloadArchiveExtension, isVersionSatisfies } from '../../util'; import { extractJdkFile, getDownloadArchiveExtension, isVersionSatisfies } from '../../util';
export enum AdoptImplementation {
Hotspot = 'Hotspot',
OpenJ9 = 'OpenJ9'
}
export class AdoptDistribution extends JavaBase { export class AdoptDistribution extends JavaBase {
constructor(installerOptions: JavaInstallerOptions) { constructor(
super('Adopt', installerOptions); installerOptions: JavaInstallerOptions,
private readonly jvmImpl: AdoptImplementation
) {
super(`Adopt-${jvmImpl}`, installerOptions);
} }
protected async findPackageForDownload(version: string): Promise<JavaDownloadRelease> { protected async findPackageForDownload(version: string): Promise<JavaDownloadRelease> {
@@ -70,6 +77,15 @@ export class AdoptDistribution extends JavaBase {
return { version: javaRelease.version, path: javaPath }; return { version: javaRelease.version, path: javaPath };
} }
protected get toolcacheFolderName(): string {
if (this.jvmImpl === AdoptImplementation.Hotspot) {
// exclude Hotspot postfix from distribution name because Hosted runners have pre-cached Adopt OpenJDK under "Java_Adopt_jdk"
// for more information see: https://github.com/actions/setup-java/pull/155#discussion_r610451063
return `Java_Adopt_${this.packageType}`;
}
return super.toolcacheFolderName;
}
private async getAvailableVersions(): Promise<IAdoptAvailableVersions[]> { private async getAvailableVersions(): Promise<IAdoptAvailableVersions[]> {
const platform = this.getPlatformOption(); const platform = this.getPlatformOption();
const arch = this.architecture; const arch = this.architecture;
@@ -83,13 +99,13 @@ export class AdoptDistribution extends JavaBase {
`project=jdk`, `project=jdk`,
'vendor=adoptopenjdk', 'vendor=adoptopenjdk',
`heap_size=normal`, `heap_size=normal`,
`jvm_impl=hotspot`,
'sort_method=DEFAULT', 'sort_method=DEFAULT',
'sort_order=DESC', 'sort_order=DESC',
`os=${platform}`, `os=${platform}`,
`architecture=${arch}`, `architecture=${arch}`,
`image_type=${imageType}`, `image_type=${imageType}`,
`release_type=${releaseType}` `release_type=${releaseType}`,
`jvm_impl=${this.jvmImpl.toLowerCase()}`
].join('&'); ].join('&');
// need to iterate through all pages to retrieve the list of all versions // need to iterate through all pages to retrieve the list of all versions
+11 -2
View File
@@ -1,11 +1,15 @@
import { AdoptDistribution } from './adopt/installer';
import { JavaBase } from './base-installer'; import { JavaBase } from './base-installer';
import { JavaInstallerOptions } from './base-models'; import { JavaInstallerOptions } from './base-models';
import { LocalDistribution } from './local/installer'; import { LocalDistribution } from './local/installer';
import { ZuluDistribution } from './zulu/installer'; import { ZuluDistribution } from './zulu/installer';
import { AdoptDistribution, AdoptImplementation } from './adopt/installer';
import { TemurinDistribution, TemurinImplementation } from './temurin/installer';
enum JavaDistribution { enum JavaDistribution {
Adopt = 'adopt', Adopt = 'adopt',
AdoptHotspot = 'adopt-hotspot',
AdoptOpenJ9 = 'adopt-openj9',
Temurin = 'temurin',
Zulu = 'zulu', Zulu = 'zulu',
JdkFile = 'jdkfile' JdkFile = 'jdkfile'
} }
@@ -19,7 +23,12 @@ export function getJavaDistribution(
case JavaDistribution.JdkFile: case JavaDistribution.JdkFile:
return new LocalDistribution(installerOptions, jdkFile); return new LocalDistribution(installerOptions, jdkFile);
case JavaDistribution.Adopt: case JavaDistribution.Adopt:
return new AdoptDistribution(installerOptions); case JavaDistribution.AdoptHotspot:
return new AdoptDistribution(installerOptions, AdoptImplementation.Hotspot);
case JavaDistribution.AdoptOpenJ9:
return new AdoptDistribution(installerOptions, AdoptImplementation.OpenJ9);
case JavaDistribution.Temurin:
return new TemurinDistribution(installerOptions, TemurinImplementation.Hotspot);
case JavaDistribution.Zulu: case JavaDistribution.Zulu:
return new ZuluDistribution(installerOptions); return new ZuluDistribution(installerOptions);
default: default:
+155
View File
@@ -0,0 +1,155 @@
import * as core from '@actions/core';
import * as tc from '@actions/tool-cache';
import fs from 'fs';
import path from 'path';
import semver from 'semver';
import { JavaBase } from '../base-installer';
import { ITemurinAvailableVersions } from './models';
import { JavaDownloadRelease, JavaInstallerOptions, JavaInstallerResults } from '../base-models';
import { extractJdkFile, getDownloadArchiveExtension, isVersionSatisfies } from '../../util';
export enum TemurinImplementation {
Hotspot = 'Hotspot'
}
export class TemurinDistribution extends JavaBase {
constructor(
installerOptions: JavaInstallerOptions,
private readonly jvmImpl: TemurinImplementation
) {
super(`Temurin-${jvmImpl}`, installerOptions);
}
protected async findPackageForDownload(version: string): Promise<JavaDownloadRelease> {
const availableVersionsRaw = await this.getAvailableVersions();
const availableVersionsWithBinaries = availableVersionsRaw
.filter(item => item.binaries.length > 0)
.map(item => {
// normalize 17.0.0-beta+33.0.202107301459 to 17.0.0+33.0.202107301459 for earlier access versions
const formattedVersion = this.stable
? item.version_data.semver
: item.version_data.semver.replace('-beta+', '+');
return {
version: formattedVersion,
url: item.binaries[0].package.link
} as JavaDownloadRelease;
});
const satisfiedVersions = availableVersionsWithBinaries
.filter(item => isVersionSatisfies(version, item.version))
.sort((a, b) => {
return -semver.compareBuild(a.version, b.version);
});
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}`
);
}
return resolvedFullVersion;
}
protected async downloadTool(javaRelease: JavaDownloadRelease): Promise<JavaInstallerResults> {
let javaPath: string;
let extractedJavaPath: string;
core.info(
`Downloading Java ${javaRelease.version} (${this.distribution}) from ${javaRelease.url} ...`
);
const javaArchivePath = await tc.downloadTool(javaRelease.url);
core.info(`Extracting Java archive...`);
let extension = getDownloadArchiveExtension();
extractedJavaPath = await extractJdkFile(javaArchivePath, extension);
const archiveName = fs.readdirSync(extractedJavaPath)[0];
const archivePath = path.join(extractedJavaPath, archiveName);
const version = this.getToolcacheVersionName(javaRelease.version);
javaPath = await tc.cacheDir(archivePath, this.toolcacheFolderName, version, this.architecture);
return { version: javaRelease.version, path: javaPath };
}
protected get toolcacheFolderName(): string {
return super.toolcacheFolderName;
}
private async getAvailableVersions(): Promise<ITemurinAvailableVersions[]> {
const platform = this.getPlatformOption();
const arch = this.architecture;
const imageType = this.packageType;
const versionRange = encodeURI('[1.0,100.0]'); // retrieve all available versions
const releaseType = this.stable ? 'ga' : 'ea';
console.time('temurin-retrieve-available-versions');
const baseRequestArguments = [
`project=jdk`,
'vendor=adoptium',
`heap_size=normal`,
'sort_method=DEFAULT',
'sort_order=DESC',
`os=${platform}`,
`architecture=${arch}`,
`image_type=${imageType}`,
`release_type=${releaseType}`,
`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 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}'`);
}
const paginationPage = (
await this.http.getJson<ITemurinAvailableVersions[]>(availableVersionsUrl)
).result;
if (paginationPage === null || paginationPage.length === 0) {
// break infinity loop because we have reached end of pagination
break;
}
availableVersions.push(...paginationPage);
page_index++;
}
if (core.isDebug()) {
core.startGroup('Print information about available versions');
console.timeEnd('temurin-retrieve-available-versions');
console.log(`Available versions: [${availableVersions.length}]`);
console.log(availableVersions.map(item => item.version_data.semver).join(', '));
core.endGroup();
}
return availableVersions;
}
private getPlatformOption(): string {
// Adoptium has own platform names so need to map them
switch (process.platform) {
case 'darwin':
return 'mac';
case 'win32':
return 'windows';
default:
return process.platform;
}
}
}
+38
View File
@@ -0,0 +1,38 @@
// Models from https://api.adoptium.net/q/swagger-ui/#/Assets/searchReleasesByVersion
export interface ITemurinAvailableVersions {
binaries: [
{
architecture: string;
heap_size: string;
image_type: string;
jvm_impl: string;
os: string;
package: {
checksum: string;
checksum_link: string;
download_count: number;
link: string;
metadata_link: string;
name: string;
size: string;
};
project: string;
scm_ref: string;
updated_at: string;
}
];
id: string;
release_link: string;
release_name: string;
release_type: string;
vendor: string;
version_data: {
build: number;
major: number;
minor: number;
openjdk_version: string;
security: string;
semver: string;
};
}
+5
View File
@@ -2,6 +2,7 @@ import * as core from '@actions/core';
import * as auth from './auth'; import * as auth from './auth';
import { getBooleanInput } from './util'; import { getBooleanInput } from './util';
import * as constants from './constants'; import * as constants from './constants';
import { restore } from './cache';
import * as path from 'path'; import * as path from 'path';
import { getJavaDistribution } from './distributions/distribution-factory'; import { getJavaDistribution } from './distributions/distribution-factory';
import { JavaInstallerOptions } from './distributions/base-models'; import { JavaInstallerOptions } from './distributions/base-models';
@@ -13,6 +14,7 @@ async function run() {
const architecture = core.getInput(constants.INPUT_ARCHITECTURE); const architecture = core.getInput(constants.INPUT_ARCHITECTURE);
const packageType = core.getInput(constants.INPUT_JAVA_PACKAGE); const packageType = core.getInput(constants.INPUT_JAVA_PACKAGE);
const jdkFile = core.getInput(constants.INPUT_JDK_FILE); const jdkFile = core.getInput(constants.INPUT_JDK_FILE);
const cache = core.getInput(constants.INPUT_CACHE);
const checkLatest = getBooleanInput(constants.INPUT_CHECK_LATEST, false); const checkLatest = getBooleanInput(constants.INPUT_CHECK_LATEST, false);
const installerOptions: JavaInstallerOptions = { const installerOptions: JavaInstallerOptions = {
@@ -40,6 +42,9 @@ async function run() {
core.info(`##[add-matcher]${path.join(matchersPath, 'java.json')}`); core.info(`##[add-matcher]${path.join(matchersPath, 'java.json')}`);
await auth.configureAuthentication(); await auth.configureAuthentication();
if (cache) {
await restore(cache);
}
} catch (error) { } catch (error) {
core.setFailed(error.message); core.setFailed(error.message);
} }
+8
View File
@@ -5,6 +5,8 @@ import * as semver from 'semver';
import * as core from '@actions/core'; import * as core from '@actions/core';
import * as tc from '@actions/tool-cache'; import * as tc from '@actions/tool-cache';
import { INPUT_JOB_STATUS } from './constants';
export function getTempDir() { export function getTempDir() {
let tempDirectory = process.env['RUNNER_TEMP'] || os.tmpdir(); let tempDirectory = process.env['RUNNER_TEMP'] || os.tmpdir();
@@ -69,3 +71,9 @@ export function getToolcachePath(toolName: string, version: string, architecture
return null; return null;
} }
export function isJobStatusSuccess() {
const jobStatus = core.getInput(INPUT_JOB_STATUS);
return jobStatus === 'success';
}