From 951664acf3af2e591cb9d57da6bd0bb92259e105 Mon Sep 17 00:00:00 2001 From: Ferdinand Thiessen Date: Sun, 20 Apr 2025 13:12:45 +0200 Subject: [PATCH 1/5] feat(node-version-file): support parsing `devEngines` field Signed-off-by: Ferdinand Thiessen --- .github/workflows/versions.yml | 15 +++++++++++ __tests__/data/package-dev-engines.json | 11 +++++++++ __tests__/main.test.ts | 33 +++++++++++++------------ docs/advanced-usage.md | 32 +++++++++++++++++++++--- src/util.ts | 12 +++++++++ 5 files changed, 84 insertions(+), 19 deletions(-) create mode 100644 __tests__/data/package-dev-engines.json diff --git a/.github/workflows/versions.yml b/.github/workflows/versions.yml index 275c042ff..8b17ffa68 100644 --- a/.github/workflows/versions.yml +++ b/.github/workflows/versions.yml @@ -168,6 +168,21 @@ jobs: - name: Verify node run: __tests__/verify-node.sh 24 + version-file-dev-engines: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest, macos-13] + steps: + - uses: actions/checkout@v4 + - name: Setup node from node version file + uses: ./ + with: + node-version-file: '__tests__/data/package-dev-engines.json' + - name: Verify node + run: __tests__/verify-node.sh 20 + version-file-volta: runs-on: ${{ matrix.os }} strategy: diff --git a/__tests__/data/package-dev-engines.json b/__tests__/data/package-dev-engines.json new file mode 100644 index 000000000..bcbdbd2a3 --- /dev/null +++ b/__tests__/data/package-dev-engines.json @@ -0,0 +1,11 @@ +{ + "engines": { + "node": "^20 || ^22" + }, + "devEngines": { + "runtime": { + "name": "node", + "version": "^20" + } + } +} diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts index ba26e64bd..dbd50f440 100644 --- a/__tests__/main.test.ts +++ b/__tests__/main.test.ts @@ -94,22 +94,23 @@ describe('main tests', () => { describe('getNodeVersionFromFile', () => { each` - contents | expected - ${'12'} | ${'12'} - ${'12.3'} | ${'12.3'} - ${'12.3.4'} | ${'12.3.4'} - ${'v12.3.4'} | ${'12.3.4'} - ${'lts/erbium'} | ${'lts/erbium'} - ${'lts/*'} | ${'lts/*'} - ${'nodejs 12.3.4'} | ${'12.3.4'} - ${'ruby 2.3.4\nnodejs 12.3.4\npython 3.4.5'} | ${'12.3.4'} - ${''} | ${''} - ${'unknown format'} | ${'unknown format'} - ${' 14.1.0 '} | ${'14.1.0'} - ${'{"volta": {"node": ">=14.0.0 <=17.0.0"}}'}| ${'>=14.0.0 <=17.0.0'} - ${'{"volta": {"extends": "./package.json"}}'}| ${'18.0.0'} - ${'{"engines": {"node": "17.0.0"}}'} | ${'17.0.0'} - ${'{}'} | ${null} + contents | expected + ${'12'} | ${'12'} + ${'12.3'} | ${'12.3'} + ${'12.3.4'} | ${'12.3.4'} + ${'v12.3.4'} | ${'12.3.4'} + ${'lts/erbium'} | ${'lts/erbium'} + ${'lts/*'} | ${'lts/*'} + ${'nodejs 12.3.4'} | ${'12.3.4'} + ${'ruby 2.3.4\nnodejs 12.3.4\npython 3.4.5'} | ${'12.3.4'} + ${''} | ${''} + ${'unknown format'} | ${'unknown format'} + ${' 14.1.0 '} | ${'14.1.0'} + ${'{"volta": {"node": ">=14.0.0 <=17.0.0"}}'} | ${'>=14.0.0 <=17.0.0'} + ${'{"volta": {"extends": "./package.json"}}'} | ${'18.0.0'} + ${'{"engines": {"node": "17.0.0"}}'} | ${'17.0.0'} + ${'{"devEngines": {"runtime": {"name": "node", "version": "22.0.0"}}}'} | ${'22.0.0'} + ${'{}'} | ${null} `.it('parses "$contents"', ({contents, expected}) => { const existsSpy = jest.spyOn(fs, 'existsSync'); existsSpy.mockImplementation(() => true); diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md index c42bbf7f7..432dbf209 100644 --- a/docs/advanced-usage.md +++ b/docs/advanced-usage.md @@ -90,7 +90,35 @@ steps: - run: npm test ``` -When using the `package.json` input, the action will look for `volta.node` first. If `volta.node` isn't defined, then it will look for `engines.node`. +When using the `package.json` input, the action will look in the following fields for a specified Node version: +1. It checks `volta.node` first. +2. Then it checks `devEngines.runtime`. +3. Then it will look for `engines.node`. +4. Otherwise it tries to resolve the file defined by [`volta.extends`](https://docs.volta.sh/advanced/workspaces) + and look for `volta.node`, `devEngines.runtime`, or `engines.node` recursively. + +### Example with `devEngines` + +When a runtime engine (`engines.node`) is defined but also a development engine (`devEngines.runtime`) then the `devEngines.runtime` version is used. +This example will install a Node version based on the `^20.10` pattern. + +```json +{ + "engines": { + "node": "^20 || ^22" + }, + "devEngines": { + "runtime": { + "name": "node", + "version": "^20.10" + } + } +} +``` + +### Example with volta pinned Node version + +When both `engines.node` and `volta.node` is defined the value in `volta.node` is used. ```json { @@ -103,8 +131,6 @@ When using the `package.json` input, the action will look for `volta.node` first } ``` -Otherwise, when [`volta.extends`](https://docs.volta.sh/advanced/workspaces) is defined, then it will resolve the corresponding file and look for `volta.node` or `engines.node` recursively. - ## Architecture You can use any of the [supported operating systems](https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners), and the compatible `architecture` can be selected using `architecture`. Values are `x86`, `x64`, `arm64`, `armv6l`, `armv7l`, `ppc64le`, `s390x` (not all of the architectures are available on all platforms). diff --git a/src/util.ts b/src/util.ts index bbe25ddf0..dd34f7e5f 100644 --- a/src/util.ts +++ b/src/util.ts @@ -26,6 +26,18 @@ export function getNodeVersionFromFile(versionFilePath: string): string | null { return manifest.volta.node; } + // support devEngines from npm 11 + if (manifest.devEngines?.runtime) { + // find an entry with name set to node and having set a version. + // the devEngines.runtime can either be an object or an array of objects + const nodeEntry = [manifest.devEngines.runtime] + .flat() + .find(({name, version}) => name?.toLowerCase() === 'node' && version); + if (nodeEntry) { + return nodeEntry.version; + } + } + if (manifest.engines?.node) { return manifest.engines.node; } From 90a8072ea6e6f0681988ab120a7105c0923547f5 Mon Sep 17 00:00:00 2001 From: Ferdinand Thiessen Date: Sat, 21 Jun 2025 14:51:59 +0200 Subject: [PATCH 2/5] test: adjust for array like `devEngines` Co-authored-by: Grigory Signed-off-by: Ferdinand Thiessen --- .github/workflows/versions.yml | 15 ++++++++ __tests__/data/package-dev-engines-array.json | 17 +++++++++ __tests__/data/package-dev-engines.json | 2 +- __tests__/main.test.ts | 35 ++++++++++--------- docs/advanced-usage.md | 2 +- 5 files changed, 52 insertions(+), 19 deletions(-) create mode 100644 __tests__/data/package-dev-engines-array.json diff --git a/.github/workflows/versions.yml b/.github/workflows/versions.yml index 8b17ffa68..d941a7d0d 100644 --- a/.github/workflows/versions.yml +++ b/.github/workflows/versions.yml @@ -183,6 +183,21 @@ jobs: - name: Verify node run: __tests__/verify-node.sh 20 + version-file-dev-engines-array: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest, macos-13] + steps: + - uses: actions/checkout@v4 + - name: Setup node from node version file + uses: ./ + with: + node-version-file: '__tests__/data/package-dev-engines-array.json' + - name: Verify node + run: __tests__/verify-node.sh 20 + version-file-volta: runs-on: ${{ matrix.os }} strategy: diff --git a/__tests__/data/package-dev-engines-array.json b/__tests__/data/package-dev-engines-array.json new file mode 100644 index 000000000..a487e016a --- /dev/null +++ b/__tests__/data/package-dev-engines-array.json @@ -0,0 +1,17 @@ +{ + "engines": { + "node": "^19" + }, + "devEngines": { + "runtime": [ + { + "name": "bun", + "version": "^1" + }, + { + "name": "node", + "version": "^20" + } + ] + } +} diff --git a/__tests__/data/package-dev-engines.json b/__tests__/data/package-dev-engines.json index bcbdbd2a3..fd4bb55f1 100644 --- a/__tests__/data/package-dev-engines.json +++ b/__tests__/data/package-dev-engines.json @@ -1,6 +1,6 @@ { "engines": { - "node": "^20 || ^22" + "node": "^19" }, "devEngines": { "runtime": { diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts index dbd50f440..4d7a79a01 100644 --- a/__tests__/main.test.ts +++ b/__tests__/main.test.ts @@ -94,23 +94,24 @@ describe('main tests', () => { describe('getNodeVersionFromFile', () => { each` - contents | expected - ${'12'} | ${'12'} - ${'12.3'} | ${'12.3'} - ${'12.3.4'} | ${'12.3.4'} - ${'v12.3.4'} | ${'12.3.4'} - ${'lts/erbium'} | ${'lts/erbium'} - ${'lts/*'} | ${'lts/*'} - ${'nodejs 12.3.4'} | ${'12.3.4'} - ${'ruby 2.3.4\nnodejs 12.3.4\npython 3.4.5'} | ${'12.3.4'} - ${''} | ${''} - ${'unknown format'} | ${'unknown format'} - ${' 14.1.0 '} | ${'14.1.0'} - ${'{"volta": {"node": ">=14.0.0 <=17.0.0"}}'} | ${'>=14.0.0 <=17.0.0'} - ${'{"volta": {"extends": "./package.json"}}'} | ${'18.0.0'} - ${'{"engines": {"node": "17.0.0"}}'} | ${'17.0.0'} - ${'{"devEngines": {"runtime": {"name": "node", "version": "22.0.0"}}}'} | ${'22.0.0'} - ${'{}'} | ${null} + contents | expected + ${'12'} | ${'12'} + ${'12.3'} | ${'12.3'} + ${'12.3.4'} | ${'12.3.4'} + ${'v12.3.4'} | ${'12.3.4'} + ${'lts/erbium'} | ${'lts/erbium'} + ${'lts/*'} | ${'lts/*'} + ${'nodejs 12.3.4'} | ${'12.3.4'} + ${'ruby 2.3.4\nnodejs 12.3.4\npython 3.4.5'} | ${'12.3.4'} + ${''} | ${''} + ${'unknown format'} | ${'unknown format'} + ${' 14.1.0 '} | ${'14.1.0'} + ${'{}'} | ${null} + ${'{"volta": {"node": ">=14.0.0 <=17.0.0"}}'} | ${'>=14.0.0 <=17.0.0'} + ${'{"volta": {"extends": "./package.json"}}'} | ${'18.0.0'} + ${'{"engines": {"node": "17.0.0"}}'} | ${'17.0.0'} + ${'{"devEngines": {"runtime": {"name": "node", "version": "22.0.0"}}}'} | ${'22.0.0'} + ${'{"devEngines": {"runtime": [{"name": "bun"}, {"name": "node", "version": "22.0.0"}]}}'} | ${'22.0.0'} `.it('parses "$contents"', ({contents, expected}) => { const existsSpy = jest.spyOn(fs, 'existsSync'); existsSpy.mockImplementation(() => true); diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md index 432dbf209..4c4189b06 100644 --- a/docs/advanced-usage.md +++ b/docs/advanced-usage.md @@ -105,7 +105,7 @@ This example will install a Node version based on the `^20.10` pattern. ```json { "engines": { - "node": "^20 || ^22" + "node": "^19" }, "devEngines": { "runtime": { From 2245dabcd061988dbe53ea82ebe855dbaaace294 Mon Sep 17 00:00:00 2001 From: Ferdinand Thiessen Date: Tue, 17 Feb 2026 18:29:37 +0100 Subject: [PATCH 3/5] ci(versions.yml): update actions and reduce duplicated tests Signed-off-by: Ferdinand Thiessen --- .github/workflows/versions.yml | 47 ++++++++++++---------------------- 1 file changed, 16 insertions(+), 31 deletions(-) diff --git a/.github/workflows/versions.yml b/.github/workflows/versions.yml index d941a7d0d..d3b125118 100644 --- a/.github/workflows/versions.yml +++ b/.github/workflows/versions.yml @@ -20,7 +20,7 @@ jobs: os: [ubuntu-latest, windows-latest, macos-latest, macos-latest-large] node-version: [20, 22, 24] steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup Node uses: ./ with: @@ -37,7 +37,7 @@ jobs: os: [ubuntu-latest, windows-latest, macos-latest-large] node-version: [lts/dubnium, lts/erbium, lts/fermium, lts/*, lts/-1] steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup Node uses: ./ with: @@ -64,7 +64,7 @@ jobs: '20.0.0-v8-canary20221101e50e45c9f8' ] steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup Node uses: ./ with: @@ -84,7 +84,7 @@ jobs: os: [ubuntu-latest, windows-latest, macos-latest, macos-latest-large] node-version: [20-nightly, 25-nightly, 24.0.0-nightly] steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup Node uses: ./ with: @@ -104,7 +104,7 @@ jobs: os: [ubuntu-latest, windows-latest, macos-latest, macos-latest-large] node-version: [20.0.0-rc.1, 22.14.0-rc.1, 24.0.0-rc.4] steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup Node uses: ./ with: @@ -124,7 +124,7 @@ jobs: os: [ubuntu-latest, windows-latest, macos-latest, macos-latest-large] node-version: [20.10.0, 22.0.0, 24.9.0] steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup Node uses: ./ with: @@ -141,7 +141,7 @@ jobs: os: [ubuntu-latest, windows-latest, macos-latest, macos-latest-large] node-version: [20, 22, 24] steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup Node and check latest uses: ./ with: @@ -160,7 +160,7 @@ jobs: node-version-file: [.nvmrc, .tool-versions, .tool-versions-node, package.json] steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup node from node version file uses: ./ with: @@ -173,9 +173,9 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, windows-latest, macos-latest, macos-13] + os: [ubuntu-latest, windows-latest, macos-latest] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup node from node version file uses: ./ with: @@ -183,21 +183,6 @@ jobs: - name: Verify node run: __tests__/verify-node.sh 20 - version-file-dev-engines-array: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, windows-latest, macos-latest, macos-13] - steps: - - uses: actions/checkout@v4 - - name: Setup node from node version file - uses: ./ - with: - node-version-file: '__tests__/data/package-dev-engines-array.json' - - name: Verify node - run: __tests__/verify-node.sh 20 - version-file-volta: runs-on: ${{ matrix.os }} strategy: @@ -205,7 +190,7 @@ jobs: matrix: os: [ubuntu-latest, windows-latest, macos-latest, macos-latest-large] steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup node from node version file uses: ./ with: @@ -220,7 +205,7 @@ jobs: matrix: os: [ubuntu-latest, windows-latest, macos-latest, macos-latest-large] steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup node from node version file uses: ./ with: @@ -236,7 +221,7 @@ jobs: os: [ubuntu-latest, windows-latest, macos-latest, macos-latest-large] node-version: [17, 19] steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup Node from dist uses: ./ with: @@ -252,7 +237,7 @@ jobs: matrix: os: [ubuntu-latest, windows-latest, macos-latest-large] steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 # test old versions which didn't have npm and layout different - name: Setup node 0.12.18 from dist uses: ./ @@ -265,7 +250,7 @@ jobs: arch: runs-on: windows-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup node 20 x86 from dist uses: ./ with: @@ -289,7 +274,7 @@ jobs: echo "LATEST_NODE_VERSION=$latestNodeVersion" >> $GITHUB_OUTPUT id: version shell: bash - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup Node uses: ./ with: From d7e640b15452b73df08a5c03e64370cb0807684c Mon Sep 17 00:00:00 2001 From: Ferdinand Thiessen Date: Tue, 17 Feb 2026 18:35:34 +0100 Subject: [PATCH 4/5] docs: consolidate advanced usage Signed-off-by: Ferdinand Thiessen --- docs/advanced-usage.md | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md index 4c4189b06..4199a3a55 100644 --- a/docs/advanced-usage.md +++ b/docs/advanced-usage.md @@ -92,41 +92,25 @@ steps: When using the `package.json` input, the action will look in the following fields for a specified Node version: 1. It checks `volta.node` first. -2. Then it checks `devEngines.runtime`. +2. Then it checks `devEngines.runtime` for an entry with `"name": "node"`. 3. Then it will look for `engines.node`. 4. Otherwise it tries to resolve the file defined by [`volta.extends`](https://docs.volta.sh/advanced/workspaces) and look for `volta.node`, `devEngines.runtime`, or `engines.node` recursively. -### Example with `devEngines` - -When a runtime engine (`engines.node`) is defined but also a development engine (`devEngines.runtime`) then the `devEngines.runtime` version is used. -This example will install a Node version based on the `^20.10` pattern. ```json { "engines": { - "node": "^19" + "node": "^22 || ^24" }, "devEngines": { "runtime": { "name": "node", - "version": "^20.10" + "version": "^24.3" } - } -} -``` - -### Example with volta pinned Node version - -When both `engines.node` and `volta.node` is defined the value in `volta.node` is used. - -```json -{ - "engines": { - "node": ">=16.0.0" }, "volta": { - "node": "16.0.0" + "node": "24.11.1" } } ``` From bc646a96d4025a6fc0cd4fe623fac18911f7f934 Mon Sep 17 00:00:00 2001 From: Ferdinand Thiessen Date: Tue, 17 Feb 2026 18:37:43 +0100 Subject: [PATCH 5/5] chore: compile assets Signed-off-by: Ferdinand Thiessen --- dist/cache-save/index.js | 11 +++++++++++ dist/setup/index.js | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/dist/cache-save/index.js b/dist/cache-save/index.js index 3a152770d..7912bcd09 100644 --- a/dist/cache-save/index.js +++ b/dist/cache-save/index.js @@ -71877,6 +71877,17 @@ function getNodeVersionFromFile(versionFilePath) { if (manifest.volta?.node) { return manifest.volta.node; } + // support devEngines from npm 11 + if (manifest.devEngines?.runtime) { + // find an entry with name set to node and having set a version. + // the devEngines.runtime can either be an object or an array of objects + const nodeEntry = [manifest.devEngines.runtime] + .flat() + .find(({ name, version }) => name?.toLowerCase() === 'node' && version); + if (nodeEntry) { + return nodeEntry.version; + } + } if (manifest.engines?.node) { return manifest.engines.node; } diff --git a/dist/setup/index.js b/dist/setup/index.js index b0c8eb601..65a59178f 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -82415,6 +82415,17 @@ function getNodeVersionFromFile(versionFilePath) { if (manifest.volta?.node) { return manifest.volta.node; } + // support devEngines from npm 11 + if (manifest.devEngines?.runtime) { + // find an entry with name set to node and having set a version. + // the devEngines.runtime can either be an object or an array of objects + const nodeEntry = [manifest.devEngines.runtime] + .flat() + .find(({ name, version }) => name?.toLowerCase() === 'node' && version); + if (nodeEntry) { + return nodeEntry.version; + } + } if (manifest.engines?.node) { return manifest.engines.node; }