Compare commits

..

4 Commits

Author SHA1 Message Date
Pelle Wessman
d4d6a972de
Merge 6ef1113e78 into a9893b0cfb 2023-05-11 15:57:26 -07:00
Pelle Wessman
6ef1113e78
Run npm run build as suggested 2023-04-28 12:04:14 +02:00
Pelle Wessman
cbe3ec3ea1
Simplifies cache fallback + add timed invalidation 2023-02-27 19:35:59 +01:00
MOREL Matthieu
6a898d25f0
feat(cache): change key to match actions/cache documentation
Signed-off-by: Matthieu MOREL <mmorel-35@users.noreply.github.com>
2023-02-27 19:35:19 +01:00
111 changed files with 33276 additions and 75646 deletions

View File

@ -7,7 +7,7 @@ module.exports = {
'eslint-config-prettier'
],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint', 'eslint-plugin-node', 'eslint-plugin-jest'],
plugins: ['@typescript-eslint', 'eslint-plugin-jest'],
rules: {
'@typescript-eslint/no-require-imports': 'error',
'@typescript-eslint/no-non-null-assertion': 'off',
@ -28,8 +28,7 @@ module.exports = {
}
],
'no-control-regex': 'off',
'no-constant-condition': ['error', {checkLoops: false}],
'node/no-extraneous-import': 'error'
'no-constant-condition': ['error', {checkLoops: false}]
},
overrides: [
{

View File

@ -15,5 +15,3 @@ jobs:
call-basic-validation:
name: Basic validation
uses: actions/reusable-workflows/.github/workflows/basic-validation.yml@main
with:
node-version: '20.x'

View File

@ -1,4 +1,4 @@
name: Check dist
name: Check dist/
on:
push:
@ -15,5 +15,3 @@ jobs:
call-check-dist:
name: Check dist/
uses: actions/reusable-workflows/.github/workflows/check-dist.yml@main
with:
node-version: '20.x'

View File

@ -21,7 +21,7 @@ jobs:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [12, 14, 16]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Clean global cache
run: npm cache clean --force
- name: Setup Node
@ -44,7 +44,7 @@ jobs:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [12, 14, 16]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Install pnpm
uses: pnpm/action-setup@v2
with:
@ -77,7 +77,7 @@ jobs:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [14, 16]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Yarn version
run: yarn --version
- name: Generate yarn file
@ -93,13 +93,13 @@ jobs:
node-version: ${{ matrix.node-version }}
cache: 'yarn'
- name: Install dependencies
run: yarn install --ignore-engines
run: yarn install
- name: Verify node and yarn
run: __tests__/verify-node.sh "${{ matrix.node-version }}"
shell: bash
node-yarn3-depencies-caching:
name: Test yarn 3 (Node ${{ matrix.node-version}}, ${{ matrix.os }})
node-yarn2-depencies-caching:
name: Test yarn 2 (Node ${{ matrix.node-version}}, ${{ matrix.os }})
runs-on: ${{ matrix.os }}
env:
YARN_ENABLE_IMMUTABLE_INSTALLS: false
@ -109,9 +109,9 @@ jobs:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [12, 14, 16]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Update yarn
run: yarn set version 3.6.4
run: yarn set version berry
- name: Yarn version
run: yarn --version
- name: Generate simple .yarnrc.yml
@ -134,112 +134,3 @@ jobs:
- name: Verify node and yarn
run: __tests__/verify-node.sh "${{ matrix.node-version }}"
shell: bash
yarn-subprojects:
name: Test yarn subprojects
strategy:
matrix:
node-version: [12, 14, 16]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: prepare sub-projects
run: __tests__/prepare-yarn-subprojects.sh yarn1
# expect
# - no errors
# - log
# ##[debug]Cache Paths:
# ##[debug]["sub2/.yarn/cache","sub3/.yarn/cache","../../../.cache/yarn/v6"]
- name: Setup Node
uses: ./
with:
node-version: ${{ matrix.node-version }}
cache: 'yarn'
cache-dependency-path: |
**/*.lock
yarn.lock
yarn-subprojects-berry-local:
name: Test yarn subprojects all locally managed
strategy:
matrix:
node-version: [12, 14, 16]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: prepare sub-projects
run: __tests__/prepare-yarn-subprojects.sh keepcache keepcache
# expect
# - no errors
# - log
# ##[info]All dependencies are managed locally by yarn3, the previous cache can be used
# ##[debug]["node-cache-Linux-yarn-401024703386272f1a950c9f014cbb1bb79a7a5b6e1fb00e8b90d06734af41ee","node-cache-Linux-yarn"]
- name: Setup Node
uses: ./
with:
node-version: ${{ matrix.node-version }}
cache: 'yarn'
cache-dependency-path: |
sub2/*.lock
sub3/*.lock
yarn-subprojects-berry-global:
name: Test yarn subprojects some locally managed
strategy:
matrix:
node-version: [12, 14, 16]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: prepare sub-projects
run: __tests__/prepare-yarn-subprojects.sh global
# expect
# - no errors
# - log must
# ##[debug]"/home/runner/work/setup-node-test/setup-node-test/sub2" dependencies are managed by yarn 3 locally
# ##[debug]"/home/runner/work/setup-node-test/setup-node-test/sub3" dependencies are not managed by yarn 3 locally
- name: Setup Node
uses: ./
with:
node-version: ${{ matrix.node-version }}
cache: 'yarn'
cache-dependency-path: |
sub2/*.lock
sub3/*.lock
yarn-subprojects-berry-git:
name: Test yarn subprojects managed by git
strategy:
matrix:
node-version: [12, 14, 16]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: prepare sub-projects
run: /bin/bash __tests__/prepare-yarn-subprojects.sh keepcache
# expect
# - no errors
# - log
# [debug]"/home/runner/work/setup-node-test/setup-node-test/sub2" has .yarn/cache - dependencies are kept in the repository
# [debug]"/home/runner/work/setup-node-test/setup-node-test/sub3" has .yarn/cache - dependencies are kept in the repository
# [debug]["node-cache-Linux-yarn-401024703386272f1a950c9f014cbb1bb79a7a5b6e1fb00e8b90d06734af41ee"]
- name: Setup Node
uses: ./
with:
node-version: ${{ matrix.node-version }}
cache: 'yarn'
cache-dependency-path: |
sub2/*.lock
sub3/*.lock

View File

@ -25,7 +25,7 @@ jobs:
env:
https_proxy: http://squid-proxy:3128
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Clear tool cache
run: rm -rf $RUNNER_TOOL_CACHE/*
- name: Setup node 14
@ -41,7 +41,7 @@ jobs:
https_proxy: http://no-such-proxy:3128
no_proxy: api.github.com,github.com,nodejs.org,registry.npmjs.org,*.s3.amazonaws.com,s3.amazonaws.com
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Clear tool cache
run: rm -rf $RUNNER_TOOL_CACHE/*
- name: Setup node 11

View File

@ -20,7 +20,7 @@ jobs:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [10, 12, 14]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Setup Node
uses: ./
with:
@ -37,7 +37,7 @@ jobs:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [lts/dubnium, lts/erbium, lts/fermium, lts/*, lts/-1]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Setup Node
uses: ./
with:
@ -61,10 +61,10 @@ jobs:
[
'20-v8-canary',
'20.0.0-v8-canary',
'20.0.0-v8-canary20221101e50e45c9f8'
'20.0.0-v8-canary20221103f7e2421e91'
]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Setup Node
uses: ./
with:
@ -85,7 +85,7 @@ jobs:
node-version:
[16.0.0-nightly20210420a0261d231c, 17-nightly, 18.0.0-nightly]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Setup Node
uses: ./
with:
@ -105,7 +105,7 @@ jobs:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [16.0.0-rc.1, 18.0.0-rc.2, 19.0.0-rc.0]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Setup Node
uses: ./
with:
@ -125,7 +125,7 @@ jobs:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [10.15, 12.16.0, 14.2.0, 16.3.0]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Setup Node
uses: ./
with:
@ -142,7 +142,7 @@ jobs:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [10, 12, 14]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Setup Node and check latest
uses: ./
with:
@ -158,10 +158,12 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version-file:
[.nvmrc, .tool-versions, .tool-versions-node, package.json]
node-version-file: [.nvmrc, .tool-versions, package.json]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Remove volta from package.json
shell: bash
run: cat <<< "$(jq 'del(.volta)' ./__tests__/data/package.json)" > ./__tests__/data/package.json
- name: Setup node from node version file
uses: ./
with:
@ -176,26 +178,11 @@ jobs:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Setup node from node version file
uses: ./
with:
node-version-file: '__tests__/data/package-volta.json'
- name: Verify node
run: __tests__/verify-node.sh 16
version-file-volta-extends:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
steps:
- uses: actions/checkout@v4
- name: Setup node from node version file
uses: ./
with:
node-version-file: '__tests__/data/package-volta-extends.json'
node-version-file: '__tests__/data/package.json'
- name: Verify node
run: __tests__/verify-node.sh 16
@ -207,7 +194,7 @@ jobs:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [11, 13]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Setup Node from dist
uses: ./
with:
@ -223,7 +210,7 @@ jobs:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
# test old versions which didn't have npm and layout different
- name: Setup node 0.12.18 from dist
uses: ./
@ -236,7 +223,7 @@ jobs:
arch:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Setup node 14 x86 from dist
uses: ./
with:
@ -260,7 +247,7 @@ jobs:
echo "LATEST_NODE_VERSION=$latestNodeVersion" >> $GITHUB_OUTPUT
id: version
shell: bash
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Setup Node
uses: ./
with:

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
.licenses/npm/@octokit/rest.dep.yml generated Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
.licenses/npm/atob-lite.dep.yml generated Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
.licenses/npm/btoa-lite.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/cross-spawn.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/form-data-3.0.1.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/ip-regex.dep.yml generated Normal file

Binary file not shown.

Binary file not shown.

BIN
.licenses/npm/is-stream.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/isobject.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/lodash.get.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/lodash.set.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/lodash.uniq.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/macos-release.dep.yml generated Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
.licenses/npm/npm-run-path.dep.yml generated Normal file

Binary file not shown.

Binary file not shown.

BIN
.licenses/npm/p-finally.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/path-key.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/psl.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/punycode.dep.yml generated Normal file

Binary file not shown.

Binary file not shown.

BIN
.licenses/npm/shebang-command.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/shebang-regex.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/signal-exit.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/strip-eof.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/tough-cookie.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/tslib-2.3.1.dep.yml generated Normal file

Binary file not shown.

Binary file not shown.

BIN
.licenses/npm/uuid-3.3.2.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/windows-release.dep.yml generated Normal file

Binary file not shown.

View File

@ -18,14 +18,14 @@ See [action.yml](action.yml)
<!-- start usage -->
```yaml
- uses: actions/setup-node@v4
- uses: actions/setup-node@v3
with:
# Version Spec of the version to use in SemVer notation.
# It also emits such aliases as lts, latest, nightly and canary builds
# Examples: 12.x, 10.15.1, >=10.15.0, lts/Hydrogen, 16-nightly, latest, node
node-version: ''
# File containing the version Spec of the version to use. Examples: package.json, .nvmrc, .node-version, .tool-versions.
# 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.
node-version-file: ''
@ -83,8 +83,8 @@ See [action.yml](action.yml)
```yaml
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- run: npm ci
@ -99,16 +99,16 @@ For information regarding locally cached versions of Node.js on GitHub hosted ru
### Supported version syntax
The `node-version` input supports the Semantic Versioning Specification, for more detailed examples please refer to [the semver package documentation](https://github.com/npm/node-semver).
The `node-version` input supports the Semantic Versioning Specification, for more detailed examples please refer to the [documentation](https://github.com/npm/node-semver).
Examples:
- Major versions: `18`, `20`
- Major versions: `14`, `16`, `18`
- More specific versions: `10.15`, `16.15.1` , `18.4.0`
- NVM LTS syntax: `lts/erbium`, `lts/fermium`, `lts/*`, `lts/-n`
- Latest release: `*` or `latest`/`current`/`node`
**Note:** Like the other values, `*` will get the latest [locally-cached Node.js version](https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2204-Readme.md#nodejs), or the latest version from [actions/node-versions](https://github.com/actions/node-versions/blob/main/versions-manifest.json), depending on the [`check-latest`](docs/advanced-usage.md#check-latest-version) input.
**Note:** Like the other values, `*` will get the latest [locally-cached Node.js version](https://github.com/actions/runner-images/blob/main/images/linux/Ubuntu2204-Readme.md#nodejs), or the latest version from [actions/node-versions](https://github.com/actions/node-versions/blob/main/versions-manifest.json), depending on the [`check-latest`](docs/advanced-usage.md#check-latest-version) input.
`current`/`latest`/`node` always resolve to the latest [dist version](https://nodejs.org/dist/index.json).
That version is then downloaded from actions/node-versions if possible, or directly from Node.js if not.
@ -134,10 +134,10 @@ See the examples of using cache for `yarn`/`pnpm` and `cache-dependency-path` in
```yaml
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 20
node-version: 16
cache: 'npm'
- run: npm ci
- run: npm test
@ -147,10 +147,10 @@ steps:
```yaml
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 20
node-version: 16
cache: 'npm'
cache-dependency-path: subdir/package-lock.json
- run: npm ci
@ -168,9 +168,9 @@ jobs:
node: [ 14, 16, 18 ]
name: Node ${{ matrix.node }} sample
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Setup node
uses: actions/setup-node@v4
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node }}
- run: npm ci
@ -184,10 +184,10 @@ jobs:
To get a higher rate limit, you can [generate a personal access token on github.com](https://github.com/settings/tokens/new) and pass it as the `token` input for the action:
```yaml
uses: actions/setup-node@v4
uses: actions/setup-node@v3
with:
token: ${{ secrets.GH_DOTCOM_TOKEN }}
node-version: 20
node-version: 16
```
If the runner is not able to access github.com, any Nodejs versions requested during a workflow run must come from the runner's tool cache. See "[Setting up the tool cache on self-hosted runners without internet access](https://docs.github.com/en/enterprise-server@3.2/admin/github-actions/managing-access-to-actions-from-githubcom/setting-up-the-tool-cache-on-self-hosted-runners-without-internet-access)" for more information.

View File

@ -1,10 +1,9 @@
import os from 'os';
import fs from 'fs';
import * as fs from 'fs';
import * as path from 'path';
import * as core from '@actions/core';
import * as io from '@actions/io';
import * as auth from '../src/authutil';
import * as cacheUtils from '../src/cache-utils';
let rcFile: string;

View File

@ -32,13 +32,13 @@ describe('cache-restore', () => {
function findCacheFolder(command: string) {
switch (command) {
case 'npm config get cache':
case utils.supportedPackageManagers.npm.getCacheFolderCommand:
return npmCachePath;
case 'pnpm store path --silent':
case utils.supportedPackageManagers.pnpm.getCacheFolderCommand:
return pnpmCachePath;
case 'yarn cache dir':
case utils.supportedPackageManagers.yarn1.getCacheFolderCommand:
return yarn1CachePath;
case 'yarn config get cacheFolder':
case utils.supportedPackageManagers.yarn2.getCacheFolderCommand:
return yarn2CachePath;
default:
return 'packge/not/found';
@ -108,7 +108,7 @@ describe('cache-restore', () => {
it.each([['npm7'], ['npm6'], ['pnpm6'], ['yarn1'], ['yarn2'], ['random']])(
'Throw an error because %s is not supported',
async packageManager => {
await expect(restoreCache(packageManager, '')).rejects.toThrow(
await expect(restoreCache(packageManager)).rejects.toThrow(
`Caching for '${packageManager}' is not supported`
);
}
@ -132,7 +132,7 @@ describe('cache-restore', () => {
}
});
await restoreCache(packageManager, '', '0');
await restoreCache(packageManager, undefined, '0');
expect(hashFilesSpy).toHaveBeenCalled();
expect(infoSpy).toHaveBeenCalledWith(
`Cache restored from key: ${platform}-0-setup-node-${packageManager}-${fileHash}`
@ -163,7 +163,7 @@ describe('cache-restore', () => {
});
restoreCacheSpy.mockImplementationOnce(() => undefined);
await restoreCache(packageManager, '', '0');
await restoreCache(packageManager, undefined, '0');
expect(hashFilesSpy).toHaveBeenCalled();
expect(infoSpy).toHaveBeenCalledWith(
`Cache not found for input keys: ${platform}-0-setup-node-${packageManager}-${fileHash}, ${platform}-0-setup-node-${packageManager}-`

View File

@ -92,9 +92,6 @@ describe('run', () => {
it('Package manager is not valid, skip caching', async () => {
inputs['cache'] = 'yarn3';
getStateSpy.mockImplementation(key =>
key === State.CachePackageManager ? inputs['cache'] : ''
);
await run();
@ -110,22 +107,18 @@ describe('run', () => {
describe('Validate unchanged cache is not saved', () => {
it('should not save cache for yarn1', async () => {
inputs['cache'] = 'yarn';
getStateSpy.mockImplementation(key =>
key === State.CachePackageManager
? inputs['cache']
: key === State.CachePrimaryKey || key === State.CacheMatchedKey
? yarnFileHash
: key === State.CachePaths
? '["/foo/bar"]'
: 'not expected'
);
getStateSpy.mockImplementation(() => yarnFileHash);
getCommandOutputSpy
.mockImplementationOnce(() => '1.2.3')
.mockImplementationOnce(() => `${commonPath}/yarn1`);
await run();
expect(getInputSpy).not.toHaveBeenCalled();
expect(getStateSpy).toHaveBeenCalledTimes(4);
expect(getCommandOutputSpy).toHaveBeenCalledTimes(0);
expect(debugSpy).toHaveBeenCalledTimes(0);
expect(getInputSpy).toHaveBeenCalled();
expect(getStateSpy).toHaveBeenCalledTimes(2);
expect(getCommandOutputSpy).toHaveBeenCalledTimes(2);
expect(debugSpy).toHaveBeenCalledWith(`yarn path is ${commonPath}/yarn1`);
expect(debugSpy).toHaveBeenCalledWith('Consumed yarn version is 1.2.3');
expect(infoSpy).toHaveBeenCalledWith(
`Cache hit occurred on the primary key ${yarnFileHash}, not saving cache.`
);
@ -134,22 +127,18 @@ describe('run', () => {
it('should not save cache for yarn2', async () => {
inputs['cache'] = 'yarn';
getStateSpy.mockImplementation(key =>
key === State.CachePackageManager
? inputs['cache']
: key === State.CachePrimaryKey || key === State.CacheMatchedKey
? yarnFileHash
: key === State.CachePaths
? '["/foo/bar"]'
: 'not expected'
);
getStateSpy.mockImplementation(() => yarnFileHash);
getCommandOutputSpy
.mockImplementationOnce(() => '2.2.3')
.mockImplementationOnce(() => `${commonPath}/yarn2`);
await run();
expect(getInputSpy).not.toHaveBeenCalled();
expect(getStateSpy).toHaveBeenCalledTimes(4);
expect(getCommandOutputSpy).toHaveBeenCalledTimes(0);
expect(debugSpy).toHaveBeenCalledTimes(0);
expect(getInputSpy).toHaveBeenCalled();
expect(getStateSpy).toHaveBeenCalledTimes(2);
expect(getCommandOutputSpy).toHaveBeenCalledTimes(2);
expect(debugSpy).toHaveBeenCalledWith(`yarn path is ${commonPath}/yarn2`);
expect(debugSpy).toHaveBeenCalledWith('Consumed yarn version is 2.2.3');
expect(infoSpy).toHaveBeenCalledWith(
`Cache hit occurred on the primary key ${yarnFileHash}, not saving cache.`
);
@ -158,44 +147,35 @@ describe('run', () => {
it('should not save cache for npm', async () => {
inputs['cache'] = 'npm';
getStateSpy.mockImplementation(key =>
key === State.CachePackageManager
? inputs['cache']
: key === State.CachePrimaryKey || key === State.CacheMatchedKey
? yarnFileHash
: key === State.CachePaths
? '["/foo/bar"]'
: 'not expected'
);
getStateSpy.mockImplementation(() => npmFileHash);
getCommandOutputSpy.mockImplementationOnce(() => `${commonPath}/npm`);
await run();
expect(getInputSpy).not.toHaveBeenCalled();
expect(getStateSpy).toHaveBeenCalledTimes(4);
expect(getCommandOutputSpy).toHaveBeenCalledTimes(0);
expect(debugSpy).toHaveBeenCalledTimes(0);
expect(getInputSpy).toHaveBeenCalled();
expect(getStateSpy).toHaveBeenCalledTimes(2);
expect(getCommandOutputSpy).toHaveBeenCalledTimes(1);
expect(debugSpy).toHaveBeenCalledWith(`npm path is ${commonPath}/npm`);
expect(infoSpy).toHaveBeenCalledWith(
`Cache hit occurred on the primary key ${npmFileHash}, not saving cache.`
);
expect(setFailedSpy).not.toHaveBeenCalled();
});
it('should not save cache for pnpm', async () => {
inputs['cache'] = 'pnpm';
getStateSpy.mockImplementation(key =>
key === State.CachePackageManager
? inputs['cache']
: key === State.CachePrimaryKey || key === State.CacheMatchedKey
? yarnFileHash
: key === State.CachePaths
? '["/foo/bar"]'
: 'not expected'
);
getStateSpy.mockImplementation(() => pnpmFileHash);
getCommandOutputSpy.mockImplementationOnce(() => `${commonPath}/pnpm`);
await run();
expect(getInputSpy).not.toHaveBeenCalled();
expect(getStateSpy).toHaveBeenCalledTimes(4);
expect(getCommandOutputSpy).toHaveBeenCalledTimes(0);
expect(debugSpy).toHaveBeenCalledTimes(0);
expect(getInputSpy).toHaveBeenCalled();
expect(getStateSpy).toHaveBeenCalledTimes(2);
expect(getCommandOutputSpy).toHaveBeenCalledTimes(1);
expect(debugSpy).toHaveBeenCalledWith(`pnpm path is ${commonPath}/pnpm`);
expect(infoSpy).toHaveBeenCalledWith(
`Cache hit occurred on the primary key ${pnpmFileHash}, not saving cache.`
);
expect(setFailedSpy).not.toHaveBeenCalled();
});
});
@ -203,24 +183,24 @@ describe('run', () => {
describe('action saves the cache', () => {
it('saves cache from yarn 1', async () => {
inputs['cache'] = 'yarn';
getStateSpy.mockImplementation((key: string) =>
key === State.CachePackageManager
? inputs['cache']
: key === State.CacheMatchedKey
? yarnFileHash
: key === State.CachePrimaryKey
? npmFileHash
: key === State.CachePaths
? '["/foo/bar"]'
: 'not expected'
);
getStateSpy.mockImplementation((name: string) => {
if (name === State.CacheMatchedKey) {
return yarnFileHash;
} else {
return npmFileHash;
}
});
getCommandOutputSpy
.mockImplementationOnce(() => '1.2.3')
.mockImplementationOnce(() => `${commonPath}/yarn1`);
await run();
expect(getInputSpy).not.toHaveBeenCalled();
expect(getStateSpy).toHaveBeenCalledTimes(4);
expect(getCommandOutputSpy).toHaveBeenCalledTimes(0);
expect(debugSpy).toHaveBeenCalledTimes(0);
expect(getInputSpy).toHaveBeenCalled();
expect(getStateSpy).toHaveBeenCalledTimes(2);
expect(getCommandOutputSpy).toHaveBeenCalledTimes(2);
expect(debugSpy).toHaveBeenCalledWith(`yarn path is ${commonPath}/yarn1`);
expect(debugSpy).toHaveBeenCalledWith('Consumed yarn version is 1.2.3');
expect(infoSpy).not.toHaveBeenCalledWith(
`Cache hit occurred on the primary key ${yarnFileHash}, not saving cache.`
);
@ -233,24 +213,24 @@ describe('run', () => {
it('saves cache from yarn 2', async () => {
inputs['cache'] = 'yarn';
getStateSpy.mockImplementation((key: string) =>
key === State.CachePackageManager
? inputs['cache']
: key === State.CacheMatchedKey
? yarnFileHash
: key === State.CachePrimaryKey
? npmFileHash
: key === State.CachePaths
? '["/foo/bar"]'
: 'not expected'
);
getStateSpy.mockImplementation((name: string) => {
if (name === State.CacheMatchedKey) {
return yarnFileHash;
} else {
return npmFileHash;
}
});
getCommandOutputSpy
.mockImplementationOnce(() => '2.2.3')
.mockImplementationOnce(() => `${commonPath}/yarn2`);
await run();
expect(getInputSpy).not.toHaveBeenCalled();
expect(getStateSpy).toHaveBeenCalledTimes(4);
expect(getCommandOutputSpy).toHaveBeenCalledTimes(0);
expect(debugSpy).toHaveBeenCalledTimes(0);
expect(getInputSpy).toHaveBeenCalled();
expect(getStateSpy).toHaveBeenCalledTimes(2);
expect(getCommandOutputSpy).toHaveBeenCalledTimes(2);
expect(debugSpy).toHaveBeenCalledWith(`yarn path is ${commonPath}/yarn2`);
expect(debugSpy).toHaveBeenCalledWith('Consumed yarn version is 2.2.3');
expect(infoSpy).not.toHaveBeenCalledWith(
`Cache hit occurred on the primary key ${yarnFileHash}, not saving cache.`
);
@ -263,24 +243,21 @@ describe('run', () => {
it('saves cache from npm', async () => {
inputs['cache'] = 'npm';
getStateSpy.mockImplementation((key: string) =>
key === State.CachePackageManager
? inputs['cache']
: key === State.CacheMatchedKey
? npmFileHash
: key === State.CachePrimaryKey
? yarnFileHash
: key === State.CachePaths
? '["/foo/bar"]'
: 'not expected'
);
getStateSpy.mockImplementation((name: string) => {
if (name === State.CacheMatchedKey) {
return npmFileHash;
} else {
return yarnFileHash;
}
});
getCommandOutputSpy.mockImplementationOnce(() => `${commonPath}/npm`);
await run();
expect(getInputSpy).not.toHaveBeenCalled();
expect(getStateSpy).toHaveBeenCalledTimes(4);
expect(getCommandOutputSpy).toHaveBeenCalledTimes(0);
expect(debugSpy).toHaveBeenCalledTimes(0);
expect(getInputSpy).toHaveBeenCalled();
expect(getStateSpy).toHaveBeenCalledTimes(2);
expect(getCommandOutputSpy).toHaveBeenCalledTimes(1);
expect(debugSpy).toHaveBeenCalledWith(`npm path is ${commonPath}/npm`);
expect(infoSpy).not.toHaveBeenCalledWith(
`Cache hit occurred on the primary key ${npmFileHash}, not saving cache.`
);
@ -293,24 +270,21 @@ describe('run', () => {
it('saves cache from pnpm', async () => {
inputs['cache'] = 'pnpm';
getStateSpy.mockImplementation((key: string) =>
key === State.CachePackageManager
? inputs['cache']
: key === State.CacheMatchedKey
? pnpmFileHash
: key === State.CachePrimaryKey
? npmFileHash
: key === State.CachePaths
? '["/foo/bar"]'
: 'not expected'
);
getStateSpy.mockImplementation((name: string) => {
if (name === State.CacheMatchedKey) {
return pnpmFileHash;
} else {
return npmFileHash;
}
});
getCommandOutputSpy.mockImplementationOnce(() => `${commonPath}/pnpm`);
await run();
expect(getInputSpy).not.toHaveBeenCalled();
expect(getStateSpy).toHaveBeenCalledTimes(4);
expect(getCommandOutputSpy).toHaveBeenCalledTimes(0);
expect(debugSpy).toHaveBeenCalledTimes(0);
expect(getInputSpy).toHaveBeenCalled();
expect(getStateSpy).toHaveBeenCalledTimes(2);
expect(getCommandOutputSpy).toHaveBeenCalledTimes(1);
expect(debugSpy).toHaveBeenCalledWith(`pnpm path is ${commonPath}/pnpm`);
expect(infoSpy).not.toHaveBeenCalledWith(
`Cache hit occurred on the primary key ${pnpmFileHash}, not saving cache.`
);
@ -323,27 +297,24 @@ describe('run', () => {
it('save with -1 cacheId , should not fail workflow', async () => {
inputs['cache'] = 'npm';
getStateSpy.mockImplementation((key: string) =>
key === State.CachePackageManager
? inputs['cache']
: key === State.CacheMatchedKey
? npmFileHash
: key === State.CachePrimaryKey
? yarnFileHash
: key === State.CachePaths
? '["/foo/bar"]'
: 'not expected'
);
getStateSpy.mockImplementation((name: string) => {
if (name === State.CacheMatchedKey) {
return npmFileHash;
} else {
return yarnFileHash;
}
});
getCommandOutputSpy.mockImplementationOnce(() => `${commonPath}/npm`);
saveCacheSpy.mockImplementation(() => {
return -1;
});
await run();
expect(getInputSpy).not.toHaveBeenCalled();
expect(getStateSpy).toHaveBeenCalledTimes(4);
expect(getCommandOutputSpy).toHaveBeenCalledTimes(0);
expect(debugSpy).toHaveBeenCalledTimes(0);
expect(getInputSpy).toHaveBeenCalled();
expect(getStateSpy).toHaveBeenCalledTimes(2);
expect(getCommandOutputSpy).toHaveBeenCalledTimes(1);
expect(debugSpy).toHaveBeenCalledWith(`npm path is ${commonPath}/npm`);
expect(infoSpy).not.toHaveBeenCalledWith(
`Cache hit occurred on the primary key ${npmFileHash}, not saving cache.`
);
@ -356,27 +327,24 @@ describe('run', () => {
it('saves with error from toolkit, should fail workflow', async () => {
inputs['cache'] = 'npm';
getStateSpy.mockImplementation((key: string) =>
key === State.CachePackageManager
? inputs['cache']
: key === State.CacheMatchedKey
? npmFileHash
: key === State.CachePrimaryKey
? yarnFileHash
: key === State.CachePaths
? '["/foo/bar"]'
: 'not expected'
);
getStateSpy.mockImplementation((name: string) => {
if (name === State.CacheMatchedKey) {
return npmFileHash;
} else {
return yarnFileHash;
}
});
getCommandOutputSpy.mockImplementationOnce(() => `${commonPath}/npm`);
saveCacheSpy.mockImplementation(() => {
throw new cache.ValidationError('Validation failed');
});
await run();
expect(getInputSpy).not.toHaveBeenCalled();
expect(getStateSpy).toHaveBeenCalledTimes(4);
expect(getCommandOutputSpy).toHaveBeenCalledTimes(0);
expect(debugSpy).toHaveBeenCalledTimes(0);
expect(getInputSpy).toHaveBeenCalled();
expect(getStateSpy).toHaveBeenCalledTimes(2);
expect(getCommandOutputSpy).toHaveBeenCalledTimes(1);
expect(debugSpy).toHaveBeenCalledWith(`npm path is ${commonPath}/npm`);
expect(infoSpy).not.toHaveBeenCalledWith(
`Cache hit occurred on the primary key ${npmFileHash}, not saving cache.`
);

View File

@ -2,18 +2,7 @@ import * as core from '@actions/core';
import * as cache from '@actions/cache';
import path from 'path';
import * as utils from '../src/cache-utils';
import {
PackageManagerInfo,
isCacheFeatureAvailable,
supportedPackageManagers,
getCommandOutput,
resetProjectDirectoriesMemoized
} from '../src/cache-utils';
import fs from 'fs';
import * as cacheUtils from '../src/cache-utils';
import * as glob from '@actions/glob';
import {Globber} from '@actions/glob';
import {MockGlobber} from './mock/glob-mock';
import {PackageManagerInfo, isCacheFeatureAvailable} from '../src/cache-utils';
describe('cache-utils', () => {
const versionYarn1 = '1.2.3';
@ -23,10 +12,8 @@ describe('cache-utils', () => {
let isFeatureAvailable: jest.SpyInstance;
let info: jest.SpyInstance;
let warningSpy: jest.SpyInstance;
let fsRealPathSyncSpy: jest.SpyInstance;
beforeEach(() => {
console.log('::stop-commands::stoptoken');
process.env['GITHUB_WORKSPACE'] = path.join(__dirname, 'data');
debugSpy = jest.spyOn(core, 'debug');
debugSpy.mockImplementation(msg => {});
@ -37,29 +24,13 @@ describe('cache-utils', () => {
isFeatureAvailable = jest.spyOn(cache, 'isFeatureAvailable');
getCommandOutputSpy = jest.spyOn(utils, 'getCommandOutput');
fsRealPathSyncSpy = jest.spyOn(fs, 'realpathSync');
fsRealPathSyncSpy.mockImplementation(dirName => {
return dirName;
});
});
afterEach(() => {
jest.resetAllMocks();
jest.clearAllMocks();
//jest.restoreAllMocks();
});
afterAll(async () => {
console.log('::stoptoken::');
jest.restoreAllMocks();
}, 100000);
describe('getPackageManagerInfo', () => {
it.each<[string, PackageManagerInfo | null]>([
['npm', utils.supportedPackageManagers.npm],
['pnpm', utils.supportedPackageManagers.pnpm],
['yarn', utils.supportedPackageManagers.yarn],
['yarn', utils.supportedPackageManagers.yarn1],
['yarn1', null],
['yarn2', null],
['npm7', null]
@ -101,263 +72,4 @@ describe('cache-utils', () => {
jest.resetAllMocks();
jest.clearAllMocks();
});
describe('getCacheDirectoriesPaths', () => {
let existsSpy: jest.SpyInstance;
let lstatSpy: jest.SpyInstance;
let globCreateSpy: jest.SpyInstance;
beforeEach(() => {
existsSpy = jest.spyOn(fs, 'existsSync');
existsSpy.mockImplementation(() => true);
lstatSpy = jest.spyOn(fs, 'lstatSync');
lstatSpy.mockImplementation(arg => ({
isDirectory: () => true
}));
globCreateSpy = jest.spyOn(glob, 'create');
globCreateSpy.mockImplementation(
(pattern: string): Promise<Globber> =>
MockGlobber.create(['/foo', '/bar'])
);
resetProjectDirectoriesMemoized();
});
afterEach(() => {
existsSpy.mockRestore();
lstatSpy.mockRestore();
globCreateSpy.mockRestore();
});
it.each([
[supportedPackageManagers.npm, ''],
[supportedPackageManagers.npm, '/dir/file.lock'],
[supportedPackageManagers.npm, '/**/file.lock'],
[supportedPackageManagers.pnpm, ''],
[supportedPackageManagers.pnpm, '/dir/file.lock'],
[supportedPackageManagers.pnpm, '/**/file.lock']
])(
'getCacheDirectoriesPaths should return one dir for non yarn',
async (packageManagerInfo, cacheDependency) => {
getCommandOutputSpy.mockImplementation(() => 'foo');
const dirs = await cacheUtils.getCacheDirectories(
packageManagerInfo,
cacheDependency
);
expect(dirs).toEqual(['foo']);
// to do not call for a version
// call once for get cache folder
expect(getCommandOutputSpy).toHaveBeenCalledTimes(1);
}
);
it('getCacheDirectoriesPaths should return one dir for yarn without cacheDependency', async () => {
getCommandOutputSpy.mockImplementation(() => 'foo');
const dirs = await cacheUtils.getCacheDirectories(
supportedPackageManagers.yarn,
''
);
expect(dirs).toEqual(['foo']);
});
it.each([
[supportedPackageManagers.npm, ''],
[supportedPackageManagers.npm, '/dir/file.lock'],
[supportedPackageManagers.npm, '/**/file.lock'],
[supportedPackageManagers.pnpm, ''],
[supportedPackageManagers.pnpm, '/dir/file.lock'],
[supportedPackageManagers.pnpm, '/**/file.lock'],
[supportedPackageManagers.yarn, ''],
[supportedPackageManagers.yarn, '/dir/file.lock'],
[supportedPackageManagers.yarn, '/**/file.lock']
])(
'getCacheDirectoriesPaths should throw for getCommandOutput returning empty',
async (packageManagerInfo, cacheDependency) => {
getCommandOutputSpy.mockImplementation((command: string) =>
// return empty string to indicate getCacheFolderPath failed
// --version still works
command.includes('version') ? '1.' : ''
);
await expect(
cacheUtils.getCacheDirectories(packageManagerInfo, cacheDependency)
).rejects.toThrow(); //'Could not get cache folder path for /dir');
}
);
it.each([
[supportedPackageManagers.yarn, '/dir/file.lock'],
[supportedPackageManagers.yarn, '/**/file.lock']
])(
'getCacheDirectoriesPaths should nothrow in case of having not directories',
async (packageManagerInfo, cacheDependency) => {
lstatSpy.mockImplementation(arg => ({
isDirectory: () => false
}));
await cacheUtils.getCacheDirectories(
packageManagerInfo,
cacheDependency
);
expect(warningSpy).toHaveBeenCalledTimes(1);
expect(warningSpy).toHaveBeenCalledWith(
`No existing directories found containing cache-dependency-path="${cacheDependency}"`
);
}
);
it.each(['1.1.1', '2.2.2'])(
'getCacheDirectoriesPaths yarn v%s should return one dir without cacheDependency',
async version => {
getCommandOutputSpy.mockImplementationOnce(() => version);
getCommandOutputSpy.mockImplementationOnce(() => `foo${version}`);
const dirs = await cacheUtils.getCacheDirectories(
supportedPackageManagers.yarn,
''
);
expect(dirs).toEqual([`foo${version}`]);
}
);
it.each(['1.1.1', '2.2.2'])(
'getCacheDirectoriesPaths yarn v%s should return 2 dirs with globbed cacheDependency',
async version => {
let dirNo = 1;
getCommandOutputSpy.mockImplementation((command: string) =>
command.includes('version') ? version : `file_${version}_${dirNo++}`
);
globCreateSpy.mockImplementation(
(pattern: string): Promise<Globber> =>
MockGlobber.create(['/tmp/dir1/file', '/tmp/dir2/file'])
);
const dirs = await cacheUtils.getCacheDirectories(
supportedPackageManagers.yarn,
'/tmp/**/file'
);
expect(dirs).toEqual([`file_${version}_1`, `file_${version}_2`]);
}
);
it.each(['1.1.1', '2.2.2'])(
'getCacheDirectoriesPaths yarn v%s should return 2 dirs with globbed cacheDependency expanding to duplicates',
async version => {
let dirNo = 1;
getCommandOutputSpy.mockImplementation((command: string) =>
command.includes('version') ? version : `file_${version}_${dirNo++}`
);
globCreateSpy.mockImplementation(
(pattern: string): Promise<Globber> =>
MockGlobber.create([
'/tmp/dir1/file',
'/tmp/dir2/file',
'/tmp/dir1/file'
])
);
const dirs = await cacheUtils.getCacheDirectories(
supportedPackageManagers.yarn,
'/tmp/**/file'
);
expect(dirs).toEqual([`file_${version}_1`, `file_${version}_2`]);
}
);
it.each(['1.1.1', '2.2.2'])(
'getCacheDirectoriesPaths yarn v%s should return 2 uniq dirs despite duplicate cache directories',
async version => {
let dirNo = 1;
getCommandOutputSpy.mockImplementation((command: string) =>
command.includes('version')
? version
: `file_${version}_${dirNo++ % 2}`
);
globCreateSpy.mockImplementation(
(pattern: string): Promise<Globber> =>
MockGlobber.create([
'/tmp/dir1/file',
'/tmp/dir2/file',
'/tmp/dir3/file'
])
);
const dirs = await cacheUtils.getCacheDirectories(
supportedPackageManagers.yarn,
'/tmp/**/file'
);
expect(dirs).toEqual([`file_${version}_1`, `file_${version}_0`]);
expect(getCommandOutputSpy).toHaveBeenCalledTimes(6);
expect(getCommandOutputSpy).toHaveBeenCalledWith(
'yarn --version',
'/tmp/dir1'
);
expect(getCommandOutputSpy).toHaveBeenCalledWith(
'yarn --version',
'/tmp/dir2'
);
expect(getCommandOutputSpy).toHaveBeenCalledWith(
'yarn --version',
'/tmp/dir3'
);
expect(getCommandOutputSpy).toHaveBeenCalledWith(
version.startsWith('1.')
? 'yarn cache dir'
: 'yarn config get cacheFolder',
'/tmp/dir1'
);
expect(getCommandOutputSpy).toHaveBeenCalledWith(
version.startsWith('1.')
? 'yarn cache dir'
: 'yarn config get cacheFolder',
'/tmp/dir2'
);
expect(getCommandOutputSpy).toHaveBeenCalledWith(
version.startsWith('1.')
? 'yarn cache dir'
: 'yarn config get cacheFolder',
'/tmp/dir3'
);
}
);
it.each(['1.1.1', '2.2.2'])(
'getCacheDirectoriesPaths yarn v%s should return 4 dirs with multiple globs',
async version => {
// simulate wrong indents
const cacheDependencyPath = `/tmp/dir1/file
/tmp/dir2/file
/tmp/**/file
`;
globCreateSpy.mockImplementation(
(pattern: string): Promise<Globber> =>
MockGlobber.create([
'/tmp/dir1/file',
'/tmp/dir2/file',
'/tmp/dir3/file',
'/tmp/dir4/file'
])
);
let dirNo = 1;
getCommandOutputSpy.mockImplementation((command: string) =>
command.includes('version') ? version : `file_${version}_${dirNo++}`
);
const dirs = await cacheUtils.getCacheDirectories(
supportedPackageManagers.yarn,
cacheDependencyPath
);
expect(dirs).toEqual([
`file_${version}_1`,
`file_${version}_2`,
`file_${version}_3`,
`file_${version}_4`
]);
}
);
});
});

