Update package.json versions as part of build step (#20579)
Fixes issue in the new build workflow where the experimental packages do not include "experimental" in the version string. This was because the previous approach relied on the RELEASE_CHANNEL environment variable, which we are no longer setting in the outer CI job, since we use the same job to build both channels. To solve, I moved the version post-processing into the build script itself. Only affects the new build workflow. Old workflow is unchanged. Longer term, I would like to remove version numbers from the source entirely, including the package.jsons. We should use a placeholder instead; that's mostly how it already works, since the release script swaps out the versions before we publish to stable.
Andrew Clark committed
Jan 13, 2021 at 11:54 UTC
e6ed2bcf424d0a25a8f628f7bb9962a29ec7d88f
2 files changed
+67
-11
.circleci/config.yml
+1
-5
@@ -168,11 +168,7 @@ jobs:
168
- checkout
169
- run: yarn workspaces info | head -n -1 > workspace_info.txt
170
- *restore_node_modules
171
- - run:
172
- command: |
173
- ./scripts/circleci/add_build_info_json.sh
174
- ./scripts/circleci/update_package_versions.sh
175
- yarn build-combined
171
+ - run: yarn build-combined
172
- persist_to_workspace:
173
root: build2
174
paths:
scripts/rollup/build-all-release-channels.js
+66
-6
@@ -4,11 +4,18 @@
4
5
const fs = require('fs');
6
const {spawnSync} = require('child_process');
7
+const path = require('path');
8
const tmp = require('tmp');
9
10
// Runs the build script for both stable and experimental release channels,
11
// by configuring an environment variable.
12
13
+const sha = (
14
+ spawnSync('git', ['show', '-s', '--format=%h']).stdout + ''
15
+).trim();
16
+const ReactVersion = JSON.parse(fs.readFileSync('packages/react/package.json'))
17
+ .version;
18
+
19
if (process.env.CIRCLE_NODE_TOTAL) {
20
// In CI, we use multiple concurrent processes. Allocate half the processes to
21
// build the stable channel, and the other half for experimental. Override
@@ -19,13 +26,19 @@ if (process.env.CIRCLE_NODE_TOTAL) {
26
if (index < halfTotal) {
27
const nodeTotal = halfTotal;
28
const nodeIndex = index;
29
+ const version = '0.0.0-' + sha;
30
+ updateTheReactVersionThatDevToolsReads(ReactVersion + '-' + sha);
31
buildForChannel('stable', nodeTotal, nodeIndex);
23
- processStable('./build');
32
+ processStable('./build', version);
33
} else {
34
const nodeTotal = total - halfTotal;
35
const nodeIndex = index - halfTotal;
36
+ const version = '0.0.0-experimental-' + sha;
37
+ updateTheReactVersionThatDevToolsReads(
38
+ ReactVersion + '-experimental-' + sha
39
+ );
40
buildForChannel('experimental', nodeTotal, nodeIndex);
28
- processExperimental('./build');
41
+ processExperimental('./build', version);
42
}
43
44
// TODO: Currently storing artifacts as `./build2` so that it doesn't conflict
@@ -34,15 +47,17 @@ if (process.env.CIRCLE_NODE_TOTAL) {
47
} else {
48
// Running locally, no concurrency. Move each channel's build artifacts into
49
// a temporary directory so that they don't conflict.
50
+ const stableVersion = '0.0.0-' + sha;
51
buildForChannel('stable', '', '');
52
const stableDir = tmp.dirSync().name;
53
fs.renameSync('./build', stableDir);
40
- processStable(stableDir);
54
+ processStable(stableDir, stableVersion);
55
56
+ const experimentalVersion = '0.0.0-experimental-' + sha;
57
buildForChannel('experimental', '', '');
58
const experimentalDir = tmp.dirSync().name;
59
fs.renameSync('./build', experimentalDir);
45
- processExperimental(experimentalDir);
60
+ processExperimental(experimentalDir, experimentalVersion);
61
62
// Then merge the experimental folder into the stable one. processExperimental
63
// will have already removed conflicting files.
@@ -68,8 +83,9 @@ function buildForChannel(channel, nodeTotal, nodeIndex) {
83
});
84
}
85
71
-function processStable(buildDir) {
86
+function processStable(buildDir, version) {
87
if (fs.existsSync(buildDir + '/node_modules')) {
88
+ updatePackageVersions(buildDir + '/node_modules', version);
89
fs.renameSync(buildDir + '/node_modules', buildDir + '/oss-stable');
90
}
91
@@ -88,8 +104,9 @@ function processStable(buildDir) {
104
}
105
}
106
91
-function processExperimental(buildDir) {
107
+function processExperimental(buildDir, version) {
108
if (fs.existsSync(buildDir + '/node_modules')) {
109
+ updatePackageVersions(buildDir + '/node_modules', version);
110
fs.renameSync(buildDir + '/node_modules', buildDir + '/oss-experimental');
111
}
112
@@ -121,3 +138,46 @@ function processExperimental(buildDir) {
138
}
139
}
140
}
141
+
142
+function updatePackageVersions(modulesDir, version) {
143
+ const allReactModuleNames = fs.readdirSync('packages');
144
+ for (const moduleName of fs.readdirSync(modulesDir)) {
145
+ const packageJSONPath = path.join(modulesDir, moduleName, 'package.json');
146
+ const stats = fs.statSync(packageJSONPath);
147
+ if (stats.isFile()) {
148
+ const packageInfo = JSON.parse(fs.readFileSync(packageJSONPath));
149
+
150
+ // Update version
151
+ packageInfo.version = version;
152
+
153
+ // Update dependency versions
154
+ if (packageInfo.dependencies) {
155
+ for (const dep of Object.keys(packageInfo.dependencies)) {
156
+ if (allReactModuleNames.includes(dep)) {
157
+ packageInfo.dependencies[dep] = version;
158
+ }
159
+ }
160
+ }
161
+ if (packageInfo.peerDependencies) {
162
+ for (const dep of Object.keys(packageInfo.peerDependencies)) {
163
+ if (allReactModuleNames.includes(dep)) {
164
+ packageInfo.peerDependencies[dep] = version;
165
+ }
166
+ }
167
+ }
168
+
169
+ // Write out updated package.json
170
+ fs.writeFileSync(packageJSONPath, JSON.stringify(packageInfo, null, 2));
171
+ }
172
+ }
173
+}
174
+
175
+function updateTheReactVersionThatDevToolsReads(version) {
176
+ // Overwrite the ReactVersion module before the build script runs so that it
177
+ // is included in the final bundles. This only runs in CI, so it's fine to
178
+ // edit the source file.
179
+ fs.writeFileSync(
180
+ './packages/shared/ReactVersion.js',
181
+ `export default '${version}';\n`
182
+ );
183
+}