From 5896cecc08fd8a1fbdfaf517e29b571164b031f7 Mon Sep 17 00:00:00 2001
From: mahabaleshwars <147705296+mahabaleshwars@users.noreply.github.com>
Date: Tue, 12 Mar 2024 19:15:42 +0530
Subject: [PATCH] Added  .tool-versions file support (#606)

* added support for tool version file

* testing with one regex

* working regex

* Checked for the file extension

* added e2e checks for tool version

* removed error warning

* updated regex to support early version

* updated regex for early version support

* updated regex for early version

* updated regex to accept early versions

* added coreinfo to analyze

* updated the regex

* updated regex

* new regex for early version

* updated regex to match the new version file format

* new regex

* changed the regex

* redex updated

* used java version regex

* regex updated

* regex modified

* regex updated

* regex updated

* regex updated

* updated regex to support early versions

* Regex updated to support all java versions

* Documentation updated to add tool version description

* Documentation updated for the tool version file

* update the advanced doc and readme file to specify tool version changes
---
 .github/workflows/e2e-versions.yml | 24 ++++++++++++++++++++----
 README.md                          |  3 ++-
 dist/cleanup/index.js              | 14 ++++++++++++--
 dist/setup/index.js                | 16 +++++++++++++---
 docs/advanced-usage.md             | 15 +++++++++++----
 src/setup-java.ts                  |  6 +++++-
 src/util.ts                        | 14 ++++++++++++--
 7 files changed, 75 insertions(+), 17 deletions(-)

diff --git a/.github/workflows/e2e-versions.yml b/.github/workflows/e2e-versions.yml
index 1f9d6e7..8b9e111 100644
--- a/.github/workflows/e2e-versions.yml
+++ b/.github/workflows/e2e-versions.yml
@@ -288,19 +288,23 @@ jobs:
       matrix:
         os: [macos-latest, windows-latest, ubuntu-latest]
         distribution: ['temurin', 'microsoft', 'corretto']
+        java-version-file: ['.java-version', '.tool-versions']
     steps:
       - name: Checkout
         uses: actions/checkout@v4
       - name: Create .java-version file
         shell: bash
         run: echo "8" > .java-version
+      - name: Create .tool-versions file
+        shell: bash
+        run: echo "java 8" > .tool-versions
       - name: setup-java
         uses: ./
         id: setup-java
         with:
           distribution: ${{ matrix.distribution }}
           java-version: 11
-          java-version-file: '.java-version'
+          java-version-file: ${{matrix.java-version-file }}
       - name: Verify Java
         run: bash __tests__/verify-java.sh "11" "${{ steps.setup-java.outputs.path }}"
         shell: bash
@@ -313,18 +317,22 @@ jobs:
       matrix:
         os: [macos-latest, windows-latest, ubuntu-latest]
         distribution: ['temurin', 'zulu', 'liberica', 'microsoft', 'corretto']
+        java-version-file: ['.java-version', '.tool-versions']
     steps:
       - name: Checkout
         uses: actions/checkout@v4
       - name: Create .java-version file
         shell: bash
         run: echo "11" > .java-version
+      - name: Create .tool-versions file
+        shell: bash
+        run: echo "java 11" > .tool-versions
       - name: setup-java
         uses: ./
         id: setup-java
         with:
           distribution: ${{ matrix.distribution }}
-          java-version-file: '.java-version'
+          java-version-file: ${{matrix.java-version-file }}
       - name: Verify Java
         run: bash __tests__/verify-java.sh "11" "${{ steps.setup-java.outputs.path }}"
         shell: bash
@@ -337,18 +345,22 @@ jobs:
       matrix:
         os: [macos-latest, windows-latest, ubuntu-latest]
         distribution: ['adopt', 'adopt-openj9', 'zulu']
+        java-version-file: ['.java-version', '.tool-versions']
     steps:
       - name: Checkout
         uses: actions/checkout@v4
       - name: Create .java-version file
         shell: bash
         run: echo "11.0.2" > .java-version
+      - name: Create .tool-versions file
+        shell: bash
+        run: echo "java 11.0.2" > .tool-versions
       - name: setup-java
         uses: ./
         id: setup-java
         with:
           distribution: ${{ matrix.distribution }}
-          java-version-file: '.java-version'
+          java-version-file: ${{matrix.java-version-file }}
       - name: Verify Java
         run: bash __tests__/verify-java.sh "11.0.2" "${{ steps.setup-java.outputs.path }}"
         shell: bash
@@ -361,18 +373,22 @@ jobs:
       matrix:
         os: [macos-latest, windows-latest, ubuntu-latest]
         distribution: ['adopt', 'zulu', 'liberica']
+        java-version-file: ['.java-version', '.tool-versions']
     steps:
       - name: Checkout
         uses: actions/checkout@v4
       - name: Create .java-version file
         shell: bash
         run: echo "openjdk64-11.0.2" > .java-version
+      - name: Create .tool-versions file
+        shell: bash
+        run: echo "java openjdk64-11.0.2" > .tool-versions
       - name: setup-java
         uses: ./
         id: setup-java
         with:
           distribution: ${{ matrix.distribution }}
-          java-version-file: '.java-version'
+          java-version-file: ${{matrix.java-version-file }}
       - name: Verify Java
         run: bash __tests__/verify-java.sh "11.0.2" "${{ steps.setup-java.outputs.path }}"
         shell: bash
diff --git a/README.md b/README.md
index 92425cc..a3ac397 100644
--- a/README.md
+++ b/README.md
@@ -27,7 +27,7 @@ This action allows you to work with Java and Scala projects.
 
   - `java-version`: The Java version that is going to be set up. Takes a whole or [semver](#supported-version-syntax) Java version. If not specified, the action will expect `java-version-file` input to be specified.
 
-  - `java-version-file`: The path to the `.java-version` file. See more details in [about `.java-version` file](docs/advanced-usage.md#Java-version-file).
+  - `java-version-file`: The path to a file containing java version. Supported file types are `.java-version` and `.tool-versions`. See more details in [about .java-version-file](docs/advanced-usage.md#Java-version-file).
    
   - `distribution`: _(required)_ Java [distribution](#supported-distributions).
 
@@ -266,6 +266,7 @@ In the example above multiple JDKs are installed for the same job. The result af
 - [Publishing using Gradle](docs/advanced-usage.md#Publishing-using-Gradle)
 - [Hosted Tool Cache](docs/advanced-usage.md#Hosted-Tool-Cache)
 - [Modifying Maven Toolchains](docs/advanced-usage.md#Modifying-Maven-Toolchains)
+- [Java Version File](docs/advanced-usage.md#Java-version-file)
 
 ## License
 
diff --git a/dist/cleanup/index.js b/dist/cleanup/index.js
index 3bb9a80..fc0b1d1 100644
--- a/dist/cleanup/index.js
+++ b/dist/cleanup/index.js
@@ -88352,9 +88352,19 @@ function isCacheFeatureAvailable() {
     return false;
 }
 exports.isCacheFeatureAvailable = isCacheFeatureAvailable;
-function getVersionFromFileContent(content, distributionName) {
+function getVersionFromFileContent(content, distributionName, versionFile) {
     var _a, _b, _c, _d, _e;
-    const javaVersionRegExp = /(?<version>(?<=(^|\s|-))(\d+\S*))(\s|$)/;
+    let javaVersionRegExp;
+    if (versionFile == '.tool-versions') {
+        javaVersionRegExp =
+            /^(java\s+)(?:\S*-)?v?(?<version>(\d+)(\.\d+)?(\.\d+)?(\+\d+)?(-ea(\.\d+)?)?)$/m;
+    }
+    else if (versionFile == '.java-version') {
+        javaVersionRegExp = /(?<version>(?<=(^|\s|-))(\d+\S*))(\s|$)/;
+    }
+    else {
+        throw new Error('Invalid version file');
+    }
     const fileContent = ((_b = (_a = content.match(javaVersionRegExp)) === null || _a === void 0 ? void 0 : _a.groups) === null || _b === void 0 ? void 0 : _b.version)
         ? (_d = (_c = content.match(javaVersionRegExp)) === null || _c === void 0 ? void 0 : _c.groups) === null || _d === void 0 ? void 0 : _d.version
         : '';
diff --git a/dist/setup/index.js b/dist/setup/index.js
index 58e3cb1..55a0964 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -125372,7 +125372,7 @@ function run() {
             if (!versions.length) {
                 core.debug('java-version input is empty, looking for java-version-file input');
                 const content = fs_1.default.readFileSync(versionFile).toString().trim();
-                const version = (0, util_1.getVersionFromFileContent)(content, distributionName);
+                const version = (0, util_1.getVersionFromFileContent)(content, distributionName, versionFile);
                 core.debug(`Parsed version from file '${version}'`);
                 if (!version) {
                     throw new Error(`No supported version was found in file ${versionFile}`);
@@ -125726,9 +125726,19 @@ function isCacheFeatureAvailable() {
     return false;
 }
 exports.isCacheFeatureAvailable = isCacheFeatureAvailable;
-function getVersionFromFileContent(content, distributionName) {
+function getVersionFromFileContent(content, distributionName, versionFile) {
     var _a, _b, _c, _d, _e;
-    const javaVersionRegExp = /(?<version>(?<=(^|\s|-))(\d+\S*))(\s|$)/;
+    let javaVersionRegExp;
+    if (versionFile == '.tool-versions') {
+        javaVersionRegExp =
+            /^(java\s+)(?:\S*-)?v?(?<version>(\d+)(\.\d+)?(\.\d+)?(\+\d+)?(-ea(\.\d+)?)?)$/m;
+    }
+    else if (versionFile == '.java-version') {
+        javaVersionRegExp = /(?<version>(?<=(^|\s|-))(\d+\S*))(\s|$)/;
+    }
+    else {
+        throw new Error('Invalid version file');
+    }
     const fileContent = ((_b = (_a = content.match(javaVersionRegExp)) === null || _a === void 0 ? void 0 : _a.groups) === null || _b === void 0 ? void 0 : _b.version)
         ? (_d = (_c = content.match(javaVersionRegExp)) === null || _c === void 0 ? void 0 : _c.groups) === null || _d === void 0 ? void 0 : _d.version
         : '';
diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md
index ede356f..c3cf42d 100644
--- a/docs/advanced-usage.md
+++ b/docs/advanced-usage.md
@@ -525,14 +525,21 @@ steps:
       something_other
 ```
 
-## Java-version file
-If the `java-version-file` input is specified, the action will try to extract the version from the file and install it.
-Action is able to recognize all variants of the version description according to [jenv](https://github.com/jenv/jenv). 
+## Java version file
+If the `java-version-file` input is specified, the action will extract the version from the file and install it.
+
+Supported files are .java-version and .tool-versions.
+In .java-version file, only the version should be specified, e.g., 17.0.7.
+In .tool-versions file, java version should be preceded by the java keyword, e.g., java 17.0.7.
+.java-version recognizes all variants of the version description according to [jenv](https://github.com/jenv/jenv) and .tool-version recognizes all variants of the version description according to [asdf](https://github.com/asdf-vm/asdf).
+
+If both java-version and java-version-file inputs are provided, the java-version input will be used.
+
 Valid entry options:
 ```
 major versions: 8, 11, 16, 17, 21
 more specific versions: 1.8.0.2, 17.0, 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
 versions with specified distribution: openjdk64-11.0.2
 ```
 If the file contains multiple versions, only the first one will be recognized.
diff --git a/src/setup-java.ts b/src/setup-java.ts
index 35a315d..73baf33 100644
--- a/src/setup-java.ts
+++ b/src/setup-java.ts
@@ -55,7 +55,11 @@ async function run() {
       );
       const content = fs.readFileSync(versionFile).toString().trim();
 
-      const version = getVersionFromFileContent(content, distributionName);
+      const version = getVersionFromFileContent(
+        content,
+        distributionName,
+        versionFile
+      );
       core.debug(`Parsed version from file '${version}'`);
 
       if (!version) {
diff --git a/src/util.ts b/src/util.ts
index 94be234..e02cea6 100644
--- a/src/util.ts
+++ b/src/util.ts
@@ -115,9 +115,19 @@ export function isCacheFeatureAvailable(): boolean {
 
 export function getVersionFromFileContent(
   content: string,
-  distributionName: string
+  distributionName: string,
+  versionFile: string
 ): string | null {
-  const javaVersionRegExp = /(?<version>(?<=(^|\s|-))(\d+\S*))(\s|$)/;
+  let javaVersionRegExp: RegExp;
+  if (versionFile == '.tool-versions') {
+    javaVersionRegExp =
+      /^(java\s+)(?:\S*-)?v?(?<version>(\d+)(\.\d+)?(\.\d+)?(\+\d+)?(-ea(\.\d+)?)?)$/m;
+  } else if (versionFile == '.java-version') {
+    javaVersionRegExp = /(?<version>(?<=(^|\s|-))(\d+\S*))(\s|$)/;
+  } else {
+    throw new Error('Invalid version file');
+  }
+
   const fileContent = content.match(javaVersionRegExp)?.groups?.version
     ? (content.match(javaVersionRegExp)?.groups?.version as string)
     : '';