1. #!/usr/bin/env node
    
  2. 
    
  3. 'use strict';
    
  4. 
    
  5. const chalk = require('chalk');
    
  6. const {exec} = require('child-process-promise');
    
  7. const inquirer = require('inquirer');
    
  8. const {homedir} = require('os');
    
  9. const {join, relative} = require('path');
    
  10. const {DRY_RUN, ROOT_PATH} = require('./configuration');
    
  11. const {
    
  12.   clear,
    
  13.   confirm,
    
  14.   confirmContinue,
    
  15.   execRead,
    
  16.   logger,
    
  17.   saveBuildMetadata,
    
  18. } = require('./utils');
    
  19. 
    
  20. // This is the primary control function for this script.
    
  21. async function main() {
    
  22.   clear();
    
  23. 
    
  24.   await confirm('Have you stopped all NPM DEV scripts?', () => {
    
  25.     const packagesPath = relative(process.cwd(), join(__dirname, 'packages'));
    
  26. 
    
  27.     console.log('Stop all NPM DEV scripts in the following directories:');
    
  28.     console.log(
    
  29.       chalk.bold('  ' + join(packagesPath, 'react-devtools-core')),
    
  30.       chalk.gray('(start:backend, start:standalone)')
    
  31.     );
    
  32.     console.log(
    
  33.       chalk.bold('  ' + join(packagesPath, 'react-devtools-inline')),
    
  34.       chalk.gray('(start)')
    
  35.     );
    
  36. 
    
  37.     const buildAndTestScriptPath = join(__dirname, 'build-and-test.js');
    
  38.     const pathToPrint = relative(process.cwd(), buildAndTestScriptPath);
    
  39. 
    
  40.     console.log('\nThen restart this release step:');
    
  41.     console.log(chalk.bold.green('  ' + pathToPrint));
    
  42.   });
    
  43. 
    
  44.   await confirm('Have you run the prepare-release script?', () => {
    
  45.     const prepareReleaseScriptPath = join(__dirname, 'prepare-release.js');
    
  46.     const pathToPrint = relative(process.cwd(), prepareReleaseScriptPath);
    
  47. 
    
  48.     console.log('Begin by running the prepare-release script:');
    
  49.     console.log(chalk.bold.green('  ' + pathToPrint));
    
  50.   });
    
  51. 
    
  52.   const archivePath = await archiveGitRevision();
    
  53.   const buildID = await downloadLatestReactBuild();
    
  54. 
    
  55.   await buildAndTestInlinePackage();
    
  56.   await buildAndTestStandalonePackage();
    
  57.   await buildAndTestExtensions();
    
  58. 
    
  59.   saveBuildMetadata({archivePath, buildID});
    
  60. 
    
  61.   printFinalInstructions();
    
  62. }
    
  63. 
    
  64. async function archiveGitRevision() {
    
  65.   const desktopPath = join(homedir(), 'Desktop');
    
  66.   const archivePath = join(desktopPath, 'DevTools.tgz');
    
  67. 
    
  68.   console.log(`Creating git archive at ${chalk.dim(archivePath)}`);
    
  69.   console.log('');
    
  70. 
    
  71.   if (!DRY_RUN) {
    
  72.     await exec(`git archive main | gzip > ${archivePath}`, {cwd: ROOT_PATH});
    
  73.   }
    
  74. 
    
  75.   return archivePath;
    
  76. }
    
  77. 
    
  78. async function buildAndTestExtensions() {
    
  79.   const extensionsPackagePath = join(
    
  80.     ROOT_PATH,
    
  81.     'packages',
    
  82.     'react-devtools-extensions'
    
  83.   );
    
  84.   const buildExtensionsPromise = exec('yarn build', {
    
  85.     cwd: extensionsPackagePath,
    
  86.   });
    
  87. 
    
  88.   await logger(
    
  89.     buildExtensionsPromise,
    
  90.     `Building browser extensions ${chalk.dim('(this may take a minute)')}`,
    
  91.     {
    
  92.       estimate: 60000,
    
  93.     }
    
  94.   );
    
  95. 
    
  96.   console.log('');
    
  97.   console.log(`Extensions have been build for Chrome, Edge, and Firefox.`);
    
  98.   console.log('');
    
  99.   console.log('Smoke test each extension before continuing:');
    
  100.   console.log(`  ${chalk.bold.green('cd ' + extensionsPackagePath)}`);
    
  101.   console.log('');
    
  102.   console.log(`  ${chalk.dim('# Test Chrome extension')}`);
    
  103.   console.log(`  ${chalk.bold.green('yarn test:chrome')}`);
    
  104.   console.log('');
    
  105.   console.log(`  ${chalk.dim('# Test Edge extension')}`);
    
  106.   console.log(`  ${chalk.bold.green('yarn test:edge')}`);
    
  107.   console.log('');
    
  108.   console.log(`  ${chalk.dim('# Firefox Chrome extension')}`);
    
  109.   console.log(`  ${chalk.bold.green('yarn test:firefox')}`);
    
  110. 
    
  111.   await confirmContinue();
    
  112. }
    
  113. 
    
  114. async function buildAndTestStandalonePackage() {
    
  115.   const corePackagePath = join(ROOT_PATH, 'packages', 'react-devtools-core');
    
  116.   const corePackageDest = join(corePackagePath, 'dist');
    
  117. 
    
  118.   await exec(`rm -rf ${corePackageDest}`);
    
  119.   const buildCorePromise = exec('yarn build', {cwd: corePackagePath});
    
  120. 
    
  121.   await logger(
    
  122.     buildCorePromise,
    
  123.     `Building ${chalk.bold('react-devtools-core')} package.`,
    
  124.     {
    
  125.       estimate: 25000,
    
  126.     }
    
  127.   );
    
  128. 
    
  129.   const standalonePackagePath = join(ROOT_PATH, 'packages', 'react-devtools');
    
  130.   const safariFixturePath = join(
    
  131.     ROOT_PATH,
    
  132.     'fixtures',
    
  133.     'devtools',
    
  134.     'standalone',
    
  135.     'index.html'
    
  136.   );
    
  137. 
    
  138.   console.log('');
    
  139.   console.log(
    
  140.     `Test the ${chalk.bold('react-devtools-core')} target before continuing:`
    
  141.   );
    
  142.   console.log(`  ${chalk.bold.green('cd ' + standalonePackagePath)}`);
    
  143.   console.log(`  ${chalk.bold.green('yarn start')}`);
    
  144.   console.log('');
    
  145.   console.log(
    
  146.     'The following fixture can be useful for testing Safari integration:'
    
  147.   );
    
  148.   console.log(`  ${chalk.dim(safariFixturePath)}`);
    
  149. 
    
  150.   await confirmContinue();
    
  151. }
    
  152. 
    
  153. async function buildAndTestInlinePackage() {
    
  154.   const inlinePackagePath = join(
    
  155.     ROOT_PATH,
    
  156.     'packages',
    
  157.     'react-devtools-inline'
    
  158.   );
    
  159.   const inlinePackageDest = join(inlinePackagePath, 'dist');
    
  160. 
    
  161.   await exec(`rm -rf ${inlinePackageDest}`);
    
  162.   const buildPromise = exec('yarn build', {cwd: inlinePackagePath});
    
  163. 
    
  164.   await logger(
    
  165.     buildPromise,
    
  166.     `Building ${chalk.bold('react-devtools-inline')} package.`,
    
  167.     {
    
  168.       estimate: 10000,
    
  169.     }
    
  170.   );
    
  171. 
    
  172.   const shellPackagePath = join(ROOT_PATH, 'packages', 'react-devtools-shell');
    
  173. 
    
  174.   console.log('');
    
  175.   console.log(`Built ${chalk.bold('react-devtools-inline')} target.`);
    
  176.   console.log('');
    
  177.   console.log('Test this build before continuing:');
    
  178.   console.log(`  ${chalk.bold.green('cd ' + shellPackagePath)}`);
    
  179.   console.log(`  ${chalk.bold.green('yarn start')}`);
    
  180. 
    
  181.   await confirmContinue();
    
  182. }
    
  183. 
    
  184. async function downloadLatestReactBuild() {
    
  185.   const releaseScriptPath = join(ROOT_PATH, 'scripts', 'release');
    
  186.   const installPromise = exec('yarn install', {cwd: releaseScriptPath});
    
  187. 
    
  188.   await logger(
    
  189.     installPromise,
    
  190.     `Installing release script dependencies. ${chalk.dim(
    
  191.       '(this may take a minute if CI is still running)'
    
  192.     )}`,
    
  193.     {
    
  194.       estimate: 5000,
    
  195.     }
    
  196.   );
    
  197. 
    
  198.   console.log('');
    
  199. 
    
  200.   const {commit} = await inquirer.prompt([
    
  201.     {
    
  202.       type: 'input',
    
  203.       name: 'commit',
    
  204.       message: 'Which React version (commit) should be used?',
    
  205.       default: 'main',
    
  206.     },
    
  207.   ]);
    
  208.   console.log('');
    
  209. 
    
  210.   const downloadScriptPath = join(
    
  211.     releaseScriptPath,
    
  212.     'download-experimental-build.js'
    
  213.   );
    
  214.   const downloadPromise = execRead(
    
  215.     `"${downloadScriptPath}" --commit=${commit}`
    
  216.   );
    
  217. 
    
  218.   const output = await logger(
    
  219.     downloadPromise,
    
  220.     'Downloading React artifacts from CI.',
    
  221.     {estimate: 15000}
    
  222.   );
    
  223. 
    
  224.   const match = output.match('--build=([0-9]+)');
    
  225.   if (match.length === 0) {
    
  226.     console.error(chalk.red(`No build ID found in "${output}"`));
    
  227.     process.exit(1);
    
  228.   }
    
  229. 
    
  230.   const buildID = match[1];
    
  231. 
    
  232.   console.log('');
    
  233.   console.log(`Downloaded artifacts for CI build ${chalk.bold(buildID)}.`);
    
  234. 
    
  235.   return buildID;
    
  236. }
    
  237. 
    
  238. function printFinalInstructions() {
    
  239.   const publishReleaseScriptPath = join(__dirname, 'publish-release.js');
    
  240.   const pathToPrint = relative(process.cwd(), publishReleaseScriptPath);
    
  241. 
    
  242.   console.log('');
    
  243.   console.log('Continue by running the publish-release script:');
    
  244.   console.log(chalk.bold.green('  ' + pathToPrint));
    
  245. }
    
  246. 
    
  247. main();