Compare commits

..

No commits in common. "main" and "v4.3.0" have entirely different histories.
main ... v4.3.0

83 changed files with 4670 additions and 9247 deletions

View File

@ -4,7 +4,7 @@
"owner": "eslint-compact", "owner": "eslint-compact",
"pattern": [ "pattern": [
{ {
"regexp": "^(.+):\\sline\\s(\\d+),\\scol\\s(\\d+),\\s([Ee]rror|[Ww]arning|[Ii]nfo)\\s-\\s(.+)\\s\\((.+)\\)$", "regexp": "^(.+):\\sline\\s(\\d+),\\scol\\s(\\d+),\\s(Error|Warning|Info)\\s-\\s(.+)\\s\\((.+)\\)$",
"file": 1, "file": 1,
"line": 2, "line": 2,
"column": 3, "column": 3,

View File

@ -4,7 +4,7 @@
"owner": "eslint-stylish", "owner": "eslint-stylish",
"pattern": [ "pattern": [
{ {
"regexp": "^\\s*([^\\s].*)$", "regexp": "^([^\\s].*)$",
"file": 1 "file": 1
}, },
{ {

View File

@ -16,4 +16,4 @@ jobs:
name: Basic validation name: Basic validation
uses: actions/reusable-workflows/.github/workflows/basic-validation.yml@main uses: actions/reusable-workflows/.github/workflows/basic-validation.yml@main
with: with:
node-version: '24.x' node-version: '20.x'

View File

@ -16,4 +16,4 @@ jobs:
name: Check dist/ name: Check dist/
uses: actions/reusable-workflows/.github/workflows/check-dist.yml@main uses: actions/reusable-workflows/.github/workflows/check-dist.yml@main
with: with:
node-version: '24.x' node-version: '20.x'

View File

@ -18,10 +18,10 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest, windows-latest, macos-latest, macos-latest-large] os: [ubuntu-latest, windows-latest, macos-latest, macos-13]
node-version: [20, 22, 24] node-version: [18, 20, 22]
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: Clean global cache - name: Clean global cache
run: npm cache clean --force run: npm cache clean --force
- name: Setup Node - name: Setup Node
@ -41,10 +41,10 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest, windows-latest, macos-latest, macos-latest-large] os: [ubuntu-latest, windows-latest, macos-latest, macos-13]
node-version: [20, 22, 24] node-version: [18, 20, 22]
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: Install pnpm - name: Install pnpm
uses: pnpm/action-setup@v4 uses: pnpm/action-setup@v4
with: with:
@ -74,14 +74,14 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest, windows-latest, macos-latest, macos-latest-large] os: [ubuntu-latest, windows-latest, macos-latest, macos-13]
node-version: [20, 22, 24] node-version: [18, 20]
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: Yarn version - name: Yarn version
run: yarn --version run: yarn --version
- name: Generate yarn file - name: Generate yarn file
run: yarn install --ignore-engines run: yarn install
- name: Remove dependencies - name: Remove dependencies
shell: pwsh shell: pwsh
run: Remove-Item node_modules -Force -Recurse run: Remove-Item node_modules -Force -Recurse
@ -106,10 +106,10 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest, windows-latest, macos-latest, macos-latest-large] os: [ubuntu-latest, windows-latest, macos-latest, macos-13]
node-version: [20, 22, 24] node-version: [18, 20, 22]
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: Update yarn - name: Update yarn
run: yarn set version 3.6.4 run: yarn set version 3.6.4
- name: Yarn version - name: Yarn version
@ -139,11 +139,11 @@ jobs:
name: Test yarn subprojects name: Test yarn subprojects
strategy: strategy:
matrix: matrix:
node-version: [20, 22, 24] node-version: [18, 20, 22]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: prepare sub-projects - name: prepare sub-projects
run: __tests__/prepare-yarn-subprojects.sh yarn1 run: __tests__/prepare-yarn-subprojects.sh yarn1
@ -166,11 +166,11 @@ jobs:
name: Test yarn subprojects all locally managed name: Test yarn subprojects all locally managed
strategy: strategy:
matrix: matrix:
node-version: [20, 22, 24] node-version: [18, 20, 22]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: prepare sub-projects - name: prepare sub-projects
run: __tests__/prepare-yarn-subprojects.sh keepcache keepcache run: __tests__/prepare-yarn-subprojects.sh keepcache keepcache
@ -193,11 +193,11 @@ jobs:
name: Test yarn subprojects some locally managed name: Test yarn subprojects some locally managed
strategy: strategy:
matrix: matrix:
node-version: [20, 22, 24] node-version: [18, 20, 22]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: prepare sub-projects - name: prepare sub-projects
run: __tests__/prepare-yarn-subprojects.sh global run: __tests__/prepare-yarn-subprojects.sh global
@ -220,11 +220,11 @@ jobs:
name: Test yarn subprojects managed by git name: Test yarn subprojects managed by git
strategy: strategy:
matrix: matrix:
node-version: [20, 22, 24] node-version: [18, 20, 22]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: prepare sub-projects - name: prepare sub-projects
run: /bin/bash __tests__/prepare-yarn-subprojects.sh keepcache run: /bin/bash __tests__/prepare-yarn-subprojects.sh keepcache
@ -243,62 +243,3 @@ jobs:
cache-dependency-path: | cache-dependency-path: |
sub2/*.lock sub2/*.lock
sub3/*.lock sub3/*.lock
node-npm-packageManager-auto-cache:
name: Test auto cache with top-level packageManager
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest, macos-latest-large]
node-version: [20, 22, 24]
steps:
- uses: actions/checkout@v6
- name: Create package.json with packageManager field
run: |
echo '{ "name": "test-project", "version": "1.0.0", "packageManager": "npm@8.0.0" }' > package.json
- name: Clean global cache
run: npm cache clean --force
- name: Setup Node with caching enabled
uses: ./
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies
run: npm install
- name: Verify node and npm
run: __tests__/verify-node.sh "${{ matrix.node-version }}"
shell: bash
node-npm-devEngines-auto-cache:
name: Test auto cache with devEngines.packageManager
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest, macos-latest-large]
node-version: [20, 22, 24]
steps:
- uses: actions/checkout@v6
- name: Create package.json with devEngines field
run: |
echo '{
"name": "test-project",
"version": "1.0.0",
"devEngines": {
"packageManager": {
"name": "npm",
"onFail": "error"
}
}
}' > package.json
- name: Clean global cache
run: npm cache clean --force
- name: Setup Node with caching enabled
uses: ./
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies
run: npm install
- name: Verify node and npm
run: __tests__/verify-node.sh "${{ matrix.node-version }}"
shell: bash

View File

@ -25,15 +25,15 @@ jobs:
env: env:
https_proxy: http://squid-proxy:3128 https_proxy: http://squid-proxy:3128
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: Clear tool cache - name: Clear tool cache
run: rm -rf $RUNNER_TOOL_CACHE/* run: rm -rf $RUNNER_TOOL_CACHE/*
- name: Setup node 24 - name: Setup node 14
uses: ./ uses: ./
with: with:
node-version: 24.x node-version: 14.x
- name: Verify node and npm - name: Verify node and npm
run: __tests__/verify-node.sh 24 run: __tests__/verify-node.sh 14
test-bypass-proxy: test-bypass-proxy:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -41,12 +41,12 @@ jobs:
https_proxy: http://no-such-proxy:3128 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 no_proxy: api.github.com,github.com,nodejs.org,registry.npmjs.org,*.s3.amazonaws.com,s3.amazonaws.com
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: Clear tool cache - name: Clear tool cache
run: rm -rf $RUNNER_TOOL_CACHE/* run: rm -rf $RUNNER_TOOL_CACHE/*
- name: Setup node 24 - name: Setup node 11
uses: ./ uses: ./
with: with:
node-version: 24 node-version: 11
- name: Verify node and npm - name: Verify node and npm
run: __tests__/verify-node.sh 24 run: __tests__/verify-node.sh 11

View File

@ -14,7 +14,7 @@ jobs:
steps: steps:
- name: Checking out - name: Checking out
uses: actions/checkout@v6 uses: actions/checkout@v4
- name: Publish - name: Publish
id: publish id: publish
uses: actions/publish-immutable-action@v0.0.4 uses: actions/publish-immutable-action@v0.0.4

View File

@ -22,7 +22,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Update the ${{ env.TAG_NAME }} tag - name: Update the ${{ env.TAG_NAME }} tag
uses: actions/publish-action@v0.4.0 uses: actions/publish-action@v0.3.0
with: with:
source-tag: ${{ env.TAG_NAME }} source-tag: ${{ env.TAG_NAME }}
slack-webhook: ${{ secrets.SLACK_WEBHOOK }} slack-webhook: ${{ secrets.SLACK_WEBHOOK }}

View File

@ -17,10 +17,10 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest, windows-latest, macos-latest, macos-latest-large] os: [ubuntu-latest, windows-latest, macos-latest, macos-13]
node-version: [20, 22, 24] node-version: [18, 20, 22]
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: Setup Node - name: Setup Node
uses: ./ uses: ./
with: with:
@ -34,10 +34,10 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest, windows-latest, macos-latest-large] os: [ubuntu-latest, windows-latest, macos-13]
node-version: [lts/dubnium, lts/erbium, lts/fermium, lts/*, lts/-1] node-version: [lts/dubnium, lts/erbium, lts/fermium, lts/*, lts/-1]
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: Setup Node - name: Setup Node
uses: ./ uses: ./
with: with:
@ -56,7 +56,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest, windows-latest, macos-latest, macos-latest-large] os: [ubuntu-latest, windows-latest, macos-latest, macos-13]
node-version: node-version:
[ [
'20-v8-canary', '20-v8-canary',
@ -64,7 +64,7 @@ jobs:
'20.0.0-v8-canary20221101e50e45c9f8' '20.0.0-v8-canary20221101e50e45c9f8'
] ]
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: Setup Node - name: Setup Node
uses: ./ uses: ./
with: with:
@ -81,10 +81,10 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest, windows-latest, macos-latest, macos-latest-large] os: [ubuntu-latest, windows-latest, macos-latest, macos-13]
node-version: [20-nightly, 25-nightly, 24.0.0-nightly] node-version: [20-nightly, 21-nightly, 18.0.0-nightly]
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: Setup Node - name: Setup Node
uses: ./ uses: ./
with: with:
@ -101,10 +101,10 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest, windows-latest, macos-latest, macos-latest-large] os: [ubuntu-latest, windows-latest, macos-latest, macos-13]
node-version: [20.0.0-rc.1, 22.14.0-rc.1, 24.0.0-rc.4] node-version: [20.0.0-rc.1, 18.0.0-rc.2, 19.0.0-rc.0]
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: Setup Node - name: Setup Node
uses: ./ uses: ./
with: with:
@ -121,10 +121,10 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest, windows-latest, macos-latest, macos-latest-large] os: [ubuntu-latest, windows-latest, macos-latest, macos-13]
node-version: [20.10.0, 22.0.0, 24.9.0] node-version: [18.20.0, 20.10.0, 22.0.0]
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: Setup Node - name: Setup Node
uses: ./ uses: ./
with: with:
@ -138,10 +138,10 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest, windows-latest, macos-latest, macos-latest-large] os: [ubuntu-latest, windows-latest, macos-latest, macos-13]
node-version: [20, 22, 24] node-version: [18, 20, 22]
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: Setup Node and check latest - name: Setup Node and check latest
uses: ./ uses: ./
with: with:
@ -156,57 +156,57 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest, windows-latest, macos-latest, macos-latest-large] os: [ubuntu-latest, windows-latest, macos-latest, macos-13]
node-version-file: node-version-file:
[.nvmrc, .tool-versions, .tool-versions-node, package.json] [.nvmrc, .tool-versions, .tool-versions-node, package.json]
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: Setup node from node version file - name: Setup node from node version file
uses: ./ uses: ./
with: with:
node-version-file: '__tests__/data/${{ matrix.node-version-file }}' node-version-file: '__tests__/data/${{ matrix.node-version-file }}'
- name: Verify node - name: Verify node
run: __tests__/verify-node.sh 24 run: __tests__/verify-node.sh 20
version-file-volta: version-file-volta:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest, windows-latest, macos-latest, macos-latest-large] os: [ubuntu-latest, windows-latest, macos-latest, macos-13]
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: Setup node from node version file - name: Setup node from node version file
uses: ./ uses: ./
with: with:
node-version-file: '__tests__/data/package-volta.json' node-version-file: '__tests__/data/package-volta.json'
- name: Verify node - name: Verify node
run: __tests__/verify-node.sh 24 run: __tests__/verify-node.sh 20
version-file-volta-extends: version-file-volta-extends:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest, windows-latest, macos-latest, macos-latest-large] os: [ubuntu-latest, windows-latest, macos-latest, macos-13]
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: Setup node from node version file - name: Setup node from node version file
uses: ./ uses: ./
with: with:
node-version-file: '__tests__/data/package-volta-extends.json' node-version-file: '__tests__/data/package-volta-extends.json'
- name: Verify node - name: Verify node
run: __tests__/verify-node.sh 24 run: __tests__/verify-node.sh 20
node-dist: node-dist:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest, windows-latest, macos-latest, macos-latest-large] os: [ubuntu-latest, windows-latest, macos-latest, macos-13]
node-version: [17, 19] node-version: [17, 19]
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: Setup Node from dist - name: Setup Node from dist
uses: ./ uses: ./
with: with:
@ -220,9 +220,9 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest, windows-latest, macos-latest-large] os: [ubuntu-latest, windows-latest, macos-13]
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
# test old versions which didn't have npm and layout different # test old versions which didn't have npm and layout different
- name: Setup node 0.12.18 from dist - name: Setup node 0.12.18 from dist
uses: ./ uses: ./
@ -235,7 +235,7 @@ jobs:
arch: arch:
runs-on: windows-latest runs-on: windows-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: Setup node 20 x86 from dist - name: Setup node 20 x86 from dist
uses: ./ uses: ./
with: with:
@ -250,7 +250,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest, windows-latest, macos-latest, macos-latest-large] os: [ubuntu-latest, windows-latest, macos-latest, macos-13]
node-version: [current, latest, node] node-version: [current, latest, node]
steps: steps:
- name: Get node version - name: Get node version
@ -259,7 +259,7 @@ jobs:
echo "LATEST_NODE_VERSION=$latestNodeVersion" >> $GITHUB_OUTPUT echo "LATEST_NODE_VERSION=$latestNodeVersion" >> $GITHUB_OUTPUT
id: version id: version
shell: bash shell: bash
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: Setup Node - name: Setup Node
uses: ./ uses: ./
with: 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.

BIN
.licenses/npm/@protobuf-ts/plugin.dep.yml generated Normal file

Binary file not shown.

BIN
.licenses/npm/@protobuf-ts/protoc.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.

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/typescript.dep.yml generated Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -12,29 +12,13 @@ This action provides the following functionality for GitHub Actions users:
- Registering problem matchers for error output - Registering problem matchers for error output
- Configuring authentication for GPR or npm - Configuring authentication for GPR or npm
## Breaking changes in V6
- Caching is now automatically enabled for npm projects when either the `devEngines.packageManager` field or the top-level `packageManager` field in `package.json` is set to `npm`. For other package managers, such as Yarn and pnpm, caching is disabled by default and must be configured manually using the `cache` input.
- The `always-auth` input has been removed, as it is deprecated and will no longer be supported in future npm releases. To ensure your workflows continue to run without warnings or errors, please remove any references to `always-auth` from your configuration.
## Breaking changes in V5
- Enabled caching by default with package manager detection if no cache input is provided.
> For workflows with elevated privileges or access to sensitive information, we recommend disabling automatic caching by setting `package-manager-cache: false` when caching is not needed for secure operation.
- Upgraded action from node20 to node24.
> Make sure your runner is on version v2.327.1 or later to ensure compatibility with this release. [See Release Notes](https://github.com/actions/runner/releases/tag/v2.327.1)
For more details, see the full release notes on the [releases page](https://github.com/actions/setup-node/releases/v5.0.0)
## Usage ## Usage
See [action.yml](action.yml) See [action.yml](action.yml)
<!-- start usage --> <!-- start usage -->
```yaml ```yaml
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
# Version Spec of the version to use in SemVer notation. # Version Spec of the version to use in SemVer notation.
# It also admits such aliases as lts/*, latest, nightly and canary builds # It also admits such aliases as lts/*, latest, nightly and canary builds
@ -73,11 +57,6 @@ See [action.yml](action.yml)
# Default: '' # Default: ''
cache: '' cache: ''
# Controls automatic caching for npm. By default, caching for npm is enabled if either the devEngines.packageManager field or the top-level packageManager field in package.json specifies npm and no explicit cache input is provided.
# To disable automatic caching for npm, set package-manager-cache to false.
# default: true
package-manager-cache: true
# Used to specify the path to a dependency file: package-lock.json, yarn.lock, etc. # 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. # 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. # Supports wildcards or a list of file names for caching multiple dependencies.
@ -94,20 +73,9 @@ See [action.yml](action.yml)
# Default: '' # Default: ''
scope: '' scope: ''
# Optional mirror to download binaries from. # Set always-auth option in npmrc file.
# Artifacts need to match the official Node.js
# Example:
# V8 Canaray Build: <mirror_url>/download/v8-canary
# RC Build: <mirror_url>/download/rc
# Official: Build <mirror_url>/dist
# Nightly build: <mirror_url>/download/nightly
# Default: '' # Default: ''
mirror: '' always-auth: ''
# Optional mirror token.
# The token will be used as a bearer token in the Authorization header
# Default: ''
mirror-token: ''
``` ```
<!-- end usage --> <!-- end usage -->
@ -115,10 +83,10 @@ See [action.yml](action.yml)
```yaml ```yaml
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
node-version: 24 node-version: 18
- run: npm ci - run: npm ci
- run: npm test - run: npm test
``` ```
@ -135,9 +103,9 @@ The `node-version` input supports the Semantic Versioning Specification, for mor
Examples: Examples:
- Major versions: `22`, `24` - Major versions: `18`, `20`
- More specific versions: `20.19`, `22.17.1` , `24.8.0` - More specific versions: `10.15`, `16.15.1` , `18.4.0`
- NVM LTS syntax: `lts/iron`, `lts/jod`, `lts/*`, `lts/-n` - NVM LTS syntax: `lts/erbium`, `lts/fermium`, `lts/*`, `lts/-n`
- Latest release: `*` or `latest`/`current`/`node` - 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/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.
@ -148,11 +116,11 @@ Since it will not be cached always, there is possibility of hitting rate limit w
### Checking in lockfiles ### Checking in lockfiles
It's **strongly recommended** to commit the lockfile of your package manager for security and performance reasons. For more information consult the "Working with lockfiles" section of the [Advanced usage](docs/advanced-usage.md#working-with-lockfiles) guide. It's **always** recommended to commit the lockfile of your package manager for security and performance reasons. For more information consult the "Working with lockfiles" section of the [Advanced usage](docs/advanced-usage.md#working-with-lockfiles) guide.
## Caching global packages data ## Caching global packages data
The action has a built-in functionality for caching and restoring dependencies. It uses [actions/cache](https://github.com/actions/cache) under the hood for caching global packages data but requires less configuration settings. Supported package managers are `npm`, `yarn`, `pnpm` (v6.10+). The `cache` input is optional. The action has a built-in functionality for caching and restoring dependencies. It uses [actions/cache](https://github.com/actions/cache) under the hood for caching global packages data but requires less configuration settings. Supported package managers are `npm`, `yarn`, `pnpm` (v6.10+). The `cache` input is optional, and caching is turned off by default.
The action defaults to search for the dependency file (`package-lock.json`, `npm-shrinkwrap.json` or `yarn.lock`) in the repository root, and uses its hash as a part of the cache key. Use `cache-dependency-path` for cases when multiple dependency files are used, or they are located in different subdirectories. The action defaults to search for the dependency file (`package-lock.json`, `npm-shrinkwrap.json` or `yarn.lock`) in the repository root, and uses its hash as a part of the cache key. Use `cache-dependency-path` for cases when multiple dependency files are used, or they are located in different subdirectories.
@ -164,10 +132,10 @@ See the examples of using cache for `yarn`/`pnpm` and `cache-dependency-path` in
```yaml ```yaml
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
node-version: 24 node-version: 20
cache: 'npm' cache: 'npm'
- run: npm ci - run: npm ci
- run: npm test - run: npm test
@ -177,30 +145,16 @@ steps:
```yaml ```yaml
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
node-version: 24 node-version: 20
cache: 'npm' cache: 'npm'
cache-dependency-path: subdir/package-lock.json cache-dependency-path: subdir/package-lock.json
- run: npm ci - run: npm ci
- run: npm test - run: npm test
``` ```
Caching for npm dependencies is automatically enabled when your `package.json` contains either `devEngines.packageManager` field or top-level `packageManager` field set to `npm`, and no explicit cache input is provided.
This behavior is controlled by the `package-manager-cache` input, which defaults to `true`. To turn off automatic caching, set `package-manager-cache` to `false`.
```yaml
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v6
with:
package-manager-cache: false
- run: npm ci
```
> If your `package.json` file does not include a `packageManager` field set to `npm`, caching will be disabled unless you explicitly enable it. For workflows with elevated privileges or access to sensitive information, we recommend disabling automatic caching for npm by setting `package-manager-cache: false` when caching is not required for secure operation.
## Matrix Testing ## Matrix Testing
```yaml ```yaml
@ -209,12 +163,12 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
node: [ 20, 22, 24 ] node: [ 14, 16, 18 ]
name: Node ${{ matrix.node }} sample name: Node ${{ matrix.node }} sample
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- name: Setup node - name: Setup node
uses: actions/setup-node@v6 uses: actions/setup-node@v4
with: with:
node-version: ${{ matrix.node }} node-version: ${{ matrix.node }}
- run: npm ci - run: npm ci
@ -228,10 +182,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: 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 ```yaml
uses: actions/setup-node@v6 uses: actions/setup-node@v4
with: with:
token: ${{ secrets.GH_DOTCOM_TOKEN }} token: ${{ secrets.GH_DOTCOM_TOKEN }}
node-version: 24 node-version: 20
``` ```
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. 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.
@ -249,7 +203,6 @@ 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 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) - [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) - [Using private packages](docs/advanced-usage.md#use-private-packages)
- [Using private mirror](docs/advanced-usage.md#use-private-mirror)
## Recommended permissions ## Recommended permissions

View File

@ -76,102 +76,115 @@ describe('authutil tests', () => {
} }
it('Sets up npmrc for npmjs', async () => { it('Sets up npmrc for npmjs', async () => {
await auth.configAuthentication('https://registry.npmjs.org/'); await auth.configAuthentication('https://registry.npmjs.org/', 'false');
expect(fs.statSync(rcFile)).toBeDefined(); expect(fs.statSync(rcFile)).toBeDefined();
const contents = fs.readFileSync(rcFile, {encoding: 'utf8'}); const contents = fs.readFileSync(rcFile, {encoding: 'utf8'});
const rc = readRcFile(rcFile); const rc = readRcFile(rcFile);
expect(rc['registry']).toBe('https://registry.npmjs.org/'); expect(rc['registry']).toBe('https://registry.npmjs.org/');
expect(rc['always-auth']).toBe('false');
}); });
it('Appends trailing slash to registry', async () => { it('Appends trailing slash to registry', async () => {
await auth.configAuthentication('https://registry.npmjs.org'); await auth.configAuthentication('https://registry.npmjs.org', 'false');
expect(fs.statSync(rcFile)).toBeDefined(); expect(fs.statSync(rcFile)).toBeDefined();
const rc = readRcFile(rcFile); const rc = readRcFile(rcFile);
expect(rc['registry']).toBe('https://registry.npmjs.org/'); expect(rc['registry']).toBe('https://registry.npmjs.org/');
expect(rc['always-auth']).toBe('false');
}); });
it('Configures scoped npm registries', async () => { it('Configures scoped npm registries', async () => {
process.env['INPUT_SCOPE'] = 'myScope'; process.env['INPUT_SCOPE'] = 'myScope';
await auth.configAuthentication('https://registry.npmjs.org'); await auth.configAuthentication('https://registry.npmjs.org', 'false');
expect(fs.statSync(rcFile)).toBeDefined(); expect(fs.statSync(rcFile)).toBeDefined();
const rc = readRcFile(rcFile); const rc = readRcFile(rcFile);
expect(rc['@myscope:registry']).toBe('https://registry.npmjs.org/'); expect(rc['@myscope:registry']).toBe('https://registry.npmjs.org/');
expect(rc['always-auth']).toBe('false');
}); });
it('Automatically configures GPR scope', async () => { it('Automatically configures GPR scope', async () => {
await auth.configAuthentication('npm.pkg.github.com'); await auth.configAuthentication('npm.pkg.github.com', 'false');
expect(fs.statSync(rcFile)).toBeDefined(); expect(fs.statSync(rcFile)).toBeDefined();
const rc = readRcFile(rcFile); const rc = readRcFile(rcFile);
expect(rc['@ownername:registry']).toBe('npm.pkg.github.com/'); expect(rc['@ownername:registry']).toBe('npm.pkg.github.com/');
expect(rc['always-auth']).toBe('false');
});
it('Sets up npmrc for always-auth true', async () => {
await auth.configAuthentication('https://registry.npmjs.org/', 'true');
expect(fs.statSync(rcFile)).toBeDefined();
const rc = readRcFile(rcFile);
expect(rc['registry']).toBe('https://registry.npmjs.org/');
expect(rc['always-auth']).toBe('true');
}); });
it('is already set the NODE_AUTH_TOKEN export it', async () => { it('is already set the NODE_AUTH_TOKEN export it', async () => {
process.env.NODE_AUTH_TOKEN = 'foobar'; process.env.NODE_AUTH_TOKEN = 'foobar';
await auth.configAuthentication('npm.pkg.github.com'); await auth.configAuthentication('npm.pkg.github.com', 'false');
expect(fs.statSync(rcFile)).toBeDefined(); expect(fs.statSync(rcFile)).toBeDefined();
const rc = readRcFile(rcFile); const rc = readRcFile(rcFile);
expect(rc['@ownername:registry']).toBe('npm.pkg.github.com/'); expect(rc['@ownername:registry']).toBe('npm.pkg.github.com/');
expect(rc['always-auth']).toBe('false');
expect(process.env.NODE_AUTH_TOKEN).toEqual('foobar'); expect(process.env.NODE_AUTH_TOKEN).toEqual('foobar');
}); });
it('configAuthentication should overwrite non-scoped with non-scoped', async () => { it('configAuthentication should overwrite non-scoped with non-scoped', async () => {
fs.writeFileSync(rcFile, 'registry=NNN'); fs.writeFileSync(rcFile, 'registry=NNN');
await auth.configAuthentication('https://registry.npmjs.org/'); await auth.configAuthentication('https://registry.npmjs.org/', 'true');
const contents = fs.readFileSync(rcFile, {encoding: 'utf8'}); const contents = fs.readFileSync(rcFile, {encoding: 'utf8'});
expect(contents).toBe( expect(contents).toBe(
`//registry.npmjs.org/:_authToken=\${NODE_AUTH_TOKEN}${os.EOL}registry=https://registry.npmjs.org/` `//registry.npmjs.org/:_authToken=\${NODE_AUTH_TOKEN}${os.EOL}registry=https://registry.npmjs.org/${os.EOL}always-auth=true`
); );
}); });
it('configAuthentication should overwrite only non-scoped', async () => { it('configAuthentication should overwrite only non-scoped', async () => {
fs.writeFileSync(rcFile, `registry=NNN${os.EOL}@myscope:registry=MMM`); fs.writeFileSync(rcFile, `registry=NNN${os.EOL}@myscope:registry=MMM`);
await auth.configAuthentication('https://registry.npmjs.org/'); await auth.configAuthentication('https://registry.npmjs.org/', 'true');
const contents = fs.readFileSync(rcFile, {encoding: 'utf8'}); const contents = fs.readFileSync(rcFile, {encoding: 'utf8'});
expect(contents).toBe( expect(contents).toBe(
`@myscope:registry=MMM${os.EOL}//registry.npmjs.org/:_authToken=\${NODE_AUTH_TOKEN}${os.EOL}registry=https://registry.npmjs.org/` `@myscope:registry=MMM${os.EOL}//registry.npmjs.org/:_authToken=\${NODE_AUTH_TOKEN}${os.EOL}registry=https://registry.npmjs.org/${os.EOL}always-auth=true`
); );
}); });
it('configAuthentication should add non-scoped to scoped', async () => { it('configAuthentication should add non-scoped to scoped', async () => {
fs.writeFileSync(rcFile, '@myscope:registry=NNN'); fs.writeFileSync(rcFile, '@myscope:registry=NNN');
await auth.configAuthentication('https://registry.npmjs.org/'); await auth.configAuthentication('https://registry.npmjs.org/', 'true');
const contents = fs.readFileSync(rcFile, {encoding: 'utf8'}); const contents = fs.readFileSync(rcFile, {encoding: 'utf8'});
expect(contents).toBe( expect(contents).toBe(
`@myscope:registry=NNN${os.EOL}//registry.npmjs.org/:_authToken=\${NODE_AUTH_TOKEN}${os.EOL}registry=https://registry.npmjs.org/` `@myscope:registry=NNN${os.EOL}//registry.npmjs.org/:_authToken=\${NODE_AUTH_TOKEN}${os.EOL}registry=https://registry.npmjs.org/${os.EOL}always-auth=true`
); );
}); });
it('configAuthentication should overwrite scoped with scoped', async () => { it('configAuthentication should overwrite scoped with scoped', async () => {
process.env['INPUT_SCOPE'] = 'myscope'; process.env['INPUT_SCOPE'] = 'myscope';
fs.writeFileSync(rcFile, `@myscope:registry=NNN`); fs.writeFileSync(rcFile, `@myscope:registry=NNN`);
await auth.configAuthentication('https://registry.npmjs.org/'); await auth.configAuthentication('https://registry.npmjs.org/', 'true');
const contents = fs.readFileSync(rcFile, {encoding: 'utf8'}); const contents = fs.readFileSync(rcFile, {encoding: 'utf8'});
expect(contents).toBe( expect(contents).toBe(
`//registry.npmjs.org/:_authToken=\${NODE_AUTH_TOKEN}${os.EOL}@myscope:registry=https://registry.npmjs.org/` `//registry.npmjs.org/:_authToken=\${NODE_AUTH_TOKEN}${os.EOL}@myscope:registry=https://registry.npmjs.org/${os.EOL}always-auth=true`
); );
}); });
it('configAuthentication should overwrite only scoped', async () => { it('configAuthentication should overwrite only scoped', async () => {
process.env['INPUT_SCOPE'] = 'myscope'; process.env['INPUT_SCOPE'] = 'myscope';
fs.writeFileSync(rcFile, `registry=NNN${os.EOL}@myscope:registry=MMM`); fs.writeFileSync(rcFile, `registry=NNN${os.EOL}@myscope:registry=MMM`);
await auth.configAuthentication('https://registry.npmjs.org/'); await auth.configAuthentication('https://registry.npmjs.org/', 'true');
const contents = fs.readFileSync(rcFile, {encoding: 'utf8'}); const contents = fs.readFileSync(rcFile, {encoding: 'utf8'});
expect(contents).toBe( expect(contents).toBe(
`registry=NNN${os.EOL}//registry.npmjs.org/:_authToken=\${NODE_AUTH_TOKEN}${os.EOL}@myscope:registry=https://registry.npmjs.org/` `registry=NNN${os.EOL}//registry.npmjs.org/:_authToken=\${NODE_AUTH_TOKEN}${os.EOL}@myscope:registry=https://registry.npmjs.org/${os.EOL}always-auth=true`
); );
}); });
it('configAuthentication should add scoped to non-scoped', async () => { it('configAuthentication should add scoped to non-scoped', async () => {
process.env['INPUT_SCOPE'] = 'myscope'; process.env['INPUT_SCOPE'] = 'myscope';
fs.writeFileSync(rcFile, `registry=MMM`); fs.writeFileSync(rcFile, `registry=MMM`);
await auth.configAuthentication('https://registry.npmjs.org/'); await auth.configAuthentication('https://registry.npmjs.org/', 'true');
const contents = fs.readFileSync(rcFile, {encoding: 'utf8'}); const contents = fs.readFileSync(rcFile, {encoding: 'utf8'});
expect(contents).toBe( expect(contents).toBe(
`registry=MMM${os.EOL}//registry.npmjs.org/:_authToken=\${NODE_AUTH_TOKEN}${os.EOL}@myscope:registry=https://registry.npmjs.org/` `registry=MMM${os.EOL}//registry.npmjs.org/:_authToken=\${NODE_AUTH_TOKEN}${os.EOL}@myscope:registry=https://registry.npmjs.org/${os.EOL}always-auth=true`
); );
}); });
@ -181,20 +194,20 @@ describe('authutil tests', () => {
rcFile, rcFile,
`@otherscope:registry=NNN${os.EOL}@myscope:registry=MMM` `@otherscope:registry=NNN${os.EOL}@myscope:registry=MMM`
); );
await auth.configAuthentication('https://registry.npmjs.org/'); await auth.configAuthentication('https://registry.npmjs.org/', 'true');
const contents = fs.readFileSync(rcFile, {encoding: 'utf8'}); const contents = fs.readFileSync(rcFile, {encoding: 'utf8'});
expect(contents).toBe( expect(contents).toBe(
`@otherscope:registry=NNN${os.EOL}//registry.npmjs.org/:_authToken=\${NODE_AUTH_TOKEN}${os.EOL}@myscope:registry=https://registry.npmjs.org/` `@otherscope:registry=NNN${os.EOL}//registry.npmjs.org/:_authToken=\${NODE_AUTH_TOKEN}${os.EOL}@myscope:registry=https://registry.npmjs.org/${os.EOL}always-auth=true`
); );
}); });
it('configAuthentication should add scoped to another scoped', async () => { it('configAuthentication should add scoped to another scoped', async () => {
process.env['INPUT_SCOPE'] = 'myscope'; process.env['INPUT_SCOPE'] = 'myscope';
fs.writeFileSync(rcFile, `@otherscope:registry=MMM`); fs.writeFileSync(rcFile, `@otherscope:registry=MMM`);
await auth.configAuthentication('https://registry.npmjs.org/'); await auth.configAuthentication('https://registry.npmjs.org/', 'true');
const contents = fs.readFileSync(rcFile, {encoding: 'utf8'}); const contents = fs.readFileSync(rcFile, {encoding: 'utf8'});
expect(contents).toBe( expect(contents).toBe(
`@otherscope:registry=MMM${os.EOL}//registry.npmjs.org/:_authToken=\${NODE_AUTH_TOKEN}${os.EOL}@myscope:registry=https://registry.npmjs.org/` `@otherscope:registry=MMM${os.EOL}//registry.npmjs.org/:_authToken=\${NODE_AUTH_TOKEN}${os.EOL}@myscope:registry=https://registry.npmjs.org/${os.EOL}always-auth=true`
); );
}); });
}); });

View File

@ -227,6 +227,7 @@ describe('setup-node', () => {
const versionSpec = '11.15.0'; const versionSpec = '11.15.0';
inputs['node-version'] = versionSpec; inputs['node-version'] = versionSpec;
inputs['always-auth'] = false;
inputs['token'] = 'faketoken'; inputs['token'] = 'faketoken';
// ... but not in the local cache // ... but not in the local cache
@ -282,6 +283,7 @@ describe('setup-node', () => {
const versionSpec = '19.0.0-v8-canary'; const versionSpec = '19.0.0-v8-canary';
inputs['node-version'] = versionSpec; inputs['node-version'] = versionSpec;
inputs['always-auth'] = false;
inputs['token'] = 'faketoken'; inputs['token'] = 'faketoken';
findSpy.mockImplementation(() => ''); findSpy.mockImplementation(() => '');
@ -322,6 +324,7 @@ describe('setup-node', () => {
inputs['node-version'] = version; inputs['node-version'] = version;
inputs['architecture'] = arch; inputs['architecture'] = arch;
inputs['always-auth'] = false;
inputs['token'] = 'faketoken'; inputs['token'] = 'faketoken';
const expectedUrl = `https://nodejs.org/download/v8-canary/v${version}/node-v${version}-${platform}-${arch}.${fileExtension}`; const expectedUrl = `https://nodejs.org/download/v8-canary/v${version}/node-v${version}-${platform}-${arch}.${fileExtension}`;
@ -495,70 +498,6 @@ describe('setup-node', () => {
); );
} }
); );
it.each([
[
'20.0.0-v8-canary',
'20.0.0-v8-canary20221103f7e2421e91',
'20.0.0-v8-canary20221030fefe1c0879',
'https://my_mirror.org/download/v8-canary/v20.0.0-v8-canary20221103f7e2421e91/node-v20.0.0-v8-canary20221103f7e2421e91-linux-x64.tar.gz'
],
[
'20-v8-canary',
'20.0.0-v8-canary20221103f7e2421e91',
'20.0.0-v8-canary20221030fefe1c0879',
'https://my_mirror.org/download/v8-canary/v20.0.0-v8-canary20221103f7e2421e91/node-v20.0.0-v8-canary20221103f7e2421e91-linux-x64.tar.gz'
],
[
'19.0.0-v8-canary',
'19.0.0-v8-canary202210187d6960f23f',
'19.0.0-v8-canary202210172ec229fc56',
'https://my_mirror.org/download/v8-canary/v19.0.0-v8-canary202210187d6960f23f/node-v19.0.0-v8-canary202210187d6960f23f-linux-x64.tar.gz'
],
[
'19-v8-canary',
'19.0.0-v8-canary202210187d6960f23f',
'19.0.0-v8-canary202210172ec229fc56',
'https://my_mirror.org/download/v8-canary/v19.0.0-v8-canary202210187d6960f23f/node-v19.0.0-v8-canary202210187d6960f23f-linux-x64.tar.gz'
]
])(
'get %s version from dist if check-latest is true',
async (input, expectedVersion, foundVersion, expectedUrl) => {
const foundToolPath = path.normalize(`/cache/node/${foundVersion}/x64`);
const toolPath = path.normalize(`/cache/node/${expectedVersion}/x64`);
inputs['node-version'] = input;
inputs['check-latest'] = 'true';
os['arch'] = 'x64';
os['platform'] = 'linux';
inputs['mirror'] = 'https://my_mirror.org';
inputs['mirror-token'] = 'faketoken';
findSpy.mockReturnValue(foundToolPath);
findAllVersionsSpy.mockReturnValue([
'20.0.0-v8-canary20221030fefe1c0879',
'19.0.0-v8-canary202210172ec229fc56',
'20.0.0-v8-canary2022102310ff1e5a8d'
]);
dlSpy.mockImplementation(async () => '/some/temp/path');
exSpy.mockImplementation(async () => '/some/other/temp/path');
cacheSpy.mockImplementation(async () => toolPath);
// act
await main.run();
// assert
expect(findAllVersionsSpy).toHaveBeenCalled();
expect(logSpy).toHaveBeenCalledWith(
`Acquiring ${expectedVersion} - ${os.arch} from ${expectedUrl}`
);
expect(logSpy).toHaveBeenCalledWith('Extracting ...');
expect(logSpy).toHaveBeenCalledWith('Adding to the cache ...');
expect(cnSpy).toHaveBeenCalledWith(
`::add-path::${path.join(toolPath, 'bin')}${osm.EOL}`
);
}
);
}); });
describe('setup-node v8 canary tests', () => { describe('setup-node v8 canary tests', () => {
@ -566,6 +505,7 @@ describe('setup-node', () => {
const versionSpec = 'v20-v8-canary'; const versionSpec = 'v20-v8-canary';
inputs['node-version'] = versionSpec; inputs['node-version'] = versionSpec;
inputs['always-auth'] = false;
inputs['token'] = 'faketoken'; inputs['token'] = 'faketoken';
os.platform = 'linux'; os.platform = 'linux';

View File

@ -1 +1 @@
v24 v20

View File

@ -1 +1 @@
nodejs 24.0.0 nodejs 20.0.0

View File

@ -1 +1 @@
node 24.0.0 node 20.0.0

View File

@ -3,6 +3,6 @@
"node": "^14.0.0" "node": "^14.0.0"
}, },
"volta": { "volta": {
"node": "24.0.0" "node": "20.0.0"
} }
} }

View File

@ -1,5 +1,5 @@
{ {
"engines": { "engines": {
"node": "^24.0.0" "node": "^20.0.0"
} }
} }

View File

@ -20,7 +20,6 @@ describe('main tests', () => {
let infoSpy: jest.SpyInstance; let infoSpy: jest.SpyInstance;
let warningSpy: jest.SpyInstance; let warningSpy: jest.SpyInstance;
let saveStateSpy: jest.SpyInstance;
let inSpy: jest.SpyInstance; let inSpy: jest.SpyInstance;
let setOutputSpy: jest.SpyInstance; let setOutputSpy: jest.SpyInstance;
let startGroupSpy: jest.SpyInstance; let startGroupSpy: jest.SpyInstance;
@ -54,8 +53,6 @@ describe('main tests', () => {
setOutputSpy.mockImplementation(() => {}); setOutputSpy.mockImplementation(() => {});
warningSpy = jest.spyOn(core, 'warning'); warningSpy = jest.spyOn(core, 'warning');
warningSpy.mockImplementation(() => {}); warningSpy.mockImplementation(() => {});
saveStateSpy = jest.spyOn(core, 'saveState');
saveStateSpy.mockImplementation(() => {});
startGroupSpy = jest.spyOn(core, 'startGroup'); startGroupSpy = jest.spyOn(core, 'startGroup');
startGroupSpy.mockImplementation(() => {}); startGroupSpy.mockImplementation(() => {});
endGroupSpy = jest.spyOn(core, 'endGroup'); endGroupSpy = jest.spyOn(core, 'endGroup');
@ -283,149 +280,4 @@ describe('main tests', () => {
); );
}); });
}); });
describe('cache feature tests', () => {
it('Should enable caching when packageManager is npm and cache input is not provided', async () => {
inputs['package-manager-cache'] = 'true';
inputs['cache'] = '';
isCacheActionAvailable.mockImplementation(() => true);
inSpy.mockImplementation(name => inputs[name]);
const readFileSpy = jest.spyOn(fs, 'readFileSync');
readFileSpy.mockImplementation(() =>
JSON.stringify({
packageManager: 'npm@10.8.2'
})
);
await main.run();
expect(saveStateSpy).toHaveBeenCalledWith(expect.anything(), 'npm');
});
it('Should enable caching when devEngines.packageManager.name is "npm" and cache input is not provided', async () => {
inputs['package-manager-cache'] = 'true';
inputs['cache'] = '';
isCacheActionAvailable.mockImplementation(() => true);
inSpy.mockImplementation(name => inputs[name]);
const readFileSpy = jest.spyOn(fs, 'readFileSync');
readFileSpy.mockImplementation(() =>
JSON.stringify({
devEngines: {
packageManager: {name: 'npm'}
}
})
);
await main.run();
expect(saveStateSpy).toHaveBeenCalledWith(expect.anything(), 'npm');
});
it('Should enable caching when devEngines.packageManager is array and one entry has name "npm"', async () => {
inputs['package-manager-cache'] = 'true';
inputs['cache'] = '';
isCacheActionAvailable.mockImplementation(() => true);
inSpy.mockImplementation(name => inputs[name]);
const readFileSpy = jest.spyOn(fs, 'readFileSync');
readFileSpy.mockImplementation(() =>
JSON.stringify({
devEngines: {
packageManager: [{name: 'pnpm'}, {name: 'npm'}]
}
})
);
await main.run();
expect(saveStateSpy).toHaveBeenCalledWith(expect.anything(), 'npm');
});
it('Should not enable caching if packageManager is "pnpm@8.0.0" and cache input is not provided', async () => {
inputs['package-manager-cache'] = 'true';
inputs['cache'] = '';
inSpy.mockImplementation(name => inputs[name]);
const readFileSpy = jest.spyOn(fs, 'readFileSync');
readFileSpy.mockImplementation(() =>
JSON.stringify({
packageManager: 'pnpm@8.0.0'
})
);
await main.run();
expect(saveStateSpy).not.toHaveBeenCalled();
});
it('Should not enable caching if devEngines.packageManager.name is "pnpm"', async () => {
inputs['package-manager-cache'] = 'true';
inputs['cache'] = '';
inSpy.mockImplementation(name => inputs[name]);
const readFileSpy = jest.spyOn(fs, 'readFileSync');
readFileSpy.mockImplementation(() =>
JSON.stringify({
devEngines: {
packageManager: {name: 'pnpm'}
}
})
);
await main.run();
expect(saveStateSpy).not.toHaveBeenCalled();
});
it('Should not enable caching if devEngines.packageManager is array without "npm"', async () => {
inputs['package-manager-cache'] = 'true';
inputs['cache'] = '';
inSpy.mockImplementation(name => inputs[name]);
const readFileSpy = jest.spyOn(fs, 'readFileSync');
readFileSpy.mockImplementation(() =>
JSON.stringify({
devEngines: {
packageManager: [{name: 'pnpm'}, {name: 'yarn'}]
}
})
);
await main.run();
expect(saveStateSpy).not.toHaveBeenCalled();
});
it('Should not enable caching if packageManager field is missing in package.json and cache input is not provided', async () => {
inputs['package-manager-cache'] = 'true';
inputs['cache'] = '';
inSpy.mockImplementation(name => inputs[name]);
const readFileSpy = jest.spyOn(fs, 'readFileSync');
readFileSpy.mockImplementation(() =>
JSON.stringify({
// packageManager field is not present
})
);
await main.run();
expect(saveStateSpy).not.toHaveBeenCalled();
});
it('Should skip caching when package-manager-cache is false', async () => {
inputs['package-manager-cache'] = 'false';
inputs['cache'] = '';
inSpy.mockImplementation(name => inputs[name]);
await main.run();
expect(saveStateSpy).not.toHaveBeenCalled();
});
it('Should enable caching with cache input explicitly provided', async () => {
inputs['package-manager-cache'] = 'true';
inputs['cache'] = 'npm';
inSpy.mockImplementation(name => inputs[name]);
isCacheActionAvailable.mockImplementation(() => true);
await main.run();
expect(saveStateSpy).toHaveBeenCalledWith(expect.anything(), 'npm');
});
});
}); });

View File

@ -255,6 +255,7 @@ describe('setup-node', () => {
const versionSpec = '13.13.1-nightly20200415947ddec091'; const versionSpec = '13.13.1-nightly20200415947ddec091';
inputs['node-version'] = versionSpec; inputs['node-version'] = versionSpec;
inputs['always-auth'] = false;
inputs['token'] = 'faketoken'; inputs['token'] = 'faketoken';
// ... but not in the local cache // ... but not in the local cache
@ -290,6 +291,7 @@ describe('setup-node', () => {
]; ];
inputs['node-version'] = versionSpec; inputs['node-version'] = versionSpec;
inputs['always-auth'] = false;
inputs['token'] = 'faketoken'; inputs['token'] = 'faketoken';
// ... but not in the local cache // ... but not in the local cache
@ -313,7 +315,7 @@ describe('setup-node', () => {
await main.run(); await main.run();
workingUrls.forEach(url => { workingUrls.forEach(url => {
expect(dlSpy).toHaveBeenCalledWith(url, undefined, undefined); expect(dlSpy).toHaveBeenCalledWith(url);
}); });
expect(cnSpy).toHaveBeenCalledWith(`::add-path::${toolPath}${osm.EOL}`); expect(cnSpy).toHaveBeenCalledWith(`::add-path::${toolPath}${osm.EOL}`);
}); });
@ -331,6 +333,7 @@ describe('setup-node', () => {
]; ];
inputs['node-version'] = versionSpec; inputs['node-version'] = versionSpec;
inputs['always-auth'] = false;
inputs['token'] = 'faketoken'; inputs['token'] = 'faketoken';
// ... but not in the local cache // ... but not in the local cache
@ -386,6 +389,7 @@ describe('setup-node', () => {
const versionSpec = '18.0.0-nightly202204180699150267'; const versionSpec = '18.0.0-nightly202204180699150267';
inputs['node-version'] = versionSpec; inputs['node-version'] = versionSpec;
inputs['always-auth'] = false;
inputs['token'] = 'faketoken'; inputs['token'] = 'faketoken';
findSpy.mockImplementation(() => ''); findSpy.mockImplementation(() => '');
@ -423,6 +427,7 @@ describe('setup-node', () => {
inputs['node-version'] = version; inputs['node-version'] = version;
inputs['architecture'] = arch; inputs['architecture'] = arch;
inputs['always-auth'] = false;
inputs['token'] = 'faketoken'; inputs['token'] = 'faketoken';
const expectedUrl = `https://nodejs.org/download/nightly/v${version}/node-v${version}-${platform}-${arch}.${fileExtension}`; const expectedUrl = `https://nodejs.org/download/nightly/v${version}/node-v${version}-${platform}-${arch}.${fileExtension}`;
@ -444,53 +449,6 @@ describe('setup-node', () => {
} }
}, 100000); }, 100000);
it('acquires specified architecture of node from mirror', async () => {
for (const {arch, version, osSpec} of [
{
arch: 'x86',
version: '18.0.0-nightly202110204cb3e06ed8',
osSpec: 'win32'
},
{
arch: 'x86',
version: '20.0.0-nightly2022101987cdf7d412',
osSpec: 'win32'
}
]) {
os.platform = osSpec;
os.arch = arch;
const fileExtension = os.platform === 'win32' ? '7z' : 'tar.gz';
const platform = {
linux: 'linux',
darwin: 'darwin',
win32: 'win'
}[os.platform];
inputs['node-version'] = version;
inputs['architecture'] = arch;
inputs['token'] = 'faketoken';
inputs['mirror'] = 'https://my-mirror.org';
inputs['mirror-token'] = 'my-mirror-token';
const expectedUrl = `https://my-mirror.org/download/nightly/v${version}/node-v${version}-${platform}-${arch}.${fileExtension}`;
// ... but not in the local cache
findSpy.mockImplementation(() => '');
findAllVersionsSpy.mockImplementation(() => []);
dlSpy.mockImplementation(async () => '/some/temp/path');
const toolPath = path.normalize(`/cache/node/${version}/${arch}`);
exSpy.mockImplementation(async () => '/some/other/temp/path');
cacheSpy.mockImplementation(async () => toolPath);
await main.run();
expect(dlSpy).toHaveBeenCalled();
expect(logSpy).toHaveBeenCalledWith(
`Acquiring ${version} - ${arch} from ${expectedUrl}`
);
}
}, 100000);
describe('nightly versions', () => { describe('nightly versions', () => {
it.each([ it.each([
[ [

View File

@ -235,6 +235,7 @@ describe('setup-node', () => {
const resolvedVersion = versionSpec; const resolvedVersion = versionSpec;
inputs['node-version'] = versionSpec; inputs['node-version'] = versionSpec;
inputs['always-auth'] = false;
inputs['token'] = 'faketoken'; inputs['token'] = 'faketoken';
const expectedUrl = const expectedUrl =
@ -281,42 +282,6 @@ describe('setup-node', () => {
expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`); expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`);
}); });
it('falls back to a version from node dist from mirror', 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';
const mirror = 'https://my_mirror_url';
inputs['node-version'] = versionSpec;
inputs['token'] = 'faketoken';
inputs['mirror'] = mirror;
inputs['mirror-token'] = 'faketoken';
// ... but not in the local cache
findSpy.mockImplementation(() => '');
dlSpy.mockImplementation(async () => '/some/temp/path');
const toolPath = path.normalize('/cache/node/11.15.0/x64');
exSpy.mockImplementation(async () => '/some/other/temp/path');
cacheSpy.mockImplementation(async () => toolPath);
await main.run();
const expPath = path.join(toolPath, 'bin');
expect(getManifestSpy).toHaveBeenCalled();
expect(logSpy).toHaveBeenCalledWith(
`Attempting to download ${versionSpec}...`
);
expect(logSpy).toHaveBeenCalledWith(
`Not found in manifest. Falling back to download directly from ${mirror}`
);
expect(dlSpy).toHaveBeenCalled();
expect(exSpy).toHaveBeenCalled();
expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${osm.EOL}`);
});
it('falls back to a version from node dist', async () => { it('falls back to a version from node dist', async () => {
os.platform = 'linux'; os.platform = 'linux';
os.arch = 'x64'; os.arch = 'x64';
@ -325,6 +290,7 @@ describe('setup-node', () => {
const versionSpec = '11.15.0'; const versionSpec = '11.15.0';
inputs['node-version'] = versionSpec; inputs['node-version'] = versionSpec;
inputs['always-auth'] = false;
inputs['token'] = 'faketoken'; inputs['token'] = 'faketoken';
// ... but not in the local cache // ... but not in the local cache
@ -382,6 +348,7 @@ describe('setup-node', () => {
const resolvedVersion = versionSpec; const resolvedVersion = versionSpec;
inputs['node-version'] = versionSpec; inputs['node-version'] = versionSpec;
inputs['always-auth'] = false;
inputs['token'] = 'faketoken'; inputs['token'] = 'faketoken';
findSpy.mockImplementation(() => ''); findSpy.mockImplementation(() => '');
@ -401,6 +368,7 @@ describe('setup-node', () => {
const versionSpec = '11.15.0'; const versionSpec = '11.15.0';
inputs['node-version'] = versionSpec; inputs['node-version'] = versionSpec;
inputs['always-auth'] = false;
inputs['token'] = 'faketoken'; inputs['token'] = 'faketoken';
// ... but not in the local cache // ... but not in the local cache
@ -443,6 +411,7 @@ describe('setup-node', () => {
inputs['node-version'] = version; inputs['node-version'] = version;
inputs['architecture'] = arch; inputs['architecture'] = arch;
inputs['always-auth'] = false;
inputs['token'] = 'faketoken'; inputs['token'] = 'faketoken';
const expectedUrl = const expectedUrl =
@ -554,6 +523,7 @@ describe('setup-node', () => {
inputs['node-version'] = versionSpec; inputs['node-version'] = versionSpec;
inputs['check-latest'] = 'true'; inputs['check-latest'] = 'true';
inputs['always-auth'] = false;
inputs['token'] = 'faketoken'; inputs['token'] = 'faketoken';
// ... but not in the local cache // ... but not in the local cache
@ -595,6 +565,7 @@ describe('setup-node', () => {
inputs['node-version'] = versionSpec; inputs['node-version'] = versionSpec;
inputs['check-latest'] = 'true'; inputs['check-latest'] = 'true';
inputs['always-auth'] = false;
inputs['token'] = 'faketoken'; inputs['token'] = 'faketoken';
// ... but not in the local cache // ... but not in the local cache
@ -857,45 +828,4 @@ describe('setup-node', () => {
} }
); );
}); });
it('acquires specified architecture of node from mirror', async () => {
for (const {arch, version, osSpec} of [
{arch: 'x86', version: '12.16.2', osSpec: 'win32'},
{arch: 'x86', version: '14.0.0', osSpec: 'win32'}
]) {
os.platform = osSpec;
os.arch = arch;
const fileExtension = os.platform === 'win32' ? '7z' : 'tar.gz';
const platform = {
linux: 'linux',
darwin: 'darwin',
win32: 'win'
}[os.platform];
inputs['node-version'] = version;
inputs['architecture'] = arch;
inputs['token'] = 'faketoken';
inputs['mirror'] = 'https://my_mirror_url';
inputs['mirror-token'] = 'faketoken';
const expectedUrl =
arch === 'x64'
? `https://github.com/actions/node-versions/releases/download/${version}/node-${version}-${platform}-${arch}.zip`
: `https://my_mirror_url/dist/v${version}/node-v${version}-${platform}-${arch}.${fileExtension}`;
// ... but not in the local cache
findSpy.mockImplementation(() => '');
dlSpy.mockImplementation(async () => '/some/temp/path');
const toolPath = path.normalize(`/cache/node/${version}/${arch}`);
exSpy.mockImplementation(async () => '/some/other/temp/path');
cacheSpy.mockImplementation(async () => toolPath);
await main.run();
expect(dlSpy).toHaveBeenCalled();
expect(logSpy).toHaveBeenCalledWith(
`Acquiring ${version} - ${arch} from ${expectedUrl}`
);
}
}, 100000);
}); });

View File

@ -194,6 +194,7 @@ describe('setup-node', () => {
const versionSpec = '13.0.0-rc.0'; const versionSpec = '13.0.0-rc.0';
inputs['node-version'] = versionSpec; inputs['node-version'] = versionSpec;
inputs['always-auth'] = false;
inputs['token'] = 'faketoken'; inputs['token'] = 'faketoken';
// ... but not in the local cache // ... but not in the local cache
@ -238,6 +239,7 @@ describe('setup-node', () => {
const versionSpec = '14.7.0-rc.1'; const versionSpec = '14.7.0-rc.1';
inputs['node-version'] = versionSpec; inputs['node-version'] = versionSpec;
inputs['always-auth'] = false;
inputs['token'] = 'faketoken'; inputs['token'] = 'faketoken';
findSpy.mockImplementation(() => ''); findSpy.mockImplementation(() => '');
@ -266,6 +268,7 @@ describe('setup-node', () => {
inputs['node-version'] = version; inputs['node-version'] = version;
inputs['architecture'] = arch; inputs['architecture'] = arch;
inputs['always-auth'] = false;
inputs['token'] = 'faketoken'; inputs['token'] = 'faketoken';
const expectedUrl = `https://nodejs.org/download/rc/v${version}/node-v${version}-${platform}-${arch}.${fileExtension}`; const expectedUrl = `https://nodejs.org/download/rc/v${version}/node-v${version}-${platform}-${arch}.${fileExtension}`;

View File

@ -7,13 +7,8 @@ fi
node_version="$(node --version)" node_version="$(node --version)"
echo "Found node version '$node_version'" echo "Found node version '$node_version'"
if [ -z "$(echo $node_version | grep --fixed-strings v$1)" ]; then
# Extract the major version from the node version (remove the 'v' prefix) echo "Unexpected version"
actual_major_version=$(echo $node_version | sed -E 's/^v([0-9]+)\..*/\1/')
expected_major_version=$(echo $1 | sed -E 's/^([0-9]+)\..*/\1/') # Extract major version from argument
if [ "$actual_major_version" != "$expected_major_version" ]; then
echo "Expected Node.js $expected_major_version.x.x but found $node_version"
exit 1 exit 1
fi fi

View File

@ -2,6 +2,9 @@ name: 'Setup Node.js environment'
description: 'Setup a Node.js environment by adding problem matchers and optionally downloading and adding it to the PATH.' description: 'Setup a Node.js environment by adding problem matchers and optionally downloading and adding it to the PATH.'
author: 'GitHub' author: 'GitHub'
inputs: inputs:
always-auth:
description: 'Set always-auth in npmrc.'
default: 'false'
node-version: node-version:
description: 'Version Spec of the version to use. Examples: 12.x, 10.15.1, >=10.15.0.' description: 'Version Spec of the version to use. Examples: 12.x, 10.15.1, >=10.15.0.'
node-version-file: node-version-file:
@ -20,15 +23,8 @@ inputs:
default: ${{ github.server_url == 'https://github.com' && github.token || '' }} default: ${{ github.server_url == 'https://github.com' && github.token || '' }}
cache: cache:
description: 'Used to specify a package manager for caching in the default directory. Supported values: npm, yarn, pnpm.' description: 'Used to specify a package manager for caching in the default directory. Supported values: npm, yarn, pnpm.'
package-manager-cache:
description: 'Set to false to disable automatic caching. By default, caching is enabled when either devEngines.packageManager or the top-level packageManager field in package.json specifies npm as the package manager.'
default: true
cache-dependency-path: 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.' 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.'
mirror:
description: 'Used to specify an alternative mirror to downlooad Node.js binaries from'
mirror-token:
description: 'The token used as Authorization header when fetching from the mirror'
# 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 # escape valve for someone having issues or needing the absolute latest which isn't cached yet
outputs: outputs:
@ -37,7 +33,7 @@ outputs:
node-version: node-version:
description: 'The installed node version.' description: 'The installed node version.'
runs: runs:
using: 'node24' using: 'node20'
main: 'dist/setup/index.js' main: 'dist/setup/index.js'
post: 'dist/cache-save/index.js' post: 'dist/cache-save/index.js'
post-if: success() post-if: success()

1610
dist/cache-save/index.js vendored

File diff suppressed because it is too large Load Diff

9982
dist/setup/index.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
## Working with lockfiles ## Working with lockfiles
Most supported package managers recommend that you **always** commit the lockfile, although implementations vary doing so generally provides the following benefits: All supported package managers recommend that you **always** commit the lockfile, although implementations vary doing so generally provides the following benefits:
- Enables faster installation for CI and production environments, due to being able to skip package resolution. - Enables faster installation for CI and production environments, due to being able to skip package resolution.
- Describes a single representation of a dependency tree such that teammates, deployments, and continuous integration are guaranteed to install exactly the same dependencies. - Describes a single representation of a dependency tree such that teammates, deployments, and continuous integration are guaranteed to install exactly the same dependencies.
@ -35,25 +35,6 @@ Ensure that `pnpm-lock.yaml` is always committed, when on CI pass `--frozen-lock
- [Working with Git - Lockfiles](https://pnpm.io/git#lockfiles) - [Working with Git - Lockfiles](https://pnpm.io/git#lockfiles)
- [Documentation of `--frozen-lockfile` option](https://pnpm.io/cli/install#--frozen-lockfile) - [Documentation of `--frozen-lockfile` option](https://pnpm.io/cli/install#--frozen-lockfile)
### Running without a lockfile
If you choose not to use a lockfile, you must ensure that **caching is disabled**. The `cache` feature relies on the lockfile to generate a unique key for the cache entry.
To run without a lockfile:
1. Do not set the `cache` input.
2. If your `package.json` contains a `packageManager` field set to npm (or devEngines.packageManager), automatic caching is enabled by default. Override this by setting `package-manager-cache: false`.
```yaml
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: '24'
package-manager-cache: false # Explicitly disable caching if you don't have a lockfile
- run: npm install
- run: npm test
```
## Check latest version ## Check latest version
The `check-latest` flag defaults to `false`. When set to `false`, 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/). Use the default or set `check-latest` to `false` if you prefer stability and if you want to ensure a specific version of Node.js is always used. The `check-latest` flag defaults to `false`. When set to `false`, 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/). Use the default or set `check-latest` to `false` if you prefer stability and if you want to ensure a specific version of Node.js is always used.
@ -64,10 +45,10 @@ If `check-latest` is set to `true`, the action first checks if the cached versio
```yaml ```yaml
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
node-version: '24' node-version: '16'
check-latest: true check-latest: true
- run: npm ci - run: npm ci
- run: npm test - run: npm test
@ -82,8 +63,8 @@ See [supported version syntax](https://github.com/actions/setup-node#supported-v
```yaml ```yaml
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
- run: npm ci - run: npm ci
@ -116,10 +97,10 @@ jobs:
runs-on: windows-latest runs-on: windows-latest
name: Node sample name: Node sample
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
node-version: '24' node-version: '14'
architecture: 'x64' # optional, x64 or x86. If not specified, x64 will be used by default architecture: 'x64' # optional, x64 or x86. If not specified, x64 will be used by default
- run: npm ci - run: npm ci
- run: npm test - run: npm test
@ -137,10 +118,10 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
name: Node sample name: Node sample
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
node-version: '24.0.0-v8-canary' # it will install the latest v8 canary release for node 24.0.0 node-version: '20.0.0-v8-canary' # it will install the latest v8 canary release for node 20.0.0
- run: npm ci - run: npm ci
- run: npm test - run: npm test
``` ```
@ -152,10 +133,10 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
name: Node sample name: Node sample
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
node-version: '24-v8-canary' # it will install the latest v8 canary release for node 24 node-version: '20-v8-canary' # it will install the latest v8 canary release for node 20
- run: npm ci - run: npm ci
- run: npm test - run: npm test
``` ```
@ -168,10 +149,10 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
name: Node sample name: Node sample
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
node-version: 'v24.0.0-v8-canary2025030537242e55ac' node-version: 'v20.1.1-v8-canary20221103f7e2421e91'
- run: npm ci - run: npm ci
- run: npm test - run: npm test
``` ```
@ -188,10 +169,10 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
name: Node sample name: Node sample
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
node-version: '24-nightly' # it will install the latest nightly release for node 24 node-version: '16-nightly' # it will install the latest nightly release for node 16
- run: npm ci - run: npm ci
- run: npm test - run: npm test
``` ```
@ -204,10 +185,10 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
name: Node sample name: Node sample
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
node-version: '24.0.0-nightly' # it will install the latest nightly release for node 24.0.0 node-version: '16.0.0-nightly' # it will install the latest nightly release for node 16.0.0
- run: npm ci - run: npm ci
- run: npm test - run: npm test
``` ```
@ -220,10 +201,10 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
name: Node sample name: Node sample
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
node-version: '24.0.0-nightly202505066102159fa1' node-version: '16.0.0-nightly20210420a0261d231c'
- run: npm ci - run: npm ci
- run: npm test - run: npm test
``` ```
@ -238,28 +219,27 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
name: Node sample name: Node sample
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
node-version: '24.0.0-rc.4' node-version: '16.0.0-rc.1'
- run: npm ci - run: npm ci
- run: npm test - run: npm test
``` ```
**Note:** Unlike nightly versions, which support version range specifiers, you must specify the exact version for a release candidate: `24.0.0-rc.4`. **Note:** Unlike nightly versions, which support version range specifiers, you must specify the exact version for a release candidate: `16.0.0-rc.1`.
## Caching packages data ## Caching packages data
The action follows [actions/cache](https://github.com/actions/cache/blob/main/examples.md#node---npm) guidelines, and caches global cache on the machine instead of `node_modules`, so cache can be reused between different Node.js versions. The action follows [actions/cache](https://github.com/actions/cache/blob/main/examples.md#node---npm) guidelines, and caches global cache on the machine instead of `node_modules`, so cache can be reused between different Node.js versions.
**Caching yarn dependencies:** **Caching yarn dependencies:**
Yarn caching handles both Yarn Classic (v1) and Yarn Berry (v2, v3, v4+). Yarn caching handles both yarn versions: 1 or 2.
```yaml ```yaml
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
node-version: '24' node-version: '14'
cache: 'yarn' cache: 'yarn'
- run: yarn install --frozen-lockfile # optional, --immutable - run: yarn install --frozen-lockfile # optional, --immutable
- run: yarn test - run: yarn test
@ -275,13 +255,13 @@ steps:
# NOTE: pnpm caching support requires pnpm version >= 6.10.0 # NOTE: pnpm caching support requires pnpm version >= 6.10.0
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: pnpm/action-setup@v4 - uses: pnpm/action-setup@v2
with: with:
version: 10 version: 6.32.9
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
node-version: '24' node-version: '14'
cache: 'pnpm' cache: 'pnpm'
- run: pnpm install - run: pnpm install
- run: pnpm test - run: pnpm test
@ -294,10 +274,10 @@ steps:
**Using wildcard patterns to cache dependencies** **Using wildcard patterns to cache dependencies**
```yaml ```yaml
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
node-version: '24' node-version: '14'
cache: 'npm' cache: 'npm'
cache-dependency-path: '**/package-lock.json' cache-dependency-path: '**/package-lock.json'
- run: npm ci - run: npm ci
@ -307,10 +287,10 @@ steps:
**Using a list of file paths to cache dependencies** **Using a list of file paths to cache dependencies**
```yaml ```yaml
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
node-version: '24' node-version: '14'
cache: 'npm' cache: 'npm'
cache-dependency-path: | cache-dependency-path: |
server/app/package-lock.json server/app/package-lock.json
@ -319,35 +299,6 @@ steps:
- run: npm test - run: npm test
``` ```
**Restore-Only Cache**
```yaml
## In some workflows, you may want to restore a cache without saving it. This can help reduce cache writes and storage usage in workflows that only need to read from cache
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
# Restore Node.js modules cache (restore-only)
- name: Restore Node modules cache
uses: actions/cache@v4
id: cache-node-modules
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
# Setup Node.js
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '24'
# Install dependencies
- run: npm install
```
> For more details related to cache scenarios, please refer [Node npm](https://github.com/actions/cache/blob/main/examples.md#node---npm).
## Multiple Operating Systems and Architectures ## Multiple Operating Systems and Architectures
```yaml ```yaml
@ -361,21 +312,21 @@ jobs:
- macos-latest - macos-latest
- windows-latest - windows-latest
node_version: node_version:
- 20 - 12
- 22 - 14
- 24 - 16
architecture: architecture:
- x64 - x64
# an extra windows-x86 run: # an extra windows-x86 run:
include: include:
- os: windows-latest - os: windows-2016
node_version: 24 node_version: 12
architecture: x86 architecture: x86
name: Node ${{ matrix.node_version }} - ${{ matrix.architecture }} on ${{ matrix.os }} name: Node ${{ matrix.node_version }} - ${{ matrix.architecture }} on ${{ matrix.os }}
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- name: Setup node - name: Setup node
uses: actions/setup-node@v6 uses: actions/setup-node@v4
with: with:
node-version: ${{ matrix.node_version }} node-version: ${{ matrix.node_version }}
architecture: ${{ matrix.architecture }} architecture: ${{ matrix.architecture }}
@ -386,16 +337,16 @@ jobs:
## Publish to npmjs and GPR with npm ## Publish to npmjs and GPR with npm
```yaml ```yaml
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
node-version: '24.x' node-version: '14.x'
registry-url: 'https://registry.npmjs.org' registry-url: 'https://registry.npmjs.org'
- run: npm ci - run: npm ci
- run: npm publish - run: npm publish
env: env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
registry-url: 'https://npm.pkg.github.com' registry-url: 'https://npm.pkg.github.com'
- run: npm publish - run: npm publish
@ -406,16 +357,16 @@ steps:
## Publish to npmjs and GPR with yarn ## Publish to npmjs and GPR with yarn
```yaml ```yaml
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
node-version: '24.x' node-version: '14.x'
registry-url: <registry url> registry-url: <registry url>
- run: yarn install --frozen-lockfile - run: yarn install --frozen-lockfile
- run: yarn publish - run: yarn publish
env: env:
NODE_AUTH_TOKEN: ${{ secrets.YARN_TOKEN }} NODE_AUTH_TOKEN: ${{ secrets.YARN_TOKEN }}
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
registry-url: 'https://npm.pkg.github.com' registry-url: 'https://npm.pkg.github.com'
- run: yarn publish - run: yarn publish
@ -426,10 +377,10 @@ steps:
## Use private packages ## Use private packages
```yaml ```yaml
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
node-version: '24.x' node-version: '14.x'
registry-url: 'https://registry.npmjs.org' registry-url: 'https://registry.npmjs.org'
# Skip post-install scripts here, as a malicious # Skip post-install scripts here, as a malicious
# script could steal NODE_AUTH_TOKEN. # script could steal NODE_AUTH_TOKEN.
@ -446,10 +397,10 @@ Below you can find a sample "Setup .yarnrc.yml" step, that is going to allow you
```yaml ```yaml
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions/setup-node@v6 - uses: actions/setup-node@v4
with: with:
node-version: '24.x' node-version: '14.x'
- name: Setup .yarnrc.yml - name: Setup .yarnrc.yml
run: | run: |
yarn config set npmScopes.my-org.npmRegistryServer "https://npm.pkg.github.com" yarn config set npmScopes.my-org.npmRegistryServer "https://npm.pkg.github.com"
@ -465,17 +416,5 @@ To access private GitHub Packages within the same organization, go to "Manage Ac
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. 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.
## Use private mirror ### 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.
It is possible to use a private mirror hosting Node.js binaries. This mirror must be a full mirror of the official Node.js distribution.
The mirror URL can be set using the `mirror` input.
It is possible to specify a token to authenticate with the mirror using the `mirror-token` input.
The token will be passed as a bearer token in the `Authorization` header.
```yaml
- uses: actions/setup-node@v6
with:
node-version: '24.x'
mirror: 'https://nodejs.org/dist'
mirror-token: 'your-mirror-token'
```

924
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,9 @@
{ {
"name": "setup-node", "name": "setup-node",
"version": "6.0.0", "version": "4.0.0",
"private": true, "private": true,
"description": "setup node action", "description": "setup node action",
"main": "lib/setup-node.js", "main": "lib/setup-node.js",
"engines": {
"node": ">=24.0.0"
},
"scripts": { "scripts": {
"build": "ncc build -o dist/setup src/setup-node.ts && ncc build -o dist/cache-save src/cache-save.ts", "build": "ncc build -o dist/setup src/setup-node.ts && ncc build -o dist/cache-save src/cache-save.ts",
"format": "prettier --no-error-on-unmatched-pattern --config ./.prettierrc.js --write \"**/*.{ts,yml,yaml}\"", "format": "prettier --no-error-on-unmatched-pattern --config ./.prettierrc.js --write \"**/*.{ts,yml,yaml}\"",
@ -28,20 +25,20 @@
"author": "GitHub", "author": "GitHub",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/cache": "^4.1.0", "@actions/cache": "^4.0.2",
"@actions/core": "^1.11.1", "@actions/core": "^1.11.1",
"@actions/exec": "^1.1.1", "@actions/exec": "^1.1.1",
"@actions/github": "^6.0.1", "@actions/github": "^5.1.1",
"@actions/glob": "^0.5.0", "@actions/glob": "^0.5.0",
"@actions/http-client": "^2.2.1", "@actions/http-client": "^2.2.1",
"@actions/io": "^1.0.2", "@actions/io": "^1.0.2",
"@actions/tool-cache": "^2.0.2", "@actions/tool-cache": "^2.0.2",
"semver": "^7.6.3", "semver": "^7.6.3",
"uuid": "^11.1.0" "uuid": "^9.0.1"
}, },
"devDependencies": { "devDependencies": {
"@types/jest": "^29.5.14", "@types/jest": "^29.5.14",
"@types/node": "^24.1.0", "@types/node": "^20.11.25",
"@types/semver": "^7.5.8", "@types/semver": "^7.5.8",
"@typescript-eslint/eslint-plugin": "^5.54.0", "@typescript-eslint/eslint-plugin": "^5.54.0",
"@typescript-eslint/parser": "^5.54.0", "@typescript-eslint/parser": "^5.54.0",
@ -53,8 +50,8 @@
"jest": "^29.7.0", "jest": "^29.7.0",
"jest-circus": "^29.7.0", "jest-circus": "^29.7.0",
"jest-each": "^29.7.0", "jest-each": "^29.7.0",
"prettier": "^3.6.2", "prettier": "^2.8.4",
"ts-jest": "^29.4.1", "ts-jest": "^29.1.2",
"typescript": "^5.4.2" "typescript": "^5.4.2"
} }
} }

View File

@ -4,7 +4,7 @@ import * as path from 'path';
import * as core from '@actions/core'; import * as core from '@actions/core';
import * as github from '@actions/github'; import * as github from '@actions/github';
export function configAuthentication(registryUrl: string) { export function configAuthentication(registryUrl: string, alwaysAuth: string) {
const npmrc: string = path.resolve( const npmrc: string = path.resolve(
process.env['RUNNER_TEMP'] || process.cwd(), process.env['RUNNER_TEMP'] || process.cwd(),
'.npmrc' '.npmrc'
@ -13,10 +13,14 @@ export function configAuthentication(registryUrl: string) {
registryUrl += '/'; registryUrl += '/';
} }
writeRegistryToFile(registryUrl, npmrc); writeRegistryToFile(registryUrl, npmrc, alwaysAuth);
} }
function writeRegistryToFile(registryUrl: string, fileLocation: string) { function writeRegistryToFile(
registryUrl: string,
fileLocation: string,
alwaysAuth: string
) {
let scope: string = core.getInput('scope'); let scope: string = core.getInput('scope');
if (!scope && registryUrl.indexOf('npm.pkg.github.com') > -1) { if (!scope && registryUrl.indexOf('npm.pkg.github.com') > -1) {
scope = github.context.repo.owner; scope = github.context.repo.owner;
@ -43,7 +47,8 @@ function writeRegistryToFile(registryUrl: string, fileLocation: string) {
const authString: string = const authString: string =
registryUrl.replace(/(^\w+:|^)/, '') + ':_authToken=${NODE_AUTH_TOKEN}'; registryUrl.replace(/(^\w+:|^)/, '') + ':_authToken=${NODE_AUTH_TOKEN}';
const registryString = `${scope}registry=${registryUrl}`; const registryString = `${scope}registry=${registryUrl}`;
newContents += `${authString}${os.EOL}${registryString}`; const alwaysAuthString = `always-auth=${alwaysAuth}`;
newContents += `${authString}${os.EOL}${registryString}${os.EOL}${alwaysAuthString}`;
fs.writeFileSync(fileLocation, newContents); fs.writeFileSync(fileLocation, newContents);
core.exportVariable('NPM_CONFIG_USERCONFIG', fileLocation); core.exportVariable('NPM_CONFIG_USERCONFIG', fileLocation);
// Export empty node_auth_token if didn't exist so npm doesn't complain about not being able to find it // Export empty node_auth_token if didn't exist so npm doesn't complain about not being able to find it

View File

@ -7,7 +7,6 @@ import {getPackageManagerInfo} from './cache-utils';
// Catch and log any unhandled exceptions. These exceptions can leak out of the uploadChunk method in // 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 // @actions/toolkit when a failed upload closes the file descriptor causing any in-process reads to
// throw an uncaught exception. Instead of failing this action, just warn. // throw an uncaught exception. Instead of failing this action, just warn.
process.on('uncaughtException', e => { process.on('uncaughtException', e => {
const warningPrefix = '[warning]'; const warningPrefix = '[warning]';
core.info(`${warningPrefix}${e.message}`); core.info(`${warningPrefix}${e.message}`);

View File

@ -167,12 +167,14 @@ const getCacheDirectoriesFromCacheDependencyPath = async (
packageManagerInfo: PackageManagerInfo, packageManagerInfo: PackageManagerInfo,
cacheDependencyPath: string cacheDependencyPath: string
): Promise<string[]> => { ): Promise<string[]> => {
const projectDirectories = const projectDirectories = await getProjectDirectoriesFromCacheDependencyPath(
await getProjectDirectoriesFromCacheDependencyPath(cacheDependencyPath); cacheDependencyPath
);
const cacheFoldersPaths = await Promise.all( const cacheFoldersPaths = await Promise.all(
projectDirectories.map(async projectDirectory => { projectDirectories.map(async projectDirectory => {
const cacheFolderPath = const cacheFolderPath = await packageManagerInfo.getCacheFolderPath(
await packageManagerInfo.getCacheFolderPath(projectDirectory); projectDirectory
);
core.debug( core.debug(
`${packageManagerInfo.name}'s cache folder "${cacheFolderPath}" configured for the directory "${projectDirectory}"` `${packageManagerInfo.name}'s cache folder "${cacheFolderPath}" configured for the directory "${projectDirectory}"`
); );

View File

@ -24,7 +24,7 @@ export default abstract class BaseDistribution {
}); });
} }
protected abstract getDistributionUrl(mirror: string): string; protected abstract getDistributionUrl(): string;
public async setupNodeJs() { public async setupNodeJs() {
let nodeJsVersions: INodeVersion[] | undefined; let nodeJsVersions: INodeVersion[] | undefined;
@ -97,19 +97,10 @@ export default abstract class BaseDistribution {
} }
protected async getNodeJsVersions(): Promise<INodeVersion[]> { protected async getNodeJsVersions(): Promise<INodeVersion[]> {
const initialUrl = this.getDistributionUrl(this.nodeInfo.mirror); const initialUrl = this.getDistributionUrl();
const dataUrl = `${initialUrl}/index.json`; const dataUrl = `${initialUrl}/index.json`;
const headers = {}; const response = await this.httpClient.getJson<INodeVersion[]>(dataUrl);
if (this.nodeInfo.mirrorToken) {
headers['Authorization'] = `Bearer ${this.nodeInfo.mirrorToken}`;
}
const response = await this.httpClient.getJson<INodeVersion[]>(
dataUrl,
headers
);
return response.result || []; return response.result || [];
} }
@ -126,7 +117,7 @@ export default abstract class BaseDistribution {
? `${fileName}.zip` ? `${fileName}.zip`
: `${fileName}.7z` : `${fileName}.7z`
: `${fileName}.tar.gz`; : `${fileName}.tar.gz`;
const initialUrl = this.getDistributionUrl(this.nodeInfo.mirror); const initialUrl = this.getDistributionUrl();
const url = `${initialUrl}/v${version}/${urlFileName}`; const url = `${initialUrl}/v${version}/${urlFileName}`;
return <INodeVersionInfo>{ return <INodeVersionInfo>{
@ -143,11 +134,7 @@ export default abstract class BaseDistribution {
`Acquiring ${info.resolvedVersion} - ${info.arch} from ${info.downloadUrl}` `Acquiring ${info.resolvedVersion} - ${info.arch} from ${info.downloadUrl}`
); );
try { try {
downloadPath = await tc.downloadTool( downloadPath = await tc.downloadTool(info.downloadUrl);
info.downloadUrl,
undefined,
this.nodeInfo.mirrorToken
);
} catch (err) { } catch (err) {
if ( if (
err instanceof tc.HTTPError && err instanceof tc.HTTPError &&
@ -181,7 +168,7 @@ export default abstract class BaseDistribution {
version: string, version: string,
arch: string = os.arch() arch: string = os.arch()
): Promise<string> { ): Promise<string> {
const initialUrl = this.getDistributionUrl(this.nodeInfo.mirror); const initialUrl = this.getDistributionUrl();
const osArch: string = this.translateArchToDistUrl(arch); const osArch: string = this.translateArchToDistUrl(arch);
// Create temporary folder to download to // Create temporary folder to download to
@ -198,34 +185,18 @@ export default abstract class BaseDistribution {
core.info(`Downloading only node binary from ${exeUrl}`); core.info(`Downloading only node binary from ${exeUrl}`);
const exePath = await tc.downloadTool( const exePath = await tc.downloadTool(exeUrl);
exeUrl,
undefined,
this.nodeInfo.mirrorToken
);
await io.cp(exePath, path.join(tempDir, 'node.exe')); await io.cp(exePath, path.join(tempDir, 'node.exe'));
const libPath = await tc.downloadTool( const libPath = await tc.downloadTool(libUrl);
libUrl,
undefined,
this.nodeInfo.mirrorToken
);
await io.cp(libPath, path.join(tempDir, 'node.lib')); await io.cp(libPath, path.join(tempDir, 'node.lib'));
} catch (err) { } catch (err) {
if (err instanceof tc.HTTPError && err.httpStatusCode == 404) { if (err instanceof tc.HTTPError && err.httpStatusCode == 404) {
exeUrl = `${initialUrl}/v${version}/node.exe`; exeUrl = `${initialUrl}/v${version}/node.exe`;
libUrl = `${initialUrl}/v${version}/node.lib`; libUrl = `${initialUrl}/v${version}/node.lib`;
const exePath = await tc.downloadTool( const exePath = await tc.downloadTool(exeUrl);
exeUrl,
undefined,
this.nodeInfo.mirrorToken
);
await io.cp(exePath, path.join(tempDir, 'node.exe')); await io.cp(exePath, path.join(tempDir, 'node.exe'));
const libPath = await tc.downloadTool( const libPath = await tc.downloadTool(libUrl);
libUrl,
undefined,
this.nodeInfo.mirrorToken
);
await io.cp(libPath, path.join(tempDir, 'node.lib')); await io.cp(libPath, path.join(tempDir, 'node.lib'));
} else { } else {
throw err; throw err;

View File

@ -4,8 +4,6 @@ export interface NodeInputs {
auth?: string; auth?: string;
checkLatest: boolean; checkLatest: boolean;
stable: boolean; stable: boolean;
mirror: string;
mirrorToken: string;
} }
export interface INodeVersionInfo { export interface INodeVersionInfo {

View File

@ -7,8 +7,7 @@ export default class NightlyNodejs extends BasePrereleaseNodejs {
super(nodeInfo); super(nodeInfo);
} }
protected getDistributionUrl(mirror: string): string { protected getDistributionUrl(): string {
const url = mirror || 'https://nodejs.org'; return 'https://nodejs.org/download/nightly';
return `${url}/download/nightly`;
} }
} }

View File

@ -84,7 +84,7 @@ export default class OfficialBuilds extends BaseDistribution {
downloadPath = await tc.downloadTool( downloadPath = await tc.downloadTool(
versionInfo.downloadUrl, versionInfo.downloadUrl,
undefined, undefined,
this.nodeInfo.mirror ? this.nodeInfo.mirrorToken : this.nodeInfo.auth this.nodeInfo.auth
); );
if (downloadPath) { if (downloadPath) {
@ -96,9 +96,7 @@ export default class OfficialBuilds extends BaseDistribution {
} }
} else { } else {
core.info( core.info(
`Not found in manifest. Falling back to download directly from ${ 'Not found in manifest. Falling back to download directly from Node'
this.nodeInfo.mirror || 'Node'
}`
); );
} }
} catch (err) { } catch (err) {
@ -178,9 +176,8 @@ export default class OfficialBuilds extends BaseDistribution {
return version; return version;
} }
protected getDistributionUrl(mirror: string): string { protected getDistributionUrl(): string {
const url = mirror || 'https://nodejs.org'; return `https://nodejs.org/dist`;
return `${url}/dist`;
} }
private getManifest(): Promise<tc.IToolRelease[]> { private getManifest(): Promise<tc.IToolRelease[]> {
@ -188,7 +185,7 @@ export default class OfficialBuilds extends BaseDistribution {
return tc.getManifestFromRepo( return tc.getManifestFromRepo(
'actions', 'actions',
'node-versions', 'node-versions',
this.nodeInfo.mirror ? this.nodeInfo.mirrorToken : this.nodeInfo.auth, this.nodeInfo.auth,
'main' 'main'
); );
} }

View File

@ -6,8 +6,7 @@ export default class RcBuild extends BaseDistribution {
super(nodeInfo); super(nodeInfo);
} }
getDistributionUrl(mirror: string): string { getDistributionUrl(): string {
const url = mirror || 'https://nodejs.org'; return 'https://nodejs.org/download/rc';
return `${url}/download/rc`;
} }
} }

