Skip to content

Commit e4135e9

Browse files
huntiefacebook-github-bot
authored andcommitted
Update test-e2e-local to use source monorepo packages for RNTestProject (#42899)
Summary: Pull Request resolved: #42899 Updates the `test-e2e-local` script to bootstrap `/tmp/RNTestProject/` using the currently checked out repository as the source of truth for all monorepo packages (previously we only did this for the `react-native` package). This enables release testers to validate a release **before** physically publishing new dependency versions via `yarn bump-all-updated-packages`. We are able to reuse the `scripts/template/initialize.js` script that is currently used for E2E validation in CI. This sets up a local Verdaccio server during project install. NOTE: The time taken for `Build packages` + Verdaccio isn't ideal, I may explore a way to reuse the published package state in a future diff. Until then, this extra time (~1 min) will still be much less pain than the `bump-all-updated-packages` + commit process loop. Changelog: [Internal] - Update test-e2e-local to use source monorepo packages for RNTestProject Reviewed By: lunaleaps Differential Revision: D53484510 fbshipit-source-id: 600a8a3257a4947d7738ab9d908d6549c38545e6
1 parent 1570062 commit e4135e9

File tree

6 files changed

+110
-65
lines changed

6 files changed

+110
-65
lines changed

.circleci/configurations/jobs.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ jobs:
360360
command: |
361361
REPO_ROOT=$(pwd)
362362
node ./scripts/releases/update-template-package.js "{\"react-native\":\"file:$REPO_ROOT/build/$(cat build/react-native-package-version)\"}"
363-
node ./scripts/template/initialize.js --projectName $PROJECT_NAME --templatePath "$REPO_ROOT/packages/react-native" --directory "/tmp/$PROJECT_NAME"
363+
node ./scripts/template/initialize.js --projectName $PROJECT_NAME --templatePath "$REPO_ROOT/packages/react-native" --directory "/tmp/$PROJECT_NAME" --verbose
364364
- with_gradle_cache:
365365
steps:
366366
- run:
@@ -458,7 +458,7 @@ jobs:
458458
PACKAGE=$(cat build/react-native-package-version)
459459
PATH_TO_PACKAGE="$REPO_ROOT/build/$PACKAGE"
460460
node ./scripts/releases/update-template-package.js "{\"react-native\":\"file:$PATH_TO_PACKAGE\"}"
461-
node ./scripts/template/initialize.js --projectName $PROJECT_NAME --templatePath "$REPO_ROOT/packages/react-native" --directory "/tmp/$PROJECT_NAME"
461+
node ./scripts/template/initialize.js --projectName $PROJECT_NAME --templatePath "$REPO_ROOT/packages/react-native" --directory "/tmp/$PROJECT_NAME" --verbose
462462
- with_xcodebuild_cache:
463463
podfile_lock_path: << parameters.podfile_lock_path >>
464464
pods_build_folder: << parameters.pods_build_folder >>

scripts/release-testing/test-e2e-local-clean.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
* - an option to uninstall the apps (RNTester, RNTestProject) from emulators
3030
*/
3131

32+
const {VERDACCIO_STORAGE_PATH} = require('../template/setup-verdaccio');
3233
const {isPackagerRunning} = require('./utils/testing-utils');
3334
const {exec, exit} = require('shelljs');
3435

@@ -61,6 +62,9 @@ exec('rm -rf packages/rn-tester/Pods');
6162
console.info('\n** Removing the RNTestProject folder **\n');
6263
exec('rm -rf /tmp/RNTestProject');
6364

65+
console.info('\n** Removing Verdaccio storage directory **\n');
66+
exec(`rm -rf ${VERDACCIO_STORAGE_PATH}`);
67+
6468
// final clean up
6569
console.info('\n** Final git level wipe **\n');
6670
// clean unstaged changes from git

scripts/release-testing/test-e2e-local.js

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@
1818
*/
1919

2020
const updateTemplatePackage = require('../releases/update-template-package');
21+
const {initNewProjectFromSource} = require('../template/initialize');
2122
const {
2223
checkPackagerRunning,
2324
launchPackagerInSeparateWindow,
2425
maybeLaunchAndroidEmulator,
2526
prepareArtifacts,
2627
setupCircleCIArtifacts,
2728
} = require('./utils/testing-utils');
29+
const debug = require('debug')('test-e2e-local');
2830
const fs = require('fs');
2931
const path = require('path');
3032
const {cd, exec, popd, pushd, pwd, sed} = require('shelljs');
@@ -34,6 +36,8 @@ const yargs = require('yargs');
3436
type Unwrap<T> = T extends Promise<infer U> ? U : T;
3537
*/
3638

39+
const REPO_ROOT = path.resolve(__dirname, '../..');
40+
3741
const argv = yargs
3842
.option('t', {
3943
alias: 'target',
@@ -211,9 +215,7 @@ async function testRNTestProject(
211215
const releaseVersion = `1000.0.0-${shortCommit}`;
212216
const buildType = 'dry-run';
213217

214-
// Prepare some variables for later use
215-
const repoRoot = pwd().toString();
216-
const reactNativePackagePath = `${repoRoot}/packages/react-native`;
218+
const reactNativePackagePath = `${REPO_ROOT}/packages/react-native`;
217219
const localNodeTGZPath = `${reactNativePackagePath}/react-native-${releaseVersion}.tgz`;
218220

219221
const mavenLocalPath =
@@ -256,13 +258,16 @@ async function testRNTestProject(
256258
});
257259

258260
pushd('/tmp/');
259-
// need to avoid the pod install step - we'll do it later
260-
exec(
261-
`node ${reactNativePackagePath}/cli.js init RNTestProject --template ${reactNativePackagePath} --skip-install`,
262-
);
261+
262+
debug('Creating RNTestProject from template');
263+
264+
await initNewProjectFromSource({
265+
projectName: 'RNTestProject',
266+
directory: '/tmp/RNTestProject',
267+
templatePath: reactNativePackagePath,
268+
});
263269

264270
cd('RNTestProject');
265-
exec('yarn install');
266271

267272
// When using CircleCI artifacts, the CI will zip maven local into a
268273
// /tmp/maven-local subfolder struct.
@@ -336,5 +341,7 @@ async function main() {
336341
}
337342
}
338343

339-
// $FlowIgnoreError[unused-promise]
340-
main();
344+
if (require.main === module) {
345+
// eslint-disable-next-line no-void
346+
void main();
347+
}

scripts/run-ci-e2e-tests.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
*/
2121

2222
const forEachPackage = require('./monorepo/for-each-package');
23-
const setupVerdaccio = require('./template/setup-verdaccio');
23+
const {setupVerdaccio} = require('./template/setup-verdaccio');
2424
const tryExecNTimes = require('./try-n-times');
2525
const {execFileSync, spawn} = require('child_process');
2626
const fs = require('fs');

scripts/template/initialize.js

Lines changed: 81 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -13,26 +13,31 @@
1313

1414
const {retry} = require('../circleci/retry');
1515
const forEachPackage = require('../monorepo/for-each-package');
16-
const setupVerdaccio = require('./setup-verdaccio');
16+
const {
17+
VERDACCIO_SERVER_URL,
18+
VERDACCIO_STORAGE_PATH,
19+
setupVerdaccio,
20+
} = require('./setup-verdaccio');
1721
const {parseArgs} = require('@pkgjs/parseargs');
22+
const chalk = require('chalk');
1823
const {execSync} = require('child_process');
1924
const path = require('path');
2025

2126
const REPO_ROOT = path.resolve(__dirname, '../..');
22-
const NPM_REGISTRY_SERVER = 'http://localhost:4873';
2327

2428
const config = {
2529
options: {
2630
projectName: {type: 'string'},
2731
templatePath: {type: 'string'},
2832
directory: {type: 'string'},
33+
verbose: {type: 'boolean', default: false},
2934
help: {type: 'boolean'},
3035
},
3136
};
3237

3338
async function main() {
3439
const {
35-
values: {help, projectName, templatePath, directory},
40+
values: {help, ...options},
3641
} = parseArgs(config);
3742

3843
if (help) {
@@ -55,94 +60,119 @@ async function main() {
5560
--projectName The name of the new React Native project.
5661
--templatePath The absolute path to the folder containing the template.
5762
--directory The absolute path to the target project directory.
63+
--verbose Print additional output. Default: false.
5864
`);
5965
return;
6066
}
6167

62-
const VERDACCIO_PID = setupVerdaccio();
68+
await initNewProjectFromSource(options);
69+
}
6370

64-
try {
65-
process.stdout.write('Bootstrapped Verdaccio \u2705\n');
71+
async function initNewProjectFromSource(
72+
{
73+
projectName,
74+
templatePath,
75+
directory,
76+
verbose = false,
77+
} /*: {projectName: string, templatePath: string, directory: string, verbose?: boolean} */,
78+
) {
79+
console.log('Starting local npm proxy (Verdaccio)');
80+
const verdaccioPid = setupVerdaccio();
81+
console.log('Done ✅');
6682

67-
process.stdout.write('Building packages...\n');
83+
try {
6884
execSync('node ./scripts/build/build.js', {
6985
cwd: REPO_ROOT,
70-
stdio: [process.stdin, process.stdout, process.stderr],
86+
stdio: 'inherit',
7187
});
88+
console.log('\nDone ✅');
7289

73-
process.stdout.write('Starting to publish every package...\n');
90+
console.log('Publishing packages to local npm proxy\n');
7491
forEachPackage(
7592
(packageAbsolutePath, packageRelativePathFromRoot, packageManifest) => {
7693
if (packageManifest.private) {
7794
return;
7895
}
7996

97+
const desc = `${packageManifest.name} (${packageRelativePathFromRoot})`;
98+
process.stdout.write(
99+
`${desc} ${chalk.dim('.').repeat(Math.max(0, 72 - desc.length))} `,
100+
);
80101
execSync(
81-
`npm publish --registry ${NPM_REGISTRY_SERVER} --access public`,
102+
`npm publish --registry ${VERDACCIO_SERVER_URL} --access public`,
82103
{
83104
cwd: packageAbsolutePath,
84-
stdio: [process.stdin, process.stdout, process.stderr],
105+
stdio: verbose ? 'inherit' : [process.stderr],
85106
},
86107
);
87-
88-
process.stdout.write(
89-
`Published ${packageManifest.name} to proxy \u2705\n`,
90-
);
108+
process.stdout.write(chalk.reset.inverse.bold.green(' DONE ') + '\n');
91109
},
92110
);
111+
console.log('\nDone ✅');
93112

94-
process.stdout.write('Published every package \u2705\n');
95-
113+
console.log('Running react-native init without install');
96114
execSync(
97-
`node cli.js init ${projectName} \
115+
`node ./packages/react-native/cli.js init ${projectName} \
98116
--directory ${directory} \
99117
--template ${templatePath} \
100118
--verbose \
101119
--skip-install \
102-
--yarn-config-options npmRegistryServer="${NPM_REGISTRY_SERVER}"`,
120+
--yarn-config-options npmRegistryServer="${VERDACCIO_SERVER_URL}"`,
103121
{
104-
cwd: `${REPO_ROOT}/packages/react-native`,
105-
stdio: [process.stdin, process.stdout, process.stderr],
122+
// Avoid loading packages/react-native/react-native.config.js
123+
cwd: REPO_ROOT,
124+
stdio: verbose ? 'inherit' : [process.stderr],
106125
},
107126
);
108-
process.stdout.write('Completed initialization of template app \u2705\n');
109-
110-
process.stdout.write('Installing dependencies in template app folder...\n');
111-
const options = {
112-
cwd: directory,
113-
stdio: [process.stdin, process.stdout, process.stderr],
114-
};
115-
116-
execSync(
117-
`yarn config set npmRegistryServer "${NPM_REGISTRY_SERVER}"`,
118-
options,
119-
);
120-
121-
execSync(
122-
'yarn config set unsafeHttpWhitelist --json \'["localhost"]\'',
123-
options,
124-
);
125-
126-
const success = await retry('yarn', options, 3, 500, ['install']);
127+
console.log('\nDone ✅');
128+
129+
console.log('Installing project dependencies');
130+
await runYarnUsingProxy(directory);
131+
console.log('Done ✅');
132+
} catch (e) {
133+
console.log('Failed ❌');
134+
throw e;
135+
} finally {
136+
console.log(`Cleanup: Killing Verdaccio process (PID: ${verdaccioPid})`);
137+
execSync(`kill -9 ${verdaccioPid}`);
138+
console.log('Done ✅');
127139

128-
if (!success) {
129-
process.stdout.write(
130-
'Failed to install dependencies in template app folder.',
131-
);
132-
throw new Error('Failed to install dependencies in template app folder.');
133-
}
140+
console.log('Cleanup: Removing Verdaccio storage directory');
141+
execSync(`rm -rf ${VERDACCIO_STORAGE_PATH}`);
142+
console.log('Done ✅');
134143

135-
process.stdout.write('Installed dependencies via Yarn \u2705\n');
136-
} finally {
137-
process.stdout.write(`Killing verdaccio. PID — ${VERDACCIO_PID}...\n`);
138-
execSync(`kill -9 ${VERDACCIO_PID}`);
139-
process.stdout.write('Killed Verdaccio process \u2705\n');
140144
// TODO(huntie): Fix memory leak from `spawn` in `setupVerdaccio` (above
141145
// kill command does not wait for kill success).
142146
process.exit(0);
143147
}
144148
}
145149

150+
async function runYarnUsingProxy(cwd /*: string */) {
151+
const execOptions = {
152+
cwd,
153+
stdio: 'inherit',
154+
};
155+
execSync(
156+
`yarn config set npmRegistryServer "${VERDACCIO_SERVER_URL}"`,
157+
execOptions,
158+
);
159+
execSync(
160+
'yarn config set unsafeHttpWhitelist --json \'["localhost"]\'',
161+
execOptions,
162+
);
163+
164+
// TODO(huntie): Review pre-existing retry limit
165+
const success = await retry('yarn', execOptions, 3, 500, ['install']);
166+
167+
if (!success) {
168+
throw new Error('Failed to install project dependencies');
169+
}
170+
}
171+
172+
module.exports = {
173+
initNewProjectFromSource,
174+
};
175+
146176
if (require.main === module) {
147177
// eslint-disable-next-line no-void
148178
void main();

scripts/template/setup-verdaccio.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,8 @@ function setupVerdaccio() /*: number */ {
4848
return verdaccioProcess.pid;
4949
}
5050

51-
module.exports = setupVerdaccio;
51+
module.exports = {
52+
setupVerdaccio,
53+
VERDACCIO_SERVER_URL,
54+
VERDACCIO_STORAGE_PATH,
55+
};

0 commit comments

Comments
 (0)