Skip to content

Commit

Permalink
[core] Add react_next workflow in CircleCI (mui#13360)
Browse files Browse the repository at this point in the history
Co-authored-by: Lukas <llukas.tyla@gmail.com>
  • Loading branch information
2 people authored and DungTiger committed Jul 23, 2024
1 parent 97887e0 commit 94161b3
Show file tree
Hide file tree
Showing 4 changed files with 209 additions and 9 deletions.
61 changes: 53 additions & 8 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ parameters:
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.
type: boolean
default: false
react-dist-tag:
description: The dist-tag of react to be used
react-version:
description: The version of react to be used
type: string
default: stable
workflow:
Expand All @@ -20,10 +20,10 @@ parameters:

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

steps:
- run:
name: Resolve React version
command: |
node scripts/useReactVersion.mjs
# log a patch for maintainers who want to check out this change
git --no-pager diff HEAD
- when:
condition: << parameters.browsers >>
steps:
Expand Down Expand Up @@ -90,7 +97,17 @@ commands:
pnpm --version
- run:
name: Install js dependencies
command: pnpm install
command: |
echo "React version $REACT_VERSION"
if [ $REACT_VERSION == "stable" ];
then
echo "pnpm install"
pnpm install
else
echo "pnpm install --no-frozen-lockfile"
pnpm install --no-frozen-lockfile
fi
- when:
condition: << parameters.browsers >>
steps:
Expand Down Expand Up @@ -146,7 +163,7 @@ jobs:
command: |
curl -Os https://uploader.codecov.io/latest/linux/codecov
chmod +x codecov
./codecov -t ${CODECOV_TOKEN} -Z -F "$REACT_DIST_TAG-jsdom"
./codecov -t ${CODECOV_TOKEN} -Z -F "$REACT_VERSION-jsdom"
test_lint:
<<: *default-job
steps:
Expand Down Expand Up @@ -330,3 +347,31 @@ workflows:
- test_e2e_website:
requires:
- checkout

react-next:
when:
equal: [react-next, << pipeline.parameters.workflow >>]
# triggers:
# - schedule:
# cron: '0 0 * * *'
# filters:
# branches:
# only:
# - master
jobs:
- test_unit:
<<: *default-context
react-version: next
name: test_unit-react@next
- test_browser:
<<: *default-context
react-version: next
name: test_browser-react@next
- test_regressions:
<<: *default-context
react-version: next
name: test_regressions-react@next
- test_e2e:
<<: *default-context
react-version: next
name: test_e2e-react@next
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@
"@octokit/plugin-retry": "^7.1.1",
"@octokit/rest": "^21.0.0",
"@playwright/test": "^1.44.1",
"@types/babel__traverse": "^7.20.6",
"@types/babel__core": "^7.20.5",
"@types/babel__traverse": "^7.20.6",
"@types/chai": "^4.3.16",
"@types/chai-dom": "^1.11.3",
"@types/fs-extra": "^11.0.4",
Expand Down
109 changes: 109 additions & 0 deletions scripts/useReactVersion.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/* eslint-disable no-console */
/**
* Given the dist tag fetch the corresponding
* version and make sure this version is used throughout the repository.
*
* If you work on this file:
* WARNING: This script can only use built-in modules since it has to run before
* `pnpm install`
*/
import childProcess from 'child_process';
import fs from 'fs';
import os from 'os';
import path from 'path';
import { promisify } from 'util';
import { getWorkspaceRoot } from './utils.mjs';

// TODO: reuse the `useReactVersion.mjs` from the monorepo

const exec = promisify(childProcess.exec);

// packages published from the react monorepo using the same version
const reactPackageNames = ['react', 'react-dom', 'react-is', 'react-test-renderer', 'scheduler'];
const devDependenciesPackageNames = ['@testing-library/react'];

// if we need to support more versions we will need to add new mapping here
const additionalVersionsMappings = {
17: {
'@testing-library/react': '^12.1.0',
},
19: {},
};

async function main(version) {
if (typeof version !== 'string') {
throw new TypeError(`expected version: string but got '${version}'`);
}

if (version === 'stable') {
console.log('Nothing to do with stable');
return;
}

const packageJsonPath = path.resolve(getWorkspaceRoot(), 'package.json');
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, { encoding: 'utf8' }));

// the version is something in format: "17.0.0"
let majorVersion = null;

if (version.startsWith('^') || version.startsWith('~') || !Number.isNaN(version.charAt(0))) {
majorVersion = version.replace('^', '').replace('~', '').split('.')[0];
}

await Promise.all(
reactPackageNames.map(async (reactPackageName) => {
const { stdout: versions } = await exec(`npm dist-tag ls ${reactPackageName} ${version}`);
const tagMapping = versions.split('\n').find((mapping) => {
return mapping.startsWith(`${version}: `);
});

let packageVersion = null;

if (tagMapping === undefined) {
// Some specific version is being requested
if (majorVersion) {
packageVersion = version;
if (reactPackageName === 'scheduler') {
// get the scheduler version from the react-dom's dependencies entry
const { stdout: reactDOMDependenciesString } = await exec(
`npm view --json react-dom@${version} dependencies`,
);
packageVersion = JSON.parse(reactDOMDependenciesString).scheduler;
}
} else {
throw new Error(`Could not find '${version}' in "${versions}"`);
}
} else {
packageVersion = tagMapping.replace(`${version}: `, '');
}

packageJson.resolutions[reactPackageName] = packageVersion;
}),
);

// At this moment all dist tags reference React 18 version, so we don't need
// to update these dependencies unless an older version is used, or when the
// next/experimental dist tag reference to a future version of React
// packageJson.devDependencies['@testing-library/react'] = 'alpha';

if (majorVersion && additionalVersionsMappings[majorVersion]) {
devDependenciesPackageNames.forEach((packageName) => {
if (!additionalVersionsMappings[majorVersion][packageName]) {
throw new Error(
`Version ${majorVersion} does not have version defined for the ${packageName}`,
);
}
packageJson.devDependencies[packageName] =
additionalVersionsMappings[majorVersion][packageName];
});
}

// add newline for clean diff
fs.writeFileSync(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}${os.EOL}`);
}

const [version = process.env.REACT_VERSION] = process.argv.slice(2);
main(version).catch((error) => {
console.error(error);
process.exit(1);
});
46 changes: 46 additions & 0 deletions test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Testing

## Testing multiple versions of React

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:

1. `node scripts/useReactVersion.mjs <version>`.

Possible values for `version`:

- default: `stable` (minimum supported React version)
- a tag on npm, for example `next`, `experimental` or `latest`
- an older version, for example `^17.0.0`

2. `pnpm install`

### CI

#### `next` version

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:

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.
2. Click `Trigger Pipeline` button.
3. Expand `Add parameters (optional)` and add the following parameter:

| Parameter type | Name | Value |
| :------------- | :--------- | :----------- |
| `string` | `workflow` | `react-next` |

4. Click `Trigger Pipeline` button.

#### Other versions

You can pass the same `version` to our CircleCI pipeline as well:

With the following API request we're triggering a run of the default workflow in
PR #24289 for `react@next`

```bash
curl --request POST \
--url https://circleci.com/api/v2/project/gh/mui/mui-x/pipeline \
--header 'content-type: application/json' \
--header 'Circle-Token: $CIRCLE_TOKEN' \
--data-raw '{"branch":"pull/24289/head","parameters":{"react-version":"next"}}'
```

0 comments on commit 94161b3

Please sign in to comment.