From 52d14579f5a91e25ae2ee855bdc224dcd2e90a23 Mon Sep 17 00:00:00 2001 From: Andrew Clark Date: Wed, 13 Jan 2021 12:35:02 -0600 Subject: [PATCH 1/2] Migrate prepare-release-from-ci to new workflow I added a `--releaseChannel (-r)` argument to script. You must choose either "stable" or "experimental", because every build job now includes both channels. The prepare-release-from-npm script is unchanged since those releases are downloaded from npm, nt CI. (As a side note, I think we should start preparing semver releases using the prepare-release-from-ci script, too, and get rid of prepare-release-from-npm. I think that was a neat idea originally but because we already run `npm pack` before storing the artifacts in CI, there's really not much additional safety; the only safeguard it adds is the requirement that a "next" release must have already been published.) --- scripts/release/prepare-release-from-ci.js | 16 +++-- .../download-build-artifacts.js | 67 ++++++++----------- .../get-latest-master-build-number.js | 8 +-- .../release/shared-commands/parse-params.js | 6 ++ scripts/release/utils.js | 6 +- 5 files changed, 47 insertions(+), 56 deletions(-) diff --git a/scripts/release/prepare-release-from-ci.js b/scripts/release/prepare-release-from-ci.js index f7222ba8ca8a..ffbfc4a9a58f 100755 --- a/scripts/release/prepare-release-from-ci.js +++ b/scripts/release/prepare-release-from-ci.js @@ -3,8 +3,7 @@ 'use strict'; const {join} = require('path'); -const {readJsonSync} = require('fs-extra'); -const {getPublicPackages, handleError} = require('./utils'); +const {handleError} = require('./utils'); const checkEnvironmentVariables = require('./shared-commands/check-environment-variables'); const downloadBuildArtifacts = require('./shared-commands/download-build-artifacts'); @@ -19,6 +18,14 @@ const run = async () => { const params = parseParams(); params.cwd = join(__dirname, '..', '..'); + const channel = params.releaseChannel; + if (channel !== 'experimental' && channel !== 'stable') { + console.error( + `Invalid release channel: "${channel}". Must be "stable" or "experimental".` + ); + process.exit(1); + } + if (!params.build) { params.build = await getLatestMasterBuildNumber(false); } @@ -26,11 +33,6 @@ const run = async () => { await checkEnvironmentVariables(params); await downloadBuildArtifacts(params); - const version = readJsonSync('./build/node_modules/react/package.json') - .version; - const isExperimental = version.includes('experimental'); - params.packages = await getPublicPackages(isExperimental); - if (!params.skipTests) { await testPackagingFixture(params); await testTracingFixture(params); diff --git a/scripts/release/shared-commands/download-build-artifacts.js b/scripts/release/shared-commands/download-build-artifacts.js index 715834193440..4d5259e24d1c 100644 --- a/scripts/release/shared-commands/download-build-artifacts.js +++ b/scripts/release/shared-commands/download-build-artifacts.js @@ -3,65 +3,56 @@ 'use strict'; const {exec} = require('child-process-promise'); -const {existsSync, readdirSync} = require('fs'); -const {readJsonSync} = require('fs-extra'); +const {existsSync} = require('fs'); const {join} = require('path'); const {getArtifactsList, logPromise} = require('../utils'); const theme = require('../theme'); -const run = async ({build, cwd}) => { +const run = async ({build, cwd, releaseChannel}) => { const artifacts = await getArtifactsList(build); - const nodeModulesArtifact = artifacts.find(entry => - entry.path.endsWith('node_modules.tgz') + const buildArtifacts = artifacts.find(entry => + entry.path.endsWith('build2.tgz') ); - if (!nodeModulesArtifact) { + if (!buildArtifacts) { console.log( theme`{error The specified build (${build}) does not contain any build artifacts.}` ); process.exit(1); } - const nodeModulesURL = nodeModulesArtifact.url; + // Download and extract artifact + await exec(`rm -rf ./build2`, {cwd}); + await exec( + `curl -L $(fwdproxy-config curl) ${buildArtifacts.url} | tar -xvz`, + { + cwd, + } + ); + // Copy to staging directory + // TODO: Consider staging the release in a different directory from the CI + // build artifacts: `./build/node_modules` -> `./staged-releases` if (!existsSync(join(cwd, 'build'))) { await exec(`mkdir ./build`, {cwd}); + } else { + await exec(`rm -rf ./build/node_modules`, {cwd}); } - - // Download and extract artifact - await exec(`rm -rf ./build/node_modules*`, {cwd}); - await exec(`curl -L ${nodeModulesURL} --output ./build/node_modules.tgz`, { - cwd, - }); - await exec(`mkdir ./build/node_modules`, {cwd}); - await exec(`tar zxvf ./build/node_modules.tgz -C ./build/node_modules/`, { - cwd, - }); - - // Unpack packages and prepare to publish - const compressedPackages = readdirSync(join(cwd, 'build/node_modules/')); - for (let i = 0; i < compressedPackages.length; i++) { - await exec( - `tar zxvf ./build/node_modules/${compressedPackages[i]} -C ./build/node_modules/`, - {cwd} - ); - const packageJSON = readJsonSync( - join(cwd, `/build/node_modules/package/package.json`) - ); - await exec( - `mv ./build/node_modules/package ./build/node_modules/${packageJSON.name}`, - {cwd} - ); + let sourceDir; + if (releaseChannel === 'stable') { + sourceDir = 'oss-stable'; + } else if (releaseChannel === 'experimental') { + sourceDir = 'oss-experimental'; + } else { + console.error('Internal error: Invalid release channel: ' + releaseChannel); + process.exit(releaseChannel); } - - // Cleanup - await exec(`rm ./build/node_modules.tgz`, {cwd}); - await exec(`rm ./build/node_modules/*.tgz`, {cwd}); + await exec(`cp -r ./build2/${sourceDir} ./build/node_modules`, {cwd}); }; -module.exports = async ({build, cwd}) => { +module.exports = async ({build, cwd, releaseChannel}) => { return logPromise( - run({build, cwd}), + run({build, cwd, releaseChannel}), theme`Downloading artifacts from Circle CI for build {build ${build}}` ); }; diff --git a/scripts/release/shared-commands/get-latest-master-build-number.js b/scripts/release/shared-commands/get-latest-master-build-number.js index 1d1787fad8f0..d0bcd56e2e04 100644 --- a/scripts/release/shared-commands/get-latest-master-build-number.js +++ b/scripts/release/shared-commands/get-latest-master-build-number.js @@ -5,11 +5,7 @@ const http = require('request-promise-json'); const {logPromise} = require('../utils'); -const run = async useExperimentalBuild => { - const targetJobName = useExperimentalBuild - ? 'process_artifacts_experimental' - : 'process_artifacts'; - +const run = async () => { // https://circleci.com/docs/api/#recent-builds-for-a-project-branch const metadataURL = `https://circleci.com/api/v1.1/project/github/facebook/react/tree/master`; const metadata = await http.get(metadataURL, true); @@ -17,7 +13,7 @@ const run = async useExperimentalBuild => { entry => entry.branch === 'master' && entry.status === 'success' && - entry.workflows.job_name === targetJobName + entry.workflows.job_name === 'process_artifacts_combined' ).build_num; return build; diff --git a/scripts/release/shared-commands/parse-params.js b/scripts/release/shared-commands/parse-params.js index 703fc0fb11b4..f079ee3b2eb7 100644 --- a/scripts/release/shared-commands/parse-params.js +++ b/scripts/release/shared-commands/parse-params.js @@ -17,6 +17,12 @@ const paramDefinitions = [ description: 'Skip automated fixture tests.', defaultValue: false, }, + { + name: 'releaseChannel', + alias: 'r', + type: String, + description: 'Release channel (stable or experimental)', + }, ]; module.exports = () => { diff --git a/scripts/release/utils.js b/scripts/release/utils.js index be191978df3f..52731d4376e0 100644 --- a/scripts/release/utils.js +++ b/scripts/release/utils.js @@ -41,11 +41,7 @@ const getArtifactsList = async buildID => { ); process.exit(1); } - const artifactsJobName = buildMetadata.workflows.job_name.endsWith( - '_experimental' - ) - ? 'process_artifacts_experimental' - : 'process_artifacts'; + const artifactsJobName = 'process_artifacts_combined'; const workflowID = buildMetadata.workflows.workflow_id; const workflowMetadataURL = `https://circleci.com/api/v2/workflow/${workflowID}/job?circle-token=${process.env.CIRCLE_CI_API_TOKEN}`; const workflowMetadata = await http.get(workflowMetadataURL, true); From 6ea9ed6922859d940a37cd33f3cce4bfd8498d06 Mon Sep 17 00:00:00 2001 From: Andrew Clark Date: Thu, 14 Jan 2021 11:11:33 -0600 Subject: [PATCH 2/2] Move validation to parse-params module --- scripts/release/prepare-release-from-ci.js | 8 -------- scripts/release/shared-commands/parse-params.js | 8 ++++++++ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/scripts/release/prepare-release-from-ci.js b/scripts/release/prepare-release-from-ci.js index ffbfc4a9a58f..dd8e143453f7 100755 --- a/scripts/release/prepare-release-from-ci.js +++ b/scripts/release/prepare-release-from-ci.js @@ -18,14 +18,6 @@ const run = async () => { const params = parseParams(); params.cwd = join(__dirname, '..', '..'); - const channel = params.releaseChannel; - if (channel !== 'experimental' && channel !== 'stable') { - console.error( - `Invalid release channel: "${channel}". Must be "stable" or "experimental".` - ); - process.exit(1); - } - if (!params.build) { params.build = await getLatestMasterBuildNumber(false); } diff --git a/scripts/release/shared-commands/parse-params.js b/scripts/release/shared-commands/parse-params.js index f079ee3b2eb7..2ec21020282f 100644 --- a/scripts/release/shared-commands/parse-params.js +++ b/scripts/release/shared-commands/parse-params.js @@ -28,5 +28,13 @@ const paramDefinitions = [ module.exports = () => { const params = commandLineArgs(paramDefinitions); + const channel = params.releaseChannel; + if (channel !== 'experimental' && channel !== 'stable') { + console.error( + `Invalid release channel (-r) "${channel}". Must be "stable" or "experimental".` + ); + process.exit(1); + } + return params; };