From 95524fec842007e678d7589a061f26e85f97447e Mon Sep 17 00:00:00 2001 From: Mateusz Bocian Date: Tue, 29 Apr 2025 13:46:22 -0400 Subject: [PATCH 1/6] feat!: end of support for v14 and v16 --- .github/workflows/workflow.yml | 16 +++---- package-lock.json | 36 +++++++------- package.json | 2 +- packages/build-info/package.json | 2 +- packages/build/package.json | 2 +- packages/build/src/plugins/node_version.ts | 44 ++---------------- packages/build/src/plugins/resolve.js | 2 - .../build/tests/core/snapshots/tests.js.md | 4 +- .../build/tests/core/snapshots/tests.js.snap | Bin 5612 -> 5618 bytes .../version_greater_than_minimum/package.json | 2 +- .../build/tests/plugins/snapshots/tests.js.md | 2 +- .../tests/plugins/snapshots/tests.js.snap | Bin 5832 -> 5836 bytes packages/build/tests/plugins/tests.js | 19 -------- packages/cache-utils/package.json | 2 +- packages/config/package.json | 2 +- packages/edge-bundler/package.json | 2 +- packages/framework-info/package.json | 2 +- packages/functions-utils/package.json | 2 +- packages/git-utils/package.json | 2 +- packages/headers-parser/package.json | 2 +- packages/js-client/package.json | 2 +- packages/nock-udp/package.json | 2 +- packages/opentelemetry-sdk-setup/package.json | 2 +- packages/opentelemetry-utils/package.json | 2 +- packages/redirect-parser/package.json | 2 +- packages/run-utils/package.json | 2 +- packages/testing/package.json | 2 +- packages/zip-it-and-ship-it/package.json | 2 +- 28 files changed, 52 insertions(+), 109 deletions(-) diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 8548fdd4cb..2323218c13 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -54,7 +54,7 @@ jobs: include: - os: ubuntu-24.04 # Earliest supported version - node-version: '14.16.0' + node-version: '18.14.0' deno-version: 'v2.2.4' fail-fast: false steps: @@ -78,7 +78,7 @@ jobs: if: ${{ !steps.release-check.outputs.IS_RELEASE }} - name: Install npm@7 run: npm install -g npm@7 - if: ${{ matrix.node-version == '14.16.0' && !steps.release-check.outputs.IS_RELEASE }} + if: ${{ matrix.node-version == '18.14.0' && !steps.release-check.outputs.IS_RELEASE }} - name: Setup Deno uses: denoland/setup-deno@v1 with: @@ -115,23 +115,23 @@ jobs: # We test on the oldest supported Node.js version, but only with a # single combination (Ubuntu) - os: ubuntu-24.04 - node-version: '14.16.0' + node-version: '18.14.0' install-command: npm ci machine: '0' - os: ubuntu-24.04 - node-version: '14.16.0' + node-version: '18.14.0' install-command: npm ci machine: '1' - os: ubuntu-24.04 - node-version: '14.16.0' + node-version: '18.14.0' install-command: npm ci machine: '2' - os: ubuntu-24.04 - node-version: '14.16.0' + node-version: '18.14.0' install-command: npm ci machine: '3' - os: ubuntu-24.04 - node-version: '14.16.0' + node-version: '18.14.0' install-command: npm ci machine: '4' fail-fast: false @@ -169,7 +169,7 @@ jobs: if: ${{ !steps.release-check.outputs.IS_RELEASE }} - name: Install npm@7 run: npm install -g npm@7 - if: ${{ matrix.node-version == '14.16.0' && !steps.release-check.outputs.IS_RELEASE }} + if: ${{ matrix.node-version == '18.14.0' && !steps.release-check.outputs.IS_RELEASE }} - name: Set up Go uses: actions/setup-go@v5 with: diff --git a/package-lock.json b/package-lock.json index df5a34547a..59dfa3b0b0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "prettier": "^3.0.0" }, "engines": { - "node": "^14.16.0 || >=16.0.0" + "node": ">=18.14.0" } }, "node_modules/@ampproject/remapping": { @@ -31872,7 +31872,7 @@ "yarn": "^1.22.22" }, "engines": { - "node": "^14.16.0 || >=16.0.0" + "node": ">=18.14.0" }, "peerDependencies": { "@netlify/opentelemetry-sdk-setup": "^1.1.0", @@ -31916,7 +31916,7 @@ "vitest": "^0.34.0" }, "engines": { - "node": "^14.16.0 || >=16.0.0" + "node": ">=18.14.0" } }, "packages/build-info/node_modules/@types/node": { @@ -31954,7 +31954,7 @@ "vitest": "^0.34.0" }, "engines": { - "node": "^14.16.0 || >=16.0.0" + "node": ">=18.14.0" } }, "packages/cache-utils/node_modules/@types/node": { @@ -32019,7 +32019,7 @@ "typescript": "^5.0.0" }, "engines": { - "node": "^14.16.0 || >=16.0.0" + "node": ">=18.14.0" } }, "packages/config/node_modules/@types/node": { @@ -32070,7 +32070,7 @@ "vitest": "^0.34.0" }, "engines": { - "node": "^14.16.0 || >=16.0.0" + "node": ">=18.14.0" } }, "packages/edge-bundler/node_modules/@types/node": { @@ -32343,7 +32343,7 @@ "vitest": "^0.34.0" }, "engines": { - "node": "^14.14.0 || >=16.0.0" + "node": ">=18.14.0" } }, "packages/functions-utils": { @@ -32363,7 +32363,7 @@ "vitest": "^0.34.0" }, "engines": { - "node": "^14.16.0 || >=16.0.0" + "node": ">=18.14.0" } }, "packages/functions-utils/node_modules/@types/node": { @@ -32390,7 +32390,7 @@ "vitest": "^0.34.0" }, "engines": { - "node": "^14.16.0 || >=16.0.0" + "node": ">=18.14.0" } }, "packages/git-utils/node_modules/@types/node": { @@ -32418,7 +32418,7 @@ "vitest": "^0.34.0" }, "engines": { - "node": "^14.16.0 || >=16.0.0" + "node": ">=18.14.0" } }, "packages/headers-parser/node_modules/@types/node": { @@ -32452,7 +32452,7 @@ "uuid": "^9.0.0" }, "engines": { - "node": "^14.16.0 || >=16.0.0" + "node": ">=18.14.0" } }, "packages/js-client/node_modules/@types/node": { @@ -32472,7 +32472,7 @@ "vitest": "^0.34.0" }, "engines": { - "node": "^14.16.0 || >=16.0.0" + "node": ">=18.14.0" } }, "packages/nock-udp/node_modules/@types/node": { @@ -32507,7 +32507,7 @@ "vitest": "^0.34.0" }, "engines": { - "node": ">=18.0.0" + "node": ">=18.14.0" }, "peerDependencies": { "@opentelemetry/api": "~1.8.0" @@ -32535,7 +32535,7 @@ "vitest": "^0.34.0" }, "engines": { - "node": ">=18.0.0" + "node": ">=18.14.0" }, "peerDependencies": { "@opentelemetry/api": "~1.8.0" @@ -32565,7 +32565,7 @@ "vitest": "^0.34.0" }, "engines": { - "node": "^14.16.0 || >=16.0.0" + "node": ">=18.14.0" } }, "packages/redirect-parser/node_modules/@types/node": { @@ -32589,7 +32589,7 @@ "vitest": "^0.34.0" }, "engines": { - "node": "^14.16.0 || >=16.0.0" + "node": ">=18.14.0" } }, "packages/run-utils/node_modules/@types/node": { @@ -32623,7 +32623,7 @@ "typescript": "^5.0.0" }, "engines": { - "node": "^14.16.0 || >=16.0.0" + "node": ">=18.14.0" } }, "packages/testing/node_modules/@types/node": { @@ -32713,7 +32713,7 @@ "vitest": "0.34.6" }, "engines": { - "node": "^14.18.0 || >=16.0.0" + "node": ">=18.14.0" } }, "packages/zip-it-and-ship-it/node_modules/@types/semver": { diff --git a/package.json b/package.json index a34b0feaef..c65807e6e0 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "prettier": "^3.0.0" }, "engines": { - "node": "^14.16.0 || >=16.0.0" + "node": ">=18.14.0" }, "lint-staged": { "!(packages/*/tests/**/fixtures/**/*)*.+(j|t)s": "eslint --ignore-path .gitignore --cache --fix", diff --git a/packages/build-info/package.json b/packages/build-info/package.json index ac93c51772..24a1febc7e 100644 --- a/packages/build-info/package.json +++ b/packages/build-info/package.json @@ -69,6 +69,6 @@ "vitest": "^0.34.0" }, "engines": { - "node": "^14.16.0 || >=16.0.0" + "node": ">=18.14.0" } } diff --git a/packages/build/package.json b/packages/build/package.json index 110cd5a93a..cc2a0220ae 100644 --- a/packages/build/package.json +++ b/packages/build/package.json @@ -157,6 +157,6 @@ } }, "engines": { - "node": "^14.16.0 || >=16.0.0" + "node": ">=18.14.0" } } diff --git a/packages/build/src/plugins/node_version.ts b/packages/build/src/plugins/node_version.ts index c515e609a2..3a1b0224c4 100644 --- a/packages/build/src/plugins/node_version.ts +++ b/packages/build/src/plugins/node_version.ts @@ -1,11 +1,9 @@ -import { dirname } from 'path' import { execPath, version as currentVersion } from 'process' import semver from 'semver' import link from 'terminal-link' import { logWarning, logWarningSubHeader } from '../log/logger.js' -import { getPackageJson } from '../utils/package.js' export type PluginsLoadedFrom = 'auto_install' | 'local' | 'package.json' @@ -23,8 +21,7 @@ export type PluginsOptions = { * This node version is minimum required to run the plugins code. * If the users preferred Node.js version is below that we have to fall back to the system node version */ -const MINIMUM_REQUIRED_NODE_VERSION = '^14.14.0 || >=16.0.0' -const UPCOMING_MINIMUM_REQUIRED_NODE_VERSION = '>=18.14.0' +const MINIMUM_REQUIRED_NODE_VERSION = '>=18.14.0' /** * Local plugins and `package.json`-installed plugins use user's preferred Node.js version if higher than our minimum @@ -33,39 +30,28 @@ const UPCOMING_MINIMUM_REQUIRED_NODE_VERSION = '>=18.14.0' * usually the system's Node.js version. * If the user Node version does not satisfy our supported engine range use our own system Node version */ -export const addPluginsNodeVersion = function ({ - featureFlags, - pluginsOptions, - nodePath, - userNodeVersion, - logs, - systemLog, -}) { +export const addPluginsNodeVersion = function ({ pluginsOptions, nodePath, userNodeVersion, logs }) { const currentNodeVersion = semver.clean(currentVersion) return Promise.all( pluginsOptions.map((pluginOptions) => addPluginNodeVersion({ - featureFlags, pluginOptions, currentNodeVersion, userNodeVersion, nodePath, logs, - systemLog, }), ), ) } const addPluginNodeVersion = async function ({ - featureFlags, pluginOptions, - pluginOptions: { loadedFrom, packageName, pluginPath }, + pluginOptions: { loadedFrom, packageName }, currentNodeVersion, userNodeVersion, nodePath, logs, - systemLog, }: { pluginOptions: PluginsOptions [key: string]: any @@ -80,28 +66,6 @@ const addPluginNodeVersion = async function ({ return systemNode } - if ( - featureFlags.build_warn_upcoming_system_version_change && - !semver.satisfies(userNodeVersion, UPCOMING_MINIMUM_REQUIRED_NODE_VERSION) - ) { - if (pluginPath) { - const pluginDir = dirname(pluginPath) - const { packageJson: pluginPackageJson } = await getPackageJson(pluginDir) - - // Ensure Node.js version is compatible with plugin's `engines.node` - const pluginNodeVersionRange = pluginPackageJson?.engines?.node - if (!pluginNodeVersionRange) { - systemLog(`plugin "${packageName}" does not specify node support range`) - } else if (semver.satisfies('22.0.0', pluginNodeVersionRange)) { - systemLog(`plugin "${packageName}" node support range includes v22`) - } else { - systemLog(`plugin "${packageName}" node support range does NOT include v22`) - } - } else { - systemLog(`plugin "${packageName}" pluginPath not available`) - } - } - if (semver.satisfies(userNodeVersion, MINIMUM_REQUIRED_NODE_VERSION)) { return userNode } @@ -113,7 +77,7 @@ const addPluginNodeVersion = async function ({ Read more about our minimum required version in our ${link( 'forums announcement', - 'https://answers.netlify.com/t/build-plugins-dropping-support-for-node-js-12/79421', + 'https://answers.netlify.com/t/build-plugins-end-of-support-for-node-js-14-node-js-16/136405', )}`, ) diff --git a/packages/build/src/plugins/resolve.js b/packages/build/src/plugins/resolve.js index 1d971857c6..dee2eb1324 100644 --- a/packages/build/src/plugins/resolve.js +++ b/packages/build/src/plugins/resolve.js @@ -40,12 +40,10 @@ export const resolvePluginsPath = async function ({ pluginsOptions.map((pluginOptions) => resolvePluginPath({ pluginOptions, buildDir, packagePath, autoPluginsDir })), ) const pluginsOptionsB = await addPluginsNodeVersion({ - featureFlags, pluginsOptions: pluginsOptionsA, nodePath, userNodeVersion, logs, - systemLog, }) const pluginsOptionsC = await addPinnedVersions({ pluginsOptions: pluginsOptionsB, api, siteInfo, sendStatus }) diff --git a/packages/build/tests/core/snapshots/tests.js.md b/packages/build/tests/core/snapshots/tests.js.md index f492542cc4..277f9bef75 100644 --- a/packages/build/tests/core/snapshots/tests.js.md +++ b/packages/build/tests/core/snapshots/tests.js.md @@ -1173,7 +1173,7 @@ Generated by [AVA](https://avajs.dev). > Warning: ./plugin.js will be executed with Node.js version 1.0.0␊ The plugin cannot be executed with your defined Node.js version 1.0.0␊ ␊ - Read more about our minimum required version in our forums announcement (https://answers.netlify.com/t/build-plugins-dropping-support-for-node-js-12/79421)␊ + Read more about our minimum required version in our forums announcement (https://answers.netlify.com/t/build-plugins-end-of-support-for-node-js-14-node-js-16/136405)␊ ␊ > Loading plugins␊ - ./plugin.js@1.0.0 from netlify.toml␊ @@ -1232,7 +1232,7 @@ Generated by [AVA](https://avajs.dev). > Warning: netlify-plugin-test will be executed with Node.js version 1.0.0␊ The plugin cannot be executed with your defined Node.js version 1.0.0␊ ␊ - Read more about our minimum required version in our forums announcement (https://answers.netlify.com/t/build-plugins-dropping-support-for-node-js-12/79421)␊ + Read more about our minimum required version in our forums announcement (https://answers.netlify.com/t/build-plugins-end-of-support-for-node-js-14-node-js-16/136405)␊ ␊ > Loading plugins␊ - netlify-plugin-test@1.0.0 from netlify.toml and package.json␊ diff --git a/packages/build/tests/core/snapshots/tests.js.snap b/packages/build/tests/core/snapshots/tests.js.snap index dcdb301de0baa2e69e598b13fbfb1d0cb6ec3716..aa1ca0226d86a65e0cf660593697ee0fc130fa86 100644 GIT binary patch delta 5551 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 E0N34NIsgCw diff --git a/packages/build/tests/plugins/fixtures/version_greater_than_minimum/package.json b/packages/build/tests/plugins/fixtures/version_greater_than_minimum/package.json index 9ecce58068..7625bb67ef 100644 --- a/packages/build/tests/plugins/fixtures/version_greater_than_minimum/package.json +++ b/packages/build/tests/plugins/fixtures/version_greater_than_minimum/package.json @@ -6,6 +6,6 @@ "license": "MIT", "repository": "test", "engines": { - "node": "^14.16.0 || >=16.0.0" + "node": ">=18.14.0" } } diff --git a/packages/build/tests/plugins/snapshots/tests.js.md b/packages/build/tests/plugins/snapshots/tests.js.md index b3215f627a..1e7a15a797 100644 --- a/packages/build/tests/plugins/snapshots/tests.js.md +++ b/packages/build/tests/plugins/snapshots/tests.js.md @@ -870,7 +870,7 @@ Generated by [AVA](https://avajs.dev). > Warning: ./plugin.js will be executed with Node.js version 1.0.0␊ The plugin cannot be executed with your defined Node.js version 1.0.0␊ ␊ - Read more about our minimum required version in our forums announcement (https://answers.netlify.com/t/build-plugins-dropping-support-for-node-js-12/79421)␊ + Read more about our minimum required version in our forums announcement (https://answers.netlify.com/t/build-plugins-end-of-support-for-node-js-14-node-js-16/136405)␊ ␊ > Loading plugins␊ - ./plugin.js@1.0.0 from netlify.toml␊ diff --git a/packages/build/tests/plugins/snapshots/tests.js.snap b/packages/build/tests/plugins/snapshots/tests.js.snap index cf15bdff620de139f16a585682e1316bae24c287..2aa6b351551a2d02ecb51d99bf5ef16aab89e596 100644 GIT binary patch delta 4920 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 delta 4971 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 z zZSK|bxNCE-mYI8X%W!nArR6I!wVa=3T(VE>mV^qpWR=a=%64yQ4%v;$-G3Stk@e+n z+^?$Z#j}&z-Q0V2y!mWq4|Ac(Gsn7vJYo8J11Dhd{;SQ5oFOyPCPWq_gd!Ic{$Si{ zRUaPB*>51rwVhxH$VJ}gw!Z0ROxB}sT9bA4CTl=0s%oyvt}V?}4ah~w%LbaW*2=tb zzp7f970fCrZH(K6h{6Xwqkp)Q2Kli>&SfXGS*xu$tL>}pi;!^)oCO$SLHxYhxu0b0 zu_t!3XX*CXm-wxIZh9YwuGN85>#fq_>=9@oG6qbQYaRUa&QVF4Q|~s zOquH;!=nnL+yW~3>3_f}If<#~%V*y$B_KbUY&7AJ85|2Cc_C2L!-4|>%4i*55Ux&p z!!b1+ACAs!l-GxZl(5WKkB5V)KFAaul5(J~CcPS$>RZvydX9Lm2^!aEX#u&=CFBRn z?$UUyyh0fUkaB2vY^bY=%!A}`j(tA|v=1|&y=6hWbkJ6@n}3cHVl^N;-Jv-FJ4IrV zEJnSG7c4t{G0XA7oX#e`&?>kYBGI22l(WsR3(6y{Y?9Tqss8rpFmt7VRMtHw9tMwa z(Ui)x<@B-dvxc}3x%a4oWi5wL4_`F;BJiDOnBoWttmX|bC`0R-Bf#z#pF9ML4A&Zm zSw%#oy2;sZ@PAtw{QWWo#4jCy zuNA}BBtlU+#n)P});Q&B8~S{J2z^R?EKkohBBuDkP4h?RVd{w#1?p+Ti{?rcQ$h5_ zQ@-W^yxJ(?1;+Z{j5&^SyR0uv?ymDi84>q8AKqC)On)XbGN(`+BRE25FjQ<{r+B#+ z8QA&mGa{0(PFHSf2GRw}AYx36n~?YZG-E>Yd)9{CI7~0M)$w8xx1wY zgSBX?5d=>9GH38tw=Oj3J7CsL%-glK)h78B31@k}V? zpNyqdeeSZn8D${q`=b!0J+nTdo{uAt!REX@j{loMs{gS_RXS2766#0^RRgawJ(?4> z(tk7x#jX+dSp>UrziULsv@WYLnw+RL6lh_@u?)Weg7kfIC^TT7Vqo2t7Q)bVGRK*N zL1v9PaTvRDKAFR9Qwp=LOT1dlEC4ghp2-F|e=r?6jh&POo`0VK&%d$Yxiat^7_*fE z(4mRF7>F7=r2uJ)l@?5I+%FGIk1j);3xB9a#nloxthI*DqV*5Uz`8Ogo58!aqX_;9RChb7EYYMxppN!oK2{-NXW` zZesePo0wzG?KVs~J!IF@d{|&jZF+0Fq*myX+S?L)>TVyqU-B7n=&k?C;Lv}(Wq)yK z6*zPm;*OGCb%1Etr3H{^K%{UeN^|fgV$oPSpO_(=?>0=kaX+igVqd3(kw7^tnln;% zM~8_6_N%}92RNqa#K-a@Hc~le?eNw><_*EuKiGKpek)<-(cz=_-+!+K+ZQ2rr9ORF ze*`G%#j+YH-++@?K#vJ{&~Or;FIv&4nbNurn1@FDp~_j&L(9XikBkQIBA;s;3GmG5k&D|*>S(!(vW+;Qy&bh_Vo$C$rEVqEClnvDICAmFC`{8&UrIOe z$;q%tFXoRPlPnTf5eee>0Ezx^UPt(=m_)b*FTazN5-0%)lf4pN0dA8V6MY4(495N1 zlb#bR0a%mD6ElA-hXWT#bx1}W+xvS@cb;_)HjkdSpq3V-BKGunuYI($zjxT#+BrOG zL2bOAOHBSy0!Eb!RPEZE?dRK_t(_O?yVb@}b$REov%BBk+|}AZ zp4rf-&g%WAu+^d!jmSwceMRt zZ*w=*>%$lA+*cfwtjRVUdFPSV*;iIA500Pg?i@ZhuUm6oNr?<*uKJ)>M;*4HroOHv z1Lm|>19f9US?e$@z5#vNy!K8_&VOB_$*2c-311I%K}{=z+Qv{3)Xa3PZ47$ya$n)> z7w}5QowW->OCr?iPXWT$uQrng6+#Qy&oq>vCyO*XpC6M`6)YuZ#@PIKTbyDZV^c3G pE@a-RPeFIIgy%Kx(lo|QJ8Kv%cbGhvv!oRu0SGc8)2yLO0RRg*kI?`C diff --git a/packages/build/tests/plugins/tests.js b/packages/build/tests/plugins/tests.js index 2cccf82df1..6f727685d0 100644 --- a/packages/build/tests/plugins/tests.js +++ b/packages/build/tests/plugins/tests.js @@ -110,25 +110,6 @@ test('Validate --node-path unsupported version does not fail when no plugins are t.snapshot(normalizeOutput(output)) }) -test('Validate --node-path version is supported by the plugin', async (t) => { - const systemLog = await tmp.file() - - const nodePath = getNodePath('16.14.0') - const output = await new Fixture('./fixtures/engines') - .withFlags({ - nodePath, - featureFlags: { build_warn_upcoming_system_version_change: true }, - systemLogFile: systemLog.fd, - debug: false, - }) - .runWithBuild() - t.true(normalizeOutput(output).includes('The Node.js version is 1.0.0 but the plugin "./plugin.js" requires >=1.0.0')) - const systemLogContents = await fs.readFile(systemLog.path, 'utf8') - await systemLog.cleanup() - - t.true(systemLogContents.includes('plugin "./plugin.js" node support range includes v22')) -}) - test('Validate --node-path exists', async (t) => { const output = await new Fixture('./fixtures/node_version_simple') .withFlags({ nodePath: '/doesNotExist' }) diff --git a/packages/cache-utils/package.json b/packages/cache-utils/package.json index 7f11877f93..8b0ec8f289 100644 --- a/packages/cache-utils/package.json +++ b/packages/cache-utils/package.json @@ -66,6 +66,6 @@ "vitest": "^0.34.0" }, "engines": { - "node": "^14.16.0 || >=16.0.0" + "node": ">=18.14.0" } } diff --git a/packages/config/package.json b/packages/config/package.json index 0b6aa2d129..73fe173493 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -93,6 +93,6 @@ "typescript": "^5.0.0" }, "engines": { - "node": "^14.16.0 || >=16.0.0" + "node": ">=18.14.0" } } diff --git a/packages/edge-bundler/package.json b/packages/edge-bundler/package.json index 028fbcd1be..e6a931d3bd 100644 --- a/packages/edge-bundler/package.json +++ b/packages/edge-bundler/package.json @@ -54,7 +54,7 @@ "vitest": "^0.34.0" }, "engines": { - "node": "^14.16.0 || >=16.0.0" + "node": ">=18.14.0" }, "dependencies": { "@import-maps/resolve": "^1.0.1", diff --git a/packages/framework-info/package.json b/packages/framework-info/package.json index e0da4e5c78..3be787ec28 100644 --- a/packages/framework-info/package.json +++ b/packages/framework-info/package.json @@ -81,7 +81,7 @@ "vitest": "^0.34.0" }, "engines": { - "node": "^14.14.0 || >=16.0.0" + "node": ">=18.14.0" }, "ava": { "verbose": true, diff --git a/packages/functions-utils/package.json b/packages/functions-utils/package.json index d7dffd9e8d..b38492bcf4 100644 --- a/packages/functions-utils/package.json +++ b/packages/functions-utils/package.json @@ -62,6 +62,6 @@ "vitest": "^0.34.0" }, "engines": { - "node": "^14.16.0 || >=16.0.0" + "node": ">=18.14.0" } } diff --git a/packages/git-utils/package.json b/packages/git-utils/package.json index 2193a8c965..87ce6f9fb1 100644 --- a/packages/git-utils/package.json +++ b/packages/git-utils/package.json @@ -62,6 +62,6 @@ "vitest": "^0.34.0" }, "engines": { - "node": "^14.16.0 || >=16.0.0" + "node": ">=18.14.0" } } diff --git a/packages/headers-parser/package.json b/packages/headers-parser/package.json index ad6128af2e..32506539ee 100644 --- a/packages/headers-parser/package.json +++ b/packages/headers-parser/package.json @@ -21,7 +21,7 @@ "netlify" ], "engines": { - "node": "^14.16.0 || >=16.0.0" + "node": ">=18.14.0" }, "author": "Netlify", "license": "MIT", diff --git a/packages/js-client/package.json b/packages/js-client/package.json index 30da7ce205..96d930e20d 100644 --- a/packages/js-client/package.json +++ b/packages/js-client/package.json @@ -60,6 +60,6 @@ "uuid": "^9.0.0" }, "engines": { - "node": "^14.16.0 || >=16.0.0" + "node": ">=18.14.0" } } diff --git a/packages/nock-udp/package.json b/packages/nock-udp/package.json index 076e8f4fb2..f5ce608e01 100644 --- a/packages/nock-udp/package.json +++ b/packages/nock-udp/package.json @@ -33,6 +33,6 @@ "vitest": "^0.34.0" }, "engines": { - "node": "^14.16.0 || >=16.0.0" + "node": ">=18.14.0" } } diff --git a/packages/opentelemetry-sdk-setup/package.json b/packages/opentelemetry-sdk-setup/package.json index 25d42c75cd..1b9eccb515 100644 --- a/packages/opentelemetry-sdk-setup/package.json +++ b/packages/opentelemetry-sdk-setup/package.json @@ -50,6 +50,6 @@ "vitest": "^0.34.0" }, "engines": { - "node": ">=18.0.0" + "node": ">=18.14.0" } } diff --git a/packages/opentelemetry-utils/package.json b/packages/opentelemetry-utils/package.json index bfb02c1d67..f2905e996c 100644 --- a/packages/opentelemetry-utils/package.json +++ b/packages/opentelemetry-utils/package.json @@ -41,6 +41,6 @@ "vitest": "^0.34.0" }, "engines": { - "node": ">=18.0.0" + "node": ">=18.14.0" } } diff --git a/packages/redirect-parser/package.json b/packages/redirect-parser/package.json index cd46f1d12f..3285dc4ca2 100644 --- a/packages/redirect-parser/package.json +++ b/packages/redirect-parser/package.json @@ -21,7 +21,7 @@ "netlify" ], "engines": { - "node": "^14.16.0 || >=16.0.0" + "node": ">=18.14.0" }, "author": "Netlify", "license": "MIT", diff --git a/packages/run-utils/package.json b/packages/run-utils/package.json index 91d5971b1f..4e743350d1 100644 --- a/packages/run-utils/package.json +++ b/packages/run-utils/package.json @@ -59,6 +59,6 @@ "vitest": "^0.34.0" }, "engines": { - "node": "^14.16.0 || >=16.0.0" + "node": ">=18.14.0" } } diff --git a/packages/testing/package.json b/packages/testing/package.json index 9eb01cb345..39b5bd5a3c 100644 --- a/packages/testing/package.json +++ b/packages/testing/package.json @@ -9,7 +9,7 @@ "lib/**" ], "engines": { - "node": "^14.16.0 || >=16.0.0" + "node": ">=18.14.0" }, "scripts": { "prebuild": "rm -rf lib", diff --git a/packages/zip-it-and-ship-it/package.json b/packages/zip-it-and-ship-it/package.json index fffa6cb43c..280af08e20 100644 --- a/packages/zip-it-and-ship-it/package.json +++ b/packages/zip-it-and-ship-it/package.json @@ -100,6 +100,6 @@ "vitest": "0.34.6" }, "engines": { - "node": "^14.18.0 || >=16.0.0" + "node": ">=18.14.0" } } From 3ec5a57cabb677be372d2936d0c2563b8bcf846d Mon Sep 17 00:00:00 2001 From: Mateusz Bocian Date: Tue, 29 Apr 2025 17:31:09 -0400 Subject: [PATCH 2/6] test: cleanup semver checks surrounding node v16 --- packages/build/tests/blobs_upload/tests.js | 49 +++---- packages/build/tests/edge_functions/tests.js | 140 +++++++++---------- packages/build/tests/frameworks_api/tests.js | 30 ++-- packages/build/tests/functions/tests.js | 135 +++++++++--------- 4 files changed, 168 insertions(+), 186 deletions(-) diff --git a/packages/build/tests/blobs_upload/tests.js b/packages/build/tests/blobs_upload/tests.js index d4d95d776a..34a9c5ad23 100644 --- a/packages/build/tests/blobs_upload/tests.js +++ b/packages/build/tests/blobs_upload/tests.js @@ -210,35 +210,32 @@ test.serial('Blobs upload step cancels deploy if blob metadata is malformed', as t.is(severityCode, 4) }) -// the monorepo works with pnpm which is not available on node 14 tests -if (semver.gte(nodeVersion, '16.9.0')) { - test.serial('monorepo > blobs upload, uploads files to deploy store', async (t) => { - const fixture = await new Fixture('./fixtures/monorepo').withCopyRoot({ git: false }) - const { success } = await fixture - .withFlags({ deployId: 'abc123', siteId: 'test', token: TOKEN, offline: true, packagePath: 'apps/app-1' }) - .runBuildProgrammatic() +test.serial('monorepo > blobs upload, uploads files to deploy store', async (t) => { + const fixture = await new Fixture('./fixtures/monorepo').withCopyRoot({ git: false }) + const { success } = await fixture + .withFlags({ deployId: 'abc123', siteId: 'test', token: TOKEN, offline: true, packagePath: 'apps/app-1' }) + .runBuildProgrammatic() - t.true(success) - t.is(t.context.blobRequests.set.length, 6) + t.true(success) + t.is(t.context.blobRequests.set.length, 6) - const storeOpts = { deployID: 'abc123', siteID: 'test', token: TOKEN } - if (semver.lt(nodeVersion, '18.0.0')) { - const nodeFetch = await import('node-fetch') - storeOpts.fetch = nodeFetch.default - } + const storeOpts = { deployID: 'abc123', siteID: 'test', token: TOKEN } + if (semver.lt(nodeVersion, '18.0.0')) { + const nodeFetch = await import('node-fetch') + storeOpts.fetch = nodeFetch.default + } - const store = getDeployStore(storeOpts) + const store = getDeployStore(storeOpts) - const blob1 = await store.getWithMetadata('something.txt') - t.is(blob1.data, 'some value') - t.deepEqual(blob1.metadata, {}) + const blob1 = await store.getWithMetadata('something.txt') + t.is(blob1.data, 'some value') + t.deepEqual(blob1.metadata, {}) - const blob2 = await store.getWithMetadata('with-metadata.txt') - t.is(blob2.data, 'another value') - t.deepEqual(blob2.metadata, { meta: 'data', number: 1234 }) + const blob2 = await store.getWithMetadata('with-metadata.txt') + t.is(blob2.data, 'another value') + t.deepEqual(blob2.metadata, { meta: 'data', number: 1234 }) - const blob3 = await store.getWithMetadata('nested/file.txt') - t.is(blob3.data, 'file value') - t.deepEqual(blob3.metadata, { some: 'metadata' }) - }) -} + const blob3 = await store.getWithMetadata('nested/file.txt') + t.is(blob3.data, 'file value') + t.deepEqual(blob3.metadata, { some: 'metadata' }) +}) diff --git a/packages/build/tests/edge_functions/tests.js b/packages/build/tests/edge_functions/tests.js index fb15cdab26..673cc15855 100644 --- a/packages/build/tests/edge_functions/tests.js +++ b/packages/build/tests/edge_functions/tests.js @@ -1,12 +1,11 @@ import { promises as fs } from 'fs' import { join } from 'path' -import { platform, version as nodeVersion } from 'process' +import { platform } from 'process' import { fileURLToPath } from 'url' import { Fixture, normalizeOutput } from '@netlify/testing' import test from 'ava' import { pathExists } from 'path-exists' -import semver from 'semver' import tmp from 'tmp-promise' import { importJsonFile } from '../../lib/utils/json.js' @@ -215,10 +214,31 @@ test.serial('cleans up the edge functions dist directory before bundling', async t.false(await pathExists(oldBundlePath)) }) -// Targeting Node 16.7.0+ because these fixtures rely on `fs.cp()`. -if (semver.gte(nodeVersion, '16.7.0')) { - test.serial('builds edge functions generated with the Frameworks API', async (t) => { - const output = await new Fixture('./fixtures/functions_user_framework') +test.serial('builds edge functions generated with the Frameworks API', async (t) => { + const output = await new Fixture('./fixtures/functions_user_framework') + .withFlags({ + debug: false, + mode: 'buildbot', + }) + .runWithBuild() + + t.snapshot(normalizeOutput(output)) + + const { routes } = await assertManifest(t, 'functions_user_framework') + + t.is(routes.length, 1) + t.deepEqual(routes[0], { + function: 'function-2', + pattern: '^/framework(?:/(.*))/?$', + excluded_patterns: ['^/framework/skip_(.*)/?$'], + path: '/framework/*', + }) +}) + +test.serial( + 'builds both edge functions generated with the Frameworks API and the ones in the internal directory', + async (t) => { + const output = await new Fixture('./fixtures/functions_user_internal_framework') .withFlags({ debug: false, mode: 'buildbot', @@ -227,69 +247,45 @@ if (semver.gte(nodeVersion, '16.7.0')) { t.snapshot(normalizeOutput(output)) - const { routes } = await assertManifest(t, 'functions_user_framework') - - t.is(routes.length, 1) - t.deepEqual(routes[0], { - function: 'function-2', - pattern: '^/framework(?:/(.*))/?$', - excluded_patterns: ['^/framework/skip_(.*)/?$'], - path: '/framework/*', - }) - }) - - test.serial( - 'builds both edge functions generated with the Frameworks API and the ones in the internal directory', - async (t) => { - const output = await new Fixture('./fixtures/functions_user_internal_framework') - .withFlags({ - debug: false, - mode: 'buildbot', - }) - .runWithBuild() - - t.snapshot(normalizeOutput(output)) - - const { routes } = await assertManifest(t, 'functions_user_internal_framework') - - t.deepEqual(routes, [ - { - function: 'frameworks-internal-conflict', - pattern: '^/frameworks-internal-conflict/frameworks/?$', - excluded_patterns: [], - path: '/frameworks-internal-conflict/frameworks', - }, - { - function: 'function-3', - pattern: '^/internal(?:/(.*))/?$', - excluded_patterns: ['^/internal/skip_(.*)/?$'], - path: '/internal/*', - }, - { - function: 'frameworks-user-conflict', - pattern: '^/frameworks-user-conflict/frameworks/?$', - excluded_patterns: [], - path: '/frameworks-user-conflict/frameworks', - }, - { - function: 'function-2', - pattern: '^/framework(?:/(.*))/?$', - excluded_patterns: ['^/framework/skip_(.*)/?$'], - path: '/framework/*', - }, - { - function: 'frameworks-user-conflict', - pattern: '^/frameworks-user-conflict/user/?$', - excluded_patterns: [], - path: '/frameworks-user-conflict/user', - }, - { - function: 'function-1', - pattern: '^/user/?$', - excluded_patterns: [], - path: '/user', - }, - ]) - }, - ) -} + const { routes } = await assertManifest(t, 'functions_user_internal_framework') + + t.deepEqual(routes, [ + { + function: 'frameworks-internal-conflict', + pattern: '^/frameworks-internal-conflict/frameworks/?$', + excluded_patterns: [], + path: '/frameworks-internal-conflict/frameworks', + }, + { + function: 'function-3', + pattern: '^/internal(?:/(.*))/?$', + excluded_patterns: ['^/internal/skip_(.*)/?$'], + path: '/internal/*', + }, + { + function: 'frameworks-user-conflict', + pattern: '^/frameworks-user-conflict/frameworks/?$', + excluded_patterns: [], + path: '/frameworks-user-conflict/frameworks', + }, + { + function: 'function-2', + pattern: '^/framework(?:/(.*))/?$', + excluded_patterns: ['^/framework/skip_(.*)/?$'], + path: '/framework/*', + }, + { + function: 'frameworks-user-conflict', + pattern: '^/frameworks-user-conflict/user/?$', + excluded_patterns: [], + path: '/frameworks-user-conflict/user', + }, + { + function: 'function-1', + pattern: '^/user/?$', + excluded_patterns: [], + path: '/user', + }, + ]) + }, +) diff --git a/packages/build/tests/frameworks_api/tests.js b/packages/build/tests/frameworks_api/tests.js index 36d4e9e623..572653309f 100644 --- a/packages/build/tests/frameworks_api/tests.js +++ b/packages/build/tests/frameworks_api/tests.js @@ -1,10 +1,9 @@ import { promises as fs } from 'fs' import { dirname, resolve } from 'path' -import { platform, version as nodeVersion } from 'process' +import { platform } from 'process' import { Fixture } from '@netlify/testing' import test from 'ava' -import semver from 'semver' import tmp from 'tmp-promise' test('Does not mutate read-only properties', async (t) => { @@ -95,23 +94,20 @@ test('Loads configuration data that has been generated by the build command usin } }) -// pnpm is not available in Node 14. -if (semver.gte(nodeVersion, '16.9.0')) { - test('In a monorepo setup, loads package-specific configuration data', async (t) => { - const fixture = await new Fixture('./fixtures/monorepo').withCopyRoot({ git: false }) - const { success, netlifyConfig } = await fixture - .withFlags({ - cwd: fixture.repositoryRoot, - packagePath: 'apps/app-1', - }) - .runWithBuildAndIntrospect() - - t.true(success) - t.deepEqual(netlifyConfig.images, { - remote_images: ['domain1.netlify', 'domain2.netlify'], +test('In a monorepo setup, loads package-specific configuration data', async (t) => { + const fixture = await new Fixture('./fixtures/monorepo').withCopyRoot({ git: false }) + const { success, netlifyConfig } = await fixture + .withFlags({ + cwd: fixture.repositoryRoot, + packagePath: 'apps/app-1', }) + .runWithBuildAndIntrospect() + + t.true(success) + t.deepEqual(netlifyConfig.images, { + remote_images: ['domain1.netlify', 'domain2.netlify'], }) -} +}) test('Configuration data is exposed to build plugins in the `onBuild` event', async (t) => { const { netlifyConfig, success } = await new Fixture('./fixtures/with_build_plugin').runWithBuildAndIntrospect() diff --git a/packages/build/tests/functions/tests.js b/packages/build/tests/functions/tests.js index e83549e9ba..4d24880d67 100644 --- a/packages/build/tests/functions/tests.js +++ b/packages/build/tests/functions/tests.js @@ -1,6 +1,5 @@ import { readdir, readFile, rm, stat, writeFile } from 'fs/promises' import { join, resolve } from 'path' -import { version as nodeVersion } from 'process' import { fileURLToPath } from 'url' import { Fixture, normalizeOutput, removeDir, getTempName, unzipFile } from '@netlify/testing' @@ -121,87 +120,81 @@ test('Functions: cleanup is only triggered when there are internal functions', a t.false(output.includes('Cleaning up leftover files from previous builds')) }) -// Targeting Node 16.7.0+ because these fixtures rely on `fs.cp()`. -if (semver.gte(nodeVersion, '16.7.0')) { - test('Functions: loads functions generated with the Frameworks API', async (t) => { - const fixture = await new Fixture('./fixtures/functions_user_and_frameworks') - .withFlags({ debug: false }) - .withCopyRoot() +test('Functions: loads functions generated with the Frameworks API', async (t) => { + const fixture = await new Fixture('./fixtures/functions_user_and_frameworks') + .withFlags({ debug: false }) + .withCopyRoot() - const output = await fixture.runWithBuild() - const functionsDist = await readdir(resolve(fixture.repositoryRoot, '.netlify/functions')) + const output = await fixture.runWithBuild() + const functionsDist = await readdir(resolve(fixture.repositoryRoot, '.netlify/functions')) - t.true(functionsDist.includes('manifest.json')) - t.true(functionsDist.includes('server.zip')) - t.true(functionsDist.includes('user.zip')) + t.true(functionsDist.includes('manifest.json')) + t.true(functionsDist.includes('server.zip')) + t.true(functionsDist.includes('user.zip')) - t.snapshot(normalizeOutput(output)) - }) + t.snapshot(normalizeOutput(output)) +}) - test('Functions: loads functions from the `.netlify/functions-internal` directory and the Frameworks API', async (t) => { - const fixture = await new Fixture('./fixtures/functions_user_internal_and_frameworks') - .withFlags({ debug: false }) - .withCopyRoot() +test('Functions: loads functions from the `.netlify/functions-internal` directory and the Frameworks API', async (t) => { + const fixture = await new Fixture('./fixtures/functions_user_internal_and_frameworks') + .withFlags({ debug: false }) + .withCopyRoot() - const output = await fixture.runWithBuild() - const functionsDist = await readdir(resolve(fixture.repositoryRoot, '.netlify/functions')) + const output = await fixture.runWithBuild() + const functionsDist = await readdir(resolve(fixture.repositoryRoot, '.netlify/functions')) - t.true(functionsDist.includes('manifest.json')) - t.true(functionsDist.includes('server.zip')) - t.true(functionsDist.includes('user.zip')) - t.true(functionsDist.includes('server-internal.zip')) + t.true(functionsDist.includes('manifest.json')) + t.true(functionsDist.includes('server.zip')) + t.true(functionsDist.includes('user.zip')) + t.true(functionsDist.includes('server-internal.zip')) - const manifest = await readFile(resolve(fixture.repositoryRoot, '.netlify/functions/manifest.json'), 'utf8') - const { functions } = JSON.parse(manifest) + const manifest = await readFile(resolve(fixture.repositoryRoot, '.netlify/functions/manifest.json'), 'utf8') + const { functions } = JSON.parse(manifest) - t.is(functions.length, 5) + t.is(functions.length, 5) - // The Frameworks API takes precedence over the legacy internal directory. - const frameworksInternalConflict = functions.find(({ name }) => name === 'frameworks-internal-conflict') - t.is(frameworksInternalConflict.routes[0].pattern, '/frameworks-internal-conflict/frameworks') + // The Frameworks API takes precedence over the legacy internal directory. + const frameworksInternalConflict = functions.find(({ name }) => name === 'frameworks-internal-conflict') + t.is(frameworksInternalConflict.routes[0].pattern, '/frameworks-internal-conflict/frameworks') - // User code takes precedence over the Frameworks API. - const frameworksUserConflict = functions.find(({ name }) => name === 'frameworks-user-conflict') - t.is(frameworksUserConflict.routes[0].pattern, '/frameworks-user-conflict/user') + // User code takes precedence over the Frameworks API. + const frameworksUserConflict = functions.find(({ name }) => name === 'frameworks-user-conflict') + t.is(frameworksUserConflict.routes[0].pattern, '/frameworks-user-conflict/user') - t.snapshot(normalizeOutput(output)) - }) -} - -// pnpm is not available in Node 14. -if (semver.gte(nodeVersion, '16.9.0')) { - test('Functions: loads functions generated with the Frameworks API in a monorepo setup', async (t) => { - const fixture = await new Fixture('./fixtures/functions_monorepo').withCopyRoot({ git: false }) - const app1 = await fixture - .withFlags({ - cwd: fixture.repositoryRoot, - packagePath: 'apps/app-1', - }) - .runWithBuildAndIntrospect() - - t.true(app1.success) - - const app2 = await fixture - .withFlags({ - cwd: fixture.repositoryRoot, - packagePath: 'apps/app-2', - }) - .runWithBuildAndIntrospect() - - t.true(app2.success) - - const app1FunctionsDist = await readdir(resolve(fixture.repositoryRoot, 'apps/app-1/.netlify/functions')) - t.is(app1FunctionsDist.length, 2) - t.true(app1FunctionsDist.includes('manifest.json')) - t.true(app1FunctionsDist.includes('server.zip')) - - const app2FunctionsDist = await readdir(resolve(fixture.repositoryRoot, 'apps/app-2/.netlify/functions')) - t.is(app2FunctionsDist.length, 3) - t.true(app2FunctionsDist.includes('manifest.json')) - t.true(app2FunctionsDist.includes('server.zip')) - t.true(app2FunctionsDist.includes('worker.zip')) - }) -} + t.snapshot(normalizeOutput(output)) +}) + +test('Functions: loads functions generated with the Frameworks API in a monorepo setup', async (t) => { + const fixture = await new Fixture('./fixtures/functions_monorepo').withCopyRoot({ git: false }) + const app1 = await fixture + .withFlags({ + cwd: fixture.repositoryRoot, + packagePath: 'apps/app-1', + }) + .runWithBuildAndIntrospect() + + t.true(app1.success) + + const app2 = await fixture + .withFlags({ + cwd: fixture.repositoryRoot, + packagePath: 'apps/app-2', + }) + .runWithBuildAndIntrospect() + + t.true(app2.success) + + const app1FunctionsDist = await readdir(resolve(fixture.repositoryRoot, 'apps/app-1/.netlify/functions')) + t.is(app1FunctionsDist.length, 2) + t.true(app1FunctionsDist.includes('manifest.json')) + t.true(app1FunctionsDist.includes('server.zip')) + + const app2FunctionsDist = await readdir(resolve(fixture.repositoryRoot, 'apps/app-2/.netlify/functions')) + t.is(app2FunctionsDist.length, 3) + t.true(app2FunctionsDist.includes('manifest.json')) + t.true(app2FunctionsDist.includes('server.zip')) + t.true(app2FunctionsDist.includes('worker.zip')) +}) test('Functions: creates metadata file', async (t) => { const fixture = await new Fixture('./fixtures/v2').withCopyRoot({ git: false }) From 99d0155cf0320d23aa58538ac6e94923dddbf43c Mon Sep 17 00:00:00 2001 From: Mateusz Bocian Date: Tue, 29 Apr 2025 17:36:39 -0400 Subject: [PATCH 3/6] ci: remove npm@7 installation step --- .github/workflows/workflow.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 2323218c13..cae3805f4f 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -76,9 +76,6 @@ jobs: node-version: ${{ matrix.node-version }} cache: 'npm' if: ${{ !steps.release-check.outputs.IS_RELEASE }} - - name: Install npm@7 - run: npm install -g npm@7 - if: ${{ matrix.node-version == '18.14.0' && !steps.release-check.outputs.IS_RELEASE }} - name: Setup Deno uses: denoland/setup-deno@v1 with: @@ -167,9 +164,6 @@ jobs: node-version: ${{ matrix.node-version }} cache: 'npm' if: ${{ !steps.release-check.outputs.IS_RELEASE }} - - name: Install npm@7 - run: npm install -g npm@7 - if: ${{ matrix.node-version == '18.14.0' && !steps.release-check.outputs.IS_RELEASE }} - name: Set up Go uses: actions/setup-go@v5 with: From 075ae9b6318ce5884bbd434ed76c9a31a9fb15c3 Mon Sep 17 00:00:00 2001 From: Mateusz Bocian Date: Mon, 12 May 2025 13:50:57 -0400 Subject: [PATCH 4/6] test: restore test for min plugin version warning --- .../build/tests/plugins/fixtures/engines/package.json | 2 +- packages/build/tests/plugins/tests.js | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/build/tests/plugins/fixtures/engines/package.json b/packages/build/tests/plugins/fixtures/engines/package.json index 2592b5e111..8aa0c5ab3f 100644 --- a/packages/build/tests/plugins/fixtures/engines/package.json +++ b/packages/build/tests/plugins/fixtures/engines/package.json @@ -6,6 +6,6 @@ "license": "MIT", "repository": "test", "engines": { - "node": ">=18.0.0" + "node": ">=99.0.0" } } diff --git a/packages/build/tests/plugins/tests.js b/packages/build/tests/plugins/tests.js index 6f727685d0..efb481bae9 100644 --- a/packages/build/tests/plugins/tests.js +++ b/packages/build/tests/plugins/tests.js @@ -110,6 +110,17 @@ test('Validate --node-path unsupported version does not fail when no plugins are t.snapshot(normalizeOutput(output)) }) +test('Validate --node-path version is supported by the plugin', async (t) => { + const nodePath = getNodePath('16.14.0') + const output = await new Fixture('./fixtures/engines') + .withFlags({ + nodePath, + debug: false, + }) + .runWithBuild() + t.true(normalizeOutput(output).includes('The Node.js version is 1.0.0 but the plugin "./plugin.js" requires >=1.0.0')) +}) + test('Validate --node-path exists', async (t) => { const output = await new Fixture('./fixtures/node_version_simple') .withFlags({ nodePath: '/doesNotExist' }) From 1b9acc1ac51d7348ebd379165afa97c84fcc70cb Mon Sep 17 00:00:00 2001 From: Mateusz Bocian Date: Wed, 14 May 2025 11:28:19 -0400 Subject: [PATCH 5/6] ci: set up corepack after installing node --- .github/workflows/workflow.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index cae3805f4f..a33e2828ca 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -146,13 +146,6 @@ jobs: with: fetch-depth: 0 if: ${{ !steps.release-check.outputs.IS_RELEASE }} - - name: corepack update - # corepack version distributed with Node.js has a problem with new package manager releases, - # so forcing fixed version of corepack here - run: npm i -g corepack --force - - name: setup pnpm/yarn - run: corepack enable - if: ${{ !steps.release-check.outputs.IS_RELEASE }} - name: Setup Deno uses: denoland/setup-deno@v1 with: @@ -164,6 +157,13 @@ jobs: node-version: ${{ matrix.node-version }} cache: 'npm' if: ${{ !steps.release-check.outputs.IS_RELEASE }} + - name: corepack update + # corepack version distributed with Node.js has a problem with new package manager releases, + # so forcing fixed version of corepack here + run: npm i -g corepack --force + - name: setup pnpm/yarn + run: corepack enable + if: ${{ !steps.release-check.outputs.IS_RELEASE }} - name: Set up Go uses: actions/setup-go@v5 with: From 74d0fcff8689564e2530f7a22293ffa7f75721dd Mon Sep 17 00:00:00 2001 From: Mateusz Bocian Date: Wed, 14 May 2025 12:08:52 -0400 Subject: [PATCH 6/6] test: skip pnpm monorepo tests in node versions that don't support it --- packages/build/tests/blobs_upload/tests.js | 49 ++++++++------- packages/build/tests/frameworks_api/tests.js | 30 +++++---- packages/build/tests/functions/tests.js | 66 +++++++++++--------- 3 files changed, 78 insertions(+), 67 deletions(-) diff --git a/packages/build/tests/blobs_upload/tests.js b/packages/build/tests/blobs_upload/tests.js index 34a9c5ad23..5891c377ff 100644 --- a/packages/build/tests/blobs_upload/tests.js +++ b/packages/build/tests/blobs_upload/tests.js @@ -210,32 +210,35 @@ test.serial('Blobs upload step cancels deploy if blob metadata is malformed', as t.is(severityCode, 4) }) -test.serial('monorepo > blobs upload, uploads files to deploy store', async (t) => { - const fixture = await new Fixture('./fixtures/monorepo').withCopyRoot({ git: false }) - const { success } = await fixture - .withFlags({ deployId: 'abc123', siteId: 'test', token: TOKEN, offline: true, packagePath: 'apps/app-1' }) - .runBuildProgrammatic() +// the monorepo works with pnpm which is not always available +if (semver.gte(nodeVersion, '18.19.0')) { + test.serial('monorepo > blobs upload, uploads files to deploy store', async (t) => { + const fixture = await new Fixture('./fixtures/monorepo').withCopyRoot({ git: false }) + const { success } = await fixture + .withFlags({ deployId: 'abc123', siteId: 'test', token: TOKEN, offline: true, packagePath: 'apps/app-1' }) + .runBuildProgrammatic() - t.true(success) - t.is(t.context.blobRequests.set.length, 6) + t.true(success) + t.is(t.context.blobRequests.set.length, 6) - const storeOpts = { deployID: 'abc123', siteID: 'test', token: TOKEN } - if (semver.lt(nodeVersion, '18.0.0')) { - const nodeFetch = await import('node-fetch') - storeOpts.fetch = nodeFetch.default - } + const storeOpts = { deployID: 'abc123', siteID: 'test', token: TOKEN } + if (semver.lt(nodeVersion, '18.0.0')) { + const nodeFetch = await import('node-fetch') + storeOpts.fetch = nodeFetch.default + } - const store = getDeployStore(storeOpts) + const store = getDeployStore(storeOpts) - const blob1 = await store.getWithMetadata('something.txt') - t.is(blob1.data, 'some value') - t.deepEqual(blob1.metadata, {}) + const blob1 = await store.getWithMetadata('something.txt') + t.is(blob1.data, 'some value') + t.deepEqual(blob1.metadata, {}) - const blob2 = await store.getWithMetadata('with-metadata.txt') - t.is(blob2.data, 'another value') - t.deepEqual(blob2.metadata, { meta: 'data', number: 1234 }) + const blob2 = await store.getWithMetadata('with-metadata.txt') + t.is(blob2.data, 'another value') + t.deepEqual(blob2.metadata, { meta: 'data', number: 1234 }) - const blob3 = await store.getWithMetadata('nested/file.txt') - t.is(blob3.data, 'file value') - t.deepEqual(blob3.metadata, { some: 'metadata' }) -}) + const blob3 = await store.getWithMetadata('nested/file.txt') + t.is(blob3.data, 'file value') + t.deepEqual(blob3.metadata, { some: 'metadata' }) + }) +} diff --git a/packages/build/tests/frameworks_api/tests.js b/packages/build/tests/frameworks_api/tests.js index 572653309f..3a3108001b 100644 --- a/packages/build/tests/frameworks_api/tests.js +++ b/packages/build/tests/frameworks_api/tests.js @@ -1,9 +1,10 @@ import { promises as fs } from 'fs' import { dirname, resolve } from 'path' -import { platform } from 'process' +import { platform, version as nodeVersion } from 'process' import { Fixture } from '@netlify/testing' import test from 'ava' +import semver from 'semver' import tmp from 'tmp-promise' test('Does not mutate read-only properties', async (t) => { @@ -94,20 +95,23 @@ test('Loads configuration data that has been generated by the build command usin } }) -test('In a monorepo setup, loads package-specific configuration data', async (t) => { - const fixture = await new Fixture('./fixtures/monorepo').withCopyRoot({ git: false }) - const { success, netlifyConfig } = await fixture - .withFlags({ - cwd: fixture.repositoryRoot, - packagePath: 'apps/app-1', +// the monorepo works with pnpm which is not always available +if (semver.gte(nodeVersion, '18.19.0')) { + test('In a monorepo setup, loads package-specific configuration data', async (t) => { + const fixture = await new Fixture('./fixtures/monorepo').withCopyRoot({ git: false }) + const { success, netlifyConfig } = await fixture + .withFlags({ + cwd: fixture.repositoryRoot, + packagePath: 'apps/app-1', + }) + .runWithBuildAndIntrospect() + + t.true(success) + t.deepEqual(netlifyConfig.images, { + remote_images: ['domain1.netlify', 'domain2.netlify'], }) - .runWithBuildAndIntrospect() - - t.true(success) - t.deepEqual(netlifyConfig.images, { - remote_images: ['domain1.netlify', 'domain2.netlify'], }) -}) +} test('Configuration data is exposed to build plugins in the `onBuild` event', async (t) => { const { netlifyConfig, success } = await new Fixture('./fixtures/with_build_plugin').runWithBuildAndIntrospect() diff --git a/packages/build/tests/functions/tests.js b/packages/build/tests/functions/tests.js index 4d24880d67..57f86829ed 100644 --- a/packages/build/tests/functions/tests.js +++ b/packages/build/tests/functions/tests.js @@ -1,5 +1,6 @@ import { readdir, readFile, rm, stat, writeFile } from 'fs/promises' import { join, resolve } from 'path' +import { version as nodeVersion } from 'process' import { fileURLToPath } from 'url' import { Fixture, normalizeOutput, removeDir, getTempName, unzipFile } from '@netlify/testing' @@ -164,37 +165,40 @@ test('Functions: loads functions from the `.netlify/functions-internal` director t.snapshot(normalizeOutput(output)) }) -test('Functions: loads functions generated with the Frameworks API in a monorepo setup', async (t) => { - const fixture = await new Fixture('./fixtures/functions_monorepo').withCopyRoot({ git: false }) - const app1 = await fixture - .withFlags({ - cwd: fixture.repositoryRoot, - packagePath: 'apps/app-1', - }) - .runWithBuildAndIntrospect() - - t.true(app1.success) - - const app2 = await fixture - .withFlags({ - cwd: fixture.repositoryRoot, - packagePath: 'apps/app-2', - }) - .runWithBuildAndIntrospect() - - t.true(app2.success) - - const app1FunctionsDist = await readdir(resolve(fixture.repositoryRoot, 'apps/app-1/.netlify/functions')) - t.is(app1FunctionsDist.length, 2) - t.true(app1FunctionsDist.includes('manifest.json')) - t.true(app1FunctionsDist.includes('server.zip')) - - const app2FunctionsDist = await readdir(resolve(fixture.repositoryRoot, 'apps/app-2/.netlify/functions')) - t.is(app2FunctionsDist.length, 3) - t.true(app2FunctionsDist.includes('manifest.json')) - t.true(app2FunctionsDist.includes('server.zip')) - t.true(app2FunctionsDist.includes('worker.zip')) -}) +// the monorepo works with pnpm which is not always available +if (semver.gte(nodeVersion, '18.19.0')) { + test('Functions: loads functions generated with the Frameworks API in a monorepo setup', async (t) => { + const fixture = await new Fixture('./fixtures/functions_monorepo').withCopyRoot({ git: false }) + const app1 = await fixture + .withFlags({ + cwd: fixture.repositoryRoot, + packagePath: 'apps/app-1', + }) + .runWithBuildAndIntrospect() + + t.true(app1.success) + + const app2 = await fixture + .withFlags({ + cwd: fixture.repositoryRoot, + packagePath: 'apps/app-2', + }) + .runWithBuildAndIntrospect() + + t.true(app2.success) + + const app1FunctionsDist = await readdir(resolve(fixture.repositoryRoot, 'apps/app-1/.netlify/functions')) + t.is(app1FunctionsDist.length, 2) + t.true(app1FunctionsDist.includes('manifest.json')) + t.true(app1FunctionsDist.includes('server.zip')) + + const app2FunctionsDist = await readdir(resolve(fixture.repositoryRoot, 'apps/app-2/.netlify/functions')) + t.is(app2FunctionsDist.length, 3) + t.true(app2FunctionsDist.includes('manifest.json')) + t.true(app2FunctionsDist.includes('server.zip')) + t.true(app2FunctionsDist.includes('worker.zip')) + }) +} test('Functions: creates metadata file', async (t) => { const fixture = await new Fixture('./fixtures/v2').withCopyRoot({ git: false })