Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Support multiple JDKs during build #44

Closed
vy opened this issue Jan 21, 2020 · 25 comments
Closed

Support multiple JDKs during build #44

vy opened this issue Jan 21, 2020 · 25 comments
Assignees
Labels
feature request New feature or request to improve the current logic investigation The issue is under investigation

Comments

@vy
Copy link

vy commented Jan 21, 2020

Certain projects might require multiple JDKs during build (e.g., Apache Log4j requires Java 7 and Java 9+ by means of toolchains.xml) and in its current form, that is not possible via setup-java.

@giltene
Copy link
Contributor

giltene commented Jan 21, 2020

+1

It appears to me that adding an optional java-home variable that would determine where to place the java package (which can currently be a jre, jdk, or jdk+fx), overriding the default location, would suffice, right? One would the use setup-java multiple times, once per version.

@jvalkeal
Copy link

I'm just wondering what happens if you define two different setup-java steps with different jvm's. Looking sources it set's this extendedJavaHome env variable:

let extendedJavaHome = 'JAVA_HOME_' + version + '_' + arch;
core.exportVariable('JAVA_HOME', toolPath);
core.exportVariable(extendedJavaHome, toolPath);
core.addPath(path.join(toolPath, 'bin'));

@mprins
Copy link

mprins commented Jan 29, 2020

I managed to do this by calling out to the setup-java action for each JDK I have confgured in my toolchain (1.8 and 11) plus once for the JDK I want to run maven with (so 3 times in total).

see B3Partners/kadaster-gds2#47

@giltene
Copy link
Contributor

giltene commented Jan 29, 2020

I'm just wondering what happens if you define two different setup-java steps with different jvm's. Looking sources it set's this extendedJavaHome env variable:

I think that knowing where the JDK was installed is not enough. Some tools expect that java versions to appear at specific file paths. E.g. https://github.com/apache/logging-log4j2/blob/64a5c73636cef24c5cbb70143eef99536944d188/.travis-toolchains.xml#L28 . You could probably do something by symlinking the requested path to where extendedJavaHome points, but that would be messy for the user, and fairly easy for us to do in installer.ts if indicated by setting an optional java-home variable

@mprins
Copy link

mprins commented Jan 29, 2020

Some tools expect that java versions to appear at specific file paths.

see:
https://github.com/B3Partners/kadaster-gds2/runs/415167771?check_suite_focus=true#step:7:14

 Inspect environment0s
JAVA_HOME_8_x64=/opt/hostedtoolcache/jdk/8.0.242/x64
Run set | grep JAVA
  set | grep JAVA
  shell: /bin/bash -e {0}
  env:
    JAVA_HOME: /opt/hostedtoolcache/jdk/8.0.242/x64
    JAVA_HOME_11.0.6_x64: /opt/hostedtoolcache/jdk/11.0.6/x64
    JAVA_HOME_8.0.242_x64: /opt/hostedtoolcache/jdk/8.0.242/x64
    JAVA_HOME_8_x64: /opt/hostedtoolcache/jdk/8.0.242/x64
    JAVA_HOME=/opt/hostedtoolcache/jdk/8.0.242/x64
    JAVA_HOME_11_X64=/usr/lib/jvm/zulu-11-azure-amd64
    JAVA_HOME_12_X64=/usr/lib/jvm/zulu-12-azure-amd64
    JAVA_HOME_7_X64=/usr/lib/jvm/zulu-7-azure-amd64
    JAVA_HOME_8_X64=/usr/lib/jvm/zulu-8-azure-amd64
    JAVA_HOME_8_x64=/opt/hostedtoolcache/jdk/8.0.242/x64

you can use environment vars in your toolchain

https://github.com/B3Partners/kadaster-gds2/blob/b0cd5c392bc1f48dec11c83c828254a868264467/.github/ubuntu-toolchains.xml#L6-L22

@koppor
Copy link

koppor commented Feb 27, 2020

This somehow refs #21. Then, one can "just" rely on environment variables.

@TheMrMilchmann
Copy link

Hi, I forked this project a while ago to change some things according to my needs. However, there were also additional changes that might be of interest to this project. (Sorry for bringing them up so late. I could have sworn that I commented about this months ago.)