View File

@ -7,8 +7,7 @@ export default class CanaryBuild extends BasePrereleaseNodejs {
super(nodeInfo); super(nodeInfo);
} }
protected getDistributionUrl(mirror: string): string { protected getDistributionUrl(): string {
const url = mirror || 'https://nodejs.org'; return 'https://nodejs.org/download/v8-canary';
return `${url}/download/v8-canary`;
} }
} }

View File

@ -1,7 +1,6 @@
import * as core from '@actions/core'; import * as core from '@actions/core';
import os from 'os'; import os from 'os';
import fs from 'fs';
import * as auth from './authutil'; import * as auth from './authutil';
import * as path from 'path'; import * as path from 'path';
@ -21,9 +20,6 @@ export async function run() {
let arch = core.getInput('architecture'); let arch = core.getInput('architecture');
const cache = core.getInput('cache'); const cache = core.getInput('cache');
const packagemanagercache =
(core.getInput('package-manager-cache') || 'true').toUpperCase() ===
'TRUE';
// if architecture supplied but node-version is not // if architecture supplied but node-version is not
// if we don't throw a warning, the already installed x64 node will be used which is not probably what user meant. // if we don't throw a warning, the already installed x64 node will be used which is not probably what user meant.
@ -40,8 +36,6 @@ export async function run() {
if (version) { if (version) {
const token = core.getInput('token'); const token = core.getInput('token');
const auth = !token ? undefined : `token ${token}`; const auth = !token ? undefined : `token ${token}`;
const mirror = core.getInput('mirror');
const mirrorToken = core.getInput('mirror-token');
const stable = const stable =
(core.getInput('stable') || 'true').toUpperCase() === 'TRUE'; (core.getInput('stable') || 'true').toUpperCase() === 'TRUE';
const checkLatest = const checkLatest =
@ -51,9 +45,7 @@ export async function run() {
checkLatest, checkLatest,
auth, auth,
stable, stable,
arch, arch
mirror,
mirrorToken
}; };
const nodeDistribution = getNodejsDistribution(nodejsInfo); const nodeDistribution = getNodejsDistribution(nodejsInfo);
await nodeDistribution.setupNodeJs(); await nodeDistribution.setupNodeJs();
@ -62,29 +54,15 @@ export async function run() {
await printEnvDetailsAndSetOutput(); await printEnvDetailsAndSetOutput();
const registryUrl: string = core.getInput('registry-url'); const registryUrl: string = core.getInput('registry-url');
const alwaysAuth: string = core.getInput('always-auth');
if (registryUrl) { if (registryUrl) {
auth.configAuthentication(registryUrl); auth.configAuthentication(registryUrl, alwaysAuth);
} }
const cacheDependencyPath = core.getInput('cache-dependency-path'); if (cache && isCacheFeatureAvailable()) {
if (isCacheFeatureAvailable()) {
// if the cache input is provided, use it for caching.
if (cache) {
core.saveState(State.CachePackageManager, cache); core.saveState(State.CachePackageManager, cache);
const cacheDependencyPath = core.getInput('cache-dependency-path');
await restoreCache(cache, cacheDependencyPath); await restoreCache(cache, cacheDependencyPath);
// package manager npm is detected from package.json, enable auto-caching for npm.
} else if (packagemanagercache) {
const resolvedPackageManager = getNameFromPackageManagerField();
if (resolvedPackageManager) {
core.info(
"Detected npm as the package manager from package.json's packageManager field. " +
'Auto caching has been enabled for npm. If you want to disable it, set package-manager-cache input to false'
);
core.saveState(State.CachePackageManager, resolvedPackageManager);
await restoreCache(resolvedPackageManager, cacheDependencyPath);
}
}
} }
const matchersPath = path.join(__dirname, '../..', '.github'); const matchersPath = path.join(__dirname, '../..', '.github');
@ -135,34 +113,3 @@ function resolveVersionInput(): string {
return version; return version;
} }
export function getNameFromPackageManagerField(): string | undefined {
const npmRegex = /^(\^)?npm(@.*)?$/; // matches "npm", "npm@...", "^npm@..."
try {
const packageJson = JSON.parse(
fs.readFileSync(
path.join(process.env.GITHUB_WORKSPACE!, 'package.json'),
'utf-8'
)
);
// Check devEngines.packageManager first (object or array)
const devPM = packageJson?.devEngines?.packageManager;
const devPMArray = devPM ? (Array.isArray(devPM) ? devPM : [devPM]) : [];
for (const obj of devPMArray) {
if (typeof obj?.name === 'string' && npmRegex.test(obj.name)) {
return 'npm';
}
}
// Check top-level packageManager
const topLevelPM = packageJson?.packageManager;
if (typeof topLevelPM === 'string' && npmRegex.test(topLevelPM)) {
return 'npm';
}
return undefined;
} catch {
return undefined;
}
}