mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
@@ -20,9 +20,13 @@ The high level process of creating releases is [documented below](#process). Ind
|
||||
|
||||
If this is your first time running the release scripts, go to the `scripts/release` directory and run `yarn` to install the dependencies.
|
||||
|
||||
## Publishing Without Tags
|
||||
## Publishing Untagged
|
||||
|
||||
The sections bekow include meaningful `--tags` in the instructions. However, keep in mind that **the `--tags` arguments is optional**, and you can omit it if you don't want to tag the release on npm at all. This can be useful when preparing breaking changes.
|
||||
The sections bekow include meaningful `--tag` in the instructions.
|
||||
|
||||
However, keep in mind that **the `--tag` arguments is optional**, and you can omit it if you don't want to tag the release on npm at all. This can be useful when preparing breaking changes.
|
||||
|
||||
Because npm requires a tag on publish, the script does it by creating a temporary tag and deleting it afterwards.
|
||||
|
||||
## Publishing Next
|
||||
|
||||
@@ -42,7 +46,7 @@ scripts/release/prepare-release-from-ci.js --build=124756
|
||||
|
||||
Once the build has been checked out and tested locally, you're ready to publish it:
|
||||
```sh
|
||||
scripts/release/publish.js --tags next
|
||||
scripts/release/publish.js --tag next
|
||||
```
|
||||
|
||||
If the OTP code expires while publishing, re-run this command and answer "y" to the questions about whether it was expected for already published packages.
|
||||
@@ -64,7 +68,7 @@ scripts/release/prepare-release-from-ci.js --build=124763
|
||||
Once the build has been checked out and tested locally, you're ready to publish it. When publishing an experimental release, use the `experimental` tag:
|
||||
|
||||
```sh
|
||||
scripts/release/publish.js --tags experimental
|
||||
scripts/release/publish.js --tag experimental
|
||||
```
|
||||
|
||||
If the OTP code expires while publishing, re-run this command and answer "y" to the questions about whether it was expected for already published packages.
|
||||
@@ -86,11 +90,13 @@ This script will prompt you to select stable version numbers for each of the pac
|
||||
Once this step is complete, you're ready to publish the release:
|
||||
|
||||
```sh
|
||||
scripts/release/publish.js --tags latest
|
||||
scripts/release/publish.js --tag latest
|
||||
```
|
||||
|
||||
If the OTP code expires while publishing, re-run this command and answer "y" to the questions about whether it was expected for already published packages.
|
||||
|
||||
Note that publishing the `latest` tag will always update the `next` tag automatically as well so they're in sync.
|
||||
|
||||
After successfully publishing the release, follow the on-screen instructions to ensure that all of the appropriate post-release steps are executed.
|
||||
|
||||
<sup>1: You can omit the `version` param if you just want to promote the latest "next" candidate to stable.</sup>
|
||||
@@ -170,7 +176,9 @@ Upon completion, this script provides instructions for tagging the Git commit th
|
||||
**Specify a `--dry` flag when running this script if you want to skip the NPM-publish step.** In this event, the script will print the NPM commands but it will not actually run them.
|
||||
|
||||
#### Example usage
|
||||
To publish a release to NPM as both `next` and `latest`:
|
||||
To publish a release to NPM as `latest`:
|
||||
```sh
|
||||
scripts/release/publish.js --tags latest
|
||||
scripts/release/publish.js --tag latest
|
||||
```
|
||||
|
||||
Note that publishing the `latest` tag will always update the `next` tag automatically as well so they're in sync.
|
||||
|
||||
@@ -6,7 +6,7 @@ const clear = require('clear');
|
||||
const {confirm} = require('../utils');
|
||||
const theme = require('../theme');
|
||||
|
||||
const run = async ({cwd, packages, skipPackages, tags}) => {
|
||||
const run = async ({cwd, packages, skipPackages}) => {
|
||||
if (skipPackages.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
+8
-16
@@ -8,24 +8,16 @@ const {join} = require('path');
|
||||
const {confirm} = require('../utils');
|
||||
const theme = require('../theme');
|
||||
|
||||
const run = async ({cwd, packages, tags}) => {
|
||||
const run = async ({cwd, packages, tag}) => {
|
||||
clear();
|
||||
|
||||
if (tags.length === 0) {
|
||||
console.log(
|
||||
theme`{spinnerSuccess ✓} You are about the publish the following packages without any tags:`
|
||||
);
|
||||
} else if (tags.length === 1) {
|
||||
console.log(
|
||||
theme`{spinnerSuccess ✓} You are about the publish the following packages under the tag {tag ${tags}}:`
|
||||
);
|
||||
} else {
|
||||
console.log(
|
||||
theme`{spinnerSuccess ✓} You are about the publish the following packages under the tags {tag ${tags.join(
|
||||
', '
|
||||
)}}:`
|
||||
);
|
||||
}
|
||||
// All latest releases are auto-tagged as next too by the script.
|
||||
let tags = tag === 'latest' ? ['latest', 'next'] : [tag];
|
||||
console.log(
|
||||
theme`{spinnerSuccess ✓} You are about the publish the following packages under the tag {tag ${tags.join(
|
||||
', '
|
||||
)}}:`
|
||||
);
|
||||
|
||||
for (let i = 0; i < packages.length; i++) {
|
||||
const packageName = packages[i];
|
||||
@@ -13,10 +13,10 @@ const paramDefinitions = [
|
||||
defaultValue: false,
|
||||
},
|
||||
{
|
||||
name: 'tags',
|
||||
name: 'tag',
|
||||
type: String,
|
||||
multiple: true,
|
||||
description: 'NPM tags to point to the new release.',
|
||||
description: 'NPM tag to point to the new release.',
|
||||
defaultValue: 'untagged',
|
||||
},
|
||||
{
|
||||
name: 'skipPackages',
|
||||
@@ -29,10 +29,17 @@ const paramDefinitions = [
|
||||
|
||||
module.exports = () => {
|
||||
const params = commandLineArgs(paramDefinitions);
|
||||
if (!params.tags || !params.tags.length) {
|
||||
params.tags = [];
|
||||
switch (params.tag) {
|
||||
case 'latest':
|
||||
case 'next':
|
||||
case 'experimental':
|
||||
case 'untagged':
|
||||
break;
|
||||
default:
|
||||
console.error('Unknown tag: "' + params.tag + '"');
|
||||
process.exit(1);
|
||||
break;
|
||||
}
|
||||
splitCommaParams(params.skipPackages);
|
||||
splitCommaParams(params.tags);
|
||||
return params;
|
||||
};
|
||||
|
||||
@@ -9,7 +9,7 @@ const {join} = require('path');
|
||||
const theme = require('../theme');
|
||||
const {execRead} = require('../utils');
|
||||
|
||||
const run = async ({cwd, packages, tags}) => {
|
||||
const run = async ({cwd, packages, tag}) => {
|
||||
// All packages are built from a single source revision,
|
||||
// so it is safe to read build info from any one of them.
|
||||
const arbitraryPackageName = packages[0];
|
||||
@@ -24,7 +24,7 @@ const run = async ({cwd, packages, tags}) => {
|
||||
|
||||
clear();
|
||||
|
||||
if (tags.length === 1 && tags[0] === 'next') {
|
||||
if (tag === 'next') {
|
||||
console.log(
|
||||
theme`{header A "next" release} {version ${version}} {header has been published!}`
|
||||
);
|
||||
@@ -35,7 +35,7 @@ const run = async ({cwd, packages, tags}) => {
|
||||
theme.caution`The release has been published but you're not done yet!`
|
||||
);
|
||||
|
||||
if (tags.includes('latest')) {
|
||||
if (tag === 'latest') {
|
||||
console.log();
|
||||
console.log(
|
||||
theme.header`Please review and commit all local, staged changes.`
|
||||
|
||||
@@ -9,7 +9,7 @@ const {join} = require('path');
|
||||
const {confirm, execRead} = require('../utils');
|
||||
const theme = require('../theme');
|
||||
|
||||
const run = async ({cwd, dry, packages, tags}, otp) => {
|
||||
const run = async ({cwd, dry, packages, tag}, otp) => {
|
||||
clear();
|
||||
|
||||
for (let i = 0; i < packages.length; i++) {
|
||||
@@ -34,25 +34,34 @@ const run = async ({cwd, dry, packages, tags}, otp) => {
|
||||
|
||||
// Publish the package and tag it.
|
||||
if (!dry) {
|
||||
await exec(`npm publish --tag=${tags[0]} --otp=${otp}`, {
|
||||
await exec(`npm publish --tag=${tag} --otp=${otp}`, {
|
||||
cwd: packagePath,
|
||||
});
|
||||
}
|
||||
console.log(theme.command(` cd ${packagePath}`));
|
||||
console.log(theme.command(` npm publish --tag=${tags[0]} --otp=${otp}`));
|
||||
console.log(theme.command(` npm publish --tag=${tag} --otp=${otp}`));
|
||||
|
||||
for (let j = 1; j < tags.length; j++) {
|
||||
if (tag === 'latest') {
|
||||
// Whenever we publish latest, also tag "next" automatically so they're in sync.
|
||||
if (!dry) {
|
||||
await exec(
|
||||
`npm dist-tag add ${packageName}@${version} ${tags[j]} --otp=${otp}`,
|
||||
{cwd: packagePath}
|
||||
`npm dist-tag add ${packageName}@${version} next --otp=${otp}`
|
||||
);
|
||||
}
|
||||
console.log(
|
||||
theme.command(
|
||||
` npm dist-tag add ${packageName}@${version} ${tags[j]} --otp=${otp}`
|
||||
` npm dist-tag add ${packageName}@${version} next --otp=${otp}`
|
||||
)
|
||||
);
|
||||
} else if (tag === 'untagged') {
|
||||
// npm doesn't let us publish without a tag at all,
|
||||
// so for one-off publishes we clean it up ourselves.
|
||||
if (!dry) {
|
||||
await exec(`npm dist-tag rm ${packageName}@untagged --otp=${otp}`);
|
||||
}
|
||||
console.log(
|
||||
theme.command(`npm dist-tag rm ${packageName}@untagged --otp=${otp}`)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ const {readFileSync, writeFileSync} = require('fs');
|
||||
const {readJson, writeJson} = require('fs-extra');
|
||||
const {join} = require('path');
|
||||
|
||||
const run = async ({cwd, packages, skipPackages, tags}) => {
|
||||
if (!tags.includes('latest')) {
|
||||
const run = async ({cwd, packages, skipPackages, tag}) => {
|
||||
if (tag !== 'latest') {
|
||||
// Don't update version numbers for alphas.
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
const {readJson} = require('fs-extra');
|
||||
const {join} = require('path');
|
||||
const theme = require('../theme');
|
||||
|
||||
const run = async ({cwd, packages, tag}) => {
|
||||
// Prevent a "next" release from ever being published as @latest
|
||||
// All canaries share a version number, so it's okay to check any of them.
|
||||
const arbitraryPackageName = packages[0];
|
||||
const packageJSONPath = join(
|
||||
cwd,
|
||||
'build',
|
||||
'node_modules',
|
||||
arbitraryPackageName,
|
||||
'package.json'
|
||||
);
|
||||
const {version} = await readJson(packageJSONPath);
|
||||
const isExperimentalVersion = version.indexOf('experimental') !== -1;
|
||||
if (version.indexOf('0.0.0') === 0) {
|
||||
if (tag === 'latest') {
|
||||
if (isExperimentalVersion) {
|
||||
console.log(
|
||||
theme`{error Experimental release} {version ${version}} {error cannot be tagged as} {tag latest}`
|
||||
);
|
||||
} else {
|
||||
console.log(
|
||||
theme`{error Next release} {version ${version}} {error cannot be tagged as} {tag latest}`
|
||||
);
|
||||
}
|
||||
process.exit(1);
|
||||
} else if (tag === 'next' && isExperimentalVersion) {
|
||||
console.log(
|
||||
theme`{error Experimental release} {version ${version}} {error cannot be tagged as} {tag next}`
|
||||
);
|
||||
process.exit(1);
|
||||
} else if (tag === 'experimental' && !isExperimentalVersion) {
|
||||
console.log(
|
||||
theme`{error Next release} {version ${version}} {error cannot be tagged as} {tag experimental}`
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
} else {
|
||||
if (tag !== 'latest') {
|
||||
console.log(
|
||||
theme`{error Stable release} {version ${version}} {error cannot be tagged as} {tag ${tag}}`
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = run;
|
||||
@@ -1,38 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
const {readJson} = require('fs-extra');
|
||||
const {join} = require('path');
|
||||
const theme = require('../theme');
|
||||
|
||||
const run = async ({cwd, packages, tags}) => {
|
||||
// Prevent a "next" release from ever being published as @latest
|
||||
// All canaries share a version number, so it's okay to check any of them.
|
||||
const arbitraryPackageName = packages[0];
|
||||
const packageJSONPath = join(
|
||||
cwd,
|
||||
'build',
|
||||
'node_modules',
|
||||
arbitraryPackageName,
|
||||
'package.json'
|
||||
);
|
||||
const {version} = await readJson(packageJSONPath);
|
||||
if (version.indexOf('0.0.0') === 0) {
|
||||
if (tags.includes('latest')) {
|
||||
console.log(
|
||||
theme`{error Next release} {version ${version}} {error cannot be tagged as} {tag latest}`
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
} else {
|
||||
if (tags.includes('next')) {
|
||||
console.log(
|
||||
theme`{error Stable release} {version ${version}} {error cannot be tagged as} {tag next}`
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = run;
|
||||
@@ -8,13 +8,13 @@ const theme = require('./theme');
|
||||
|
||||
const checkNPMPermissions = require('./publish-commands/check-npm-permissions');
|
||||
const confirmSkippedPackages = require('./publish-commands/confirm-skipped-packages');
|
||||
const confirmVersionAndTags = require('./publish-commands/confirm-version-and-tags');
|
||||
const confirmVersionAndTag = require('./publish-commands/confirm-version-and-tag');
|
||||
const parseParams = require('./publish-commands/parse-params');
|
||||
const printFollowUpInstructions = require('./publish-commands/print-follow-up-instructions');
|
||||
const promptForOTP = require('./publish-commands/prompt-for-otp');
|
||||
const publishToNPM = require('./publish-commands/publish-to-npm');
|
||||
const updateStableVersionNumbers = require('./publish-commands/update-stable-version-numbers');
|
||||
const validateTags = require('./publish-commands/validate-tags');
|
||||
const validateTag = require('./publish-commands/validate-tag');
|
||||
const validateSkipPackages = require('./publish-commands/validate-skip-packages');
|
||||
|
||||
const run = async () => {
|
||||
@@ -37,9 +37,9 @@ const run = async () => {
|
||||
}
|
||||
});
|
||||
|
||||
await validateTags(params);
|
||||
await validateTag(params);
|
||||
await confirmSkippedPackages(params);
|
||||
await confirmVersionAndTags(params);
|
||||
await confirmVersionAndTag(params);
|
||||
await validateSkipPackages(params);
|
||||
await checkNPMPermissions(params);
|
||||
const otp = await promptForOTP(params);
|
||||
|
||||
Reference in New Issue
Block a user