Remove the trigger-react-native-release to use the GHA workflow_dispatch UI (#44898)

Summary:
This change removes the need for the trigger-react-native-release.js script.
Thanks to the migration to Github Actions, we can now leverage the GHA workflow UI to trigger a Prepare Release job that creates a github tag that will spin a new release.

The pro of this approach are:
- less code to maintain: instead of a complex trigger release scripts, we only have to maintain two very straightforward scripts for the CI
- easier to trigger a release: instead of running a script, we can now just use the GH UI

The `trigger-react-native-release` script was doing the following steps:
- check that we are in the release branch ==> Already implemented in the GHA workflow
- Gets the branch name (not needed) ==> the job will automatically run on the stable branch
- Check for unsent changes (not needed) ==> we are not in a local environment
- get the gh token (not needed) ==> You need to be logged in GH and have write access to the repo
- get the version ==> provided as a parameter
- fails if the tag is already there ==> Functionality added in the workflow
- Parse and validate the version ==> Functionality added to the action prepare-release action + the JS Script
- Compute the npmTag ==> Functionality added to the action prepare-release action + the JS Script
- trigger the release workflow ==> The GH UI does that for us

## Changelog:
[Internal] - Remove the trigger-react-native-release.js

Pull Request resolved: https://github.com/facebook/react-native/pull/44898

Test Plan: Testing in Production!

Reviewed By: cortinico, huntie

Differential Revision: D58461470

Pulled By: cipolleschi

fbshipit-source-id: 32bb0ee91370c9483a29e2ca2e18e24557d5fd53
This commit is contained in:
Riccardo Cipolleschi 2024-06-13 08:19:58 -07:00 committed by Facebook GitHub Bot
parent 726a4a1e5e
commit ece68f0efd
6 changed files with 99 additions and 253 deletions

View File

@ -1,24 +1,18 @@
name: prepare_release
description: Prepare React Native release
name: create_release
description: Creates a new React Native release
runs:
using: composite
steps:
- name: Yarn install
shell: bash
run: yarn install --non-interactive
- name: Versioning workspace packages
shell: bash
run: |
node scripts/releases/set-version "${{ inputs.version }}" --skip-react-native-version
- name: Versioning react-native package
shell: bash
run: |
node scripts/releases/set-rn-version.js -v "<< parameters.version >>" --build-type "release"
- name: Creating release commit
shell: bash
run: |
git commit -a -m "Release ${{ inputs.version }}" -m "#publish-packages-to-npm&${{ inputs.tag }}"
git tag -a "v${{ inputs.version }}" -m "v${{ inputs.version }}"
node scripts/releases/create-release-commit.js \
--reactNativeVersion "${{ inputs.version }}" \
--tagAsLatestRelease "${{ inputs.is_latest_on_npm }}" \
--dryRun "${{ inputs.dry_run }}"
GIT_PAGER=cat git show HEAD
- name: Update "latest" tag if needed
shell: bash

View File

@ -1,16 +1,17 @@
name: Prepare Release
name: Create release
on:
workflow_dispatch:
inputs:
version:
description: 'The version of React Native we want to release'
description: 'The version of React Native we want to release. For example 0.75.0-rc.0'
required: true
type: string
tag:
description: 'The tag name that will be associated with the published npm packages. A tag of "latest" will also be written as a Git tag.'
is_latest_on_npm:
description: 'Whether we want to tag this release as latest on NPM'
required: true
type: string
type: boolean
default: false
dry_run:
description: 'Whether the job should be executed in dry-run mode or not'
type: boolean
@ -33,6 +34,15 @@ jobs:
fi
- name: Print output
run: echo "ON_STABLE_BRANCH ${{steps.check_stable_branch.outputs.ON_STABLE_BRANCH}}"
- name: Check if tag already exists
id: check_if_tag_exists
run: |
TAG="v${{ inputs.version }}"
TAG_EXISTS=$(git tag -l "$TAG")
if [[ -n "$TAG_EXISTS" ]]; then
echo "Version tag already exists!"
echo "TAG_EXISTS=true" >> $GITHUB_OUTPUT
fi
- name: Execute Prepare Release
if: ${{ steps.check_stable_branch.outputs.ON_STABLE_BRANCH }}
uses: ./.github/actions/prepare_release
if: ${{ steps.check_stable_branch.outputs.ON_STABLE_BRANCH && !steps.check_if_tag_exists.outputs.TAG_EXISTS }}
uses: ./.github/actions/create-release

View File

@ -1,11 +0,0 @@
# scripts/releases-local
Local-only release scripts.
## Commands
For information on command arguments, run `node <command> --help`.
### `trigger-react-native-release.js`
Trigger the external release publishing workflow on CircleCI.

View File

@ -1,223 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
* @oncall react_native
*/
'use strict';
const checkForGitChanges = require('../monorepo/check-for-git-changes');
const {failIfTagExists} = require('../releases/utils/release-utils');
const {
isReleaseBranch,
parseVersion,
} = require('../releases/utils/version-utils');
const {exitIfNotOnGit, getBranchName} = require('../scm-utils');
const {getPackages} = require('../utils/monorepo');
const chalk = require('chalk');
const inquirer = require('inquirer');
const request = require('request');
const {echo, exit} = require('shelljs');
const yargs = require('yargs');
/**
* This script walks a releaser through bumping the version for a release
* It will commit the appropriate tags to trigger the CircleCI jobs.
*/
let argv = yargs
.option('r', {
alias: 'remote',
default: 'origin',
})
.option('t', {
alias: 'token',
describe:
'Your GitHub personal API token. See https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens.',
required: true,
})
.option('v', {
alias: 'to-version',
describe: 'Version you aim to release, ex. 0.67.0-rc.1, 0.66.3',
required: true,
})
.option('dry-run', {
type: 'boolean',
default: false,
})
.check(() => {
const branch = exitIfNotOnGit(
() => getBranchName(),
"Not in git. You can't invoke trigger-react-native-release from outside a git repo.",
);
exitIfNotOnReleaseBranch(branch);
return true;
}).argv;
function exitIfNotOnReleaseBranch(branch /*: string */) {
if (!isReleaseBranch(branch)) {
console.log(
'This script must be run in a react-native git repository checkout and on a release branch',
);
exit(1);
}
}
/**
* Get the next version that all workspace packages will be set to.
*
* This approach is specific to the 0.74 release. For 0.75, the `--to-version`
* value will be used instead, setting all packages to a single version.
*/
async function getNextMonorepoPackagesVersion() /*: Promise<string | null> */ {
// Based on last publish before this strategy
const _0_74_MIN_PATCH = 75;
const packages = await getPackages({
includeReactNative: false,
});
let patchVersion = _0_74_MIN_PATCH;
for (const pkg of Object.values(packages)) {
const {version} = pkg.packageJson;
if (!version.startsWith('0.74.') || version.endsWith('-main')) {
return null;
}
const {patch} = parseVersion(version, 'release');
patchVersion = Math.max(patchVersion, parseInt(patch, 10) + 1);
}
return '0.74.' + patchVersion;
}
function triggerReleaseWorkflow(options /*: $FlowFixMe */) {
return new Promise((resolve, reject) => {
request(options, function (error, response, body) {
if (error) {
reject(error);
} else {
resolve(body);
}
});
});
}
async function main() {
const branch = exitIfNotOnGit(
() => getBranchName(),
"Not in git. You can't invoke trigger-react-native-release from outside a git repo.",
);
// check for uncommitted changes
if (checkForGitChanges()) {
echo(
chalk.red(
'Found uncommitted changes. Please commit or stash them before running this script',
),
);
exit(1);
}
// $FlowFixMe[prop-missing]
const token = argv.token;
// $FlowFixMe[prop-missing]
const releaseVersion = argv.toVersion;
failIfTagExists(releaseVersion, 'release');
const {pushed} = await inquirer.prompt({
type: 'confirm',
name: 'pushed',
message: `This script will trigger a release with whatever changes are on the remote branch: ${branch}. \nMake sure you have pushed any updates remotely.`,
});
if (!pushed) {
// $FlowFixMe[prop-missing]
console.log(`Please run 'git push ${argv.remote} ${branch}'`);
exit(1);
return;
}
let latest = false;
const {version, prerelease} = parseVersion(releaseVersion, 'release');
if (!prerelease) {
const {setLatest} = await inquirer.prompt({
type: 'confirm',
name: 'setLatest',
message: `Do you want to set ${version} as "latest" release on npm?`,
});
latest = setLatest;
}
const npmTag = latest ? 'latest' : !prerelease ? branch : 'next';
const {confirmRelease} = await inquirer.prompt({
type: 'confirm',
name: 'confirmRelease',
message: `Releasing version "${version}" with npm tag "${npmTag}". Is this correct?`,
});
if (!confirmRelease) {
console.log('Aborting.');
return;
}
let nextMonorepoPackagesVersion = await getNextMonorepoPackagesVersion();
if (nextMonorepoPackagesVersion == null) {
// TODO(T182538198): Once this warning is hit, we can remove the
// `release_monorepo_packages_version` logic from here and the CI jobs,
// see other TODOs.
console.warn(
'Warning: No longer on the 0.74-stable branch, meaning we will ' +
'write all package versions identically. Please double-check the ' +
'generated diff to see if this is correct.',
);
nextMonorepoPackagesVersion = version;
}
const parameters = {
version: version,
tag: npmTag,
// $FlowFixMe[prop-missing]
dry_run: argv.dryRun,
};
const options = {
method: 'POST',
url: 'https://api.github.com/repos/facebook/react-native/actions/workflows/prepare-release/dispatches',
headers: {
Authorization: `Bearer ${token}`,
Accept: 'application/vnd.github+json',
'X-GitHub-Api-Version': '2022-11-28',
},
body: {
ref: branch,
inputs: parameters,
},
json: true,
};
// See response: https://docs.github.com/en/rest/actions/workflows?apiVersion=2022-11-28#create-a-workflow-dispatch-event
await triggerReleaseWorkflow(options);
console.log(
// $FlowFixMe[incompatible-use]
'Monitor your release workflow: https://github.com/facebook/react-native/actions/workflows/prepare-release.yml',
);
// TODO
// - Output the release changelog to paste into Github releases
// - Link to release discussions to update
// - Verify RN-diff publish is through
}
// $FlowFixMe[unused-promise]
main().then(() => {
exit(0);
});

View File

@ -21,3 +21,7 @@ Updates relevant files in the `react-native` package and template to materialize
### `update-template-package`
Updates workspace dependencies in the template app`package.json`
### `create-release-commit`
Creates a release commit to trigger a new release

View File

@ -0,0 +1,72 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
* @oncall react_native
*/
const setVersion = require('../releases/set-version');
const {getBranchName} = require('../scm-utils');
const {parseVersion} = require('./utils/version-utils');
const {execSync} = require('child_process');
const yargs = require('yargs');
async function main() {
const argv = await yargs
.option('reactNativeVersion', {
describe: 'The new React Native version.',
type: 'string',
required: true,
})
.option('tagAsLatestRelease', {
describe:
'Whether the version should be published as the latest version on npm.',
type: 'boolean',
default: false,
})
.option('dryRun', {
description: 'Whether we should push the commit to github or not',
type: 'boolean',
default: true,
}).argv;
const buildType = 'release';
const version = argv.reactNativeVersion;
const latest = argv.tagAsLatestRelease;
const dryRun = argv.dryRun;
const branch = getBranchName();
console.info(`Running on branch: ${branch}`);
console.info('Validating version', version);
const {prerelease} = parseVersion(version, buildType);
const npmTag = latest ? 'latest' : prerelease ? 'next' : branch;
console.info('NPM tag:', npmTag);
console.info('Setting version for monorepo packages and react-native');
await setVersion(version, false); // version, skip-react-native
if (dryRun) {
console.info('Running in dry-run mode, skipping git commit');
console.info(
`git commit -a -m "Release ${version}" -m "#publish-packages-to-npm&${npmTag}"`,
);
console.info(`git tag -a v${version} -m "v${version}"`);
return;
}
console.info('Committing to git');
execSync(
`git commit -a -m "Release ${version}" -m "#publish-packages-to-npm&${npmTag}"`,
);
execSync(`git tag -a v${version} -m "v${version}"`);
}
if (require.main === module) {
// eslint-disable-next-line no-void
void main();
}