Add CI job to check npm dependencies (#22881)
Checks that if one React package depends on another, the current version satisfies the given dependency range. That way we don't forget to bump dependencies when we release a new version.
Andrew Clark committed
Dec 8, 2021 at 02:09 UTC
06f403481fe1f30d6952ad60ecd759b410962926
3 files changed
+78
-2
.circleci/config.yml
+17
-1
@@ -205,11 +205,24 @@ jobs:
205
environment: *environment
206
steps:
207
- checkout
208
- - attach_workspace: *attach_workspace
208
+ - attach_workspace:
209
+ at: .
210
- run: yarn workspaces info | head -n -1 > workspace_info.txt
211
- *restore_node_modules
212
- run: yarn lint-build
213
214
+ yarn_check_release_dependencies:
215
+ docker: *docker
216
+ environment: *environment
217
+ steps:
218
+ - checkout
219
+ - attach_workspace:
220
+ at: .
221
+ - run: yarn workspaces info | head -n -1 > workspace_info.txt
222
+ - *restore_node_modules
223
+ - run: yarn check-release-dependencies
224
+
225
+
226
check_error_codes:
227
docker: *docker
228
environment: *environment
@@ -427,6 +440,9 @@ workflows:
440
- yarn_lint_build:
441
requires:
442
- yarn_build_combined
443
+ - yarn_check_release_dependencies:
444
+ requires:
445
+ - yarn_build_combined
446
- check_error_codes:
447
requires:
448
- yarn_build_combined
package.json
+2
-1
@@ -145,7 +145,8 @@
145
"publish-prereleases": "node ./scripts/release/publish-using-ci-workflow.js",
146
"download-build": "node ./scripts/release/download-experimental-build.js",
147
"download-build-for-head": "node ./scripts/release/download-experimental-build.js --commit=$(git rev-parse HEAD)",
148
- "download-build-in-codesandbox-ci": "cd scripts/release && yarn install && cd ../../ && yarn download-build-for-head || yarn build-combined --type=node react/index react-dom scheduler"
148
+ "download-build-in-codesandbox-ci": "cd scripts/release && yarn install && cd ../../ && yarn download-build-for-head || yarn build-combined --type=node react/index react-dom scheduler",
149
+ "check-release-dependencies": "node ./scripts/release/check-release-dependencies"
150
},
151
"resolutions": {
152
"react-is": "npm:react-is"
scripts/release/check-release-dependencies.js
new
+59
@@ -0,0 +1,59 @@
1
+'use strict';
2
+
3
+/* eslint-disable no-for-of-loops/no-for-of-loops */
4
+
5
+const fs = require('fs');
6
+const semver = require('semver');
7
+
8
+const {stablePackages} = require('../../ReactVersions');
9
+
10
+function main() {
11
+ if (!fs.existsSync('./build/oss-stable-semver')) {
12
+ throw new Error('No build artifacts found');
13
+ }
14
+
15
+ const packages = new Map();
16
+ for (const packageName in stablePackages) {
17
+ if (!fs.existsSync(`build/oss-stable-semver/${packageName}/package.json`)) {
18
+ throw new Error(`${packageName}`);
19
+ } else {
20
+ const info = JSON.parse(
21
+ fs.readFileSync(`build/oss-stable-semver/${packageName}/package.json`)
22
+ );
23
+ packages.set(info.name, info);
24
+ }
25
+ }
26
+
27
+ for (const [packageName, info] of packages) {
28
+ if (info.dependencies) {
29
+ for (const [depName, depRange] of Object.entries(info.dependencies)) {
30
+ if (packages.has(depName)) {
31
+ const releaseVersion = packages.get(depName).version;
32
+ checkDependency(packageName, depName, releaseVersion, depRange);
33
+ }
34
+ }
35
+ }
36
+
37
+ if (info.peerDependencies) {
38
+ for (const [depName, depRange] of Object.entries(info.peerDependencies)) {
39
+ if (packages.has(depName)) {
40
+ const releaseVersion = packages.get(depName).version;
41
+ checkDependency(packageName, depName, releaseVersion, depRange);
42
+ }
43
+ }
44
+ }
45
+ }
46
+}
47
+
48
+function checkDependency(packageName, depName, version, range) {
49
+ if (!semver.satisfies(version, range)) {
50
+ throw new Error(
51
+ `${packageName} has an invalid dependency on ${depName}: ${range}` +
52
+ '\n\n' +
53
+ 'Actual version is: ' +
54
+ version
55
+ );
56
+ }
57
+}
58
+
59
+main();