From 2936fe8cda9cf52952329ff4ac173c5d916a0ac1 Mon Sep 17 00:00:00 2001
From: "Jacob Parish (JP250552)" <75643994+JP250552@users.noreply.github.com>
Date: Tue, 21 Nov 2023 13:02:28 -0600
Subject: [PATCH 01/12] Added option to enable corepack (#1)

Co-authored-by: Steven <steven@ceriously.com>
Co-authored-by: Sayak Mukhopadhyay <mukhopadhyaysayak@gmail.com>
Co-authored-by: Jacob Parish <jacob.parish.1@gmail.com>
---
 README.md                            | 23 ++++++++++----------
 __tests__/official-installer.test.ts | 32 ++++++++++++++++++++++++++++
 action.yml                           |  5 ++++-
 dist/cache-save/index.js             | 17 ++++++++++++++-
 dist/setup/index.js                  | 19 ++++++++++++++++-
 docs/advanced-usage.md               | 29 +++++++++++++++++++++++++
 src/main.ts                          |  9 +++++++-
 src/util.ts                          | 13 +++++++++++
 8 files changed, 132 insertions(+), 15 deletions(-)

diff --git a/README.md b/README.md
index 20d23405..613100fe 100644
--- a/README.md
+++ b/README.md
@@ -26,22 +26,22 @@ See [action.yml](action.yml)
     node-version: ''
 
     # File containing the version Spec of the version to use.  Examples: .nvmrc, .node-version, .tool-versions.
-    # If node-version and node-version-file are both provided the action will use version from node-version. 
+    # If node-version and node-version-file are both provided the action will use version from node-version.
     node-version-file: ''
 
-    # Set this option if you want the action to check for the latest available version 
+    # Set this option if you want the action to check for the latest available version
     # that satisfies the version spec.
-    # It will only get affect for lts Nodejs versions (12.x, >=10.15.0, lts/Hydrogen). 
+    # It will only get affect for lts Nodejs versions (12.x, >=10.15.0, lts/Hydrogen).
     # Default: false
     check-latest: false
 
     # Target architecture for Node to use. Examples: x86, x64. Will use system architecture by default.
-    # Default: ''. The action use system architecture by default 
+    # Default: ''. The action use system architecture by default
     architecture: ''
 
-    # Used to pull node distributions from https://github.com/actions/node-versions. 
-    # Since there's a default, this is typically not supplied by the user. 
-    # When running this action on github.com, the default value is sufficient. 
+    # Used to pull node distributions from https://github.com/actions/node-versions.
+    # Since there's a default, this is typically not supplied by the user.
+    # When running this action on github.com, the default value is sufficient.
     # When running on GHES, you can pass a personal access token for github.com if you are experiencing rate limiting.
     #
     # We recommend using a service account with the least permissions necessary. Also
@@ -57,18 +57,18 @@ See [action.yml](action.yml)
     # Default: ''
     cache: ''
 
-    # Used to specify the path to a dependency file: package-lock.json, yarn.lock, etc. 
-    # It will generate hash from the target file for primary key. It works only If cache is specified.  
+    # Used to specify the path to a dependency file: package-lock.json, yarn.lock, etc.
+    # It will generate hash from the target file for primary key. It works only If cache is specified.
     # Supports wildcards or a list of file names for caching multiple dependencies.
     # Default: ''
     cache-dependency-path: ''
 
-    # Optional registry to set up for auth. Will set the registry in a project level .npmrc and .yarnrc file, 
+    # Optional registry to set up for auth. Will set the registry in a project level .npmrc and .yarnrc file,
     # and set up auth to read in from env.NODE_AUTH_TOKEN.
     # Default: ''
     registry-url: ''
 
-    # Optional scope for authenticating against scoped registries. 
+    # Optional scope for authenticating against scoped registries.
     # Will fall back to the repository owner when using the GitHub Packages registry (https://npm.pkg.github.com/).
     # Default: ''
     scope: ''
@@ -203,6 +203,7 @@ If the runner is not able to access github.com, any Nodejs versions requested du
  - [Publishing to npmjs and GPR with npm](docs/advanced-usage.md#publish-to-npmjs-and-gpr-with-npm)
  - [Publishing to npmjs and GPR with yarn](docs/advanced-usage.md#publish-to-npmjs-and-gpr-with-yarn)
  - [Using private packages](docs/advanced-usage.md#use-private-packages)
+ - [Enabling Corepack](docs/advanced-usage.md#enabling-corepack)
 
 ## License
 
diff --git a/__tests__/official-installer.test.ts b/__tests__/official-installer.test.ts
index 2d36c19c..778b5196 100644
--- a/__tests__/official-installer.test.ts
+++ b/__tests__/official-installer.test.ts
@@ -825,4 +825,36 @@ describe('setup-node', () => {
       }
     );
   });
+
+  describe('corepack flag', () => {
+    it('use corepack if specified', async () => {
+      inputs['corepack'] = 'true';
+      await main.run();
+      expect(getExecOutputSpy).toHaveBeenCalledWith(
+        'corepack',
+        ['enable'],
+        expect.anything()
+      );
+    });
+
+    it('use corepack with given package manager', async () => {
+      inputs['corepack'] = 'npm';
+      await main.run();
+      expect(getExecOutputSpy).toHaveBeenCalledWith(
+        'corepack',
+        ['enable', 'npm'],
+        expect.anything()
+      );
+    });
+
+    it('use corepack with multiple package managers', async () => {
+      inputs['corepack'] = 'npm yarn';
+      await main.run();
+      expect(getExecOutputSpy).toHaveBeenCalledWith(
+        'corepack',
+        ['enable', 'npm', 'yarn'],
+        expect.anything()
+      );
+    });
+  });
 });
diff --git a/action.yml b/action.yml
index 40af8838..689afa35 100644
--- a/action.yml
+++ b/action.yml
@@ -25,10 +25,13 @@ inputs:
     description: 'Used to specify a package manager for caching in the default directory. Supported values: npm, yarn, pnpm.'
   cache-dependency-path:
     description: 'Used to specify the path to a dependency file: package-lock.json, yarn.lock, etc. Supports wildcards or a list of file names for caching multiple dependencies.'
+  corepack:
+    description: 'Used to specify whether to enable Corepack. Set to true to enable all package managers or set it to one or more package manager names separated by a space. Supported package manager names: npm, yarn, pnpm.'
+    default: 'false'
 # TODO: add input to control forcing to pull from cloud or dist.
 #       escape valve for someone having issues or needing the absolute latest which isn't cached yet
 outputs:
-  cache-hit: 
+  cache-hit:
     description: 'A boolean value to indicate if a cache was hit.'
   node-version:
     description: 'The installed node version.'
diff --git a/dist/cache-save/index.js b/dist/cache-save/index.js
index 0b7060e5..05f3e582 100644
--- a/dist/cache-save/index.js
+++ b/dist/cache-save/index.js
@@ -83321,7 +83321,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
     });
 };
 Object.defineProperty(exports, "__esModule", ({ value: true }));
-exports.unique = exports.printEnvDetailsAndSetOutput = exports.parseNodeVersionFile = void 0;
+exports.enableCorepack = exports.unique = exports.printEnvDetailsAndSetOutput = exports.parseNodeVersionFile = void 0;
 const core = __importStar(__nccwpck_require__(2186));
 const exec = __importStar(__nccwpck_require__(1514));
 function parseNodeVersionFile(contents) {
@@ -83393,6 +83393,21 @@ const unique = () => {
     };
 };
 exports.unique = unique;
+function enableCorepack(input) {
+    return __awaiter(this, void 0, void 0, function* () {
+        const corepackArgs = ['enable'];
+        if (input.length > 0 && input !== 'false') {
+            if (input !== 'true') {
+                const packageManagers = input.split(' ');
+                corepackArgs.push(...packageManagers);
+            }
+            yield exec.getExecOutput('corepack', corepackArgs, {
+                ignoreReturnCode: true
+            });
+        }
+    });
+}
+exports.enableCorepack = enableCorepack;
 
 
 /***/ }),
diff --git a/dist/setup/index.js b/dist/setup/index.js
index 0512f3a7..4c58b1d7 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -93698,6 +93698,8 @@ function run() {
             if (registryUrl) {
                 auth.configAuthentication(registryUrl, alwaysAuth);
             }
+            const corepack = core.getInput('corepack') || 'false';
+            yield (0, util_1.enableCorepack)(corepack);
             if (cache && (0, cache_utils_1.isCacheFeatureAvailable)()) {
                 core.saveState(constants_1.State.CachePackageManager, cache);
                 const cacheDependencyPath = core.getInput('cache-dependency-path');
@@ -93775,7 +93777,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
     });
 };
 Object.defineProperty(exports, "__esModule", ({ value: true }));
-exports.unique = exports.printEnvDetailsAndSetOutput = exports.parseNodeVersionFile = void 0;
+exports.enableCorepack = exports.unique = exports.printEnvDetailsAndSetOutput = exports.parseNodeVersionFile = void 0;
 const core = __importStar(__nccwpck_require__(2186));
 const exec = __importStar(__nccwpck_require__(1514));
 function parseNodeVersionFile(contents) {
@@ -93847,6 +93849,21 @@ const unique = () => {
     };
 };
 exports.unique = unique;
