Skip to content

Commit c5ebe6b

Browse files
committed
[ci] Prepare publish workflow
Fixes up a few things in the script and workflow to make it possible to run in CI without interactive prompts.
1 parent 227e841 commit c5ebe6b

File tree

9 files changed

+152
-72
lines changed

9 files changed

+152
-72
lines changed

.github/workflows/runtime_releases_from_npm_manual.yml

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,22 @@ on:
1212
description: Version to publish for the specified packages
1313
type: string
1414
only_packages:
15-
description: Space separated list of packages to publish on NPM. Use this OR skip_packages, not together.
15+
description: Packages to publish (space separated)
1616
type: string
1717
skip_packages:
18-
description: Space separated list of packages to NOT publish on NPM. Use this OR only_packages, not together.
18+
description: Packages to NOT publish (space separated)
1919
type: string
2020
tags:
21-
description: Space separated list of tags to tag the release with on NPM
21+
description: NPM tags (space separated)
2222
type: string
23-
default: "['untagged']"
23+
default: untagged
2424
dry:
2525
required: true
26-
description: Don't actually publish, just run a dry run
26+
description: Dry run instead of publish?
2727
type: boolean
2828
default: true
2929
force_notify:
30-
description: Force a Discord notification
30+
description: Force a Discord notification?
3131
type: boolean
3232
default: false
3333

