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

Download Circle CI artifact and prepare canary release #14225

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions scripts/release/build-commands/print-post-build-summary.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ module.exports = ({cwd, dry, path, version}) => {
1. Open {yellow.bold ${standaloneFixturePath}} in the browser.
2. It should say {italic "Hello world!"}
3. Next go to {yellow.bold ${packagingFixturesPath}} and run {bold node build-all.js}
4. Install the "serve" module ({bold npm install -g serve})
5. Go to the repo root and {bold serve -s .}
6. Open {blue.bold http://localhost:5000/fixtures/packaging}
4. Install the "pushstate-server" module ({bold npm install -g pushstate-server})
5. Go to the repo root and {bold pushstate-server -s .}
6. Open {blue.bold http://localhost:9000/fixtures/packaging}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

pushstate-server works better

7. Verify every iframe shows {italic "Hello world!"}

After completing the above steps, resume the release process by running:
Expand Down
19 changes: 3 additions & 16 deletions scripts/release/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,12 @@ const {exec} = require('child_process');

// Follows the steps outlined in github.com/facebook/react/issues/10620
const run = async () => {
const chalk = require('chalk');
const logUpdate = require('log-update');
const {getPublicPackages, getPackages} = require('./utils');
const {getPublicPackages, getPackages, handleError} = require('./utils');

const addGitTag = require('./build-commands/add-git-tag');
const buildArtifacts = require('./build-commands/build-artifacts');
const checkCircleCiStatus = require('./build-commands/check-circle-ci-status');
const checkEnvironmentVariables = require('./build-commands/check-environment-variables');
const checkEnvironmentVariables = require('./shared-commands/check-environment-variables');
const checkNpmPermissions = require('./build-commands/check-npm-permissions');
const checkPackageDependencies = require('./build-commands/check-package-dependencies');
const checkUncommittedChanges = require('./build-commands/check-uncommitted-changes');
Expand Down Expand Up @@ -55,18 +53,7 @@ const run = async () => {
await addGitTag(params);
await printPostBuildSummary(params);
} catch (error) {
logUpdate.clear();

const message = error.message.trim().replace(/\n +/g, '\n');
const stack = error.stack.replace(error.message, '');

console.log(
`${chalk.bgRed.white(' ERROR ')} ${chalk.red(message)}\n\n${chalk.gray(
stack
)}`
);

process.exit(1);
handleError(error);
}
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/usr/bin/env node

'use strict';

const chalk = require('chalk');
const http = require('request-promise-json');
const {exec} = require('child-process-promise');
const {readdirSync} = require('fs');
const {readJsonSync} = require('fs-extra');
const {logPromise} = require('../utils');

const run = async ({build, cwd}) => {
// https://circleci.com/docs/2.0/artifacts/#downloading-all-artifacts-for-a-build-on-circleci
const metadataURL = `https://circleci.com/api/v1.1/project/github/facebook/react/${build}/artifacts?circle-token=${
process.env.CIRCLE_CI_API_TOKEN
}`;
const metadata = await http.get(metadataURL, true);
const nodeModulesURL = metadata.find(
entry => entry.path === 'home/circleci/project/node_modules.tgz'
).url;

// Download and extract artifact
await exec(`rm -rf ${cwd}/build/node_modules*`);
await exec(`curl ${nodeModulesURL} --output ${cwd}/build/node_modules.tgz`);
await exec(`mkdir ${cwd}/build/node_modules`);
await exec(
`tar zxvf ${cwd}/build/node_modules.tgz -C ${cwd}/build/node_modules/`
);

// Unpack packages and parepare to publish
const compressedPackages = readdirSync('build/node_modules/');
for (let i = 0; i < compressedPackages.length; i++) {
await exec(
`tar zxvf ${cwd}/build/node_modules/${
compressedPackages[i]
} -C ${cwd}/build/node_modules/`
);
const packageJSON = readJsonSync(
`${cwd}/build/node_modules/package/package.json`
);
await exec(
`mv ${cwd}/build/node_modules/package ${cwd}/build/node_modules/${
packageJSON.name
}`
);
}

// Cleanup
await exec(`rm ${cwd}/build/node_modules.tgz`);
await exec(`rm ${cwd}/build/node_modules/*.tgz`);
};

module.exports = async ({build, cwd}) => {
return logPromise(
run({build, cwd}),
`Downloading artifacts from Circle CI for build ${chalk.yellow.bold(
`${build}`
)}`
);
};
65 changes: 65 additions & 0 deletions scripts/release/prepare-canary-commands/parse-params.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#!/usr/bin/env node

'use strict';

const chalk = require('chalk');
const commandLineArgs = require('command-line-args');
const commandLineUsage = require('command-line-usage');
const figlet = require('figlet');

const paramDefinitions = [
{
name: 'build',
type: Number,
description:
'Circle CI build identifier (e.g. https://circleci.com/gh/facebook/react/<build>)',
defaultValue: false,
},
{
name: 'path',
type: String,
alias: 'p',
description:
'Location of React repository to release; defaults to [bold]{cwd}',
defaultValue: '.',
},
];

module.exports = () => {
const params = commandLineArgs(paramDefinitions);

if (!params.build) {
const usage = commandLineUsage([
{
content: chalk
.hex('#61dafb')
.bold(figlet.textSync('react', {font: 'Graffiti'})),
raw: true,
},
{
content:
'Prepare a Circle CI build to be published to NPM as a canary.',
},
{
header: 'Options',
optionList: paramDefinitions,
},
{
header: 'Examples',
content: [
{
desc: 'Example:',
example: '$ ./prepare-canary.js [bold]{--build=}[underline]{12639}',
},
],
},
]);
console.log(usage);
process.exit(1);
}

return {
...params,
cwd: params.path, // For script convenience
};
};
40 changes: 40 additions & 0 deletions scripts/release/prepare-canary-commands/print-summary.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/usr/bin/env node

'use strict';

const chalk = require('chalk');
const {join, relative} = require('path');

module.exports = ({cwd, build, path}) => {
const publishPath = relative(
process.env.PWD,
join(__dirname, '../publish.js')
);
const command = `${publishPath}` + (path ? ` -p ${path}` : '');

const packagingFixturesPath = join(cwd, 'fixtures/packaging');
const standaloneFixturePath = join(
cwd,
'fixtures/packaging/babel-standalone/dev.html'
);

console.log(
chalk`
{green.bold A potential canary has been prepared!}
Next there are a couple of manual steps:

{bold.underline Smoke test the packages}

1. Open {yellow.bold ${standaloneFixturePath}} in the browser.
2. It should say {italic "Hello world!"}
3. Next go to {yellow.bold ${packagingFixturesPath}} and run {bold node build-all.js}
4. Install the "pushstate-server" module ({bold npm install -g pushstate-server})
5. Go to the repo root and {bold pushstate-server -s .}
6. Open {blue.bold http://localhost:9000/fixtures/packaging}
7. Verify every iframe shows {italic "Hello world!"}

After completing the above steps, you can publish this canary by running:
{yellow.bold ${command}}
`.replace(/\n +/g, '\n')
);
};
24 changes: 24 additions & 0 deletions scripts/release/prepare-canary.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/env node

'use strict';

const {handleError} = require('./utils');

const checkEnvironmentVariables = require('./shared-commands/check-environment-variables');
const downloadBuildArtifacts = require('./prepare-canary-commands/download-build-artifacts');
const parseParams = require('./prepare-canary-commands/parse-params');
const printSummary = require('./prepare-canary-commands/print-summary');

const run = async () => {
try {
const params = parseParams();

await checkEnvironmentVariables(params);
await downloadBuildArtifacts(params);
await printSummary(params);
} catch (error) {
handleError(error);
}
};

run();
17 changes: 2 additions & 15 deletions scripts/release/publish.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

'use strict';

const chalk = require('chalk');
const logUpdate = require('log-update');
const {getPublicPackages} = require('./utils');
const {getPublicPackages, handleError} = require('./utils');

const checkBuildStatus = require('./publish-commands/check-build-status');
const commitChangelog = require('./publish-commands/commit-changelog');
Expand All @@ -27,18 +25,7 @@ const run = async () => {
await publishToNpm(params);
await printPostPublishSummary(params);
} catch (error) {
logUpdate.clear();

const message = error.message.trim().replace(/\n +/g, '\n');
const stack = error.stack.replace(error.message, '');

console.log(
`${chalk.bgRed.white(' ERROR ')} ${chalk.red(message)}\n\n${chalk.gray(
stack
)}`
);

process.exit(1);
handleError(error);
}
};

Expand Down
16 changes: 16 additions & 0 deletions scripts/release/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,21 @@ const getUnexecutedCommands = () => {
}
};

const handleError = error => {
logUpdate.clear();

const message = error.message.trim().replace(/\n +/g, '\n');
const stack = error.stack.replace(error.message, '');

console.log(
`${chalk.bgRed.white(' ERROR ')} ${chalk.red(message)}\n\n${chalk.gray(
stack
)}`
);

process.exit(1);
};

const logPromise = async (promise, text, isLongRunningTask = false) => {
const {frames, interval} = dots;

Expand Down Expand Up @@ -119,6 +134,7 @@ module.exports = {
getPackages,
getPublicPackages,
getUnexecutedCommands,
handleError,
logPromise,
runYarnTask,
};