Skip to content

Commit 3d4fad5

Browse files
committed
[ci] Parallelize yarn build and yarn lint-build
ghstack-source-id: fc61ba266b164d9bf3831d4d6e37da261481a916 Pull Request resolved: #30071
1 parent f748eb7 commit 3d4fad5

File tree

4 files changed

+995
-49
lines changed

4 files changed

+995
-49
lines changed

.circleci/config.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ jobs:
9797
steps:
9898
- checkout
9999
- setup_node_modules
100-
- run: yarn build
100+
- run: yarn build --ci=circleci
101101
- persist_to_workspace:
102102
root: .
103103
paths:

.github/workflows/runtime_build.yml

+39-12
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,34 @@ on:
88
- 'compiler/**'
99

1010
jobs:
11+
define_build_params:
12+
name: Build build params
13+
runs-on: ubuntu-latest
14+
outputs:
15+
bundle_type: ${{ steps.define_bundle_types.outputs.result }}
16+
release_channel: ${{ steps.define_release_channels.outputs.result }}
17+
steps:
18+
- uses: actions/checkout@v4
19+
- uses: actions/github-script@v7
20+
id: define_bundle_types
21+
with:
22+
script: |
23+
const {bundleTypes} = require('./scripts/rollup/bundles');
24+
return Object.values(bundleTypes);
25+
- uses: actions/github-script@v7
26+
id: define_release_channels
27+
with:
28+
script: |
29+
return ['stable', 'experimental'];
30+
1131
build:
1232
name: yarn build
1333
runs-on: ubuntu-latest
34+
needs: define_build_params
35+
strategy:
36+
matrix:
37+
bundle_type: ${{ fromJSON(needs.define_build_params.outputs.bundle_type) }}
38+
release_channel: ${{ fromJSON(needs.define_build_params.outputs.release_channel) }}
1439
steps:
1540
- uses: actions/checkout@v4
1641
- uses: actions/setup-node@v4
@@ -25,17 +50,21 @@ jobs:
2550
path: "**/node_modules"
2651
key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }}
2752
- run: yarn install --frozen-lockfile
28-
- run: yarn build
29-
- name: Cache build
30-
uses: actions/cache@v4
31-
id: build_cache
53+
- run: yarn build --b=${{ matrix.bundle_type }} --r=${{ matrix.release_channel }} --ci=github
54+
- name: Archive build
55+
uses: actions/upload-artifact@v4
3256
with:
33-
path: "build/**"
34-
key: yarn-build-${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }}
57+
name: ${{ matrix.bundle_type }}-${{ matrix.release_channel }}
58+
path: |
59+
build/**
3560
3661
lint_build:
3762
name: yarn lint-build
38-
needs: build
63+
needs: [define_build_params, build]
64+
strategy:
65+
matrix:
66+
bundle_type: ${{ fromJSON(needs.define_build_params.outputs.bundle_type) }}
67+
release_channel: ${{ fromJSON(needs.define_build_params.outputs.release_channel) }}
3968
runs-on: ubuntu-latest
4069
steps:
4170
- uses: actions/checkout@v4
@@ -50,11 +79,9 @@ jobs:
5079
with:
5180
path: "**/node_modules"
5281
key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }}
53-
- name: Restore cached build
54-
uses: actions/cache@v4
55-
id: build_cache
82+
- name: Restore archived build
83+
uses: actions/download-artifact@v4
5684
with:
57-
path: "build/**"
58-
key: yarn-build-${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }}
85+
name: ${{ matrix.bundle_type }}-${{ matrix.release_channel }}
5986
- run: yarn install --frozen-lockfile
6087
- run: yarn lint-build

scripts/rollup/build-all-release-channels.js

+84-36
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ const {
1515
canaryChannelLabel,
1616
rcNumber,
1717
} = require('../../ReactVersions');
18+
const yargs = require('yargs');
19+
const Bundles = require('./bundles');
20+
const {buildEverything} = require('./build-ghaction');
1821

1922
// Runs the build script for both stable and experimental release channels,
2023
// by configuring an environment variable.
@@ -53,44 +56,87 @@ fs.writeFileSync(
5356
`export default '${PLACEHOLDER_REACT_VERSION}';\n`
5457
);
5558

