Add prepare_release_new workflow, configure via flag (#43518)

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

This is a minimum approach to achieve a **single-command publish flow** for React Native, unifying the previous `yarn bump-all-updated-packages` and `yarn trigger-react-native-release` workflow entry points.

This diff aims to change as little as possible to achieve the above — introducing a new job that merges operations to create the versioning commit. The triggered publish jobs are unchanged. In future, we may follow this change with further simplifications down the workflow tree.

**Key changes**

- Adds a new CircleCI workflow, `prepare_release_new`, which versions **all packages** and writes a single release commit.
- This replaces `yarn bump-all-updated-packages`, now implemented with the newer `set-version` script.
- Wires this up as an experiment within `trigger-react-native-release.js`, conditionally running the new workflow when `--use-new-workflow` is passed.

**Not changed**

- The single release commit written will continue to trigger both of the existing CI workflows on push (`publish_release` and `publish_bumped_packages`), which are unchanged.
    - The commit summary now includes the `#publish-packages-to-npm` marker, in order to trigger `publish_bumped_packages`.
- Usage: Release Crew members will continue to use the existing local script entry point (as [documented in the releases repo](https://github.com/reactwg/react-native-releases/blob/main/docs/guide-release-process.md#step-7-publish-react-native)), with the opt in flag.
    ```
    yarn trigger-react-native-release --use-new-workflow [...args]
    ```

After we're happy with the E2E behaviour of this workflow in the next 0.74 RC, I will follow up by dropping the `--use-new-workflow` flag and removing the old scripts (T182533699).

Changelog: [Internal]

Reviewed By: cortinico

Differential Revision: D54956345

fbshipit-source-id: 35fd7af8f3e60a39507b5d978ccd97472bf03ddb
This commit is contained in:
Alex Hunt 2024-03-18 02:22:46 -07:00 committed by Facebook GitHub Bot
parent 06dc448d85
commit 14a7202983
5 changed files with 197 additions and 13 deletions

View File

@ -12,6 +12,15 @@ parameters:
default: false
type: boolean
# Experimental unified release workflow
run_new_release_workflow:
default: false
type: boolean
run_nightly_workflow:
default: false
type: boolean
release_latest:
default: false
type: boolean
@ -20,7 +29,15 @@ parameters:
default: ""
type: string
run_nightly_workflow:
release_monorepo_packages_version:
default: ""
type: string
release_tag:
default: ""
type: string
release_dry_run:
default: false
type: boolean

View File

@ -1107,6 +1107,71 @@ jobs:
node ./scripts/releases-ci/prepare-package-for-release.js -v "$VERSION" -l << parameters.latest >> --dry-run << parameters.dryrun >>
# Experimental unified release workflow
# Replaces `prepare_package_for_release`
#
# Writes a new commit and tag(s), which will trigger the `publish_release`
# and `publish_bumped_packages` workflows.
prepare_release_new:
parameters:
version:
type: string
# TODO(T182538198): Required for 0.74.x, where workspace packages are out
# of sync with react-native. This will be removed for 0.75+.
monorepo_packages_version:
type: string
tag:
type: string
dry_run:
type: boolean
default: false
executor: reactnativeios
steps:
- checkout_code_with_cache
- run_yarn
- add_ssh_keys:
fingerprints:
- "1f:c7:61:c4:e2:ff:77:e3:cc:ca:a7:34:c2:79:e3:3c"
- brew_install:
package: cmake
- run:
name: Versioning workspace packages
command: |
node scripts/releases/set-version "<< parameters.monorepo_packages_version >>" --skip-react-native-version
- run:
name: Versioning react-native package
command: |
node scripts/releases/set-rn-version.js -v "<< parameters.version >>" --build-type "release"
- run:
name: Updating RNTester Podfile.lock
command: |
cd packages/rn-tester/
bundle install
bundle exec pod install
- run:
name: Creating release commit
command: |
git commit -a -m "Release << parameters.version >>\n\n#publish-packages-to-npm&<< parameters.tag >>"
git tag -a "v<< parameters.version >>" -m "v<< parameters.version >>"
git show HEAD
- when:
condition:
equal: ["latest", << parameters.tag >>]
steps:
- run:
name: Updating "latest" tag
command: |
git tag -d "latest"
git push origin :latest
git tag -a "latest" -m "latest"
- unless:
condition: << parameters.dry_run >>
steps:
run:
name: Pushing release commit
command: |
git push origin $CIRCLE_BRANCH --follow-tags
build_npm_package:
parameters:
release_type:

View File

@ -129,14 +129,30 @@ parameters:
default: false
type: boolean
run_new_release_workflow:
default: false
type: boolean
run_nightly_workflow:
default: false
type: boolean
release_latest:
default: false
type: boolean
release_version:
default: "9999"
default: ""
type: string
run_nightly_workflow:
release_monorepo_packages_version:
default: ""
type: string
release_tag:
default: ""
type: string
release_dry_run:
default: false
type: boolean

View File

@ -6,6 +6,7 @@
# when:
# and:
# - equal: [ false, << pipeline.parameters.run_release_workflow >> ]
# - equal: [ false, << pipeline.parameters.run_new_release_workflow >> ]
# - equal: [ false, << pipeline.parameters.run_nightly_workflow >> ]
#
# It's setup this way so we can trigger a release via a POST
@ -25,6 +26,17 @@ workflows:
version: << pipeline.parameters.release_version >>
latest : << pipeline.parameters.release_latest >>
# Experimental unified release workflow
create_release_new:
when: << pipeline.parameters.run_new_release_workflow >>
jobs:
- prepare_release_new:
name: prepare_release_new
version: << pipeline.parameters.release_version >>
monorepo_packages_version: << pipeline.parameters.release_monorepo_packages_version >>
tag: << pipeline.parameters.release_tag >>
dry_run: << pipeline.parameters.release_dry_run >>
# This job will run only when a tag is published due to all the jobs being filtered.
publish_release:
jobs:
@ -79,6 +91,7 @@ workflows:
when:
and:
- equal: [ false, << pipeline.parameters.run_release_workflow >> ]
- equal: [ false, << pipeline.parameters.run_new_release_workflow >> ]
- equal: [ false, << pipeline.parameters.run_nightly_workflow >> ]
jobs:
# Run lints on every commit
@ -128,6 +141,7 @@ workflows:
when:
and:
- equal: [ false, << pipeline.parameters.run_release_workflow >> ]
- equal: [ false, << pipeline.parameters.run_new_release_workflow >> ]
- equal: [ false, << pipeline.parameters.run_nightly_workflow >> ]
jobs:
- find_and_publish_bumped_packages:

View File

@ -49,6 +49,16 @@ let argv = yargs
describe: 'Version you aim to release, ex. 0.67.0-rc.1, 0.66.3',
required: true,
})
.option('dry-run', {
type: 'boolean',
default: false,
})
// TODO(T182533699): Remove arg once new workflow is default
.option('use-new-workflow', {
describe: 'When set, triggers the experimental unified release workflow.',
type: 'boolean',
default: false,
})
.check(() => {
const branch = exitIfNotOnGit(
() => getBranchName(),
@ -78,7 +88,6 @@ const buildExecutor =
if (packageManifest.private) {
return;
}
if (
detectPackageUnreleasedChanges(
packageRelativePathFromRoot,
@ -117,6 +126,36 @@ async function exitIfUnreleasedPackages() {
}
}
/**
* 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 @react-native/dev-middleware@0.74.5
const _0_74_MIN_PATCH = 6;
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 {minor} = parseVersion(version, 'release');
patchVersion = Math.max(patchVersion, parseInt(minor, 10) + 1);
}
return '0.74.' + patchVersion;
}
function triggerReleaseWorkflow(options /*: $FlowFixMe */) {
return new Promise((resolve, reject) => {
request(options, function (error, response, body) {
@ -145,11 +184,16 @@ async function main() {
exit(1);
}
// $FlowFixMe[prop-missing]
const useNewWorkflow: boolean = argv.useNewWorkflow;
// now check for unreleased packages
try {
await exitIfUnreleasedPackages();
} catch (error) {
exit(1);
if (!useNewWorkflow) {
try {
await exitIfUnreleasedPackages();
} catch (error) {
exit(1);
}
}
// $FlowFixMe[prop-missing]
@ -194,11 +238,39 @@ async function main() {
return;
}
const parameters = {
release_version: version,
release_latest: latest,
run_release_workflow: true,
};
let nextMonorepoPackagesVersion;
if (useNewWorkflow) {
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 = useNewWorkflow
? {
release_version: version,
release_latest: latest,
run_release_workflow: true,
}
: {
run_new_release_workflow: true,
release_version: version,
release_tag: npmTag,
// NOTE: Necessary for 0.74, should be dropped for 0.75+
release_monorepo_packages_version: nextMonorepoPackagesVersion,
// $FlowFixMe[prop-missing]
release_dry_run: argv.dryRun,
};
const options = {
method: 'POST',