+function enableCorepack(input) {
+    return __awaiter(this, void 0, void 0, function* () {
+        const corepackArgs = ['enable'];
+        if (input.length > 0 && input !== 'false') {
+            if (input !== 'true') {
+                const packageManagers = input.split(' ');
+                corepackArgs.push(...packageManagers);
+            }
+            yield exec.getExecOutput('corepack', corepackArgs, {
+                ignoreReturnCode: true
+            });
+        }
+    });
+}
+exports.enableCorepack = enableCorepack;
 
 
 /***/ }),
diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md
index 079b8bfa..0d1ddf4e 100644
--- a/docs/advanced-usage.md
+++ b/docs/advanced-usage.md
@@ -416,3 +416,32 @@ Please refer to the [Ensuring workflow access to your package - Configuring a pa
 
 ### always-auth input
 The always-auth input sets `always-auth=true` in .npmrc file. With this option set [npm](https://docs.npmjs.com/cli/v6/using-npm/config#always-auth)/yarn sends the authentication credentials when making a request to the registries.
+
+## Enabling Corepack
+You can enable [Corepack](https://github.com/nodejs/corepack) by using the `corepack` input. You can then use `pnpm` and `yarn` commands in your project.
+
+```yaml
+steps:
+- uses: actions/checkout@v3
+- uses: actions/setup-node@v3
+  with:
+    node-version: '16.x'
+    corepack: true
+- name: Install dependencies
+  run: yarn install --immutable
+```
+
+You can also pass package manager names separated by a space to enable corepack for specific package managers only.
+
+```yaml
+steps:
+- uses: actions/checkout@v3
+- uses: actions/setup-node@v3
+  with:
+    node-version: '16.x'
+    corepack: yarn pnpm
+- name: Install dependencies
+  run: yarn install --immutable
+```
+
+This option by default is `false` as Corepack is still in experimental phase.
diff --git a/src/main.ts b/src/main.ts
index ac051766..082815a7 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -8,7 +8,11 @@ import * as path from 'path';
 import {restoreCache} from './cache-restore';
 import {isCacheFeatureAvailable} from './cache-utils';
 import {getNodejsDistribution} from './distributions/installer-factory';
-import {parseNodeVersionFile, printEnvDetailsAndSetOutput} from './util';
+import {
+  parseNodeVersionFile,
+  printEnvDetailsAndSetOutput,
+  enableCorepack
+} from './util';
 import {State} from './constants';
 
 export async function run() {
@@ -60,6 +64,9 @@ export async function run() {
       auth.configAuthentication(registryUrl, alwaysAuth);
     }
 
+    const corepack = core.getInput('corepack') || 'false';
+    await enableCorepack(corepack);
+
     if (cache && isCacheFeatureAvailable()) {
       core.saveState(State.CachePackageManager, cache);
       const cacheDependencyPath = core.getInput('cache-dependency-path');
diff --git a/src/util.ts b/src/util.ts
index 3ae94a2d..d0b417ad 100644
--- a/src/util.ts
+++ b/src/util.ts
@@ -70,3 +70,16 @@ export const unique = () => {
     return true;
   };
 };
+
+export async function enableCorepack(input: string): Promise<void> {
+  const corepackArgs = ['enable'];
+  if (input.length > 0 && input !== 'false') {
+    if (input !== 'true') {
+      const packageManagers = input.split(' ');
+      corepackArgs.push(...packageManagers);
+    }
+    await exec.getExecOutput('corepack', corepackArgs, {
+      ignoreReturnCode: true
+    });
+  }
+}

From 7c0fdd03f544655a07e8bf1ab1f0873d1306a784 Mon Sep 17 00:00:00 2001
From: Jacob Parish <jacob.parish.1@gmail.com>
Date: Tue, 21 Nov 2023 13:31:24 -0600
Subject: [PATCH 02/12] test: updated tests

---
 __tests__/main.test.ts               | 52 ++++++++++++++++++++++++++++
 __tests__/official-installer.test.ts | 32 -----------------
 2 files changed, 52 insertions(+), 32 deletions(-)

diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts
index b5724875..e7d92a51 100644
--- a/__tests__/main.test.ts
+++ b/__tests__/main.test.ts
@@ -300,4 +300,56 @@ describe('main tests', () => {
       );
     });
   });
+
+  describe('corepack flag', () => {
+    it('should not enable corepack when no input', async () => {
+      inputs['corepack'] = '';
+      await main.run();
+      expect(getExecOutputSpy).not.toHaveBeenCalledWith(
+        'corepack',
+        expect.anything(),
+        expect.anything()
+      );
+    });
+
+    it('should not enable corepack when input is "false"', async () => {
+      inputs['corepack'] = 'false';
+      await main.run();
+      expect(getExecOutputSpy).not.toHaveBeenCalledWith(
+        'corepack',
+        expect.anything(),
+        expect.anything()
+      );
+    });
+
+    it('should enable corepack when input is "true"', async () => {
+      inputs['corepack'] = 'true';
+      await main.run();
+      expect(getExecOutputSpy).toHaveBeenCalledWith(
+        'corepack',
+        ['enable'],
+        expect.anything()
+      );
+    });
+
+    it('should enable corepack with a single package manager', async () => {
+      inputs['corepack'] = 'npm';
+      await main.run();
+      expect(getExecOutputSpy).toHaveBeenCalledWith(
+        'corepack',
+        ['enable', 'npm'],
+        expect.anything()
+      );
+    });
+
+    it('should enable corepack with multiple package managers', async () => {
+      inputs['corepack'] = 'npm yarn';
+      await main.run();
+      expect(getExecOutputSpy).toHaveBeenCalledWith(
+        'corepack',
+        ['enable', 'npm', 'yarn'],
+        expect.anything()
+      );
+    });
+  });
 });
diff --git a/__tests__/official-installer.test.ts b/__tests__/official-installer.test.ts
index 778b5196..2d36c19c 100644
--- a/__tests__/official-installer.test.ts
+++ b/__tests__/official-installer.test.ts
@@ -825,36 +825,4 @@ describe('setup-node', () => {
       }
     );
   });
-
-  describe('corepack flag', () => {
-    it('use corepack if specified', async () => {
-      inputs['corepack'] = 'true';
-      await main.run();
-      expect(getExecOutputSpy).toHaveBeenCalledWith(
-        'corepack',
-        ['enable'],
-        expect.anything()
-      );
-    });
-
-    it('use corepack with given package manager', async () => {
-      inputs['corepack'] = 'npm';
-      await main.run();
-      expect(getExecOutputSpy).toHaveBeenCalledWith(
-        'corepack',
-        ['enable', 'npm'],
-        expect.anything()
-      );
-    });
-
-    it('use corepack with multiple package managers', async () => {
-      inputs['corepack'] = 'npm yarn';
-      await main.run();
-      expect(getExecOutputSpy).toHaveBeenCalledWith(
-        'corepack',
-        ['enable', 'npm', 'yarn'],
-        expect.anything()
-      );
-    });
-  });
 });

From f9532b258e7ddfc36a3f549c77f42ea4ddc4db64 Mon Sep 17 00:00:00 2001
From: Jacob Parish <jacob.parish.1@gmail.com>
Date: Tue, 21 Nov 2023 13:46:39 -0600
Subject: [PATCH 03/12] docs: node version

---
 docs/advanced-usage.md | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md
index 0d1ddf4e..057434c7 100644
--- a/docs/advanced-usage.md
+++ b/docs/advanced-usage.md
@@ -157,7 +157,7 @@ jobs:
 
 ## Nightly versions
 
-You can specify a nightly version to download it from https://nodejs.org/download/nightly. 
+You can specify a nightly version to download it from https://nodejs.org/download/nightly.
 
 ### Install the nightly build for a major version
 
@@ -265,7 +265,7 @@ steps:
 - run: pnpm test
 ```
 
-> **Note**: By default `--frozen-lockfile` option is passed starting from pnpm `6.10.x`. It will be automatically added if you run it on [CI](https://pnpm.io/cli/install#--frozen-lockfile). 
+> **Note**: By default `--frozen-lockfile` option is passed starting from pnpm `6.10.x`. It will be automatically added if you run it on [CI](https://pnpm.io/cli/install#--frozen-lockfile).
 > If the `pnpm-lock.yaml` file changes then pass `--frozen-lockfile` option.
 
 
@@ -425,7 +425,7 @@ steps:
 - uses: actions/checkout@v3
 - uses: actions/setup-node@v3
   with:
-    node-version: '16.x'
+    node-version: '18.x'
     corepack: true
 - name: Install dependencies
   run: yarn install --immutable
@@ -438,7 +438,7 @@ steps:
 - uses: actions/checkout@v3
 - uses: actions/setup-node@v3
   with:
-    node-version: '16.x'
+    node-version: '18.x'
     corepack: yarn pnpm
 - name: Install dependencies
   run: yarn install --immutable

From 28c91a3bbc8c3f744ebc5b02f54ca99d68047620 Mon Sep 17 00:00:00 2001
From: Jacob Parish <jacob.parish.1@gmail.com>
Date: Tue, 21 Nov 2023 13:47:29 -0600
Subject: [PATCH 04/12] docs: actions versions

---
 docs/advanced-usage.md | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md
index 057434c7..0b2e82ae 100644
--- a/docs/advanced-usage.md
+++ b/docs/advanced-usage.md
@@ -422,8 +422,8 @@ You can enable [Corepack](https://github.com/nodejs/corepack) by using the `core
 
 ```yaml
 steps:
-- uses: actions/checkout@v3
-- uses: actions/setup-node@v3
+- uses: actions/checkout@v4
+- uses: actions/setup-node@v4
   with:
     node-version: '18.x'
     corepack: true
@@ -435,8 +435,8 @@ You can also pass package manager names separated by a space to enable corepack
 
 ```yaml
 steps:
