From 65e569986d68ca41a74a7f86d367de21bc2afc4f Mon Sep 17 00:00:00 2001 From: Paul Rastoin <45004772+prastoin@users.noreply.github.com> Date: Thu, 27 Feb 2025 15:18:07 +0100 Subject: [PATCH] [ENHC] Create `Yarn` constraints to validate `node` version (#10542) ## Introduction This is PR is a suggestion ! And should be discussed With yarn `^4`, during installation won't raise an error if current dev env does not satisfies the `engines` policy. We have usually 10+ contributors support request regarding higher node version issue per week I would have preferred a very declarative integration using npm [engines](https://docs.npmjs.com/cli/v11/configuring-npm/package-json#engines) but this does not seems to be natively supported by `yarn` We should keep in mind that this might block any machines from our CICD if they have diff node version installed ( such as running the project on a different node version could result in bugs too ) ## Implem Created a yarn [constraints](https://yarnpkg.com/features/constraints) run after each installation that checking if current node version satisfies defined engines range ( might also be done for others engines entries ) I assume we will always have the same engines policy for every packages, at least that's not a consideration from now ## Further We could refactor our package.json engines into only one using `Yarn.set` etc ## Resource - https://yarnpkg.com/configuration/yarnrc - https://yarnpkg.com/features/constraints ## Note - Not running constraints in `preInstall` hook as won't be effective on fresh install - [engine-strict](https://docs.npmjs.com/cli/v8/using-npm/config#engine-strict) is an npm-config - [devEngines](https://docs.npmjs.com/cli/v11/configuring-npm/package-json#devengines) are npm feature too ( for instance pnpm current PR https://github.com/pnpm/pnpm/issues/8153 ) ## Conclusion As always any suggestions are more than welcomed ! --- .yarnrc.yml | 2 ++ package.json | 2 ++ yarn.config.cjs | 31 +++++++++++++++++++++++++++++++ yarn.lock | 10 ++++++++++ 4 files changed, 45 insertions(+) create mode 100644 yarn.config.cjs diff --git a/.yarnrc.yml b/.yarnrc.yml index a4ae24677..c4cbec52f 100644 --- a/.yarnrc.yml +++ b/.yarnrc.yml @@ -2,6 +2,8 @@ enableHardenedMode: true enableInlineHunks: true +enableConstraintsChecks: true + nodeLinker: node-modules yarnPath: .yarn/releases/yarn-4.4.0.cjs diff --git a/package.json b/package.json index 79261e146..3dfd1adc8 100644 --- a/package.json +++ b/package.json @@ -1,4 +1,5 @@ { + "private": true, "dependencies": { "@air/react-drag-to-select": "^5.0.8", "@apollo/client": "^3.7.17", @@ -293,6 +294,7 @@ "@typescript-eslint/utils": "6.21.0", "@vitejs/plugin-react-swc": "^3.5.0", "@vitest/ui": "1.4.0", + "@yarnpkg/types": "^4.0.0", "chromatic": "^6.18.0", "concurrently": "^8.2.2", "cross-var": "^1.1.0", diff --git a/yarn.config.cjs b/yarn.config.cjs new file mode 100644 index 000000000..a1b844a26 --- /dev/null +++ b/yarn.config.cjs @@ -0,0 +1,31 @@ +// @ts-check +/** @type {import('@yarnpkg/types')} */ +const { defineConfig, Yarn } = require('@yarnpkg/types'); +const semver = require('semver'); + +const MONOREPO_ROOT_WORKSPACE = 'twenty'; + +module.exports = defineConfig({ + async constraints({ Yarn }) { + const rootWorkspace = Yarn.workspace({ ident: MONOREPO_ROOT_WORKSPACE }); + if (!rootWorkspace) { + throw new Error( + `Should never occur, ${MONOREPO_ROOT_WORKSPACE} workspace not found`, + ); + } + + const requiredNodeVersion = rootWorkspace.manifest.engines?.node; + if (!requiredNodeVersion) { + throw new Error( + `Should never occur, ${requiredNodeVersion} could not find node range in engines manifest`, + ); + } + + const currentNodeVersion = process.version; + if (!semver.satisfies(currentNodeVersion, requiredNodeVersion)) { + throw new Error( + `Node version ${currentNodeVersion} doesn't match the required version, please use ${requiredNodeVersion}`, + ); + } + }, +}); diff --git a/yarn.lock b/yarn.lock index d49f0bb1b..21f785b2f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -19925,6 +19925,15 @@ __metadata: languageName: node linkType: hard +"@yarnpkg/types@npm:^4.0.0": + version: 4.0.0 + resolution: "@yarnpkg/types@npm:4.0.0" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10c0/41f67a4aa5c414c1e228f51453451fa15e0dd70c5cf2b1ae1ca142a3f018f25e4a37e60372cd0f5970c755e1804a2e31e208bff427add1cf13f899b0b9adc1e0 + languageName: node + linkType: hard + "@zapier/secret-scrubber@npm:^1.0.8": version: 1.1.1 resolution: "@zapier/secret-scrubber@npm:1.1.1" @@ -47239,6 +47248,7 @@ __metadata: "@vitest/ui": "npm:1.4.0" "@wyw-in-js/vite": "npm:^0.5.3" "@xyflow/react": "npm:^12.4.2" + "@yarnpkg/types": "npm:^4.0.0" add: "npm:^2.0.6" addressparser: "npm:^1.0.1" afterframe: "npm:^1.0.2"