Skip to content

Commit 94161b3

Browse files
cherniavskiiLukasTy
authored andcommitted
[core] Add react_next workflow in CircleCI (mui#13360)
Co-authored-by: Lukas <[email protected]>
1 parent 97887e0 commit 94161b3

File tree

4 files changed

+209
-9
lines changed

4 files changed

+209
-9
lines changed

.circleci/config.yml

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ parameters:
55
description: Whether to force browserstack usage. We have limited resources on browserstack so the pipeline might decide to skip browserstack if this parameter isn't set to true.
66
type: boolean
77
default: false
8-
react-dist-tag:
9-
description: The dist-tag of react to be used
8+
react-version:
9+
description: The version of react to be used
1010
type: string
1111
default: stable
1212
workflow:
@@ -20,10 +20,10 @@ parameters:
2020

2121
default-job: &default-job
2222
parameters:
23-
react-dist-tag:
24-
description: The dist-tag of react to be used
23+
react-version:
24+
description: The version of react to be used
2525
type: string
26-
default: << pipeline.parameters.react-dist-tag >>
26+
default: << pipeline.parameters.react-version >>
2727
e2e-base-url:
2828
description: The base url for running end-to-end test
2929
type: string
@@ -33,7 +33,7 @@ default-job: &default-job
3333
PLAYWRIGHT_BROWSERS_PATH: /tmp/pw-browsers
3434
# expose it globally otherwise we have to thread it from each job to the install command
3535
BROWSERSTACK_FORCE: << pipeline.parameters.browserstack-force >>
36-
REACT_DIST_TAG: << parameters.react-dist-tag >>
36+
REACT_VERSION: << parameters.react-version >>
3737
working_directory: /tmp/mui
3838
docker:
3939
- image: cimg/node:18.20
@@ -59,6 +59,13 @@ commands:
5959
description: 'Set to true if you intend to any browser (for example with playwright).'
6060

6161
steps:
62+
- run:
63+
name: Resolve React version
64+
command: |
65+
node scripts/useReactVersion.mjs
66+
# log a patch for maintainers who want to check out this change
67+
git --no-pager diff HEAD
68+
6269
- when:
6370
condition: << parameters.browsers >>
6471
steps:
@@ -90,7 +97,17 @@ commands:
9097
pnpm --version
9198
- run:
9299
name: Install js dependencies
93-
command: pnpm install
100+
command: |
101+
echo "React version $REACT_VERSION"
102+
if [ $REACT_VERSION == "stable" ];
103+
then
104+
echo "pnpm install"
105+
pnpm install
106+
else
107+
echo "pnpm install --no-frozen-lockfile"
108+
pnpm install --no-frozen-lockfile
109+
fi
110+
94111
- when:
95112
condition: << parameters.browsers >>
96113
steps:
@@ -146,7 +163,7 @@ jobs:
146163
command: |
147164
curl -Os https://uploader.codecov.io/latest/linux/codecov
148165
chmod +x codecov
149-
./codecov -t ${CODECOV_TOKEN} -Z -F "$REACT_DIST_TAG-jsdom"
166+
./codecov -t ${CODECOV_TOKEN} -Z -F "$REACT_VERSION-jsdom"
150167
test_lint:
151168
<<: *default-job
152169
steps:
@@ -330,3 +347,31 @@ workflows:
330347
- test_e2e_website:
331348
requires:
332349
- checkout
350+
351+
react-next:
352+
when:
353+
equal: [react-next, << pipeline.parameters.workflow >>]
354+
# triggers:
355+
# - schedule:
356+
# cron: '0 0 * * *'
357+
# filters:
358+
# branches:
359+
# only:
360+
# - master
361+
jobs:
362+
- test_unit:
363+
<<: *default-context
364+
react-version: next
365+
name: test_unit-react@next
366+
- test_browser:
367+
<<: *default-context
368+
react-version: next
369+
name: test_browser-react@next
370+
- test_regressions:
371+
<<: *default-context
372+
react-version: next
373+
name: test_regressions-react@next
374+
- test_e2e:
375+
<<: *default-context
376+
react-version: next
377+
name: test_e2e-react@next

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,8 @@
9595
"@octokit/plugin-retry": "^7.1.1",
9696
"@octokit/rest": "^21.0.0",
9797
"@playwright/test": "^1.44.1",
98-
"@types/babel__traverse": "^7.20.6",
9998
"@types/babel__core": "^7.20.5",
99+
"@types/babel__traverse": "^7.20.6",
100100
"@types/chai": "^4.3.16",
101101
"@types/chai-dom": "^1.11.3",
102102
"@types/fs-extra": "^11.0.4",

scripts/useReactVersion.mjs

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/* eslint-disable no-console */
2+
/**
3+
* Given the dist tag fetch the corresponding
4+
* version and make sure this version is used throughout the repository.
5+
*
6+
* If you work on this file:
7+
* WARNING: This script can only use built-in modules since it has to run before
8+
* `pnpm install`
9+
*/
10+
import childProcess from 'child_process';
11+
import fs from 'fs';
12+
import os from 'os';
13+
import path from 'path';
14+
import { promisify } from 'util';
15+
import { getWorkspaceRoot } from './utils.mjs';
16+
17+
// TODO: reuse the `useReactVersion.mjs` from the monorepo
18+
19+
const exec = promisify(childProcess.exec);
20+
21+
// packages published from the react monorepo using the same version
22+
const reactPackageNames = ['react', 'react-dom', 'react-is', 'react-test-renderer', 'scheduler'];
23+
const devDependenciesPackageNames = ['@testing-library/react'];
24+
25+
// if we need to support more versions we will need to add new mapping here
26+
const additionalVersionsMappings = {
27+
17: {
28+
'@testing-library/react': '^12.1.0',
29+
},
30+
19: {},
31+
};
32+
33+
async function main(version) {
34+
if (typeof version !== 'string') {
35+
throw new TypeError(`expected version: string but got '${version}'`);
36+
}
37+
38+
if (version === 'stable') {
39+
console.log('Nothing to do with stable');
40+
return;
41+
}
42+
43+
const packageJsonPath = path.resolve(getWorkspaceRoot(), 'package.json');
44+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, { encoding: 'utf8' }));
45+
46+
// the version is something in format: "17.0.0"
47+
let majorVersion = null;
48+
49+
if (version.startsWith('^') || version.startsWith('~') || !Number.isNaN(version.charAt(0))) {
50+
majorVersion = version.replace('^', '').replace('~', '').split('.')[0];
51+
}
52+
53+
await Promise.all(
54+
reactPackageNames.map(async (reactPackageName) => {
55+
const { stdout: versions } = await exec(`npm dist-tag ls ${reactPackageName} ${version}`);
56+
const tagMapping = versions.split('\n').find((mapping) => {
57+
return mapping.startsWith(`${version}: `);
58+
});
59+
60+
let packageVersion = null;
61+
62+
if (tagMapping === undefined) {
63+
// Some specific version is being requested
64+
if (majorVersion) {
65+
packageVersion = version;
66+
if (reactPackageName === 'scheduler') {
67+
// get the scheduler version from the react-dom's dependencies entry
68+
const { stdout: reactDOMDependenciesString } = await exec(
69+
`npm view --json react-dom@${version} dependencies`,
70+
);
71+
packageVersion = JSON.parse(reactDOMDependenciesString).scheduler;
72+
}
73+
} else {
74+
throw new Error(`Could not find '${version}' in "${versions}"`);
75+
}
76+
} else {
77+
packageVersion = tagMapping.replace(`${version}: `, '');
78+
}
79+
80+
packageJson.resolutions[reactPackageName] = packageVersion;
81+
}),
82+
);
83+
84+
// At this moment all dist tags reference React 18 version, so we don't need
85+
// to update these dependencies unless an older version is used, or when the
86+
// next/experimental dist tag reference to a future version of React
87+
// packageJson.devDependencies['@testing-library/react'] = 'alpha';
88+
89+
if (majorVersion && additionalVersionsMappings[majorVersion]) {
90+
devDependenciesPackageNames.forEach((packageName) => {
91+
if (!additionalVersionsMappings[majorVersion][packageName]) {
92+
throw new Error(
93+
`Version ${majorVersion} does not have version defined for the ${packageName}`,
94+
);
95+
}
96+
packageJson.devDependencies[packageName] =
97+
additionalVersionsMappings[majorVersion][packageName];
98+
});
99+
}
100+
101+
// add newline for clean diff
102+
fs.writeFileSync(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}${os.EOL}`);
103+
}
104+
105+
const [version = process.env.REACT_VERSION] = process.argv.slice(2);
106+
main(version).catch((error) => {
107+
console.error(error);
108+
process.exit(1);
109+
});

test/README.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Testing
2+
3+
## Testing multiple versions of React
4+
5+
You can check integration of different versions of React (for example different [release channels](https://react.dev/community/versioning-policy) or PRs to React) by running the following commands:
6+
7+
1. `node scripts/useReactVersion.mjs <version>`.
8+
9+
Possible values for `version`:
10+
11+
- default: `stable` (minimum supported React version)
12+
- a tag on npm, for example `next`, `experimental` or `latest`
13+
- an older version, for example `^17.0.0`
14+
15+
2. `pnpm install`
16+
17+
### CI
18+
19+
#### `next` version
20+
21+
For `react@next` specifically, there's a `react-next` workflow in our CircleCI pipeline that you can trigger in CircleCI on the PR you want to test:
22+
23+
1. Go to https://app.circleci.com/pipelines/github/mui/mui-x?branch=pull/PR_NUMBER and replace `PR_NUMBER` with the PR number you want to test.
24+
2. Click `Trigger Pipeline` button.
25+
3. Expand `Add parameters (optional)` and add the following parameter:
26+
27+
| Parameter type | Name | Value |
28+
| :------------- | :--------- | :----------- |
29+
| `string` | `workflow` | `react-next` |
30+
31+
4. Click `Trigger Pipeline` button.
32+
33+
#### Other versions
34+
35+
You can pass the same `version` to our CircleCI pipeline as well:
36+
37+
With the following API request we're triggering a run of the default workflow in
38+
PR #24289 for `react@next`
39+
40+
```bash
41+
curl --request POST \
42+
--url https://circleci.com/api/v2/project/gh/mui/mui-x/pipeline \
43+
--header 'content-type: application/json' \
44+
--header 'Circle-Token: $CIRCLE_TOKEN' \
45+
--data-raw '{"branch":"pull/24289/head","parameters":{"react-version":"next"}}'
46+
```

0 commit comments

Comments
 (0)