56-
if (process.env.CIRCLE_NODE_TOTAL) {
57-
// In CI, we use multiple concurrent processes. Allocate half the processes to
58-
// build the stable channel, and the other half for experimental. Override
59-
// the environment variables to "trick" the underlying build script.
60-
const total = parseInt(process.env.CIRCLE_NODE_TOTAL, 10);
61-
const halfTotal = Math.floor(total / 2);
62-
const index = parseInt(process.env.CIRCLE_NODE_INDEX, 10);
63-
if (index < halfTotal) {
64-
const nodeTotal = halfTotal;
65-
const nodeIndex = index;
66-
buildForChannel('stable', nodeTotal, nodeIndex);
67-
processStable('./build');
59+
const argv = yargs.wrap(yargs.terminalWidth()).options({
60+
releaseChannel: {
61+
alias: 'r',
62+
describe: 'Build the given release channel.',
63+
requiresArg: true,
64+
type: 'string',
65+
default: 'experimental',
66+
choices: ['experimental', 'stable'],
67+
},
68+
bundleType: {
69+
alias: 'b',
70+
describe: 'Build the given bundle type.',
71+
requiresArg: true,
72+
type: 'string',
73+
choices: Object.values(Bundles.bundleTypes),
74+
},
75+
ci: {
76+
describe: 'Run tests in CI',
77+
requiresArg: false,
78+
type: 'choices',
79+
choices: ['circleci', 'github'],
80+
},
81+
}).argv;
82+
83+
async function main() {
84+
if (argv.ci === 'github') {
85+
// ./scripts/rollup/build was being used by spawning a new process and passing via ENV variables
86+
// so let's just preserve this for now and rewrite it later to just take a function arg
87+
process.env.RELEASE_CHANNEL = argv.releaseChannel;
88+
await buildEverything(argv.bundleType);
89+
switch (argv.releaseChannel) {
90+
case 'stable': {
91+
processStable('./build');
92+
break;
93+
}
94+
case 'experimental': {
95+
processExperimental('./build');
96+
break;
97+
}
98+
default:
99+
throw new Error(`Unknown release channel ${argv.releaseChannel}`);
100+
}
101+
} else if (argv.ci === 'circleci') {
102+
// In CI, we use multiple concurrent processes. Allocate half the processes to
103+
// build the stable channel, and the other half for experimental. Override
104+
// the environment variables to "trick" the underlying build script.
105+
const total = parseInt(process.env.CIRCLE_NODE_TOTAL, 10);
106+
const halfTotal = Math.floor(total / 2);
107+
const index = parseInt(process.env.CIRCLE_NODE_INDEX, 10);
108+
if (index < halfTotal) {
109+
const nodeTotal = halfTotal;
110+
const nodeIndex = index;
111+
buildForChannel('stable', nodeTotal, nodeIndex);
112+
processStable('./build');
113+
} else {
114+
const nodeTotal = total - halfTotal;
115+
const nodeIndex = index - halfTotal;
116+
buildForChannel('experimental', nodeTotal, nodeIndex);
117+
processExperimental('./build');
118+
}
68119
} else {
69-
const nodeTotal = total - halfTotal;
70-
const nodeIndex = index - halfTotal;
71-
buildForChannel('experimental', nodeTotal, nodeIndex);
72-
processExperimental('./build');
120+
// Running locally, no concurrency. Move each channel's build artifacts into
121+
// a temporary directory so that they don't conflict.
122+
buildForChannel('stable', '', '');
123+
const stableDir = tmp.dirSync().name;
124+
crossDeviceRenameSync('./build', stableDir);
125+
processStable(stableDir);
126+
buildForChannel('experimental', '', '');
127+
const experimentalDir = tmp.dirSync().name;
128+
crossDeviceRenameSync('./build', experimentalDir);
129+
processExperimental(experimentalDir);
130+
131+
// Then merge the experimental folder into the stable one. processExperimental
132+
// will have already removed conflicting files.
133+
//
134+
// In CI, merging is handled automatically by CircleCI's workspace feature.
135+
mergeDirsSync(experimentalDir + '/', stableDir + '/');
136+
137+
// Now restore the combined directory back to its original name
138+
crossDeviceRenameSync(stableDir, './build');
73139
}
74-
} else {
75-
// Running locally, no concurrency. Move each channel's build artifacts into
76-
// a temporary directory so that they don't conflict.
77-
buildForChannel('stable', '', '');
78-
const stableDir = tmp.dirSync().name;
79-
crossDeviceRenameSync('./build', stableDir);
80-
processStable(stableDir);
81-
buildForChannel('experimental', '', '');
82-
const experimentalDir = tmp.dirSync().name;
83-
crossDeviceRenameSync('./build', experimentalDir);
84-
processExperimental(experimentalDir);
85-
86-
// Then merge the experimental folder into the stable one. processExperimental
87-
// will have already removed conflicting files.
88-
//
89-
// In CI, merging is handled automatically by CircleCI's workspace feature.
90-
mergeDirsSync(experimentalDir + '/', stableDir + '/');
91-
92-
// Now restore the combined directory back to its original name
93-
crossDeviceRenameSync(stableDir, './build');
94140
}
95141

96142
function buildForChannel(channel, nodeTotal, nodeIndex) {
@@ -457,3 +503,5 @@ function mergeDirsSync(source, destination) {
457503
}
458504
}
459505
}
506+
507+
main();

0 commit comments

Comments
 (0)