Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate prepare-release-from-ci to new workflow #20581

Merged
merged 2 commits into from Jan 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 1 addition & 7 deletions scripts/release/prepare-release-from-ci.js
Expand Up @@ -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');
Expand All @@ -26,11 +25,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);
Expand Down
67 changes: 29 additions & 38 deletions scripts/release/shared-commands/download-build-artifacts.js
Expand Up @@ -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`,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @acdlite I'm trying to execute this script on a Windows machine and it looks like it assumes Unix heavily. I'm trying to rewrite this in a more xplat fashion, but I can't figure out what fwdproxy-config curl is or returns. If you could point me to the package that enables this command or something, that'd be great. Thanks!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@acdlite friendly ping

{
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/`,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When this was originally added, we didn't store the entire build directory as a CI artifact. Just the npm packages.

The reason we stored each module as an individual tarball was because we ran npm pack to run any npm pre-processing, like filtering files out based on the package.files array. The build script already does this, though, so we can skip the extra step.

{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}}`
);
};
Expand Up @@ -5,19 +5,15 @@
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);
const build = metadata.find(
entry =>
entry.branch === 'master' &&
entry.status === 'success' &&
entry.workflows.job_name === targetJobName
entry.workflows.job_name === 'process_artifacts_combined'
).build_num;

return build;
Expand Down
14 changes: 14 additions & 0 deletions scripts/release/shared-commands/parse-params.js
Expand Up @@ -17,10 +17,24 @@ const paramDefinitions = [
description: 'Skip automated fixture tests.',
defaultValue: false,
},
{
name: 'releaseChannel',
alias: 'r',
type: String,
description: 'Release channel (stable or experimental)',
},
];

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;
};
6 changes: 1 addition & 5 deletions scripts/release/utils.js
Expand Up @@ -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);
Expand Down