-- uses: actions/checkout@v3
-- uses: actions/setup-node@v3
+- uses: actions/checkout@v4
+- uses: actions/setup-node@v4
   with:
     node-version: '18.x'
     corepack: yarn pnpm

From d8a8b93089a020a119d54ba91b6fa4553389aba4 Mon Sep 17 00:00:00 2001
From: Jacob Parish <jacob.parish.1@gmail.com>
Date: Tue, 21 Nov 2023 13:49:41 -0600
Subject: [PATCH 05/12] docs: remove reference to experimental

---
 docs/advanced-usage.md | 2 --
 1 file changed, 2 deletions(-)

diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md
index 0b2e82ae..7739c08c 100644
--- a/docs/advanced-usage.md
+++ b/docs/advanced-usage.md
@@ -443,5 +443,3 @@ steps:
 - name: Install dependencies
   run: yarn install --immutable
 ```
-
-This option by default is `false` as Corepack is still in experimental phase.

From c73bf9098a639e60a138e5caf34368347ba22106 Mon Sep 17 00:00:00 2001
From: Jacob Parish <jacob.parish.1@gmail.com>
Date: Tue, 6 Feb 2024 09:27:54 -0600
Subject: [PATCH 06/12] fix: pr review adjustments

---
 __tests__/main.test.ts   | 33 +++++++++------------------------
 dist/cache-save/index.js |  9 ++++-----
 dist/setup/index.js      |  9 ++++-----
 src/util.ts              |  9 ++++-----
 4 files changed, 21 insertions(+), 39 deletions(-)

diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts
index 41310ab0..97883cff 100644
--- a/__tests__/main.test.ts
+++ b/__tests__/main.test.ts
@@ -11,6 +11,7 @@ import each from 'jest-each';
 
 import * as main from '../src/main';
 import * as util from '../src/util';
+import * as cacheUtil from '../src/cache-utils';
 import OfficialBuilds from '../src/distributions/official_builds/official_builds';
 
 describe('main tests', () => {
@@ -25,6 +26,7 @@ describe('main tests', () => {
   let endGroupSpy: jest.SpyInstance;
 
   let getExecOutputSpy: jest.SpyInstance;
+  let getCommandOutputSpy: jest.SpyInstance;
 
   let getNodeVersionFromFileSpy: jest.SpyInstance;
   let cnSpy: jest.SpyInstance;
@@ -56,6 +58,7 @@ describe('main tests', () => {
     inSpy.mockImplementation(name => inputs[name]);
 
     getExecOutputSpy = jest.spyOn(exec, 'getExecOutput');
+    getCommandOutputSpy = jest.spyOn(cacheUtil, 'getCommandOutput');
 
     findSpy = jest.spyOn(tc, 'find');
 
@@ -274,50 +277,32 @@ describe('main tests', () => {
     it('should not enable corepack when no input', async () => {
       inputs['corepack'] = '';
       await main.run();
-      expect(getExecOutputSpy).not.toHaveBeenCalledWith(
-        'corepack',
-        expect.anything(),
-        expect.anything()
-      );
+      expect(getCommandOutputSpy).not.toHaveBeenCalledWith('corepack');
     });
 
     it('should not enable corepack when input is "false"', async () => {
       inputs['corepack'] = 'false';
       await main.run();
-      expect(getExecOutputSpy).not.toHaveBeenCalledWith(
-        'corepack',
-        expect.anything(),
-        expect.anything()
-      );
+      expect(getCommandOutputSpy).not.toHaveBeenCalledWith('corepack');
     });
 
     it('should enable corepack when input is "true"', async () => {
       inputs['corepack'] = 'true';
       await main.run();
-      expect(getExecOutputSpy).toHaveBeenCalledWith(
-        'corepack',
-        ['enable'],
-        expect.anything()
-      );
+      expect(getCommandOutputSpy).toHaveBeenCalledWith('corepack enable');
     });
 
     it('should enable corepack with a single package manager', async () => {
       inputs['corepack'] = 'npm';
       await main.run();
-      expect(getExecOutputSpy).toHaveBeenCalledWith(
-        'corepack',
-        ['enable', 'npm'],
-        expect.anything()
-      );
+      expect(getCommandOutputSpy).toHaveBeenCalledWith('corepack enable npm');
     });
 
     it('should enable corepack with multiple package managers', async () => {
       inputs['corepack'] = 'npm yarn';
       await main.run();
-      expect(getExecOutputSpy).toHaveBeenCalledWith(
-        'corepack',
-        ['enable', 'npm', 'yarn'],
-        expect.anything()
+      expect(getCommandOutputSpy).toHaveBeenCalledWith(
+        'corepack enable npm yarn'
       );
     });
   });
diff --git a/dist/cache-save/index.js b/dist/cache-save/index.js
index dda290fb..00385962 100644
--- a/dist/cache-save/index.js
+++ b/dist/cache-save/index.js
@@ -83338,6 +83338,7 @@ const core = __importStar(__nccwpck_require__(2186));
 const exec = __importStar(__nccwpck_require__(1514));
 const fs_1 = __importDefault(__nccwpck_require__(7147));
 const path_1 = __importDefault(__nccwpck_require__(1017));
+const cache_utils_1 = __nccwpck_require__(1678);
 function getNodeVersionFromFile(versionFilePath) {
     var _a, _b, _c, _d, _e;
     if (!fs_1.default.existsSync(versionFilePath)) {
@@ -83431,15 +83432,13 @@ const unique = () => {
 exports.unique = unique;
 function enableCorepack(input) {
     return __awaiter(this, void 0, void 0, function* () {
-        const corepackArgs = ['enable'];
-        if (input.length > 0 && input !== 'false') {
+        if (input.length && input !== 'false') {
+            const corepackArgs = ['enable'];
             if (input !== 'true') {
                 const packageManagers = input.split(' ');
                 corepackArgs.push(...packageManagers);
             }
-            yield exec.getExecOutput('corepack', corepackArgs, {
-                ignoreReturnCode: true
-            });
+            yield (0, cache_utils_1.getCommandOutput)(`corepack ${corepackArgs.join(' ')}`);
         }
     });
 }
diff --git a/dist/setup/index.js b/dist/setup/index.js
index 31947aba..ccc9d2aa 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -93787,6 +93787,7 @@ const core = __importStar(__nccwpck_require__(2186));
 const exec = __importStar(__nccwpck_require__(1514));
 const fs_1 = __importDefault(__nccwpck_require__(7147));
 const path_1 = __importDefault(__nccwpck_require__(1017));
+const cache_utils_1 = __nccwpck_require__(1678);
 function getNodeVersionFromFile(versionFilePath) {
     var _a, _b, _c, _d, _e;
     if (!fs_1.default.existsSync(versionFilePath)) {
@@ -93880,15 +93881,13 @@ const unique = () => {
 exports.unique = unique;
 function enableCorepack(input) {
     return __awaiter(this, void 0, void 0, function* () {
-        const corepackArgs = ['enable'];
-        if (input.length > 0 && input !== 'false') {
+        if (input.length && input !== 'false') {
+            const corepackArgs = ['enable'];
             if (input !== 'true') {
                 const packageManagers = input.split(' ');
                 corepackArgs.push(...packageManagers);
             }
-            yield exec.getExecOutput('corepack', corepackArgs, {
-                ignoreReturnCode: true
-            });
+            yield (0, cache_utils_1.getCommandOutput)(`corepack ${corepackArgs.join(' ')}`);
         }
     });
 }
diff --git a/src/util.ts b/src/util.ts
index acfab3f6..00872a10 100644
--- a/src/util.ts
+++ b/src/util.ts
@@ -3,6 +3,7 @@ import * as exec from '@actions/exec';
 
 import fs from 'fs';
 import path from 'path';
+import {getCommandOutput} from './cache-utils';
 
 export function getNodeVersionFromFile(versionFilePath: string): string | null {
   if (!fs.existsSync(versionFilePath)) {
@@ -107,14 +108,12 @@ export const unique = () => {
 };
 
 export async function enableCorepack(input: string): Promise<void> {
-  const corepackArgs = ['enable'];
-  if (input.length > 0 && input !== 'false') {
+  if (input.length && input !== 'false') {
+    const corepackArgs = ['enable'];
     if (input !== 'true') {
       const packageManagers = input.split(' ');
       corepackArgs.push(...packageManagers);
     }
-    await exec.getExecOutput('corepack', corepackArgs, {
-      ignoreReturnCode: true
-    });
+    await getCommandOutput(`corepack ${corepackArgs.join(' ')}`);
   }
 }

From 0c618ceb2e48275dc06e86901822fd966ce75ba2 Mon Sep 17 00:00:00 2001
From: Jacob Parish <jacob.parish.1@gmail.com>
Date: Tue, 6 Feb 2024 09:46:03 -0600
Subject: [PATCH 07/12] test: added e2e test, improved unit test

---
 .github/workflows/e2e-cache.yml | 38 +++++++++++++++++++++++++++++++++
 __tests__/main.test.ts          |  4 ++--
 2 files changed, 40 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/e2e-cache.yml b/.github/workflows/e2e-cache.yml
index a0f20639..424dcaf4 100644
--- a/.github/workflows/e2e-cache.yml
+++ b/.github/workflows/e2e-cache.yml
@@ -135,6 +135,44 @@ jobs:
         run: __tests__/verify-node.sh "${{ matrix.node-version }}"
         shell: bash
 
+  node-yarn4-corepack-dependencies-caching:
+    name: Test yarn 4 (Node ${{ matrix.node-version}}, ${{ matrix.os }})
+    runs-on: ${{ matrix.os }}
+    env:
+      YARN_ENABLE_IMMUTABLE_INSTALLS: false
+    strategy:
+      fail-fast: false
+      matrix:
+        os: [ubuntu-latest, windows-latest, macos-latest]
+        node-version: [18, 20]
+    steps:
+      - uses: actions/checkout@v4
+      - name: Update yarn
+        run: yarn set version 4.1.0
+      - name: Yarn version
+        run: yarn --version
+      - name: Generate simple .yarnrc.yml
+        run: |
+          echo "nodeLinker: node-modules" >> .yarnrc.yml
+      - name: Generate yarn file
+        run: yarn install
+      - name: Remove dependencies
+        shell: pwsh
+        run: Remove-Item node_modules -Force -Recurse
+      - name: Clean global cache
+        run: yarn cache clean --all
+      - name: Setup Node
+        uses: ./
+        with:
+          node-version: ${{ matrix.node-version }}
+          cache: 'yarn'
+          corepack: true
+      - name: Install dependencies
+        run: yarn install
+      - name: Verify node and yarn
+        run: __tests__/verify-node.sh "${{ matrix.node-version }}"
+        shell: bash
+
   yarn-subprojects:
     name: Test yarn subprojects
     strategy:
diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts
index 97883cff..da025ce3 100644
--- a/__tests__/main.test.ts
+++ b/__tests__/main.test.ts
@@ -277,13 +277,13 @@ describe('main tests', () => {
     it('should not enable corepack when no input', async () => {
       inputs['corepack'] = '';
       await main.run();
-      expect(getCommandOutputSpy).not.toHaveBeenCalledWith('corepack');
+      expect(getCommandOutputSpy).not.toHaveBeenCalledWith(expect.stringContaining('corepack'));
     });
 
     it('should not enable corepack when input is "false"', async () => {
       inputs['corepack'] = 'false';
       await main.run();
-      expect(getCommandOutputSpy).not.toHaveBeenCalledWith('corepack');
+      expect(getCommandOutputSpy).not.toHaveBeenCalledWith(expect.stringContaining('corepack'));
     });
 
     it('should enable corepack when input is "true"', async () => {

From 4c2fa5a76f57e2c029c999a12be8a08e05df96e0 Mon Sep 17 00:00:00 2001
From: Jacob Parish <jacob.parish.1@gmail.com>
Date: Tue, 25 Mar 2025 09:53:39 -0500
Subject: [PATCH 08/12] feat: install corepack before enabling

---
 __tests__/main.test.ts   | 11 +++++--
 dist/cache-save/index.js | 62 +++++++++++++++++++++-------------------
 dist/setup/index.js      | 58 +++++++++++++++++++------------------
 src/util.ts              |  1 +
 4 files changed, 72 insertions(+), 60 deletions(-)

diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts
index 9aed769c..076870eb 100644
--- a/__tests__/main.test.ts
+++ b/__tests__/main.test.ts
@@ -288,30 +288,37 @@ describe('main tests', () => {
     it('should not enable corepack when no input', async () => {
       inputs['corepack'] = '';
       await main.run();
-      expect(getCommandOutputSpy).not.toHaveBeenCalledWith(expect.stringContaining('corepack'));
+      expect(getCommandOutputSpy).not.toHaveBeenCalledWith(
+        expect.stringContaining('corepack')
+      );
     });
 
     it('should not enable corepack when input is "false"', async () => {
       inputs['corepack'] = 'false';
       await main.run();
-      expect(getCommandOutputSpy).not.toHaveBeenCalledWith(expect.stringContaining('corepack'));
+      expect(getCommandOutputSpy).not.toHaveBeenCalledWith(
+        expect.stringContaining('corepack')
+      );
     });
 
     it('should enable corepack when input is "true"', async () => {
       inputs['corepack'] = 'true';
       await main.run();
+      expect(getCommandOutputSpy).toHaveBeenCalledWith('npm i -g corepack');
       expect(getCommandOutputSpy).toHaveBeenCalledWith('corepack enable');
     });
 
     it('should enable corepack with a single package manager', async () => {
       inputs['corepack'] = 'npm';
       await main.run();
+      expect(getCommandOutputSpy).toHaveBeenCalledWith('npm i -g corepack');
       expect(getCommandOutputSpy).toHaveBeenCalledWith('corepack enable npm');
     });
 
     it('should enable corepack with multiple package managers', async () => {
       inputs['corepack'] = 'npm yarn';
       await main.run();
+      expect(getCommandOutputSpy).toHaveBeenCalledWith('npm i -g corepack');
       expect(getCommandOutputSpy).toHaveBeenCalledWith(
         'corepack enable npm yarn'
       );
diff --git a/dist/cache-save/index.js b/dist/cache-save/index.js
index b45cd2b8..9f982d98 100644
--- a/dist/cache-save/index.js
+++ b/dist/cache-save/index.js
@@ -2151,7 +2151,7 @@ function retry(name, method, getStatusCode, maxAttempts = constants_1.DefaultRet
 exports.retry = retry;
 function retryTypedResponse(name, method, maxAttempts = constants_1.DefaultRetryAttempts, delay = constants_1.DefaultRetryDelay) {
     return __awaiter(this, void 0, void 0, function* () {
-        return yield retry(name, method, (response) => response.statusCode, maxAttempts, delay,
+        return yield retry(name, method, (response) => response.statusCode, maxAttempts, delay, 
         // If the error object contains the statusCode property, extract it and return
         // an TypedResponse<T> so it can be processed by the retry logic.
         (error) => {
@@ -6305,8 +6305,8 @@ class OidcClient {
             const res = yield httpclient
                 .getJson(id_token_url)
                 .catch(error => {
-                throw new Error(`Failed to get ID Token. \n
-        Error Code : ${error.statusCode}\n
+                throw new Error(`Failed to get ID Token. \n 
+        Error Code : ${error.statusCode}\n 
         Error Message: ${error.message}`);
             });
             const id_token = (_a = res.result) === null || _a === void 0 ? void 0 : _a.value;
