Skip to content

Commit ddcbc78

Browse files
kelsetfacebook-github-bot
authored andcommitted
fix(releases): re-add the file for RN release versioning (#38887)
Summary: For some reason when my PR #38666 got imported the renaming of `bump-oss-version` to `trigger-react-native-release` changed into just removing the bump-oss-version: c956a1b which is, ofc, not ideal. This PR simply readds it. ## Changelog: <!-- Help reviewers and the release process by writing your own changelog entry. Pick one each for the category and type tags: [ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message For more details, see: https://reactnative.dev/contributing/changelogs-in-pull-requests --> [INTERNAL] [FIXED] - re-add the file for RN release versioning Pull Request resolved: #38887 Test Plan: N/A Reviewed By: cipolleschi Differential Revision: D48190224 Pulled By: cortinico fbshipit-source-id: 2bd6cb19daa9c08a51f555e050142f626216bdb4
1 parent e480f89 commit ddcbc78

File tree

1 file changed

+221
-0
lines changed

1 file changed

+221
-0
lines changed
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
#!/usr/bin/env node
2+
/**
3+
* Copyright (c) Meta Platforms, Inc. and affiliates.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*
8+
* @format
9+
*/
10+
11+
'use strict';
12+
13+
/**
14+
* This script walks a releaser through bumping the version for a release
15+
* It will commit the appropriate tags to trigger the CircleCI jobs.
16+
*/
17+
const {exit, echo} = require('shelljs');
18+
const chalk = require('chalk');
19+
const yargs = require('yargs');
20+
const inquirer = require('inquirer');
21+
const request = require('request');
22+
const path = require('path');
23+
const {getBranchName, exitIfNotOnGit} = require('./scm-utils');
24+
25+
const {parseVersion, isReleaseBranch} = require('./version-utils');
26+
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, '..');
32+
33+
let argv = yargs
34+
.option('r', {
35+
alias: 'remote',
36+
default: 'origin',
37+
})
38+
.option('t', {
39+
alias: 'token',
40+
describe:
41+
'Your CircleCI personal API token. See https://circleci.com/docs/2.0/managing-api-tokens/#creating-a-personal-api-token to set one',
42+
required: true,
43+
})
44+
.option('v', {
45+
alias: 'to-version',
46+
describe: 'Version you aim to release, ex. 0.67.0-rc.1, 0.66.3',
47+
required: true,
48+
})
49+
.check(() => {
50+
const branch = exitIfNotOnGit(
51+
() => getBranchName(),
52+
"Not in git. You can't invoke trigger-react-native-release from outside a git repo.",
53+
);
54+
exitIfNotOnReleaseBranch(branch);
55+
return true;
56+
}).argv;
57+
58+
function exitIfNotOnReleaseBranch(branch) {
59+
if (!isReleaseBranch(branch)) {
60+
console.log(
61+
'This script must be run in a react-native git repository checkout and on a release branch',
62+
);
63+
exit(1);
64+
}
65+
}
66+
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+
113+
function triggerReleaseWorkflow(options) {
114+
return new Promise((resolve, reject) => {
115+
request(options, function (error, response, body) {
116+
if (error) {
117+
reject(error);
118+
} else {
119+
resolve(body);
120+
}
121+
});
122+
});
123+
}
124+
125+
async function main() {
126+
const branch = exitIfNotOnGit(
127+
() => getBranchName(),
128+
"Not in git. You can't invoke trigger-react-native-release from outside a git repo.",
129+
);
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+
148+
const token = argv.token;
149+
const releaseVersion = argv.toVersion;
150+
failIfTagExists(releaseVersion, 'release');
151+
152+
const {pushed} = await inquirer.prompt({
153+
type: 'confirm',
154+
name: 'pushed',
155+
message: `This script will trigger a release with whatever changes are on the remote branch: ${branch}. \nMake sure you have pushed any updates remotely.`,
156+
});
157+
158+
if (!pushed) {
159+
console.log(`Please run 'git push ${argv.remote} ${branch}'`);
160+
exit(1);
161+
return;
162+
}
163+
164+
let latest = false;
165+
const {version, prerelease} = parseVersion(releaseVersion, 'release');
166+
if (!prerelease) {
167+
const {setLatest} = await inquirer.prompt({
168+
type: 'confirm',
169+
name: 'setLatest',
170+
message: `Do you want to set ${version} as "latest" release on npm?`,
171+
});
172+
latest = setLatest;
173+
}
174+
175+
const npmTag = latest ? 'latest' : !prerelease ? branch : 'next';
176+
const {confirmRelease} = await inquirer.prompt({
177+
type: 'confirm',
178+
name: 'confirmRelease',
179+
message: `Releasing version "${version}" with npm tag "${npmTag}". Is this correct?`,
180+
});
181+
182+
if (!confirmRelease) {
183+
console.log('Aborting.');
184+
return;
185+
}
186+
187+
const parameters = {
188+
release_version: version,
189+
release_latest: latest,
190+
run_release_workflow: true,
191+
};
192+
193+
const options = {
194+
method: 'POST',
195+
url: 'https://circleci.com/api/v2/project/github/facebook/react-native/pipeline',
196+
headers: {
197+
'Circle-Token': token,
198+
'content-type': 'application/json',
199+
},
200+
body: {
201+
branch,
202+
parameters,
203+
},
204+
json: true,
205+
};
206+
207+
// See response: https://circleci.com/docs/api/v2/#operation/triggerPipeline
208+
const body = await triggerReleaseWorkflow(options);
209+
console.log(
210+
`Monitor your release workflow: https://app.circleci.com/pipelines/github/facebook/react-native/${body.number}`,
211+
);
212+
213+
// TODO
214+
// - Output the release changelog to paste into Github releases
215+
// - Link to release discussions to update
216+
// - Verify RN-diff publish is through
217+
}
218+
219+
main().then(() => {
220+
exit(0);
221+
});

0 commit comments

Comments
 (0)