Repository: actions/setup-java (TypeScript)

Issue:
JAVA_HOME is not set correctly on MacOS for local (jdkFile) installed JDKs that are present in the tool cache
**Description:**
Local installed JDKs using the jdkFile option that are already present in the tool cache are not checked for suffix 'Contents/Home' on macos, so as a result the JAVA_HOME is not set correctly.

**Task version:**
v3

**Platform:**
- [ ] Ubuntu
- [x] macOS
- [ ] Windows

**Runner type:**
- [x] Hosted
- [x] Self-hosted

**Repro steps:**  
- run a workflow with setup-java with a jdkFile option on a self-hosted runner on MacOS using a JDK that places files in 'Contents/Home'
- the first time this works fine. JAVA_HOME is set correctly including 'Contents/Home'
- run the workflow again, this time the JDK will already be present in the tool cache
- setup-java now sets JAVA_HOME without the 'Contents/Home' suffix

**Expected behavior:**
When the JDK is available in the tool cache, JAVA_HOME must be set correctly.

**Actual behavior:**
When the JDK is available in the tool cache, JAVA_HOME is set without checking if the JDK is placed in 'Contents/Home'


Discussion:
hi @erwin1, thank you for the report. We will take a look at it
By the way, could you provide us public repo with repro steps?
Thanks.

Here's a public repo: https://github.com/erwin1/setup-java-mac-sscce 
On a hosted runner it's a bit harder to reproduce because every run happens on a different runner (so less chance of having a tool cache).

Although I was able to reproduce with a trick to use setup-java again in the same job.

This fails:
https://github.com/erwin1/setup-java-mac-sscce/actions/runs/3344915283/jobs/5539822614

And using the proposed fix from #397 it works:
https://github.com/erwin1/setup-java-mac-sscce/actions/runs/3344942099/jobs/5539881412


added 2 unit tests of which one fails (`java is resolved from toolcache including Contents/Home on MacOS`) without the proposed fix
Any chance we can move this forward?
hi @erwin1, sorry for the delayed answer, thank you for the repo I will take a look again :)
We are still regularly running into this issue, so it would be great to get a review on the PR. Thanks!
Hello @erwin1. We've merged your pull request. For now you can try to use this changes with `actions/setup-java@main`. We'll ping you when new release is ready. 

For now I'm going to reopen it until we release a new version. 
Thanks, using `@main` works as expected now:
https://github.com/erwin1/setup-java-mac-sscce/actions/runs/4606608821