@@ -11102,7 +11102,7 @@ class Serializer {
     /**
      * The provided model mapper.
      */
-    modelMappers = {},
+    modelMappers = {}, 
     /**
      * Whether the contents are XML or not.
      */
@@ -13218,7 +13218,7 @@ class NodeFetchHttpClient {
             body = uploadReportStream;
         }
         const platformSpecificRequestInit = await this.prepareRequest(httpRequest);
-        const requestInit = Object.assign({ body: body, headers: httpRequest.headers.rawHeaders(), method: httpRequest.method,
+        const requestInit = Object.assign({ body: body, headers: httpRequest.headers.rawHeaders(), method: httpRequest.method, 
             // the types for RequestInit are from the browser, which expects AbortSignal to
             // have `reason` and `throwIfAborted`, but these don't exist on our polyfill
             // for Node.
@@ -13417,7 +13417,7 @@ class BaseRequestPolicy {
     /**
      * The next policy in the pipeline. Each policy is responsible for executing the next one if the request is to continue through the pipeline.
      */
-    _nextPolicy,
+    _nextPolicy, 
     /**
      * The options that can be passed to a given request policy.
      */
@@ -14395,7 +14395,7 @@ function createTokenCycler(credential, scopes, tokenCyclerOptions) {
             const tryGetAccessToken = () => credential.getToken(scopes, getTokenOptions);
             // Take advantage of promise chaining to insert an assignment to `token`
             // before the refresh can be considered done.
-            refreshWorker = beginRefresh(tryGetAccessToken, options.retryIntervalInMs,
+            refreshWorker = beginRefresh(tryGetAccessToken, options.retryIntervalInMs, 
             // If we don't have a token, then we should timeout immediately
             (_a = token === null || token === void 0 ? void 0 : token.expiresOnTimestamp) !== null && _a !== void 0 ? _a : Date.now())
                 .then((_token) => {
@@ -15202,7 +15202,7 @@ class ServiceClient {
      * @param credentials - The credentials used for authentication with the service.
      * @param options - The service client options that govern the behavior of the client.
      */
-    constructor(credentials,
+    constructor(credentials, 
     /* eslint-disable-next-line @azure/azure-sdk/ts-naming-options */
     options) {
         if (!options) {
@@ -34182,7 +34182,7 @@ function createTokenCycler(credential, scopes, tokenCyclerOptions) {
             const tryGetAccessToken = () => credential.getToken(scopes, getTokenOptions);
             // Take advantage of promise chaining to insert an assignment to `token`
             // before the refresh can be considered done.
-            refreshWorker = beginRefresh(tryGetAccessToken, options.retryIntervalInMs,
+            refreshWorker = beginRefresh(tryGetAccessToken, options.retryIntervalInMs, 
             // If we don't have a token, then we should timeout immediately
             (_a = token === null || token === void 0 ? void 0 : token.expiresOnTimestamp) !== null && _a !== void 0 ? _a : Date.now())
                 .then((_token) => {
@@ -38602,7 +38602,7 @@ const fsCreateReadStream = fs__namespace.createReadStream;
  * append blob, or page blob.
  */
 class BlobClient extends StorageClient {
-    constructor(urlOrConnectionString, credentialOrPipelineOrContainerName, blobNameOrOptions,
+    constructor(urlOrConnectionString, credentialOrPipelineOrContainerName, blobNameOrOptions, 
     // Legacy, no fix for eslint error without breaking. Disable it for this interface.
     /* eslint-disable-next-line @azure/azure-sdk/ts-naming-options*/
     options) {
@@ -39650,7 +39650,7 @@ class BlobClient extends StorageClient {
  * AppendBlobClient defines a set of operations applicable to append blobs.
  */
 class AppendBlobClient extends BlobClient {
-    constructor(urlOrConnectionString, credentialOrPipelineOrContainerName, blobNameOrOptions,
+    constructor(urlOrConnectionString, credentialOrPipelineOrContainerName, blobNameOrOptions, 
     // Legacy, no fix for eslint error without breaking. Disable it for this interface.
     /* eslint-disable-next-line @azure/azure-sdk/ts-naming-options*/
     options) {
@@ -39906,7 +39906,7 @@ class AppendBlobClient extends BlobClient {
  * BlockBlobClient defines a set of operations applicable to block blobs.
  */
 class BlockBlobClient extends BlobClient {
-    constructor(urlOrConnectionString, credentialOrPipelineOrContainerName, blobNameOrOptions,
+    constructor(urlOrConnectionString, credentialOrPipelineOrContainerName, blobNameOrOptions, 
     // Legacy, no fix for eslint error without breaking. Disable it for this interface.
     /* eslint-disable-next-line @azure/azure-sdk/ts-naming-options*/
     options) {
@@ -40535,7 +40535,7 @@ class BlockBlobClient extends BlobClient {
                 if (options.onProgress) {
                     options.onProgress({ loadedBytes: transferProgress });
                 }
-            },
+            }, 
             // concurrency should set a smaller value than maxConcurrency, which is helpful to
             // reduce the possibility when a outgoing handler waits for stream data, in
             // this situation, outgoing handlers are blocked.
@@ -40560,7 +40560,7 @@ class BlockBlobClient extends BlobClient {
  * PageBlobClient defines a set of operations applicable to page blobs.
  */
 class PageBlobClient extends BlobClient {
-    constructor(urlOrConnectionString, credentialOrPipelineOrContainerName, blobNameOrOptions,
+    constructor(urlOrConnectionString, credentialOrPipelineOrContainerName, blobNameOrOptions, 
     // Legacy, no fix for eslint error without breaking. Disable it for this interface.
     /* eslint-disable-next-line @azure/azure-sdk/ts-naming-options*/
     options) {
@@ -41818,7 +41818,7 @@ class BatchHeaderFilterPolicyFactory {
  * @see https://docs.microsoft.com/en-us/rest/api/storageservices/blob-batch
  */
 class BlobBatchClient {
-    constructor(url, credentialOrPipeline,
+    constructor(url, credentialOrPipeline, 
     // Legacy, no fix for eslint error without breaking. Disable it for this interface.
     /* eslint-disable-next-line @azure/azure-sdk/ts-naming-options*/
     options) {
@@ -41850,7 +41850,7 @@ class BlobBatchClient {
     createBatch() {
         return new BlobBatch();
     }
-    async deleteBlobs(urlsOrBlobClients, credentialOrOptions,
+    async deleteBlobs(urlsOrBlobClients, credentialOrOptions, 
     // Legacy, no fix for eslint error without breaking. Disable it for this interface.
     /* eslint-disable-next-line @azure/azure-sdk/ts-naming-options*/
     options) {
@@ -41865,7 +41865,7 @@ class BlobBatchClient {
         }
         return this.submitBatch(batch);
     }
-    async setBlobsAccessTier(urlsOrBlobClients, credentialOrTier, tierOrOptions,
+    async setBlobsAccessTier(urlsOrBlobClients, credentialOrTier, tierOrOptions, 
     // Legacy, no fix for eslint error without breaking. Disable it for this interface.
     /* eslint-disable-next-line @azure/azure-sdk/ts-naming-options*/
     options) {
@@ -41957,7 +41957,7 @@ class BlobBatchClient {
  * A ContainerClient represents a URL to the Azure Storage container allowing you to manipulate its blobs.
  */
 class ContainerClient extends StorageClient {
-    constructor(urlOrConnectionString, credentialOrPipelineOrContainerName,
+    constructor(urlOrConnectionString, credentialOrPipelineOrContainerName, 
     // Legacy, no fix for eslint error without breaking. Disable it for this interface.
     /* eslint-disable-next-line @azure/azure-sdk/ts-naming-options*/
     options) {
@@ -43669,7 +43669,7 @@ function generateAccountSASQueryParameters(accountSASSignatureValues, sharedKeyC
  * to manipulate blob containers.
  */
 class BlobServiceClient extends StorageClient {
-    constructor(url, credentialOrPipeline,
+    constructor(url, credentialOrPipeline, 
     // Legacy, no fix for eslint error without breaking. Disable it for this interface.
     /* eslint-disable-next-line @azure/azure-sdk/ts-naming-options*/
     options) {
@@ -43701,7 +43701,7 @@ class BlobServiceClient extends StorageClient {
      *                                  `BlobEndpoint=https://myaccount.blob.core.windows.net/;QueueEndpoint=https://myaccount.queue.core.windows.net/;FileEndpoint=https://myaccount.file.core.windows.net/;TableEndpoint=https://myaccount.table.core.windows.net/;SharedAccessSignature=sasString`
      * @param options - Optional. Options to configure the HTTP pipeline.
      */
-    static fromConnectionString(connectionString,
+    static fromConnectionString(connectionString, 
     // Legacy, no fix for eslint error without breaking. Disable it for this interface.
     /* eslint-disable-next-line @azure/azure-sdk/ts-naming-options*/
     options) {
@@ -49137,7 +49137,7 @@ class BinaryWriter {
      * Write a `sint64` value, a signed, zig-zag-encoded 64-bit varint.
      */
     sint64(value) {
-        let long = pb_long_1.PbLong.from(value),
+        let long = pb_long_1.PbLong.from(value), 
         // zigzag encode
         sign = long.hi >> 31, lo = (long.lo << 1) ^ sign, hi = ((long.hi << 1) | (long.lo >>> 31)) ^ sign;
         goog_varint_1.varint64write(lo, hi, this.buf);
@@ -88239,12 +88239,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
     return (mod && mod.__esModule) ? mod : { "default": mod };
 };
 Object.defineProperty(exports, "__esModule", ({ value: true }));
-exports.unique = exports.printEnvDetailsAndSetOutput = exports.getNodeVersionFromFile = void 0;
+exports.enableCorepack = exports.unique = exports.printEnvDetailsAndSetOutput = exports.getNodeVersionFromFile = void 0;
 const core = __importStar(__nccwpck_require__(7484));
 const exec = __importStar(__nccwpck_require__(5236));
 const io = __importStar(__nccwpck_require__(4994));
 const fs_1 = __importDefault(__nccwpck_require__(9896));
 const path_1 = __importDefault(__nccwpck_require__(6928));
+const cache_utils_1 = __nccwpck_require__(4673);
 function getNodeVersionFromFile(versionFilePath) {
     var _a, _b, _c, _d, _e;
     if (!fs_1.default.existsSync(versionFilePath)) {
@@ -88345,6 +88346,7 @@ function enableCorepack(input) {
                 const packageManagers = input.split(' ');
                 corepackArgs.push(...packageManagers);
             }
+            yield (0, cache_utils_1.getCommandOutput)('npm i -g corepack');
             yield (0, cache_utils_1.getCommandOutput)(`corepack ${corepackArgs.join(' ')}`);
         }
     });
@@ -90271,7 +90273,7 @@ module.exports = /*#__PURE__*/JSON.parse('[[[0,44],"disallowed_STD3_valid"],[[45
 /************************************************************************/
 /******/ 	// The module cache
 /******/ 	var __webpack_module_cache__ = {};
-/******/
+/******/ 	
 /******/ 	// The require function
 /******/ 	function __nccwpck_require__(moduleId) {
 /******/ 		// Check if module is in cache
@@ -90285,7 +90287,7 @@ module.exports = /*#__PURE__*/JSON.parse('[[[0,44],"disallowed_STD3_valid"],[[45
 /******/ 			// no module.loaded needed
 /******/ 			exports: {}
 /******/ 		};
-/******/
+/******/ 	
 /******/ 		// Execute the module function
 /******/ 		var threw = true;
 /******/ 		try {
@@ -90294,23 +90296,23 @@ module.exports = /*#__PURE__*/JSON.parse('[[[0,44],"disallowed_STD3_valid"],[[45
 /******/ 		} finally {
 /******/ 			if(threw) delete __webpack_module_cache__[moduleId];
 /******/ 		}
-/******/
+/******/ 	
 /******/ 		// Return the exports of the module
 /******/ 		return module.exports;
 /******/ 	}
-/******/
+/******/ 	
 /************************************************************************/
 /******/ 	/* webpack/runtime/compat */
-/******/
+/******/ 	
 /******/ 	if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = __dirname + "/";
-/******/
+/******/ 	
 /************************************************************************/
-/******/
+/******/ 	
 /******/ 	// startup
 /******/ 	// Load entry module and return exports
 /******/ 	// This entry module is referenced by other modules so it can't be inlined
 /******/ 	var __webpack_exports__ = __nccwpck_require__(3579);
 /******/ 	module.exports = __webpack_exports__;
-/******/
+/******/ 	
 /******/ })()
 ;
\ No newline at end of file
diff --git a/dist/setup/index.js b/dist/setup/index.js
index d9d09531..499239be 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -2151,7 +2151,7 @@ function retry(name, method, getStatusCode, maxAttempts = constants_1.DefaultRet
 exports.retry = retry;
 function retryTypedResponse(name, method, maxAttempts = constants_1.DefaultRetryAttempts, delay = constants_1.DefaultRetryDelay) {
     return __awaiter(this, void 0, void 0, function* () {
-        return yield retry(name, method, (response) => response.statusCode, maxAttempts, delay,
+        return yield retry(name, method, (response) => response.statusCode, maxAttempts, delay, 
         // If the error object contains the statusCode property, extract it and return
         // an TypedResponse<T> so it can be processed by the retry logic.
         (error) => {
@@ -6305,8 +6305,8 @@ class OidcClient {
             const res = yield httpclient
                 .getJson(id_token_url)
                 .catch(error => {
-                throw new Error(`Failed to get ID Token. \n
-        Error Code : ${error.statusCode}\n
+                throw new Error(`Failed to get ID Token. \n 
+        Error Code : ${error.statusCode}\n 
         Error Message: ${error.message}`);
             });
             const id_token = (_a = res.result) === null || _a === void 0 ? void 0 : _a.value;
@@ -13871,7 +13871,7 @@ class Serializer {
     /**
      * The provided model mapper.
      */
-    modelMappers = {},
+    modelMappers = {}, 
     /**
      * Whether the contents are XML or not.
      */
@@ -15987,7 +15987,7 @@ class NodeFetchHttpClient {
             body = uploadReportStream;
         }
         const platformSpecificRequestInit = await this.prepareRequest(httpRequest);
-        const requestInit = Object.assign({ body: body, headers: httpRequest.headers.rawHeaders(), method: httpRequest.method,
+        const requestInit = Object.assign({ body: body, headers: httpRequest.headers.rawHeaders(), method: httpRequest.method, 
             // the types for RequestInit are from the browser, which expects AbortSignal to
             // have `reason` and `throwIfAborted`, but these don't exist on our polyfill
             // for Node.
@@ -16186,7 +16186,7 @@ class BaseRequestPolicy {
     /**
      * The next policy in the pipeline. Each policy is responsible for executing the next one if the request is to continue through the pipeline.
      */
-    _nextPolicy,
+    _nextPolicy, 
     /**
      * The options that can be passed to a given request policy.
      */
@@ -17164,7 +17164,7 @@ function createTokenCycler(credential, scopes, tokenCyclerOptions) {
             const tryGetAccessToken = () => credential.getToken(scopes, getTokenOptions);
             // Take advantage of promise chaining to insert an assignment to `token`
             // before the refresh can be considered done.
-            refreshWorker = beginRefresh(tryGetAccessToken, options.retryIntervalInMs,
+            refreshWorker = beginRefresh(tryGetAccessToken, options.retryIntervalInMs, 
             // If we don't have a token, then we should timeout immediately
             (_a = token === null || token === void 0 ? void 0 : token.expiresOnTimestamp) !== null && _a !== void 0 ? _a : Date.now())
                 .then((_token) => {
@@ -17971,7 +17971,7 @@ class ServiceClient {
      * @param credentials - The credentials used for authentication with the service.
      * @param options - The service client options that govern the behavior of the client.
      */
-    constructor(credentials,
+    constructor(credentials, 
     /* eslint-disable-next-line @azure/azure-sdk/ts-naming-options */
     options) {
         if (!options) {
@@ -36951,7 +36951,7 @@ function createTokenCycler(credential, scopes, tokenCyclerOptions) {
             const tryGetAccessToken = () => credential.getToken(scopes, getTokenOptions);
             // Take advantage of promise chaining to insert an assignment to `token`
             // before the refresh can be considered done.
-            refreshWorker = beginRefresh(tryGetAccessToken, options.retryIntervalInMs,
+            refreshWorker = beginRefresh(tryGetAccessToken, options.retryIntervalInMs, 
             // If we don't have a token, then we should timeout immediately
             (_a = token === null || token === void 0 ? void 0 : token.expiresOnTimestamp) !== null && _a !== void 0 ? _a : Date.now())
                 .then((_token) => {
@@ -41371,7 +41371,7 @@ const fsCreateReadStream = fs__namespace.createReadStream;
  * append blob, or page blob.
  */
 class BlobClient extends StorageClient {
-    constructor(urlOrConnectionString, credentialOrPipelineOrContainerName, blobNameOrOptions,
+    constructor(urlOrConnectionString, credentialOrPipelineOrContainerName, blobNameOrOptions, 
     // Legacy, no fix for eslint error without breaking. Disable it for this interface.
     /* eslint-disable-next-line @azure/azure-sdk/ts-naming-options*/
     options) {
@@ -42419,7 +42419,7 @@ class BlobClient extends StorageClient {
  * AppendBlobClient defines a set of operations applicable to append blobs.
  */
 class AppendBlobClient extends BlobClient {
-    constructor(urlOrConnectionString, credentialOrPipelineOrContainerName, blobNameOrOptions,
+    constructor(urlOrConnectionString, credentialOrPipelineOrContainerName, blobNameOrOptions, 
     // Legacy, no fix for eslint error without breaking. Disable it for this interface.
     /* eslint-disable-next-line @azure/azure-sdk/ts-naming-options*/
     options) {
@@ -42675,7 +42675,7 @@ class AppendBlobClient extends BlobClient {
  * BlockBlobClient defines a set of operations applicable to block blobs.
  */
 class BlockBlobClient extends BlobClient {
-    constructor(urlOrConnectionString, credentialOrPipelineOrContainerName, blobNameOrOptions,
+    constructor(urlOrConnectionString, credentialOrPipelineOrContainerName, blobNameOrOptions, 
     // Legacy, no fix for eslint error without breaking. Disable it for this interface.
     /* eslint-disable-next-line @azure/azure-sdk/ts-naming-options*/
     options) {
@@ -43304,7 +43304,7 @@ class BlockBlobClient extends BlobClient {
                 if (options.onProgress) {
                     options.onProgress({ loadedBytes: transferProgress });
                 }
-            },
+            }, 
             // concurrency should set a smaller value than maxConcurrency, which is helpful to
             // reduce the possibility when a outgoing handler waits for stream data, in
             // this situation, outgoing handlers are blocked.
@@ -43329,7 +43329,7 @@ class BlockBlobClient extends BlobClient {
  * PageBlobClient defines a set of operations applicable to page blobs.
  */
 class PageBlobClient extends BlobClient {
-    constructor(urlOrConnectionString, credentialOrPipelineOrContainerName, blobNameOrOptions,
+    constructor(urlOrConnectionString, credentialOrPipelineOrContainerName, blobNameOrOptions, 
     // Legacy, no fix for eslint error without breaking. Disable it for this interface.
     /* eslint-disable-next-line @azure/azure-sdk/ts-naming-options*/
     options) {
@@ -44587,7 +44587,7 @@ class BatchHeaderFilterPolicyFactory {
  * @see https://docs.microsoft.com/en-us/rest/api/storageservices/blob-batch
  */
 class BlobBatchClient {
-    constructor(url, credentialOrPipeline,
+    constructor(url, credentialOrPipeline, 
     // Legacy, no fix for eslint error without breaking. Disable it for this interface.
     /* eslint-disable-next-line @azure/azure-sdk/ts-naming-options*/
     options) {
@@ -44619,7 +44619,7 @@ class BlobBatchClient {
     createBatch() {
         return new BlobBatch();
     }
-    async deleteBlobs(urlsOrBlobClients, credentialOrOptions,
+    async deleteBlobs(urlsOrBlobClients, credentialOrOptions, 
     // Legacy, no fix for eslint error without breaking. Disable it for this interface.
     /* eslint-disable-next-line @azure/azure-sdk/ts-naming-options*/
     options) {
@@ -44634,7 +44634,7 @@ class BlobBatchClient {
         }
         return this.submitBatch(batch);
     }
-    async setBlobsAccessTier(urlsOrBlobClients, credentialOrTier, tierOrOptions,
+    async setBlobsAccessTier(urlsOrBlobClients, credentialOrTier, tierOrOptions, 
     // Legacy, no fix for eslint error without breaking. Disable it for this interface.
     /* eslint-disable-next-line @azure/azure-sdk/ts-naming-options*/
     options) {
@@ -44726,7 +44726,7 @@ class BlobBatchClient {
  * A ContainerClient represents a URL to the Azure Storage container allowing you to manipulate its blobs.
  */
 class ContainerClient extends StorageClient {
-    constructor(urlOrConnectionString, credentialOrPipelineOrContainerName,
+    constructor(urlOrConnectionString, credentialOrPipelineOrContainerName, 
     // Legacy, no fix for eslint error without breaking. Disable it for this interface.
     /* eslint-disable-next-line @azure/azure-sdk/ts-naming-options*/
     options) {
@@ -46438,7 +46438,7 @@ function generateAccountSASQueryParameters(accountSASSignatureValues, sharedKeyC
  * to manipulate blob containers.
  */
 class BlobServiceClient extends StorageClient {
-    constructor(url, credentialOrPipeline,
+    constructor(url, credentialOrPipeline, 
     // Legacy, no fix for eslint error without breaking. Disable it for this interface.
     /* eslint-disable-next-line @azure/azure-sdk/ts-naming-options*/
     options) {
@@ -46470,7 +46470,7 @@ class BlobServiceClient extends StorageClient {
      *                                  `BlobEndpoint=https://myaccount.blob.core.windows.net/;QueueEndpoint=https://myaccount.queue.core.windows.net/;FileEndpoint=https://myaccount.file.core.windows.net/;TableEndpoint=https://myaccount.table.core.windows.net/;SharedAccessSignature=sasString`
      * @param options - Optional. Options to configure the HTTP pipeline.
      */
-    static fromConnectionString(connectionString,
+    static fromConnectionString(connectionString, 
     // Legacy, no fix for eslint error without breaking. Disable it for this interface.
     /* eslint-disable-next-line @azure/azure-sdk/ts-naming-options*/
     options) {
@@ -54272,7 +54272,7 @@ class BinaryWriter {
      * Write a `sint64` value, a signed, zig-zag-encoded 64-bit varint.
      */
     sint64(value) {
-        let long = pb_long_1.PbLong.from(value),
+        let long = pb_long_1.PbLong.from(value), 
         // zigzag encode
         sign = long.hi >> 31, lo = (long.lo << 1) ^ sign, hi = ((long.hi << 1) | (long.lo >>> 31)) ^ sign;
         goog_varint_1.varint64write(lo, hi, this.buf);
@@ -97917,12 +97917,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
     return (mod && mod.__esModule) ? mod : { "default": mod };
 };
 Object.defineProperty(exports, "__esModule", ({ value: true }));
-exports.unique = exports.printEnvDetailsAndSetOutput = exports.getNodeVersionFromFile = void 0;
+exports.enableCorepack = exports.unique = exports.printEnvDetailsAndSetOutput = exports.getNodeVersionFromFile = void 0;
 const core = __importStar(__nccwpck_require__(7484));
 const exec = __importStar(__nccwpck_require__(5236));
 const io = __importStar(__nccwpck_require__(4994));
 const fs_1 = __importDefault(__nccwpck_require__(9896));
 const path_1 = __importDefault(__nccwpck_require__(6928));
+const cache_utils_1 = __nccwpck_require__(4673);
 function getNodeVersionFromFile(versionFilePath) {
     var _a, _b, _c, _d, _e;
     if (!fs_1.default.existsSync(versionFilePath)) {
@@ -98023,6 +98024,7 @@ function enableCorepack(input) {
                 const packageManagers = input.split(' ');
                 corepackArgs.push(...packageManagers);
             }
+            yield (0, cache_utils_1.getCommandOutput)('npm i -g corepack');
             yield (0, cache_utils_1.getCommandOutput)(`corepack ${corepackArgs.join(' ')}`);
         }
     });
@@ -99949,7 +99951,7 @@ module.exports = /*#__PURE__*/JSON.parse('[[[0,44],"disallowed_STD3_valid"],[[45
 /************************************************************************/
 /******/ 	// The module cache
 /******/ 	var __webpack_module_cache__ = {};
-/******/
+/******/ 	
 /******/ 	// The require function
 /******/ 	function __nccwpck_require__(moduleId) {
 /******/ 		// Check if module is in cache
@@ -99963,7 +99965,7 @@ module.exports = /*#__PURE__*/JSON.parse('[[[0,44],"disallowed_STD3_valid"],[[45
 /******/ 			// no module.loaded needed
 /******/ 			exports: {}
 /******/ 		};
-/******/
+/******/ 	
 /******/ 		// Execute the module function
 /******/ 		var threw = true;
 /******/ 		try {
@@ -99972,16 +99974,16 @@ module.exports = /*#__PURE__*/JSON.parse('[[[0,44],"disallowed_STD3_valid"],[[45
 /******/ 		} finally {
 /******/ 			if(threw) delete __webpack_module_cache__[moduleId];
 /******/ 		}
-/******/
+/******/ 	
 /******/ 		// Return the exports of the module
 /******/ 		return module.exports;
 /******/ 	}
-/******/
+/******/ 	
 /************************************************************************/
 /******/ 	/* webpack/runtime/compat */
-/******/
+/******/ 	
 /******/ 	if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = __dirname + "/";
-/******/
+/******/ 	
 /************************************************************************/
 var __webpack_exports__ = {};
 // This entry need to be wrapped in an IIFE because it need to be in strict mode.
diff --git a/src/util.ts b/src/util.ts
index af8f903a..6aef3651 100644
--- a/src/util.ts
+++ b/src/util.ts
@@ -115,6 +115,7 @@ export async function enableCorepack(input: string): Promise<void> {
       const packageManagers = input.split(' ');
       corepackArgs.push(...packageManagers);
     }
+    await getCommandOutput('npm i -g corepack');
     await getCommandOutput(`corepack ${corepackArgs.join(' ')}`);
   }
 }

From 108e90108c402eb6bc48f93e904bd444066cd438 Mon Sep 17 00:00:00 2001
From: Jacob Parish <jacob.parish.1@gmail.com>
Date: Tue, 25 Mar 2025 10:02:05 -0500
Subject: [PATCH 09/12] fix: removed extra corepack commands

---
 __tests__/main.test.ts   | 17 -----------------
 action.yml               |  2 +-
 dist/cache-save/index.js |  6 ------
 dist/setup/index.js      |  6 ------
 docs/advanced-usage.md   | 15 +--------------
 src/util.ts              |  6 ------
 6 files changed, 2 insertions(+), 50 deletions(-)

diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts
index 076870eb..dd814ce5 100644
--- a/__tests__/main.test.ts
+++ b/__tests__/main.test.ts
@@ -305,23 +305,6 @@ describe('main tests', () => {
       inputs['corepack'] = 'true';
       await main.run();
       expect(getCommandOutputSpy).toHaveBeenCalledWith('npm i -g corepack');
-      expect(getCommandOutputSpy).toHaveBeenCalledWith('corepack enable');
-    });
-
-    it('should enable corepack with a single package manager', async () => {
-      inputs['corepack'] = 'npm';
-      await main.run();
-      expect(getCommandOutputSpy).toHaveBeenCalledWith('npm i -g corepack');
-      expect(getCommandOutputSpy).toHaveBeenCalledWith('corepack enable npm');
-    });
-
-    it('should enable corepack with multiple package managers', async () => {
-      inputs['corepack'] = 'npm yarn';
-      await main.run();
-      expect(getCommandOutputSpy).toHaveBeenCalledWith('npm i -g corepack');
-      expect(getCommandOutputSpy).toHaveBeenCalledWith(
-        'corepack enable npm yarn'
-      );
     });
   });
 });
diff --git a/action.yml b/action.yml
index 78fbfbbb..16d58835 100644
--- a/action.yml
+++ b/action.yml
@@ -26,7 +26,7 @@ inputs:
   cache-dependency-path:
     description: 'Used to specify the path to a dependency file: package-lock.json, yarn.lock, etc. Supports wildcards or a list of file names for caching multiple dependencies.'
   corepack:
-    description: 'Used to specify whether to enable Corepack. Set to true to enable all package managers or set it to one or more package manager names separated by a space. Supported package manager names: npm, yarn, pnpm.'
+    description: 'Used to specify whether to enable Corepack.'
     default: 'false'
 # TODO: add input to control forcing to pull from cloud or dist.
 #       escape valve for someone having issues or needing the absolute latest which isn't cached yet
diff --git a/dist/cache-save/index.js b/dist/cache-save/index.js
index 9f982d98..dd2f9fb4 100644
--- a/dist/cache-save/index.js
+++ b/dist/cache-save/index.js
@@ -88341,13 +88341,7 @@ exports.unique = unique;
 function enableCorepack(input) {
     return __awaiter(this, void 0, void 0, function* () {
         if (input.length && input !== 'false') {
-            const corepackArgs = ['enable'];
-            if (input !== 'true') {
-                const packageManagers = input.split(' ');
-                corepackArgs.push(...packageManagers);
-            }
             yield (0, cache_utils_1.getCommandOutput)('npm i -g corepack');
-            yield (0, cache_utils_1.getCommandOutput)(`corepack ${corepackArgs.join(' ')}`);
         }
     });
 }
diff --git a/dist/setup/index.js b/dist/setup/index.js
index 499239be..c5ea08da 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -98019,13 +98019,7 @@ exports.unique = unique;
 function enableCorepack(input) {
     return __awaiter(this, void 0, void 0, function* () {
         if (input.length && input !== 'false') {
-            const corepackArgs = ['enable'];
-            if (input !== 'true') {
-                const packageManagers = input.split(' ');
-                corepackArgs.push(...packageManagers);
-            }
             yield (0, cache_utils_1.getCommandOutput)('npm i -g corepack');
-            yield (0, cache_utils_1.getCommandOutput)(`corepack ${corepackArgs.join(' ')}`);
         }
     });
 }
diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md
index a1e947cd..cf84d0fd 100644
--- a/docs/advanced-usage.md
+++ b/docs/advanced-usage.md
@@ -427,21 +427,8 @@ steps:
 - uses: actions/checkout@v4
 - uses: actions/setup-node@v4
   with:
-    node-version: '18.x'
+    node-version: '22.x'
     corepack: true
 - name: Install dependencies
   run: yarn install --immutable
 ```
-
-You can also pass package manager names separated by a space to enable corepack for specific package managers only.
-
-```yaml
-steps:
-- uses: actions/checkout@v4
-- uses: actions/setup-node@v4
-  with:
-    node-version: '18.x'
-    corepack: yarn pnpm
-- name: Install dependencies
-  run: yarn install --immutable
-```
diff --git a/src/util.ts b/src/util.ts
index 6aef3651..e5621aca 100644
--- a/src/util.ts
+++ b/src/util.ts
@@ -110,12 +110,6 @@ export const unique = () => {
 
 export async function enableCorepack(input: string): Promise<void> {
   if (input.length && input !== 'false') {
-    const corepackArgs = ['enable'];
-    if (input !== 'true') {
-      const packageManagers = input.split(' ');
-      corepackArgs.push(...packageManagers);
-    }
     await getCommandOutput('npm i -g corepack');
-    await getCommandOutput(`corepack ${corepackArgs.join(' ')}`);
   }
 }

From 788fa93aab76868da2797f81e82d3dbf6375d503 Mon Sep 17 00:00:00 2001
From: Jacob Parish <jacob.parish.1@gmail.com>
Date: Tue, 25 Mar 2025 10:03:25 -0500
Subject: [PATCH 10/12] test: updated e2e test

---
 .github/workflows/e2e-cache.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/e2e-cache.yml b/.github/workflows/e2e-cache.yml
index 9674fe4c..672318a4 100644
--- a/.github/workflows/e2e-cache.yml
+++ b/.github/workflows/e2e-cache.yml
@@ -144,7 +144,7 @@ jobs:
       fail-fast: false
       matrix:
         os: [ubuntu-latest, windows-latest, macos-latest]
-        node-version: [18, 20]
+        node-version: [18, 20, 22]
     steps:
       - uses: actions/checkout@v4
       - name: Update yarn

From 4478bd47024b3eae8425bf7fed57d49db8282d3e Mon Sep 17 00:00:00 2001
From: Jacob Parish <jacob.parish.1@gmail.com>
Date: Tue, 25 Mar 2025 10:10:32 -0500
Subject: [PATCH 11/12] docs: update wording

---
 action.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/action.yml b/action.yml
index 16d58835..3876806c 100644
--- a/action.yml
+++ b/action.yml
@@ -26,7 +26,7 @@ inputs:
   cache-dependency-path:
     description: 'Used to specify the path to a dependency file: package-lock.json, yarn.lock, etc. Supports wildcards or a list of file names for caching multiple dependencies.'
   corepack:
-    description: 'Used to specify whether to enable Corepack.'
+    description: 'Enables Corepack which allows the use of other package managers.'
     default: 'false'
 # TODO: add input to control forcing to pull from cloud or dist.
 #       escape valve for someone having issues or needing the absolute latest which isn't cached yet

From aa9724272b8a9ea9fca3d51295a2cc4707e35ec2 Mon Sep 17 00:00:00 2001
From: Jacob Parish <jacob.parish.1@gmail.com>
Date: Tue, 25 Mar 2025 11:13:23 -0500
Subject: [PATCH 12/12] feat: allow specifying a version

---
 __tests__/main.test.ts   | 22 ++++++++++++++++++++--
 action.yml               |  2 +-
 dist/cache-save/index.js |  3 ++-
 dist/setup/index.js      |  3 ++-
 docs/advanced-usage.md   | 13 +++++++++++++
 src/util.ts              |  3 ++-
 6 files changed, 40 insertions(+), 6 deletions(-)

diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts
index dd814ce5..1b80b79b 100644
--- a/__tests__/main.test.ts
+++ b/__tests__/main.test.ts
@@ -301,10 +301,28 @@ describe('main tests', () => {
       );
     });
 
-    it('should enable corepack when input is "true"', async () => {
+    it('should install latest corepack when input is "true"', async () => {
       inputs['corepack'] = 'true';
       await main.run();
-      expect(getCommandOutputSpy).toHaveBeenCalledWith('npm i -g corepack');
+      expect(getCommandOutputSpy).toHaveBeenCalledWith(
+        'npm i -g corepack@latest'
+      );
+    });
+
+    it('should install latest corepack when input is "latest"', async () => {
+      inputs['corepack'] = 'latest';
+      await main.run();
+      expect(getCommandOutputSpy).toHaveBeenCalledWith(
+        'npm i -g corepack@latest'
+      );
+    });
+
+    it('should install a specific version of corepack when specified', async () => {
+      inputs['corepack'] = '0.32.0';
+      await main.run();
+      expect(getCommandOutputSpy).toHaveBeenCalledWith(
+        'npm i -g corepack@0.32.0'
+      );
     });
   });
 });
diff --git a/action.yml b/action.yml
index 3876806c..b97744f8 100644
--- a/action.yml
+++ b/action.yml
@@ -26,7 +26,7 @@ inputs:
   cache-dependency-path:
     description: 'Used to specify the path to a dependency file: package-lock.json, yarn.lock, etc. Supports wildcards or a list of file names for caching multiple dependencies.'
   corepack:
-    description: 'Enables Corepack which allows the use of other package managers.'
+    description: 'Enables Corepack which allows the use of other package managers. Can provide a version string to install a specific version.'
     default: 'false'
 # TODO: add input to control forcing to pull from cloud or dist.
 #       escape valve for someone having issues or needing the absolute latest which isn't cached yet
diff --git a/dist/cache-save/index.js b/dist/cache-save/index.js
index dd2f9fb4..488b3e0d 100644
--- a/dist/cache-save/index.js
+++ b/dist/cache-save/index.js
@@ -88341,7 +88341,8 @@ exports.unique = unique;
 function enableCorepack(input) {
     return __awaiter(this, void 0, void 0, function* () {
         if (input.length && input !== 'false') {
-            yield (0, cache_utils_1.getCommandOutput)('npm i -g corepack');
+            const version = input === 'true' ? 'latest' : input;
+            yield (0, cache_utils_1.getCommandOutput)(`npm i -g corepack@${version}`);
         }
     });
 }
diff --git a/dist/setup/index.js b/dist/setup/index.js
index c5ea08da..9f7d342c 100644
--- a/dist/setup/index.js
+++ b/dist/setup/index.js
@@ -98019,7 +98019,8 @@ exports.unique = unique;
 function enableCorepack(input) {
     return __awaiter(this, void 0, void 0, function* () {
         if (input.length && input !== 'false') {
-            yield (0, cache_utils_1.getCommandOutput)('npm i -g corepack');
+            const version = input === 'true' ? 'latest' : input;
+            yield (0, cache_utils_1.getCommandOutput)(`npm i -g corepack@${version}`);
         }
     });
 }
diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md
index cf84d0fd..42f1c945 100644
--- a/docs/advanced-usage.md
+++ b/docs/advanced-usage.md
@@ -432,3 +432,16 @@ steps:
 - name: Install dependencies
   run: yarn install --immutable
 ```
+
+You can also pass a version string to install a specific version of corepack.
+
+```yaml
+steps:
+- uses: actions/checkout@v4
+- uses: actions/setup-node@v4
+  with:
+    node-version: '18.x'
+    corepack: '0.32.0'
+- name: Install dependencies
+  run: yarn install --immutable
+```
diff --git a/src/util.ts b/src/util.ts
index e5621aca..dc546abc 100644
--- a/src/util.ts
+++ b/src/util.ts
@@ -110,6 +110,7 @@ export const unique = () => {
 
 export async function enableCorepack(input: string): Promise<void> {
   if (input.length && input !== 'false') {
-    await getCommandOutput('npm i -g corepack');
+    const version = input === 'true' ? 'latest' : input;
+    await getCommandOutput(`npm i -g corepack@${version}`);
   }
 }