Skip to content

Commit

Permalink
Added publish command and slightly refactored some other command mess…
Browse files Browse the repository at this point in the history
…aging
  • Loading branch information
Brian Vaughn committed Nov 17, 2018
1 parent 75f0f8e commit 8f6e199
Show file tree
Hide file tree
Showing 23 changed files with 457 additions and 121 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@
"testRegex": "/scripts/jest/dont-run-jest-directly\\.js$"
},
"scripts": {
"build": "npm run version-check && node ./scripts/rollup/build.js",
"build": "node ./scripts/rollup/build.js",
"linc": "node ./scripts/tasks/linc.js",
"lint": "node ./scripts/tasks/eslint.js",
"lint-build": "node ./scripts/rollup/validate/index.js",
Expand Down
3 changes: 2 additions & 1 deletion scripts/release/ci-add-build-info-json.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const run = async () => {

const cwd = join(__dirname, '..', '..');

const {checksum, commit, branch} = await getBuildInfo();
const {branch, checksum, commit, reactVersion} = await getBuildInfo();

const packages = getPackages(join(cwd, 'packages'));
const packagesDir = join(cwd, 'packages');
Expand All @@ -26,6 +26,7 @@ const run = async () => {
checksum,
commit,
environment: 'ci',
reactVersion,
};

for (let i = 0; i < packages.length; i++) {
Expand Down
4 changes: 2 additions & 2 deletions scripts/release/ci-update-package-versions.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ const run = async () => {

const cwd = join(__dirname, '..', '..');

const {version} = await getBuildInfo();
const {reactVersion, version} = await getBuildInfo();

await updateVersionsForCanary(cwd, version);
await updateVersionsForCanary(cwd, reactVersion, version);
};

// Install (or update) release script dependencies before proceeding.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const {writeJson} = require('fs-extra');
const {join} = require('path');
const {getPackages, logPromise} = require('../utils');

const run = async ({branch, checksum, commit, tempDirectory}) => {
const run = async ({branch, checksum, commit, reactVersion, tempDirectory}) => {
const packages = getPackages(join(tempDirectory, 'packages'));
const packagesDir = join(tempDirectory, 'packages');

Expand All @@ -16,6 +16,7 @@ const run = async ({branch, checksum, commit, tempDirectory}) => {
checksum,
commit,
environment: 'local',
reactVersion,
};

for (let i = 0; i < packages.length; i++) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/env node

'use strict';

const chalk = require('chalk');
const clear = require('clear');
const {confirm} = require('../utils');

const run = async () => {
clear();

console.log(
chalk.red(
'This script does not run any automated tests.' +
'You should run them manually before creating a canary release.'
)
);

await confirm('Do you want to proceed?');

clear();
};

module.exports = run;
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const run = async ({cwd, dry, tempDirectory}) => {
`cp -r ${tempDirectory}/build/node_modules/*.tgz ${cwd}/build/node_modules/`
);

// Unpack packages and parepare to publish.
// Unpack packages and prepare to publish.
const compressedPackages = readdirSync('build/node_modules/');
for (let i = 0; i < compressedPackages.length; i++) {
await exec(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
const chalk = require('chalk');
const {logPromise, updateVersionsForCanary} = require('../utils');

module.exports = async ({tempDirectory, version}) => {
module.exports = async ({reactVersion, tempDirectory, version}) => {
return logPromise(
updateVersionsForCanary(tempDirectory, version),
updateVersionsForCanary(tempDirectory, reactVersion, version),
`Updating version numbers (${chalk.yellow.bold(version)})`
);
};
22 changes: 19 additions & 3 deletions scripts/release/create-canary.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ const {getBuildInfo, handleError} = require('./utils');

// This script is an escape hatch!
// It exists for special case manual builds.
// The typical suggesgted release process is to create a canary from a CI artifact.
// The typical suggested release process is to create a canary from a CI artifact.
// This build script is optimized for speed and simplicity.
// It doesn't run all of the tests that the CI environment runs.
// You're expected to run those manually before publishing a release.

const addBuildInfoJSON = require('./create-canary-commands/add-build-info-json');
const buildArtifacts = require('./create-canary-commands/build-artifacts');
const confirmAutomatedTesting = require('./create-canary-commands/confirm-automated-testing');
const copyRepoToTempDirectory = require('./create-canary-commands/copy-repo-to-temp-directory');
const npmPackAndUnpack = require('./create-canary-commands/npm-pack-and-unpack');
const printPrereleaseSummary = require('./shared-commands/print-prerelease-summary');
Expand All @@ -23,10 +24,25 @@ const updateVersionNumbers = require('./create-canary-commands/update-version-nu
const run = async () => {
try {
const cwd = join(__dirname, '..', '..');
const {branch, checksum, commit, version} = await getBuildInfo();
const {
branch,
checksum,
commit,
reactVersion,
version,
} = await getBuildInfo();
const tempDirectory = join(tmpdir(), `react-${commit}`);
const params = {branch, checksum, commit, cwd, tempDirectory, version};
const params = {
branch,
checksum,
commit,
cwd,
reactVersion,
tempDirectory,
version,
};

await confirmAutomatedTesting(params);
await copyRepoToTempDirectory(params);
await updateVersionNumbers(params);
await addBuildInfoJSON(params);
Expand Down
3 changes: 2 additions & 1 deletion scripts/release/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@
"dependencies": {
"chalk": "^2.1.0",
"child-process-promise": "^2.2.1",
"clear": "^0.1.0",
"cli-spinners": "^1.1.0",
"command-line-args": "^4.0.7",
"command-line-usage": "^4.0.1",
"diff": "^3.5.0",
"figlet": "^1.2.0",
"folder-hash": "^2.1.2",
"fs-extra": "^4.0.2",
"log-update": "^2.1.0",
"print-diff": "^0.1.1",
"prompt-promise": "^1.0.3",
"request-promise-json": "^1.0.4",
"semver": "^5.4.1"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const run = async ({build, cwd}) => {
`tar zxvf ${cwd}/build/node_modules.tgz -C ${cwd}/build/node_modules/`
);

// Unpack packages and parepare to publish
// Unpack packages and prepare to publish
const compressedPackages = readdirSync('build/node_modules/');
for (let i = 0; i < compressedPackages.length; i++) {
await exec(
Expand Down
1 change: 0 additions & 1 deletion scripts/release/prepare-canary-commands/parse-params.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ const paramDefinitions = [
type: Number,
description:
'Circle CI build identifier (e.g. https://circleci.com/gh/facebook/react/<build>)',
defaultValue: false,
},
];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,23 @@
'use strict';

const chalk = require('chalk');
const clear = require('clear');
const {readFileSync, writeFileSync} = require('fs');
const {readJson, writeJson} = require('fs-extra');
const {join} = require('path');
const printDiff = require('print-diff');
const {confirm, execRead} = require('../utils');
const {join, relative} = require('path');
const {confirm, execRead, printDiff} = require('../utils');

const run = async ({cwd, packages, version}, versionsMap) => {
const nodeModulesPath = join(cwd, 'build/node_modules');

// Cache all package JSONs for easy lookup below.
const sourcePackageJSONs = new Map();
const targetPackageJSONs = new Map();
for (let i = 0; i < packages.length; i++) {
const packageName = packages[i];
const sourcePackageJSON = await readJson(
join(cwd, 'packages', packageName, 'package.json')
);
sourcePackageJSONs.set(packageName, sourcePackageJSON);
const targetPackageJSON = await readJson(
join(nodeModulesPath, packageName, 'package.json')
);
targetPackageJSONs.set(packageName, targetPackageJSON);
}

const updateDependencies = async (targetPackageJSON, key) => {
Expand All @@ -50,7 +45,7 @@ const run = async ({cwd, packages, version}, versionsMap) => {
// If the source dependency's version and the constraint match,
// we will need to update the constraint to point at the dependency's new release version,
// (e.g. scheduler@^0.11.0 becomes scheduler@^0.12.0 when we release scheduler 0.12.0).
// Othewise we leave the constraint alone (e.g. react@^16.0.0 doesn't change between releases).
// Otherwise we leave the constraint alone (e.g. react@^16.0.0 doesn't change between releases).
// Note that in both cases, we must update the target package JSON,
// since canary releases are all locked to the canary version (e.g. 0.0.0-ddaf2b07c).
if (
Expand All @@ -74,7 +69,7 @@ const run = async ({cwd, packages, version}, versionsMap) => {
// Update all package JSON versions and their dependencies/peerDependencies.
// This must be done in a way that respects semver constraints (e.g. 16.7.0, ^16.7.0, ^16.0.0).
// To do this, we use the dependencies defined in the source package JSONs,
// because the canary dependencies have already been falttened to an exact match (e.g. 0.0.0-ddaf2b07c).
// because the canary dependencies have already been flattened to an exact match (e.g. 0.0.0-ddaf2b07c).
for (let i = 0; i < packages.length; i++) {
const packageName = packages[i];
const packageJSONPath = join(nodeModulesPath, packageName, 'package.json');
Expand All @@ -87,6 +82,8 @@ const run = async ({cwd, packages, version}, versionsMap) => {
await writeJson(packageJSONPath, packageJSON, {spaces: 2});
}

clear();

// Print the map of versions and their dependencies for confirmation.
const printDependencies = (maybeDependency, label) => {
if (maybeDependency) {
Expand Down Expand Up @@ -115,6 +112,20 @@ const run = async ({cwd, packages, version}, versionsMap) => {
}
await confirm('Do the versions above look correct?');

clear();

// A separate "React version" is used for the embedded renderer version to support DevTools,
// since it needs to distinguish between different version ranges of React.
// We need to replace it as well as the canary version number.
const buildInfoPath = join(nodeModulesPath, 'react', 'build-info.json');
const {reactVersion} = await readJson(buildInfoPath);

// We print the diff to the console for review,
// but it can be large so let's also write it to disk.
const diffPath = join(cwd, 'build', 'temp.diff');
let diff = '';
let numFilesModified = 0;

// Find-and-replace hard coded version (in built JS) for renderers.
for (let i = 0; i < packages.length; i++) {
const packageName = packages[i];
Expand All @@ -126,18 +137,30 @@ const run = async ({cwd, packages, version}, versionsMap) => {
);
files = files.split('\n');
files.forEach(path => {
const newStableVersion = versionsMap.get(packageName);
const beforeContents = readFileSync(path, 'utf8', {cwd});
const afterContents = beforeContents.replace(
new RegExp(version, 'g'),
versionsMap.get(packageName)
);
let afterContents = beforeContents;
// Replace all canary version numbers (e.g. header @license).
while (afterContents.indexOf(version) >= 0) {
afterContents = afterContents.replace(version, newStableVersion);
}
// Replace inline renderer version numbers (e.g. shared/ReactVersion).
while (afterContents.indexOf(reactVersion) >= 0) {
afterContents = afterContents.replace(reactVersion, newStableVersion);
}
if (beforeContents !== afterContents) {
printDiff(beforeContents, afterContents);
numFilesModified++;
diff += printDiff(path, beforeContents, afterContents);
writeFileSync(path, afterContents, {cwd});
}
});
}
await confirm('Do the replacements above look correct?');
writeFileSync(diffPath, diff, {cwd});
console.log(chalk.green(`\n${numFilesModified} files have been updated.`));
console.log(
chalk`A full diff is availbale at {yellow ${relative(cwd, diffPath)}}.`
);
await confirm('Do changes changes look correct?');
};

// Run this directly because logPromise would interfere with printing package dependencies.
Expand Down
40 changes: 40 additions & 0 deletions scripts/release/publish-commands/check-npm-permissions.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 {execRead, logPromise} = require('../utils');

const run = async ({cwd, packages, version}) => {
const currentUser = await execRead('npm whoami');
const failedProjects = [];

const checkProject = async project => {
const owners = (await execRead(`npm owner ls ${project}`))
.split('\n')
.filter(owner => owner)
.map(owner => owner.split(' ')[0]);

if (!owners.includes(currentUser)) {
failedProjects.push(project);
}
};

await logPromise(
Promise.all(packages.map(checkProject)),
`Checking ${chalk.yellow.bold(currentUser)}'s NPM permissions`
);

if (failedProjects.length) {
throw Error(
chalk`
Insufficient NPM permissions
{white NPM user {yellow.bold ${currentUser}} is not an owner for:}
{red ${failedProjects.join(', ')}}
{white Please contact a React team member to be added to the above project(s).}
`
);
}
};

module.exports = run;
48 changes: 48 additions & 0 deletions scripts/release/publish-commands/confirm-version-and-tags.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/usr/bin/env node

'use strict';

const chalk = require('chalk');
const clear = require('clear');
const {readJson} = require('fs-extra');
const {join} = require('path');
const {confirm} = require('../utils');

const run = async ({cwd, packages, tags}) => {
clear();

if (tags.length === 1) {
console.log(
chalk`{green ✓} You are about the publish the following packages under the tag {yellow ${tags}}`
);
} else {
console.log(
chalk`{green ✓} You are about the publish the following packages under the tags {yellow ${tags.join(
', '
)}}`
);
}

// Cache all package JSONs for easy lookup below.
for (let i = 0; i < packages.length; i++) {
const packageName = packages[i];
const packageJSONPath = join(
cwd,
'build/node_modules',
packageName,
'package.json'
);
const packageJSON = await readJson(packageJSONPath);
console.log(
chalk`• {green ${packageName}} @ {yellow ${chalk.yellow(
packageJSON.version
)}}`
);
}

await confirm('Do you want to proceed?');
};

// Run this directly because it's fast,
// and logPromise would interfere with console prompting.
module.exports = run;
Loading

0 comments on commit 8f6e199

Please sign in to comment.