Supporting multiple JDKs was an important feature I needed at that time and the solution I ended up going with is adding an additional input parameter to the action used to specify the "target" environment variable/s with the following semantics:

  • If the target is not specified explicitly, only JAVA_HOME is set to point to the JDK.
  • If the target is specified explicitly, it is interpreted as a ; separated list of environment variables that will be set to point to the JDK. (JAVA_HOME is not set to point to the JDK unless the input explicitly contains JAVA_HOME.)

Naturally, this makes it incredibly easy to work with multiple JDK versions since their locations could simply be pointed to by separate environment variables. For example:

- uses: AdoptOpenJDK/install-jdk@v1
  with:
    version: '8'
- uses: AdoptOpenJDK/install-jdk@v1
  with:
    version: '9'
    targets: 'JDK_9'

This snippet suffices is sufficient to set up a Java 8 and Java 9 for parallel use. Here, 8 will be pointed to by JAVA_HOME, and 9 will be pointed to by JDK_9. (Also, note that this would also fix #21.)

Some tools expect that java versions to appear at specific file paths.

Additionally, should it become necessary to provide control about the directory in which the JDK should reside in (I have not seen the need arise yet), it would be possible to add this as an additional property. In my opinion, controlling the location of the file-system and the environment variables are orthogonal concepts that should not be configurable separately.

If you are interested I would love to get this integrated upstream and I would be happy to contribute.

@jonashackt
Copy link

jonashackt commented Jan 7, 2021

I wonder if the matrix strategy is already everything we need here (as also stated on stackoverflow). I implemented this in codecentric/cxf-spring-boot-starter's action configuration in the .github/workflows/maven.yml:

name: github

on: [push]

jobs:
  build:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        java-version: [ 8, 11, 15 ]

    steps:
    - uses: actions/checkout@v2
    - uses: actions/setup-java@v1
      with:
        java-version: ${{ matrix.java-version }}
    - run: mvn -B install --no-transfer-progress --file pom.xml

@mprins
Copy link

mprins commented Jan 7, 2021

steps:
- uses: actions/checkout@v2
- uses: actions/setup-java@v1
  with:
    java-version: ${{ matrix.java-version }}

No, this only installs 1 java version for one build, not multiple java versions for 1 build

@jonashackt
Copy link

Ah I see. Didn't get that first, maybe the issue could be refrased a bit like Support multiple JDKs during a single build step or similar.

@dmitry-shibanov dmitry-shibanov added the feature request New feature or request to improve the current logic label Jan 14, 2021
@nipafx
Copy link

nipafx commented Mar 9, 2021

Since Java 9, jlink can be used to create runtime images that are a subset of the full JDK (and hence OS-specific). For that, the tool needs an unzipped JDK lying around. The cool thing is that it can also create runtime images for a different OS than it is executed on, but then it of course needs that OS's JDK.

So it would be nice if setup-java could not only setup (and configure in toolchains.xml) different Java versions, but also JDKs for different operating systems.

@bmarwell
Copy link

bmarwell commented Apr 9, 2021

Since Java 9, jlink can be used to create runtime images that are a subset of the full JDK (and hence OS-specific). For that, the tool needs an unzipped JDK lying around. The cool thing is that it can also create runtime images for a different OS than it is executed on, but then it of course needs that OS's JDK.

Look what we did for the maven-jlink-plugin:
https://github.com/apache/maven-jlink-plugin/blob/master/.github/workflows/maven.yml

While we could migrate to v2 and still use AdoptOpenJDK/install-jdk@v1 for the secondary java, it would be nice to have this as an out-of-the-box experience.

@evpaassen
Copy link

For the Gradle users, it would be incredibly useful if Gradle could auto-detect JVMs provisioned by the setup-java action using their Toolchains for JVM projects feature.

There's already an issue in the Gradle repository to make this happen, but it needs a way to detect the provisioned JVMs: gradle/gradle#14903. Perhaps a bit of guidance from the maintainers of this action could get things running?

@bmarwell
Copy link

bmarwell commented Jun 1, 2021

Any update on this?

@laeubi
Copy link

laeubi commented Aug 4, 2021

The tycho project could use that as well...

rognan added a commit to rognan/deno-gradle-plugin that referenced this issue Nov 28, 2021
Gradle will by default use the same JDK for building the project as it
does for running Gradle. Newer JDKs are assumed to be more performant,
contain fewer bugs and to come with desirable features that we would
like to utilize in our build, but doing so should not endanger
backwards compatibility for the plugin itself. We can do that now by
utilizing Gradle toolchains, which allows us to use one JDK/JRE for
running Gradle and the other for building the project, i.e. executing
`javac`.

Doing this requires us to make multiple JDKs available to the Gradle
build action for each individual execution of the build. The setup-java
action doesn't support this at the moment, and the multiple build steps
configured for actions/setup-java in this commit is at best a
workaround for this, and at worst a bad assumption with respect to no
environment variables or other settings being overwritten. Also,
there's no handling of duplicate invocations of the action with the end
result being duplicate JDKs installed. Hopefully both actions/setup-java
and gradle/gradle-build-action will handle this case gracefully.

For more details, see:
- actions/setup-java#44
- gradle/gradle#14903
rognan added a commit to rognan/deno-gradle-plugin that referenced this issue Nov 28, 2021
Gradle will by default use the same JDK for building the project as it
does for running Gradle. Newer JDKs are assumed to be more performant,
contain fewer bugs and to come with desirable features that we would
like to utilize in our build, but doing so should not endanger
backwards compatibility for the plugin itself. We can do that now by
utilizing Gradle toolchains, which allows us to use one JDK/JRE for
running Gradle and the other for building the project, i.e. executing
`javac`.

Doing this requires us to make multiple JDKs available to the Gradle
build action for each individual execution of the build. The setup-java
action doesn't support this at the moment, and the multiple build steps
configured for actions/setup-java in this commit is at best a
workaround for this, and at worst a bad assumption with respect to no
environment variables or other settings being overwritten. Also,
there's no handling of duplicate invocations of the action with the end
result being duplicate JDKs installed. Hopefully both actions/setup-java
and gradle/gradle-build-action will handle this case gracefully.

For more details, see:
- actions/setup-java#44
- gradle/gradle#14903
rognan added a commit to rognan/deno-gradle-plugin that referenced this issue Nov 28, 2021
This commit decouples the JDK running Gradle from the one building the
project.

Gradle will by default use the same JDK for building the project as it
does for running Gradle. Newer JDKs are assumed to be more performant,
contain fewer bugs and to come with desirable features that we would
like to utilize in our build, but doing so should not endanger
backwards compatibility for the plugin itself. We can do that now by
utilizing Gradle toolchains, which allows us to use one JDK/JRE for
running Gradle and the other for building the project, i.e. executing
`javac`.

Doing this requires us to make multiple JDKs available to the Gradle
build action for each individual execution of the build. The setup-java
action doesn't support this at the moment, and the multiple build steps
configured for actions/setup-java in this commit is at best a
workaround for this, and at worst a bad assumption with respect to
environment variables or other settings being overwritten. Furthermore,
there's no handling of duplicate invocations of the action.

Hopefully both actions/setup-java and gradle/gradle-build-action will
handle all of this gracefully.

For more details, see:
- actions/setup-java#44
- gradle/gradle#14903
rognan added a commit to rognan/deno-gradle-plugin that referenced this issue Nov 29, 2021
This commit decouples the JDK running Gradle from the one building the
project.

Gradle will by default use the same JDK for building the project as it
does for running Gradle. Newer JDKs are assumed to be more performant,
contain fewer bugs and to come with desirable features that we would
like to utilize in our build, but doing so should not endanger
backwards compatibility for the plugin itself. We can do that now by
utilizing Gradle toolchains, which allows us to use one JDK/JRE for
running Gradle and the other for building the project, i.e. executing
`javac`.

Doing this requires us to make multiple JDKs available to the Gradle
build action for each individual execution of the build. The setup-java
action doesn't support this at the moment, and the multiple build steps
configured for actions/setup-java in this commit is at best a
workaround for this, and at worst a bad assumption with respect to
environment variables or other settings being overwritten. Furthermore,
there's no handling of duplicate invocations of the action.

Hopefully both actions/setup-java and gradle/gradle-build-action will
handle all of this gracefully.

For more details, see:
- actions/setup-java#44
- gradle/gradle#14903
@laeubi
Copy link

laeubi commented Jun 5, 2022

and configure in toolchains.xml

There is even a PR for this already, would be cool if it could be merged: #282

I ended up going with is adding an additional input parameter to the action used to specify the "target" environment variable/s with the following semantics:

* If the target is not specified explicitly, only `JAVA_HOME` is set to point to the JDK.

* If the target is specified explicitly, it is interpreted as a `;` separated list of environment variables that will be set to point to the JDK. (`JAVA_HOME` is **not** set to point to the JDK unless the input explicitly contains `JAVA_HOME`.)

Naturally, this makes it incredibly easy to work with multiple JDK versions since their locations could simply be pointed to by separate environment variables

This sounds really useful do you think you can open a PR?

@dmitry-shibanov any chance this could be implemented soon or a PR being accepted for this?

@e-korolevskii
Copy link
Contributor

Hello @laeubi,

We will explore this pull request and the possibility of adding this functionality.

@e-korolevskii e-korolevskii added the investigation The issue is under investigation label Jun 9, 2022
@e-korolevskii e-korolevskii removed their assignment Jul 4, 2022
@dsame
Copy link
Contributor

dsame commented Jul 5, 2022

hello @vy, i believe the solution suggested by @jvalkeal do exactly that was requested:

    - uses: actions/setup-java@v1
      with:
        java-version: 8
    
    - uses: actions/setup-java@v1
      with:
        java-version: 11
    
    - uses: actions/setup-java@v1
      with:
        java-version: 15

installs all 3 JDKs in their own directory under /opt/hostedtoolcache/jdk.

And in case if it is needed to know the exact location of every JDK just store them somewhere, say in environment :

    - uses: actions/setup-java@v1
    with:
      java-version: 8
  - run: echo "JAVA_8=$JAVA_HOME" >> $GITHUB_ENV
  
  - uses: actions/setup-java@v1
    with:
      java-version: 11
  - run: echo "JAVA_11=$JAVA_HOME" >> $GITHUB_ENV
  
  - uses: actions/setup-java@v1
    with:
      java-version: 15
  - run: echo "JAVA_15=$JAVA_HOME" >> $GITHUB_ENV

the result is

#set|grep JAVA
JAVA_[1](https://github.com/akv-demo/setup-java-test/runs/7204409652?check_suite_focus=true#step:9:1)1=/opt/hostedtoolcache/jdk/11.0.[15](https://github.com/akv-demo/setup-java-test/runs/7204409652?check_suite_focus=true#step:9:16)/x64
JAVA_15=/opt/hostedtoolcache/jdk/15.0.7/x64
JAVA_8=/opt/hostedtoolcache/jdk/8.0.332/x64
JAVA_HOME=/opt/hostedtoolcache/jdk/15.0.7/x64
JAVA_HOME_11_0_15_X64=/opt/hostedtoolcache/jdk/11.0.15/x64
JAVA_HOME_11_X64=/usr/lib/jvm/temurin-11-jdk-amd64
JAVA_HOME_15_0_7_X64=/opt/hostedtoolcache/jdk/15.0.7/x64
JAVA_HOME_[17](https://github.com/akv-demo/setup-java-test/runs/7204409652?check_suite_focus=true#step:9:18)_X64=/usr/lib/jvm/temurin-17-jdk-amd64
JAVA_HOME_8_0_332_X64=/opt/hostedtoolcache/jdk/8.0.332/x64
JAVA_HOME_8_X64=/usr/lib/jvm/temurin-8-jdk-amd64

and

#ls  /opt/hostedtoolcache/jdk/
11.0.15
15.0.7
8.0.332

i think this approach is more straightforward than complicating the action with non-obvious inputs

@dsame dsame self-assigned this Jul 5, 2022
@vy
Copy link
Author

vy commented Jul 6, 2022

Agreed that the concern expressed at the beginning can be addressed by running the action multiple times with different Java versions. As a matter of fact, that is what we ended up doing in Log4j too.

@vy vy closed this as completed Jul 6, 2022
@laeubi
Copy link

laeubi commented Jul 6, 2022

@vy if this is really the solution for this issue, it should mention the snippet on the Help/Readme page, I think this is not that obvious to the usual user.

@dsame
Copy link
Contributor

dsame commented Jul 7, 2022

@laeubi thank you for the suggestion, can you please take a look at this PR and confirm it is enough to clarify the use case?

@dsame dsame reopened this Jul 7, 2022
@dsame
Copy link
Contributor

dsame commented Jul 15, 2022

The snippet to install multiple JDKs and keep the paths to each in the intermediate variables added to README by the PR #351

@Okeanos
Copy link
Contributor

Okeanos commented Aug 17, 2022

I am currently working on #276 (see #282 as already mentioned by @laeubi), i.e. directly supporting a generation of the toolchains.xml file mentioned in the initial issue comment. The changes are currently being reviewed and do the following things:

  • (optionally) generate a toolchains.xml into the default location, i.e. ~/.m2/toolchains.xml, or {{settings-path}}/toolchains.xml if the input value is specified in the setup-java step
  • add a toolchain with vendor, version, jdkHome, and (custom or default) id for the specified JDK
  • update any existing toolchains.xml in the specified path to add additional JDKs to it without removing existing entries

Checkout the aforementioned issue and PR for more details or in case you want to leave feedback; specifically before the maintainers decide the implementation is integration-worthy.

@nielsbasjes
Copy link

FYI: I have managed to make this work for my own project like this: https://github.com/nielsbasjes/yauaa/blob/main/.github/workflows/build.yml#L43

@dmitry-shibanov dmitry-shibanov self-assigned this Sep 9, 2022
@dmitry-shibanov
Copy link
Contributor

Hello everyone. We released a new version of setup-java with support of multiple jdks. For now I'm going to close the issue. If you have any concerns feel free to ping us.

rognan added a commit to rognan/deno-gradle-plugin that referenced this issue Sep 17, 2022
This commit decouples the JDK running Gradle from the one building the
project.

Gradle will by default use the same JDK for building the project as it
does for running Gradle. Newer JDKs are assumed to be more performant,
contain fewer bugs and to come with desirable features that we would
like to utilize in our build, but doing so should not endanger
backwards compatibility for the plugin itself. We can do that now by
utilizing Gradle toolchains, which allows us to use one JDK/JRE for
running Gradle and the other for building the project, i.e. executing
`javac`.

Doing this requires us to make multiple JDKs available to the Gradle
build action for each individual execution of the build. The setup-java
action doesn't support this at the moment, and the multiple build steps
configured for actions/setup-java in this commit is at best a
workaround for this, and at worst a bad assumption with respect to
environment variables or other settings being overwritten. Furthermore,
there's no handling of duplicate invocations of the action.

Hopefully both actions/setup-java and gradle/gradle-build-action will
handle all of this gracefully.

For more details, see:
- actions/setup-java#44
- gradle/gradle#14903
rognan added a commit to rognan/deno-gradle-plugin that referenced this issue Sep 17, 2022
This commit decouples the JDK running Gradle from the one building the
project.

Gradle will by default use the same JDK for building the project as it
does for running Gradle. Newer JDKs are assumed to be more performant,
contain fewer bugs and to come with desirable features that we would
like to utilize in our build, but doing so should not endanger
backwards compatibility for the plugin itself. We can do that now by
utilizing Gradle toolchains, which allows us to use one JDK/JRE for
running Gradle and the other for building the project, i.e. executing
`javac`.

Doing this requires us to make multiple JDKs available to the Gradle
build action for each individual execution of the build. The setup-java
action doesn't support this at the moment, and the multiple build steps
configured for actions/setup-java in this commit is at best a
workaround for this, and at worst a bad assumption with respect to
environment variables or other settings being overwritten. Furthermore,
there's no handling of duplicate invocations of the action.

Hopefully both actions/setup-java and gradle/gradle-build-action will
handle all of this gracefully.

For more details, see:
- actions/setup-java#44
- gradle/gradle#14903
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
feature request New feature or request to improve the current logic investigation The issue is under investigation
Projects
None yet
Development

No branches or pull requests