Skip to content

Commit 9157841

Browse files
committed
chore(releases): improve bump oss script to allow less human errors (#38666)
Summary: One of the limitations of the existing flow for the release crew is that they need to manually remember to publish all the other packages in the monorepo ahead of a new patch release - this PR modifies the logic for the bump-oss-version script (and makes it available via yarn) so that it will not run if: * there are git changes lying around * if some of the packages need a new release it required a bit of refactoring to extract some portions of the logic from the bump-all-package-versions script, but I think the end result is pretty decent. ## Changelog: <!-- Help reviewers and the release process by writing your own changelog entry. Pick one each for the category and type tags: For more details, see: https://reactnative.dev/contributing/changelogs-in-pull-requests --> [INTERNAL] [CHANGED] - improve bump oss script to allow less human errors Pull Request resolved: #38666 Test Plan: * checkout this branch * comment L54 of bump-oss-version.js (to remove the check on the branch name) * run `yarn bump-all-updated-packages`, verify that it works and that it detects that some packages have unreleased code * run `yarn bump-oss-version -t asd -v asd` (the "fake" parameters are needed to pass the yargs check), verify that it will throw an error because it finds a package that has unreleased code Reviewed By: mdvacca Differential Revision: D48156963 Pulled By: cortinico fbshipit-source-id: 2473ad5a84578c5236c905fd9aa9a88113fe8d22 # Conflicts: # scripts/publish-npm.js re-add the file nit # Conflicts: # package.json
1 parent 7636e4c commit 9157841

File tree

5 files changed

+134
-31
lines changed

5 files changed

+134
-31
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,8 @@
103103
"test-typescript": "dtslint types",
104104
"test-typescript-offline": "dtslint --localTs node_modules/typescript/lib types",
105105
"bump-all-updated-packages": "node ./scripts/monorepo/bump-all-updated-packages",
106-
"align-package-versions": "node ./scripts/monorepo/align-package-versions.js"
106+
"align-package-versions": "node ./scripts/monorepo/align-package-versions.js",
107+
"trigger-react-native-release": "node ./scripts/trigger-react-native-release.js"
107108
},
108109
"peerDependencies": {
109110
"react": "18.2.0"
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @format
8+
*/
9+
10+
const chalk = require('chalk');
11+
const {echo, exec} = require('shelljs');
12+
13+
const detectPackageUnreleasedChanges = (
14+
packageRelativePathFromRoot,
15+
packageName,
16+
ROOT_LOCATION,
17+
) => {
18+
const hashOfLastCommitInsidePackage = exec(
19+
`git log -n 1 --format=format:%H -- ${packageRelativePathFromRoot}`,
20+
{cwd: ROOT_LOCATION, silent: true},
21+
).stdout.trim();
22+
23+
const hashOfLastCommitThatChangedVersion = exec(
24+
`git log -G\\"version\\": --format=format:%H -n 1 -- ${packageRelativePathFromRoot}/package.json`,
25+
{cwd: ROOT_LOCATION, silent: true},
26+
).stdout.trim();
27+
28+
if (hashOfLastCommitInsidePackage === hashOfLastCommitThatChangedVersion) {
29+
echo(
30+
`\uD83D\uDD0E No changes for package ${chalk.green(
31+
packageName,
32+
)} since last version bump`,
33+
);
34+
return false;
35+
} else {
36+
echo(`\uD83D\uDCA1 Found changes for ${chalk.yellow(packageName)}:`);
37+
exec(
38+
`git log --pretty=oneline ${hashOfLastCommitThatChangedVersion}..${hashOfLastCommitInsidePackage} ${packageRelativePathFromRoot}`,
39+
{
40+
cwd: ROOT_LOCATION,
41+
},
42+
);
43+
echo();
44+
45+
return true;
46+
}
47+
};
48+
49+
module.exports = detectPackageUnreleasedChanges;

scripts/monorepo/bump-all-updated-packages/index.js

Lines changed: 8 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const {
2424
const forEachPackage = require('../for-each-package');
2525
const checkForGitChanges = require('../check-for-git-changes');
2626
const bumpPackageVersion = require('./bump-package-version');
27+
const detectPackageUnreleasedChanges = require('./bump-utils');
2728

2829
const ROOT_LOCATION = path.join(__dirname, '..', '..', '..');
2930

@@ -61,35 +62,16 @@ const buildExecutor =
6162
return;
6263
}
6364

64-
const hashOfLastCommitInsidePackage = exec(
65-
`git log -n 1 --format=format:%H -- ${packageRelativePathFromRoot}`,
66-
{cwd: ROOT_LOCATION, silent: true},
67-
).stdout.trim();
68-
69-
const hashOfLastCommitThatChangedVersion = exec(
70-
`git log -G\\"version\\": --format=format:%H -n 1 -- ${packageRelativePathFromRoot}/package.json`,
71-
{cwd: ROOT_LOCATION, silent: true},
72-
).stdout.trim();
73-
74-
if (hashOfLastCommitInsidePackage === hashOfLastCommitThatChangedVersion) {
75-
echo(
76-
`\uD83D\uDD0E No changes for package ${chalk.green(
77-
packageName,
78-
)} since last version bump`,
79-
);
80-
65+
if (
66+
!detectPackageUnreleasedChanges(
67+
packageRelativePathFromRoot,
68+
packageName,
69+
ROOT_LOCATION,
70+
)
71+
) {
8172
return;
8273
}
8374

84-
echo(`\uD83D\uDCA1 Found changes for ${chalk.yellow(packageName)}:`);
85-
exec(
86-
`git log --pretty=oneline ${hashOfLastCommitThatChangedVersion}..${hashOfLastCommitInsidePackage} ${packageRelativePathFromRoot}`,
87-
{
88-
cwd: ROOT_LOCATION,
89-
},
90-
);
91-
echo();
92-
9375
await inquirer
9476
.prompt([
9577
{

scripts/publish-npm.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ const rawVersion =
9999
: // For nightly we continue to use 0.0.0 for clarity for npm
100100
nightlyBuild
101101
? '0.0.0'
102-
: // For pre-release and stable releases, we use the git tag of the version we're releasing (set in bump-oss-version)
102+
: // For pre-release and stable releases, we use the git tag of the version we're releasing (set in trigger-react-native-release)
103103
buildTag;
104104

105105
let version,

scripts/bump-oss-version.js renamed to scripts/trigger-react-native-release.js

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,21 @@
1414
* This script walks a releaser through bumping the version for a release
1515
* It will commit the appropriate tags to trigger the CircleCI jobs.
1616
*/
17-
const {exit} = require('shelljs');
17+
const {exit, echo} = require('shelljs');
18+
const chalk = require('chalk');
1819
const yargs = require('yargs');
1920
const inquirer = require('inquirer');
2021
const request = require('request');
22+
const path = require('path');
2123
const {getBranchName, exitIfNotOnGit} = require('./scm-utils');
2224

2325
const {parseVersion, isReleaseBranch} = require('./version-utils');
2426
const {failIfTagExists} = require('./release-utils');
27+
const checkForGitChanges = require('./monorepo/check-for-git-changes');
28+
const forEachPackage = require('./monorepo/for-each-package');
29+
const detectPackageUnreleasedChanges = require('./monorepo/bump-all-updated-packages/bump-utils.js');
30+
31+
const ROOT_LOCATION = path.join(__dirname, '..');
2532

2633
let argv = yargs
2734
.option('r', {
@@ -42,7 +49,7 @@ let argv = yargs
4249
.check(() => {
4350
const branch = exitIfNotOnGit(
4451
() => getBranchName(),
45-
"Not in git. You can't invoke bump-oss-versions.js from outside a git repo.",
52+
"Not in git. You can't invoke trigger-react-native-release from outside a git repo.",
4653
);
4754
exitIfNotOnReleaseBranch(branch);
4855
return true;
@@ -57,6 +64,52 @@ function exitIfNotOnReleaseBranch(branch) {
5764
}
5865
}
5966

67+
const buildExecutor =
68+
(packageAbsolutePath, packageRelativePathFromRoot, packageManifest) =>
69+
async () => {
70+
const {name: packageName} = packageManifest;
71+
if (packageManifest.private) {
72+
return;
73+
}
74+
75+
if (
76+
detectPackageUnreleasedChanges(
77+
packageRelativePathFromRoot,
78+
packageName,
79+
ROOT_LOCATION,
80+
)
81+
) {
82+
// if I enter here, I want to throw an error upward
83+
throw new Error(
84+
`Package ${packageName} has unreleased changes. Please release it first.`,
85+
);
86+
}
87+
};
88+
89+
const buildAllExecutors = () => {
90+
const executors = [];
91+
92+
forEachPackage((...params) => {
93+
executors.push(buildExecutor(...params));
94+
});
95+
96+
return executors;
97+
};
98+
99+
async function exitIfUnreleasedPackages() {
100+
// use the other script to verify that there's no packages in the monorepo
101+
// that have changes that haven't been released
102+
103+
const executors = buildAllExecutors();
104+
for (const executor of executors) {
105+
await executor().catch(error => {
106+
echo(chalk.red(error));
107+
// need to throw upward
108+
throw error;
109+
});
110+
}
111+
}
112+
60113
function triggerReleaseWorkflow(options) {
61114
return new Promise((resolve, reject) => {
62115
request(options, function (error, response, body) {
@@ -72,8 +125,26 @@ function triggerReleaseWorkflow(options) {
72125
async function main() {
73126
const branch = exitIfNotOnGit(
74127
() => getBranchName(),
75-
"Not in git. You can't invoke bump-oss-versions.js from outside a git repo.",
128+
"Not in git. You can't invoke trigger-react-native-release from outside a git repo.",
76129
);
130+
131+
// check for uncommitted changes
132+
if (checkForGitChanges()) {
133+
echo(
134+
chalk.red(
135+
'Found uncommitted changes. Please commit or stash them before running this script',
136+
),
137+
);
138+
exit(1);
139+
}
140+
141+
// now check for unreleased packages
142+
try {
143+
await exitIfUnreleasedPackages();
144+
} catch (error) {
145+
exit(1);
146+
}
147+
77148
const token = argv.token;
78149
const releaseVersion = argv.toVersion;
79150
failIfTagExists(releaseVersion, 'release');

0 commit comments

Comments
 (0)