Compare commits

..

5 Commits

Author SHA1 Message Date
Satishchoudhary94
67f2ddafd2 Merge dff445bec7 into 6044e13b5d 2026-01-18 19:46:07 +05:30
Satishchoudhary94
dff445bec7 fix(#1357): Gracefully handle missing pnpm installation during cache
This change prevents the action from failing immediately when pnpm is specified
in packageManager but not yet installed (e.g., when using corepack).

Changes:
- Add isPackageManagerInstalled() function to check if a package manager exists
- Update restoreCache to skip caching with a warning if package manager not found
- Update cachePackages to skip cache save with a warning if package manager not found
- This allows workflows to continue instead of failing
- Users can either install pnpm first or disable caching with package-manager-cache: false

Fixes #1357
Related: https://github.com/actions/setup-node/issues/1357
2026-01-18 14:08:11 +00:00
aparnajyothi-y
6044e13b5d Docs: bump actions/checkout from v5 to v6 (#1468)
* Update versions.yml

* Update versions.yml

* doc update

* revert vesrions.yml
2026-01-14 21:04:21 -06:00
Panashe Fundira
8e494633d0 Fix README typo (#1226) 2026-01-14 17:08:53 -06:00
Andreas Deininger
621ac41091 README.md: bump to latest released checkout version v6 (#1446) 2026-01-14 17:06:36 -06:00
9 changed files with 152 additions and 1516 deletions

View File

@@ -115,7 +115,7 @@ See [action.yml](action.yml)
```yaml
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: 24
@@ -123,7 +123,7 @@ steps:
- run: npm test
```
The `node-version` input is optional. If not supplied, the node version from PATH will be used. However, it is recommended to always specify Node.js version and don't rely on the system one.
The `node-version` input is optional. If not supplied, the node version from PATH will be used. However, it is recommended to always specify Node.js version and not rely on the system one.
The action will first check the local cache for a semver match. If unable to find a specific version in the cache, the action will attempt to download a version of Node.js. It will pull LTS versions from [node-versions releases](https://github.com/actions/node-versions/releases) and on miss or failure will fall back to the previous behavior of downloading directly from [node dist](https://nodejs.org/dist/).
@@ -164,7 +164,7 @@ See the examples of using cache for `yarn`/`pnpm` and `cache-dependency-path` in
```yaml
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: 24
@@ -177,7 +177,7 @@ steps:
```yaml
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: 24
@@ -193,7 +193,7 @@ This behavior is controlled by the `package-manager-cache` input, which defaults
```yaml
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
package-manager-cache: false
@@ -212,7 +212,7 @@ jobs:
node: [ 20, 22, 24 ]
name: Node ${{ matrix.node }} sample
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Setup node
uses: actions/setup-node@v6
with:

View File

@@ -44084,6 +44084,14 @@ const cachePackages = async (packageManager) => {
core.debug(`Caching for '${packageManager}' is not supported`);
return;
}
// Check if the package manager is installed before attempting to save cache
// This prevents cache save failures for package managers that may not be installed
const isInstalled = await (0, cache_utils_1.isPackageManagerInstalled)(packageManager);
if (!isInstalled) {
core.warning(`Package manager '${packageManager}' was not found in the PATH. ` +
`Skipping cache save.`);
return;
}
if (!cachePaths.length) {
// TODO: core.getInput has a bug - it can return undefined despite its definition (tests only?)
// export declare function getInput(name: string, options?: InputOptions): string;
@@ -44147,7 +44155,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.repoHasYarnBerryManagedDependencies = exports.getCacheDirectories = exports.resetProjectDirectoriesMemoized = exports.getPackageManagerInfo = exports.getCommandOutputNotEmpty = exports.getCommandOutput = exports.supportedPackageManagers = void 0;
exports.repoHasYarnBerryManagedDependencies = exports.getCacheDirectories = exports.resetProjectDirectoriesMemoized = exports.isPackageManagerInstalled = exports.getPackageManagerInfo = exports.getCommandOutputNotEmpty = exports.getCommandOutput = exports.supportedPackageManagers = void 0;
exports.isGhes = isGhes;
exports.isCacheFeatureAvailable = isCacheFeatureAvailable;
const core = __importStar(__nccwpck_require__(37484));
@@ -44218,6 +44226,25 @@ const getPackageManagerInfo = async (packageManager) => {
}
};
exports.getPackageManagerInfo = getPackageManagerInfo;
/**
* Checks if a package manager is installed and available on the PATH
* This helps prevent cache failures when a package manager is specified
* but not yet installed (e.g., pnpm via corepack)
* See: https://github.com/actions/setup-node/issues/1357
*/
const isPackageManagerInstalled = async (packageManager) => {
try {
const { exitCode } = await exec.getExecOutput(`${packageManager} --version`, undefined, {
ignoreReturnCode: true,
silent: true
});
return exitCode === 0;
}
catch {
return false;
}
};
exports.isPackageManagerInstalled = isPackageManagerInstalled;
/**
* getProjectDirectoriesFromCacheDependencyPath is called twice during `restoreCache`
* - first through `getCacheDirectories`

31
dist/setup/index.js vendored
View File

@@ -53696,6 +53696,16 @@ const restoreCache = async (packageManager, cacheDependencyPath) => {
if (!packageManagerInfo) {
throw new Error(`Caching for '${packageManager}' is not supported`);
}
// Check if the package manager is installed before attempting to cache
// This prevents cache failures for package managers that need to be installed first
// See: https://github.com/actions/setup-node/issues/1357
const isInstalled = await (0, cache_utils_1.isPackageManagerInstalled)(packageManager);
if (!isInstalled) {
core.warning(`Package manager '${packageManager}' was not found in the PATH. ` +
`Skipping cache restore. Please ensure the package manager is installed ` +
`before running this action or set 'package-manager-cache: false' to disable caching.`);
return;
}
const platform = process.env.RUNNER_OS;
const arch = os_1.default.arch();
const cachePaths = await (0, cache_utils_1.getCacheDirectories)(packageManagerInfo, cacheDependencyPath);
@@ -53785,7 +53795,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.repoHasYarnBerryManagedDependencies = exports.getCacheDirectories = exports.resetProjectDirectoriesMemoized = exports.getPackageManagerInfo = exports.getCommandOutputNotEmpty = exports.getCommandOutput = exports.supportedPackageManagers = void 0;
exports.repoHasYarnBerryManagedDependencies = exports.getCacheDirectories = exports.resetProjectDirectoriesMemoized = exports.isPackageManagerInstalled = exports.getPackageManagerInfo = exports.getCommandOutputNotEmpty = exports.getCommandOutput = exports.supportedPackageManagers = void 0;
exports.isGhes = isGhes;
exports.isCacheFeatureAvailable = isCacheFeatureAvailable;
const core = __importStar(__nccwpck_require__(37484));
@@ -53856,6 +53866,25 @@ const getPackageManagerInfo = async (packageManager) => {
}
};
exports.getPackageManagerInfo = getPackageManagerInfo;
/**
* Checks if a package manager is installed and available on the PATH
* This helps prevent cache failures when a package manager is specified
* but not yet installed (e.g., pnpm via corepack)
* See: https://github.com/actions/setup-node/issues/1357
*/
const isPackageManagerInstalled = async (packageManager) => {
try {
const { exitCode } = await exec.getExecOutput(`${packageManager} --version`, undefined, {
ignoreReturnCode: true,
silent: true
});
return exitCode === 0;
}
catch {
return false;
}
};
exports.isPackageManagerInstalled = isPackageManagerInstalled;
/**
* getProjectDirectoriesFromCacheDependencyPath is called twice during `restoreCache`
* - first through `getCacheDirectories`

View File

@@ -8,7 +8,7 @@ Currently, `actions/setup-node` supports caching dependencies for Npm and Yarn p
For the first iteration, we have decided to not support cases where `package-lock.json` / `yarn.lock` are located outside of repository root.
Current implementation searches the following file patterns in the repository root: `package-lock.json`, `yarn.lock` (in order of resolving priorities)
Obviously, it made build-in caching unusable for mono-repos and repos with complex structure.
Obviously, it made built-in caching unusable for mono-repos and repos with complex structure.
We would like to revisit this decision and add customization for dependencies lock file location.
## Proposal
@@ -24,7 +24,7 @@ The second option looks more generic because it allows to:
## Decision
Add `cache-dependency-path` input that will accept path (relative to repository root) to dependencies lock file.
If provided path contains wildcards, the action will search all maching files and calculate common hash like `${{ hashFiles('**/package-lock.json') }}` YAML construction does.
If provided path contains wildcards, the action will search all matching files and calculate common hash like `${{ hashFiles('**/package-lock.json') }}` YAML construction does.
The hash of provided matched files will be used as a part of cache key.
Yaml examples:

1538
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -51,7 +51,7 @@
"eslint-plugin-jest": "^27.9.0",
"eslint-plugin-node": "^11.1.0",
"jest": "^29.7.0",
"jest-circus": "^30.2.0",
"jest-circus": "^29.7.0",
"jest-each": "^29.7.0",
"prettier": "^3.6.2",
"ts-jest": "^29.4.1",

View File

@@ -9,6 +9,7 @@ import {State} from './constants';
import {
getCacheDirectories,
getPackageManagerInfo,
isPackageManagerInstalled,
repoHasYarnBerryManagedDependencies,
PackageManagerInfo
} from './cache-utils';
@@ -21,6 +22,20 @@ export const restoreCache = async (
if (!packageManagerInfo) {
throw new Error(`Caching for '${packageManager}' is not supported`);
}
// Check if the package manager is installed before attempting to cache
// This prevents cache failures for package managers that need to be installed first
// See: https://github.com/actions/setup-node/issues/1357
const isInstalled = await isPackageManagerInstalled(packageManager);
if (!isInstalled) {
core.warning(
`Package manager '${packageManager}' was not found in the PATH. ` +
`Skipping cache restore. Please ensure the package manager is installed ` +
`before running this action or set 'package-manager-cache: false' to disable caching.`
);
return;
}
const platform = process.env.RUNNER_OS;
const arch = os.arch();

View File

@@ -2,7 +2,7 @@ import * as core from '@actions/core';
import * as cache from '@actions/cache';
import {State} from './constants';
import {getPackageManagerInfo} from './cache-utils';
import {getPackageManagerInfo, isPackageManagerInstalled} from './cache-utils';
// Catch and log any unhandled exceptions. These exceptions can leak out of the uploadChunk method in
// @actions/toolkit when a failed upload closes the file descriptor causing any in-process reads to
@@ -45,6 +45,17 @@ const cachePackages = async (packageManager: string) => {
return;
}
// Check if the package manager is installed before attempting to save cache
// This prevents cache save failures for package managers that may not be installed
const isInstalled = await isPackageManagerInstalled(packageManager);
if (!isInstalled) {
core.warning(
`Package manager '${packageManager}' was not found in the PATH. ` +
`Skipping cache save.`
);
return;
}
if (!cachePaths.length) {
// TODO: core.getInput has a bug - it can return undefined despite its definition (tests only?)
// export declare function getInput(name: string, options?: InputOptions): string;

View File

@@ -110,6 +110,30 @@ export const getPackageManagerInfo = async (packageManager: string) => {
}
};
/**
* Checks if a package manager is installed and available on the PATH
* This helps prevent cache failures when a package manager is specified
* but not yet installed (e.g., pnpm via corepack)
* See: https://github.com/actions/setup-node/issues/1357
*/
export const isPackageManagerInstalled = async (
packageManager: string
): Promise<boolean> => {
try {
const {exitCode} = await exec.getExecOutput(
`${packageManager} --version`,
undefined,
{
ignoreReturnCode: true,
silent: true
}
);
return exitCode === 0;
} catch {
return false;
}
};
/**
* getProjectDirectoriesFromCacheDependencyPath is called twice during `restoreCache`
* - first through `getCacheDirectories`