@@ -52,8 +52,8 @@ jobs:
5252
embed-author-icon-url: ${{ github.event.sender.avatar_url }}
5353
embed-title: '⚠️ Publishing release from NPM'
5454
embed-description: |
55-
```
56-
inputs: ${{ toJson(inputs) }}
55+
```json
56+
${{ toJson(inputs) }}
5757
```
5858
embed-url: https://github.com/facebook/react/actions/runs/${{ github.run_id }}
5959

@@ -81,11 +81,41 @@ jobs:
8181
- run: cp ./scripts/release/ci-npmrc ~/.npmrc
8282
- if: '${{ inputs.only_packages }}'
8383
run: |
84-
scripts/release/prepare-release-from-npm.js --skipTests --version=${{ inputs.version_to_promote }} --onlyPackages=${{ inputs.only_packages }}
84+
echo -e "===== Preparing release from NPM =====\n"
85+
scripts/release/prepare-release-from-npm.js \
86+
--ci \
87+
--skipTests \
88+
--version=${{ inputs.version_to_promote }} \
89+
--publishVersion=${{ inputs.version_to_publish }} \
90+
--onlyPackages=${{ inputs.only_packages }}
91+
92+
echo -e "\n\n===== Check prepared files =====\n"
8593
ls -R build/node_modules
86-
# scripts/release/publish.js --ci --tags=${{ inputs.tags }} --publishVersion=${{ inputs.version_to_publish }} --onlyPackages=${{ inputs.only_packages }} --dry=${{ inputs.dry || 'false' }}
94+
95+
echo -e "\n\n===== Publishing to NPM =====\n"
96+
scripts/release/publish.js \
97+
--ci \
98+
--tags=${{ inputs.tags }} \
99+
--publishVersion=${{ inputs.version_to_publish }} \
100+
--onlyPackages=${{ inputs.only_packages }} \
101+
--dry=${{ inputs.dry }}
87102
- if: '${{ inputs.skip_packages }}'
88103
run: |
89-
scripts/release/prepare-release-from-npm.js --skipTests --version=${{ inputs.version_to_promote }} --skipPackages=${{ inputs.skip_packages }}
104+
echo -e "===== Preparing release from NPM =====\n"
105+
scripts/release/prepare-release-from-npm.js \
106+
--ci \
107+
--skipTests \
108+
--version=${{ inputs.version_to_promote }} \
109+
--publishVersion=${{ inputs.version_to_publish }} \
110+
--skipPackages=${{ inputs.skip_packages }}
111+
112+
echo -e "\n\n===== Check prepared files =====\n"
90113
ls -R build/node_modules
91-
# scripts/release/publish.js --ci --tags=${{ inputs.tags }} --publishVersion=${{ inputs.version_to_publish }} --skipPackages=${{ inputs.skip_packages }} --dry=${{ inputs.dry || 'false' }}
114+
115+
echo -e "\n\n===== Publishing to NPM =====\n"
116+
scripts/release/publish.js \
117+
--ci \
118+
--tags=${{ inputs.tags }} \
119+
--publishVersion=${{ inputs.version_to_publish }} \
120+
--skipPackages=${{ inputs.skip_packages }} \
121+
--dry=${{ inputs.dry }}

scripts/release/prepare-release-from-npm-commands/confirm-stable-version-numbers.js

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const semver = require('semver');
77
const theme = require('../theme');
88
const {confirm} = require('../utils');
99

10-
const run = async ({skipPackages}, versionsMap) => {
10+
const run = async ({ci, skipPackages}, versionsMap) => {
1111
const groupedVersionsMap = new Map();
1212

1313
// Group packages with the same source versions.
@@ -22,44 +22,46 @@ const run = async ({skipPackages}, versionsMap) => {
2222
}
2323
});
2424

25-
// Prompt user to confirm or override each version group.
26-
const entries = [...groupedVersionsMap.entries()];
27-
for (let i = 0; i < entries.length; i++) {
28-
const [bestGuessVersion, packages] = entries[i];
29-
const packageNames = packages.map(name => theme.package(name)).join(', ');
25+
if (ci !== true) {
26+
// Prompt user to confirm or override each version group if not running in CI.
27+
const entries = [...groupedVersionsMap.entries()];
28+
for (let i = 0; i < entries.length; i++) {
29+
const [bestGuessVersion, packages] = entries[i];
30+
const packageNames = packages.map(name => theme.package(name)).join(', ');
3031

31-
let version = bestGuessVersion;
32-
if (
33-
skipPackages.some(skipPackageName => packages.includes(skipPackageName))
34-
) {
35-
await confirm(
36-
theme`{spinnerSuccess ✓} Version for ${packageNames} will remain {version ${bestGuessVersion}}`
37-
);
38-
} else {
39-
const defaultVersion = bestGuessVersion
40-
? theme.version(` (default ${bestGuessVersion})`)
41-
: '';
42-
version =
43-
(await prompt(
44-
theme`{spinnerSuccess ✓} Version for ${packageNames}${defaultVersion}: `
45-
)) || bestGuessVersion;
46-
prompt.done();
47-
}
32+
let version = bestGuessVersion;
33+
if (
34+
skipPackages.some(skipPackageName => packages.includes(skipPackageName))
35+
) {
36+
await confirm(
37+
theme`{spinnerSuccess ✓} Version for ${packageNames} will remain {version ${bestGuessVersion}}`
38+
);
39+
} else {
40+
const defaultVersion = bestGuessVersion
41+
? theme.version(` (default ${bestGuessVersion})`)
42+
: '';
43+
version =
44+
(await prompt(
45+
theme`{spinnerSuccess ✓} Version for ${packageNames}${defaultVersion}: `
46+
)) || bestGuessVersion;
47+
prompt.done();
48+
}
4849

49-
// Verify a valid version has been supplied.
50-
try {
51-
semver(version);
50+
// Verify a valid version has been supplied.
51+
try {
52+
semver(version);
5253

53-
packages.forEach(packageName => {
54-
versionsMap.set(packageName, version);
55-
});
56-
} catch (error) {
57-
console.log(
58-
theme`{spinnerError ✘} Version {version ${version}} is invalid.`
59-
);
54+
packages.forEach(packageName => {
55+
versionsMap.set(packageName, version);
56+
});
57+
} catch (error) {
58+
console.log(
59+
theme`{spinnerError ✘} Version {version ${version}} is invalid.`
60+
);
6061

61-
// Prompt again
62-
i--;
62+
// Prompt again
63+
i--;
64+
}
6365
}
6466
}
6567
};

scripts/release/prepare-release-from-npm-commands/guess-stable-version-numbers.js

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,38 +5,52 @@
55
const semver = require('semver');
66
const {execRead, logPromise} = require('../utils');
77

8-
const run = async ({cwd, packages, skipPackages}, versionsMap) => {
8+
const run = async (
9+
{cwd, packages, skipPackages, ci, publishVersion},
10+
versionsMap
11+
) => {
912
const branch = await execRead('git branch | grep \\* | cut -d " " -f2', {
1013
cwd,
1114
});
1215

1316
for (let i = 0; i < packages.length; i++) {
1417
const packageName = packages[i];
1518

16-
try {
17-
// In case local package JSONs are outdated,
18-
// guess the next version based on the latest NPM release.
19-
const version = await execRead(`npm show ${packageName} version`);
20-
21-
if (skipPackages.includes(packageName)) {
22-
versionsMap.set(packageName, version);
19+
if (ci === true) {
20+
if (publishVersion != null) {
21+
versionsMap.set(packageName, publishVersion);
2322
} else {
24-
const {major, minor, patch} = semver(version);
25-
26-
// Guess the next version by incrementing patch.
27-
// The script will confirm this later.
28-
// By default, new releases from mains should increment the minor version number,
29-
// and patch releases should be done from branches.
30-
if (branch === 'main') {
31-
versionsMap.set(packageName, `${major}.${minor + 1}.0`);
23+
console.error(
24+
'When running in CI mode, a publishVersion must be supplied'
25+
);
26+
process.exit(1);
27+
}
28+
} else {
29+
try {
30+
// In case local package JSONs are outdated,
31+
// guess the next version based on the latest NPM release.
32+
const version = await execRead(`npm show ${packageName} version`);
33+
34+
if (skipPackages.includes(packageName)) {
35+
versionsMap.set(packageName, version);
3236
} else {
33-
versionsMap.set(packageName, `${major}.${minor}.${patch + 1}`);
37+
const {major, minor, patch} = semver(version);
38+
39+
// Guess the next version by incrementing patch.
40+
// The script will confirm this later.
41+
// By default, new releases from mains should increment the minor version number,
42+
// and patch releases should be done from branches.
43+
if (branch === 'main') {
44+
versionsMap.set(packageName, `${major}.${minor + 1}.0`);
45+
} else {
46+
versionsMap.set(packageName, `${major}.${minor}.${patch + 1}`);
47+
}
3448
}
49+
} catch (error) {
50+
// If the package has not yet been published,
51+
// we'll require a version number to be entered later.
52+
versionsMap.set(packageName, null);
3553
}
36-
} catch (error) {
37-
// If the package has not yet been published,
38-
// we'll require a version number to be entered later.
39-
versionsMap.set(packageName, null);
4054
}
4155
}
4256
};

scripts/release/prepare-release-from-npm-commands/parse-params.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,17 @@ const paramDefinitions = [
3939
description:
4040
'Version of published "next" release (e.g. 0.0.0-0e526bcec-20210202)',
4141
},
42+
{
43+
name: 'publishVersion',
44+
type: String,
45+
description: 'Version to publish',
46+
},
47+
{
48+
name: 'ci',
49+
type: Boolean,
50+
description: 'Run in automated environment, without interactive prompts.',
51+
defaultValue: false,
52+
},
4253
];
4354

4455
module.exports = () => {

scripts/release/prepare-release-from-npm-commands/update-stable-version-numbers.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const {join, relative} = require('path');
99
const {confirm, execRead, printDiff} = require('../utils');
1010
const theme = require('../theme');
1111

12-
const run = async ({cwd, packages, version}, versionsMap) => {
12+
const run = async ({cwd, packages, version, ci}, versionsMap) => {
1313
const nodeModulesPath = join(cwd, 'build/node_modules');
1414

1515
// Cache all package JSONs for easy lookup below.
@@ -107,7 +107,9 @@ const run = async ({cwd, packages, version}, versionsMap) => {
107107
printDependencies(packageJSON.dependencies, 'dependency');
108108
printDependencies(packageJSON.peerDependencies, 'peer');
109109
}
110-
await confirm('Do the versions above look correct?');
110+
if (ci !== true) {
111+
await confirm('Do the versions above look correct?');
112+
}
111113

112114
clear();
113115

@@ -167,7 +169,9 @@ const run = async ({cwd, packages, version}, versionsMap) => {
167169
console.log(
168170
theme`A full diff is available at {path ${relative(cwd, diffPath)}}.`
169171
);
170-
await confirm('Do the changes above look correct?');
172+
if (ci !== true) {
173+
await confirm('Do the changes above look correct?');
174+
}
171175
} else {
172176
console.log(
173177
theme`Skipping React renderer version update because React is not included in the release.`

scripts/release/prepare-release-from-npm.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@ const run = async () => {
2626
params.version = await getLatestNextVersion();
2727
}
2828

29+
if (params.onlyPackages.length > 0 && params.skipPackages.length > 0) {
30+
console.error(
31+
'--onlyPackages and --skipPackages cannot be used together'
32+
);
33+
process.exit(1);
34+
}
35+
2936
params.packages = await getPublicPackages(isExperimental);
3037
params.packages = params.packages.filter(packageName => {
3138
if (params.onlyPackages.length > 0) {

scripts/release/publish-commands/confirm-version-and-tags.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ const run = async ({cwd, packages, tags, ci}) => {
3838
console.log(
3939
theme`• {package ${packageName}} {version ${packageJSON.version}}`
4040
);
41+
if (ci) {
42+
console.log(packageJSON);
43+
}
4144
}
4245

4346
if (!ci) {

scripts/release/publish-commands/publish-to-npm.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ const run = async ({cwd, dry, tags, ci}, packageName, otp) => {
2727
await confirm('Is this expected?');
2828
}
2929
} else {
30-
console.log(theme`{spinnerSuccess ✓} Publishing {package ${packageName}}`);
30+
console.log(
31+
theme`{spinnerSuccess ✓} Publishing {package ${packageName}}${dry ? ' (dry-run)' : ''}`
32+
);
3133

3234
// Publish the package and tag it.
3335
if (!dry) {

scripts/release/publish.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@ const run = async () => {
3131
params.cwd = join(__dirname, '..', '..');
3232
params.packages = await getPublicPackages(isExperimental);
3333

34+
if (params.onlyPackages.length > 0 && params.skipPackages.length > 0) {
35+
console.error(
36+
'--onlyPackages and --skipPackages cannot be used together'
37+
);
38+
process.exit(1);
39+
}
40+
3441
if (params.onlyPackages.length > 0) {
3542
params.packages = params.packages.filter(packageName => {
3643
return params.onlyPackages.includes(packageName);

0 commit comments

Comments
 (0)