Hi, @erwin1  👋 The [new version](https://github.com/actions/setup-java/releases/tag/v3.12.0) of the setup-java is released. Please, check it out.

I'm going to close this issue, If you have any additions or questions feel free to ping us.



Patch:
diff --git a/dist/setup/index.js b/dist/setup/index.js
index 2d095d423..b9308830c 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -104608,17 +104608,17 @@ class LocalDistribution extends base_installer_1.JavaBase {
                 const archiveName = fs_1.default.readdirSync(extractedJavaPath)[0];
                 const archivePath = path_1.default.join(extractedJavaPath, archiveName);
                 const javaVersion = this.version;
-                let javaPath = yield tc.cacheDir(archivePath, this.toolcacheFolderName, this.getToolcacheVersionName(javaVersion), this.architecture);
-                // for different Java distributions, postfix can exist or not so need to check both cases
-                if (process.platform === 'darwin' &&
-                    fs_1.default.existsSync(path_1.default.join(javaPath, constants_1.MACOS_JAVA_CONTENT_POSTFIX))) {
-                    javaPath = path_1.default.join(javaPath, constants_1.MACOS_JAVA_CONTENT_POSTFIX);
-                }
+                const javaPath = yield tc.cacheDir(archivePath, this.toolcacheFolderName, this.getToolcacheVersionName(javaVersion), this.architecture);
                 foundJava = {
                     version: javaVersion,
                     path: javaPath
                 };
             }
+            // JDK folder may contain postfix "Contents/Home" on macOS
+            const macOSPostfixPath = path_1.default.join(foundJava.path, constants_1.MACOS_JAVA_CONTENT_POSTFIX);
+            if (process.platform === 'darwin' && fs_1.default.existsSync(macOSPostfixPath)) {
+                foundJava.path = macOSPostfixPath;
+            }
             core.info(`Setting Java ${foundJava.version} as default`);
             this.setJavaDefault(foundJava.version, foundJava.path);
             return foundJava;
diff --git a/src/distributions/local/installer.ts b/src/distributions/local/installer.ts
index 72c2d27f1..adfac4998 100644
--- a/src/distributions/local/installer.ts
+++ b/src/distributions/local/installer.ts
@@ -47,27 +47,28 @@ export class LocalDistribution extends JavaBase {
       const archivePath = path.join(extractedJavaPath, archiveName);
       const javaVersion = this.version;
 
-      let javaPath = await tc.cacheDir(
+      const javaPath = await tc.cacheDir(
         archivePath,
         this.toolcacheFolderName,
         this.getToolcacheVersionName(javaVersion),
         this.architecture
       );
 
-      // for different Java distributions, postfix can exist or not so need to check both cases
-      if (
-        process.platform === 'darwin' &&
-        fs.existsSync(path.join(javaPath, MACOS_JAVA_CONTENT_POSTFIX))
-      ) {
-        javaPath = path.join(javaPath, MACOS_JAVA_CONTENT_POSTFIX);
-      }
-
       foundJava = {
         version: javaVersion,
         path: javaPath
       };
     }
 
+    // JDK folder may contain postfix "Contents/Home" on macOS
+    const macOSPostfixPath = path.join(
+      foundJava.path,
+      MACOS_JAVA_CONTENT_POSTFIX
+    );
+    if (process.platform === 'darwin' && fs.existsSync(macOSPostfixPath)) {
+      foundJava.path = macOSPostfixPath;
+    }
+
     core.info(`Setting Java ${foundJava.version} as default`);
 
     this.setJavaDefault(foundJava.version, foundJava.path);


Test patch:
diff --git a/__tests__/distributors/local-installer.test.ts b/__tests__/distributors/local-installer.test.ts
index 717f97ad0..8e9d5d437 100644
--- a/__tests__/distributors/local-installer.test.ts
+++ b/__tests__/distributors/local-installer.test.ts
@@ -214,6 +214,93 @@ describe('setupJava', () => {
     );
   });
 
+  it('java is resolved from toolcache including Contents/Home on MacOS', async () => {
+    const inputs = {
+      version: actualJavaVersion,
+      architecture: 'x86',
+      packageType: 'jdk',
+      checkLatest: false
+    };
+    const jdkFile = 'not_existing_one';
+    const expected = {
+      version: actualJavaVersion,
+      path: path.join(
+        'Java_jdkfile_jdk',
+        inputs.version,
+        inputs.architecture,
+        'Contents',
+        'Home'
+      )
+    };
+    const originalPlatform = process.platform;
+    Object.defineProperty(process, 'platform', {
+      value: 'darwin'
+    });
+
+    spyFsStat = jest.spyOn(fs, 'existsSync');
+    spyFsStat.mockImplementation((file: string) => {
+      return file.endsWith('Home');
+    });
+
+    mockJavaBase = new LocalDistribution(inputs, jdkFile);
+    await expect(mockJavaBase.setupJava()).resolves.toEqual(expected);
+    expect(spyGetToolcachePath).toHaveBeenCalled();
+    expect(spyCoreInfo).toHaveBeenCalledWith(
+      `Resolved Java ${actualJavaVersion} from tool-cache`
+    );
+    expect(spyCoreInfo).not.toHaveBeenCalledWith(
+      `Java ${inputs.version} was not found in tool-cache. Trying to unpack JDK file...`
+    );
+
+    Object.defineProperty(process, 'platform', {
+      value: originalPlatform
+    });
+  });
+
+  it('java is unpacked from jdkfile including Contents/Home on MacOS', async () => {
+    const inputs = {
+      version: '11.0.289',
+      architecture: 'x86',
+      packageType: 'jdk',
+      checkLatest: false
+    };
+    const jdkFile = expectedJdkFile;
+    const expected = {
+      version: '11.0.289',
+      path: path.join(
+        'Java_jdkfile_jdk',
+        inputs.version,
+        inputs.architecture,
+        'Contents',
+        'Home'
+      )
+    };
+    const originalPlatform = process.platform;
+    Object.defineProperty(process, 'platform', {
+      value: 'darwin'
+    });
+    spyFsStat = jest.spyOn(fs, 'existsSync');
+    spyFsStat.mockImplementation((file: string) => {
+      return file.endsWith('Home');
+    });
+
+    mockJavaBase = new LocalDistribution(inputs, jdkFile);
+    await expect(mockJavaBase.setupJava()).resolves.toEqual(expected);
+    expect(spyTcFindAllVersions).toHaveBeenCalled();
+    expect(spyCoreInfo).not.toHaveBeenCalledWith(
+      `Resolved Java ${actualJavaVersion} from tool-cache`
+    );
+    expect(spyCoreInfo).toHaveBeenCalledWith(
+      `Extracting Java from '${jdkFile}'`
+    );
+    expect(spyCoreInfo).toHaveBeenCalledWith(
+      `Java ${inputs.version} was not found in tool-cache. Trying to unpack JDK file...`
+    );
+    Object.defineProperty(process, 'platform', {
+      value: originalPlatform
+    });
+  });
+
   it.each([
     [
       {