View File

@ -1 +0,0 @@
node 14.0.0

View File

@ -1,5 +0,0 @@
{
"volta": {
"extends": "./package-volta.json"
}
}

View File

@ -1,8 +0,0 @@
{
"engines": {
"node": "^14.0.0"
},
"volta": {
"node": "16.0.0"
}
}

View File

@ -1,5 +1,8 @@
{
"engines": {
"node": "^14.0.0"
},
"volta": {
"node": "16.0.0"
}
}

View File

@ -2,7 +2,6 @@ import * as core from '@actions/core';
import * as exec from '@actions/exec';
import * as tc from '@actions/tool-cache';
import * as cache from '@actions/cache';
import * as io from '@actions/io';
import fs from 'fs';
import path from 'path';
@ -25,13 +24,11 @@ describe('main tests', () => {
let startGroupSpy: jest.SpyInstance;
let endGroupSpy: jest.SpyInstance;
let whichSpy: jest.SpyInstance;
let existsSpy: jest.SpyInstance;
let getExecOutputSpy: jest.SpyInstance;
let getNodeVersionFromFileSpy: jest.SpyInstance;
let parseNodeVersionSpy: jest.SpyInstance;
let cnSpy: jest.SpyInstance;
let findSpy: jest.SpyInstance;
let isCacheActionAvailable: jest.SpyInstance;
@ -44,7 +41,6 @@ describe('main tests', () => {
// node
os = {};
console.log('::stop-commands::stoptoken');
process.env['GITHUB_WORKSPACE'] = path.join(__dirname, 'data');
process.env['GITHUB_PATH'] = ''; // Stub out ENV file functionality so we can verify it writes to standard out
process.env['GITHUB_OUTPUT'] = ''; // Stub out ENV file functionality so we can verify it writes to standard out
infoSpy = jest.spyOn(core, 'info');
@ -60,18 +56,18 @@ describe('main tests', () => {
inSpy = jest.spyOn(core, 'getInput');
inSpy.mockImplementation(name => inputs[name]);
whichSpy = jest.spyOn(io, 'which');
getExecOutputSpy = jest.spyOn(exec, 'getExecOutput');
findSpy = jest.spyOn(tc, 'find');
isCacheActionAvailable = jest.spyOn(cache, 'isFeatureAvailable');
existsSpy = jest.spyOn(fs, 'existsSync');
cnSpy = jest.spyOn(process.stdout, 'write');
cnSpy.mockImplementation(line => {
// uncomment to debug
process.stderr.write('write:' + line + '\n');
// process.stderr.write('write:' + line + '\n');
});
setupNodeJsSpy = jest.spyOn(OfficialBuilds.prototype, 'setupNodeJs');
@ -89,7 +85,7 @@ describe('main tests', () => {
jest.restoreAllMocks();
}, 100000);
describe('getNodeVersionFromFile', () => {
describe('parseNodeVersionFile', () => {
each`
contents | expected
${'12'} | ${'12'}
@ -104,27 +100,9 @@ describe('main tests', () => {
${'unknown format'} | ${'unknown format'}
${' 14.1.0 '} | ${'14.1.0'}
${'{"volta": {"node": ">=14.0.0 <=17.0.0"}}'}| ${'>=14.0.0 <=17.0.0'}
${'{"volta": {"extends": "./package.json"}}'}| ${'18.0.0'}
${'{"engines": {"node": "17.0.0"}}'} | ${'17.0.0'}
${'{}'} | ${null}
`.it('parses "$contents"', ({contents, expected}) => {
const existsSpy = jest.spyOn(fs, 'existsSync');
existsSpy.mockImplementation(() => true);
const readFileSpy = jest.spyOn(fs, 'readFileSync');
readFileSpy.mockImplementation(filePath => {
if (
typeof filePath === 'string' &&
path.basename(filePath) === 'package.json'
) {
// Special case for volta.extends
return '{"volta": {"node": "18.0.0"}}';
}
return contents;
});
expect(util.getNodeVersionFromFile('file')).toBe(expected);
expect(util.parseNodeVersionFile(contents)).toBe(expected);
});
});
@ -147,10 +125,6 @@ describe('main tests', () => {
return {stdout: obj[command], stderr: '', exitCode: 0};
});
whichSpy.mockImplementation(cmd => {
return `some/${cmd}/path`;
});
await util.printEnvDetailsAndSetOutput();
expect(setOutputSpy).toHaveBeenCalledWith('node-version', obj['node']);
@ -167,17 +141,10 @@ describe('main tests', () => {
describe('node-version-file flag', () => {
beforeEach(() => {
delete inputs['node-version'];
inputs['node-version-file'] = '.nvmrc';
getNodeVersionFromFileSpy = jest.spyOn(util, 'getNodeVersionFromFile');
parseNodeVersionSpy = jest.spyOn(util, 'parseNodeVersionFile');
});
afterEach(() => {
getNodeVersionFromFileSpy.mockRestore();
});
it('does not read node-version-file if node-version is provided', async () => {
it('not used if node-version is provided', async () => {
// Arrange
inputs['node-version'] = '12';
@ -185,54 +152,107 @@ describe('main tests', () => {
await main.run();
// Assert
expect(inputs['node-version']).toBeDefined();
expect(inputs['node-version-file']).toBeDefined();
expect(getNodeVersionFromFileSpy).not.toHaveBeenCalled();
expect(parseNodeVersionSpy).toHaveBeenCalledTimes(0);
}, 10000);
it('not used if node-version-file not provided', async () => {
// Act
await main.run();
// Assert
expect(parseNodeVersionSpy).toHaveBeenCalledTimes(0);
});
it('reads node-version-file if provided', async () => {
// Arrange
const versionSpec = 'v14';
const versionFile = '.nvmrc';
const expectedVersionSpec = '14';
process.env['GITHUB_WORKSPACE'] = path.join(__dirname, 'data');
inputs['node-version-file'] = versionFile;
parseNodeVersionSpy.mockImplementation(() => expectedVersionSpec);
existsSpy.mockImplementationOnce(
input => input === path.join(__dirname, 'data', versionFile)
);
// Act
await main.run();
// Assert
expect(existsSpy).toHaveBeenCalledTimes(1);
expect(existsSpy).toHaveReturnedWith(true);
expect(parseNodeVersionSpy).toHaveBeenCalledWith(versionSpec);
expect(infoSpy).toHaveBeenCalledWith(
`Resolved ${versionFile} as ${expectedVersionSpec}`
);
}, 10000);
it('reads package.json as node-version-file if provided', async () => {
// Arrange
const versionSpec = fs.readFileSync(
path.join(__dirname, 'data/package.json'),
'utf-8'
);
const versionFile = 'package.json';
const expectedVersionSpec = '14';
process.env['GITHUB_WORKSPACE'] = path.join(__dirname, 'data');
inputs['node-version-file'] = versionFile;
parseNodeVersionSpy.mockImplementation(() => expectedVersionSpec);
existsSpy.mockImplementationOnce(
input => input === path.join(__dirname, 'data', versionFile)
);
// Act
await main.run();
// Assert
expect(existsSpy).toHaveBeenCalledTimes(1);
expect(existsSpy).toHaveReturnedWith(true);
expect(parseNodeVersionSpy).toHaveBeenCalledWith(versionSpec);
expect(infoSpy).toHaveBeenCalledWith(
`Resolved ${versionFile} as ${expectedVersionSpec}`
);
}, 10000);
it('both node-version-file and node-version are provided', async () => {
inputs['node-version'] = '12';
const versionSpec = 'v14';
const versionFile = '.nvmrc';
const expectedVersionSpec = '14';
process.env['GITHUB_WORKSPACE'] = path.join(__dirname, '..');
inputs['node-version-file'] = versionFile;
parseNodeVersionSpy.mockImplementation(() => expectedVersionSpec);
// Act
await main.run();
// Assert
expect(existsSpy).toHaveBeenCalledTimes(0);
expect(parseNodeVersionSpy).not.toHaveBeenCalled();
expect(warningSpy).toHaveBeenCalledWith(
'Both node-version and node-version-file inputs are specified, only node-version will be used'
);
});
it('does not read node-version-file if node-version-file is not provided', async () => {
// Arrange
delete inputs['node-version-file'];
it('should throw an error if node-version-file is not found', async () => {
const versionFile = '.nvmrc';
const versionFilePath = path.join(__dirname, '..', versionFile);
inputs['node-version-file'] = versionFile;
// Act
await main.run();
// Assert
expect(getNodeVersionFromFileSpy).not.toHaveBeenCalled();
});
it('reads node-version-file', async () => {
// Arrange
const expectedVersionSpec = '14';
getNodeVersionFromFileSpy.mockImplementation(() => expectedVersionSpec);
// Act
await main.run();
// Assert
expect(getNodeVersionFromFileSpy).toHaveBeenCalled();
expect(infoSpy).toHaveBeenCalledWith(
`Resolved ${inputs['node-version-file']} as ${expectedVersionSpec}`
);
}, 10000);
it('should throw an error if node-version-file is not accessible', async () => {
// Arrange
inputs['node-version-file'] = 'non-existing-file';
const versionFilePath = path.join(
__dirname,
'data',
inputs['node-version-file']
inSpy.mockImplementation(name => inputs[name]);
existsSpy.mockImplementationOnce(
input => input === path.join(__dirname, 'data', versionFile)
);
// Act
await main.run();
// Assert
expect(getNodeVersionFromFileSpy).toHaveBeenCalled();
expect(existsSpy).toHaveBeenCalled();
expect(existsSpy).toHaveReturnedWith(false);
expect(parseNodeVersionSpy).not.toHaveBeenCalled();
expect(cnSpy).toHaveBeenCalledWith(
`::error::The specified node version file at: ${versionFilePath} does not exist${osm.EOL}`
);

View File

@ -1,18 +0,0 @@
import {MockGlobber} from './glob-mock';
describe('mocked globber tests', () => {
it('globber should return generator', async () => {
const globber = new MockGlobber(['aaa', 'bbb', 'ccc']);
const generator = globber.globGenerator();
const result: string[] = [];
for await (const itemPath of generator) {
result.push(itemPath);
}
expect(result).toEqual(['aaa', 'bbb', 'ccc']);
});
it('globber should return glob', async () => {
const globber = new MockGlobber(['aaa', 'bbb', 'ccc']);
const result: string[] = await globber.glob();
expect(result).toEqual(['aaa', 'bbb', 'ccc']);
});
});

View File

@ -1,29 +0,0 @@
import {Globber} from '@actions/glob';
export class MockGlobber implements Globber {
private readonly expected: string[];
constructor(expected: string[]) {
this.expected = expected;
}
getSearchPaths(): string[] {
return this.expected.slice();
}
async glob(): Promise<string[]> {
const result: string[] = [];
for await (const itemPath of this.globGenerator()) {
result.push(itemPath);
}
return result;
}
async *globGenerator(): AsyncGenerator<string, void> {
for (const e of this.expected) {
yield e;
}
}
static async create(expected: string[]): Promise<MockGlobber> {
return new MockGlobber(expected);
}
}

View File

@ -95,8 +95,6 @@ describe('setup-node', () => {
res = <INodeVersion[]>nodeTestDistRc;
} else if (url.includes('/nightly')) {
res = <INodeVersion[]>nodeTestDistNightly;
} else if (url.includes('/v8-canary')) {
res = <INodeVersion[]>nodeV8CanaryTestDist;
} else {
res = <INodeVersion[]>nodeTestDist;
}

View File

@ -248,9 +248,6 @@ describe('setup-node', () => {
const toolPath = path.normalize('/cache/node/12.16.2/x64');
exSpy.mockImplementation(async () => '/some/other/temp/path');
cacheSpy.mockImplementation(async () => toolPath);
whichSpy.mockImplementation(cmd => {
return `some/${cmd}/path`;
});
await main.run();
@ -360,41 +357,6 @@ describe('setup-node', () => {
expect(cnSpy).toHaveBeenCalledWith(`::error::${errMsg}${osm.EOL}`);
});
it('reports when download failed but version exists', async () => {
os.platform = 'linux';
os.arch = 'x64';
// a version which is not in the manifest but is in node dist
const versionSpec = '11.15.0';
inputs['node-version'] = versionSpec;
inputs['always-auth'] = false;
inputs['token'] = 'faketoken';
// ... but not in the local cache
findSpy.mockImplementation(() => '');
dlSpy.mockImplementationOnce(async () => {
throw new tc.HTTPError(404);
});
await main.run();
expect(getManifestSpy).toHaveBeenCalled();
expect(logSpy).toHaveBeenCalledWith(
`Attempting to download ${versionSpec}...`
);
expect(logSpy).toHaveBeenCalledWith(
'Not found in manifest. Falling back to download directly from Node'
);
expect(dlSpy).toHaveBeenCalled();
expect(warningSpy).toHaveBeenCalledWith(
`Node version ${versionSpec} for platform ${os.platform} and architecture ${os.arch} was found but failed to download. ` +
'This usually happens when downloadable binaries are not fully updated at https://nodejs.org/. ' +
'To resolve this issue you may either fall back to the older version or try again later.'
);
});
it('acquires specified architecture of node', async () => {
for (const {arch, version, osSpec} of [
{arch: 'x86', version: '12.16.2', osSpec: 'win32'},

View File

@ -1,59 +0,0 @@
#!/bin/sh -e
export YARN_ENABLE_IMMUTABLE_INSTALLS=false
rm package.json
rm package-lock.json
echo "create yarn2 project in the sub2"
mkdir sub2
cd sub2
cat <<EOT >package.json
{
"name": "subproject",
"dependencies": {
"random": "^3.0.6",
"uuid": "^9.0.0"
}
}
EOT
yarn set version 2.4.3
yarn install
echo "create yarn3 project in the sub3"
cd ..
mkdir sub3
cd sub3
cat <<EOT >package.json
{
"name": "subproject",
"dependencies": {
"random": "^3.0.6",
"uuid": "^9.0.0"
}
}
EOT
yarn set version 3.5.1
yarn install
if [ x$1 = 'xglobal' ];then
echo enableGlobalCache
echo 'enableGlobalCache: true' >> .yarnrc.yml
fi
cd ..
if [ x$1 != 'xkeepcache' -a x$2 != 'xkeepcache' ]; then
rm -rf sub2/.yarn/cache
rm -rf sub3/.yarn/cache
fi
if [ x$1 = 'xyarn1' ];then
echo "create yarn1 project in the root"
cat <<EOT >package.json
{
"name": "subproject",
"dependencies": {
"random": "^3.0.6",
"uuid": "^9.0.0"
}
}
EOT
yarn set version 1.22.19
yarn install
fi

View File

@ -8,7 +8,7 @@ inputs:
node-version:
description: 'Version Spec of the version to use. Examples: 12.x, 10.15.1, >=10.15.0.'
node-version-file:
description: 'File containing the version Spec of the version to use. Examples: package.json, .nvmrc, .node-version, .tool-versions.'
description: 'File containing the version Spec of the version to use. Examples: .nvmrc, .node-version, .tool-versions.'
architecture:
description: 'Target architecture for Node to use. Examples: x86, x64. Will use system architecture by default.'
check-latest:
@ -27,7 +27,7 @@ inputs:
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.'
cache-invalidate-after-days:
description: 'Used to control how often the fallback cache is invalidated automatically.'
# TODO: add input to control forcing to pull from cloud or dist.
# 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:
@ -35,7 +35,7 @@ outputs:
node-version:
description: 'The installed node version.'
runs:
using: 'node20'
using: 'node16'
main: 'dist/setup/index.js'
post: 'dist/cache-save/index.js'
post-if: success()

41295
dist/cache-save/index.js vendored

File diff suppressed because one or more lines are too long

55738
dist/setup/index.js vendored

File diff suppressed because one or more lines are too long

View File

@ -45,8 +45,8 @@ If `check-latest` is set to `true`, the action first checks if the cached versio
```yaml
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '16'
check-latest: true
@ -63,8 +63,8 @@ See [supported version syntax](https://github.com/actions/setup-node#supported-v
```yaml
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version-file: '.nvmrc'
- run: npm ci
@ -84,8 +84,6 @@ When using the `package.json` input, the action will look for `volta.node` first
}
```
Otherwise, when [`volta.extends`](https://docs.volta.sh/advanced/workspaces) is defined, then it will resolve the corresponding file and look for `volta.node` or `engines.node` recursively.
## Architecture
You can use any of the [supported operating systems](https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners), and the compatible `architecture` can be selected using `architecture`. Values are `x86`, `x64`, `arm64`, `armv6l`, `armv7l`, `ppc64le`, `s390x` (not all of the architectures are available on all platforms).
@ -97,8 +95,8 @@ jobs:
runs-on: windows-latest
name: Node sample
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '14'
architecture: 'x64' # optional, x64 or x86. If not specified, x64 will be used by default
@ -118,8 +116,8 @@ jobs:
runs-on: ubuntu-latest
name: Node sample
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '20.0.0-v8-canary' # it will install the latest v8 canary release for node 20.0.0
- run: npm ci
@ -133,8 +131,8 @@ jobs:
runs-on: ubuntu-latest
name: Node sample
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '20-v8-canary' # it will install the latest v8 canary release for node 20
- run: npm ci
@ -149,8 +147,8 @@ jobs:
runs-on: ubuntu-latest
name: Node sample
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 'v20.1.1-v8-canary20221103f7e2421e91'
- run: npm ci
@ -169,8 +167,8 @@ jobs:
runs-on: ubuntu-latest
name: Node sample
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '16-nightly' # it will install the latest nightly release for node 16
- run: npm ci
@ -185,8 +183,8 @@ jobs:
runs-on: ubuntu-latest
name: Node sample
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '16.0.0-nightly' # it will install the latest nightly release for node 16.0.0
- run: npm ci
@ -201,8 +199,8 @@ jobs:
runs-on: ubuntu-latest
name: Node sample
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '16.0.0-nightly20210420a0261d231c'
- run: npm ci
@ -219,8 +217,8 @@ jobs:
runs-on: ubuntu-latest
name: Node sample
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '16.0.0-rc.1'
- run: npm ci
@ -236,8 +234,8 @@ The action follows [actions/cache](https://github.com/actions/cache/blob/main/ex
Yarn caching handles both yarn versions: 1 or 2.
```yaml
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '14'
cache: 'yarn'
@ -255,27 +253,23 @@ steps:
# NOTE: pnpm caching support requires pnpm version >= 6.10.0
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- uses: pnpm/action-setup@v2
with:
version: 6.32.9
- uses: actions/setup-node@v4
- uses: actions/setup-node@v3
with:
node-version: '14'
cache: 'pnpm'
- run: pnpm install
- run: pnpm install --frozen-lockfile
- 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).
> If the `pnpm-lock.yaml` file changes then pass `--frozen-lockfile` option.
**Using wildcard patterns to cache dependencies**
```yaml
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '14'
cache: 'npm'
@ -287,8 +281,8 @@ steps:
**Using a list of file paths to cache dependencies**
```yaml
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '14'
cache: 'npm'
@ -324,9 +318,9 @@ jobs:
architecture: x86
name: Node ${{ matrix.node_version }} - ${{ matrix.architecture }} on ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Setup node
uses: actions/setup-node@v4
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node_version }}
architecture: ${{ matrix.architecture }}
@ -337,8 +331,8 @@ jobs:
## Publish to npmjs and GPR with npm
```yaml
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '14.x'
registry-url: 'https://registry.npmjs.org'
@ -346,7 +340,7 @@ steps:
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- uses: actions/setup-node@v4
- uses: actions/setup-node@v3
with:
registry-url: 'https://npm.pkg.github.com'
- run: npm publish
@ -357,8 +351,8 @@ steps:
## Publish to npmjs and GPR with yarn
```yaml
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '14.x'
registry-url: <registry url>
@ -366,7 +360,7 @@ steps:
- run: yarn publish
env:
NODE_AUTH_TOKEN: ${{ secrets.YARN_TOKEN }}
- uses: actions/setup-node@v4
- uses: actions/setup-node@v3
with:
registry-url: 'https://npm.pkg.github.com'
- run: yarn publish
@ -377,8 +371,8 @@ steps:
## Use private packages
```yaml
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '14.x'
registry-url: 'https://registry.npmjs.org'
@ -397,8 +391,8 @@ Below you can find a sample "Setup .yarnrc.yml" step, that is going to allow you
```yaml
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '14.x'
- name: Setup .yarnrc.yml
@ -407,14 +401,11 @@ steps:
yarn config set npmScopes.my-org.npmAlwaysAuth true
yarn config set npmScopes.my-org.npmAuthToken $NPM_AUTH_TOKEN
env:
NPM_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_AUTH_TOKEN: ${{ secrets.YARN_TOKEN }}
- name: Install dependencies
run: yarn install --immutable
```
To access private GitHub Packages within the same organization, go to "Manage Actions access" in Package settings and set the repositories you want to access.
Please refer to the [Ensuring workflow access to your package - Configuring a package's access control and visibility](https://docs.github.com/en/packages/learn-github-packages/configuring-a-packages-access-control-and-visibility#ensuring-workflow-access-to-your-package) for more details.
NOTE: As per https://github.com/actions/setup-node/issues/49 you cannot use `secrets.GITHUB_TOKEN` to access private GitHub Packages within the same organisation but in a different repository.
### 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.

Some files were not shown because too many files have changed in this diff Show More