From 1d05315a113521fa77bf25a6cda6dd51f18814bf Mon Sep 17 00:00:00 2001 From: Alex Hunt Date: Tue, 19 Mar 2024 05:09:08 -0700 Subject: [PATCH 1/2] [skip ci] Switch to new release workflow as default (#43533) Summary: Switch to the new unified release workflow by default, now that this has been validated on the `0.74-stable` branch. - Remove `--use-new-workflow` flag and remove legacy logic. - Remove legacy `prepare_package_for_release` CI job, and use `run_new_release_workflow` -> `run_release_workflow` as new workflow condition match. Changelog: [Internal] Reviewed By: cortinico Differential Revision: D55027120 --- .circleci/config.yml | 9 - .circleci/configurations/jobs.yml | 35 +--- .../configurations/test_workflows/testAll.yml | 11 +- .../test_workflows/testAndroid.yml | 11 +- .../configurations/test_workflows/testIOS.yml | 11 +- .circleci/configurations/top_level.yml | 8 - .circleci/configurations/workflows.yml | 21 +-- .../prepare-package-for-release.js | 154 ------------------ .../trigger-react-native-release.js | 120 +++----------- 9 files changed, 43 insertions(+), 337 deletions(-) delete mode 100755 scripts/releases-ci/prepare-package-for-release.js diff --git a/.circleci/config.yml b/.circleci/config.yml index af889bdc060522..a642711e33d1af 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -12,19 +12,10 @@ 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 - release_version: default: "" type: string diff --git a/.circleci/configurations/jobs.yml b/.circleci/configurations/jobs.yml index d48e4b6c7b6415..2ac0543448c6cd 100644 --- a/.circleci/configurations/jobs.yml +++ b/.circleci/configurations/jobs.yml @@ -1076,43 +1076,10 @@ jobs: # ------------------------- # JOBS: Releases # ------------------------- - prepare_package_for_release: - parameters: - version: - type: string - latest: - type: boolean - default: false - dryrun: - 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: "Set new react-native version and commit changes" - command: | - VERSION=<< parameters.version >> - - if [[ -z "$VERSION" ]]; then - VERSION=$(grep '"version"' package.json | cut -d '"' -f 4 | head -1) - echo "Using the version from the package.json: $VERSION" - fi - - 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: + prepare_release: parameters: version: type: string diff --git a/.circleci/configurations/test_workflows/testAll.yml b/.circleci/configurations/test_workflows/testAll.yml index 9525846607ad7b..efa04aaa28551b 100644 --- a/.circleci/configurations/test_workflows/testAll.yml +++ b/.circleci/configurations/test_workflows/testAll.yml @@ -4,11 +4,12 @@ - equal: [ false, << pipeline.parameters.run_release_workflow >> ] - equal: [ false, << pipeline.parameters.run_nightly_workflow >> ] jobs: - - prepare_package_for_release: - name: prepare_package_for_release - version: '' - latest : false - dryrun: true + - prepare_release: + name: "prepare_release (dry run test)" + version: "0.73.0" + monorepo_packages_version: "0.73.0" + tag: latest + dry_run: true - prepare_hermes_workspace - build_android: release_type: "dry-run" diff --git a/.circleci/configurations/test_workflows/testAndroid.yml b/.circleci/configurations/test_workflows/testAndroid.yml index 08f925eca37b61..5b65f9cafafeda 100644 --- a/.circleci/configurations/test_workflows/testAndroid.yml +++ b/.circleci/configurations/test_workflows/testAndroid.yml @@ -4,11 +4,12 @@ - equal: [ false, << pipeline.parameters.run_release_workflow >> ] - equal: [ false, << pipeline.parameters.run_nightly_workflow >> ] jobs: - - prepare_package_for_release: - name: prepare_package_for_release - version: '' - latest : false - dryrun: true + - prepare_release: + name: "prepare_release (dry run test)" + version: "0.73.0" + monorepo_packages_version: "0.73.0" + tag: latest + dry_run: true - prepare_hermes_workspace - build_android: release_type: "dry-run" diff --git a/.circleci/configurations/test_workflows/testIOS.yml b/.circleci/configurations/test_workflows/testIOS.yml index a1e6c479cfe571..1ab77a6248d410 100644 --- a/.circleci/configurations/test_workflows/testIOS.yml +++ b/.circleci/configurations/test_workflows/testIOS.yml @@ -4,11 +4,12 @@ - equal: [ false, << pipeline.parameters.run_release_workflow >> ] - equal: [ false, << pipeline.parameters.run_nightly_workflow >> ] jobs: - - prepare_package_for_release: - name: prepare_package_for_release - version: '' - latest : false - dryrun: true + - prepare_release: + name: "prepare_release (dry run test)" + version: "0.73.0" + monorepo_packages_version: "0.73.0" + tag: latest + dry_run: true - prepare_hermes_workspace - build_android: release_type: "dry-run" diff --git a/.circleci/configurations/top_level.yml b/.circleci/configurations/top_level.yml index 4c76d009a026cb..3dfc1fa42fc9e2 100644 --- a/.circleci/configurations/top_level.yml +++ b/.circleci/configurations/top_level.yml @@ -129,18 +129,10 @@ 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: "" type: string diff --git a/.circleci/configurations/workflows.yml b/.circleci/configurations/workflows.yml index cb74962959d3a1..e74f8ce39cd132 100644 --- a/.circleci/configurations/workflows.yml +++ b/.circleci/configurations/workflows.yml @@ -6,7 +6,6 @@ # 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 @@ -16,22 +15,12 @@ workflows: version: 2 - # This workflow should only be triggered by release script - package_release: + # Release workflow, triggered by `yarn trigger-react-native-release` + create_release: when: << pipeline.parameters.run_release_workflow >> jobs: - # This job will push a tag that will trigger the publish_release workflow - - prepare_package_for_release: - name: prepare_package_for_release - 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 + - prepare_release: + name: prepare_release version: << pipeline.parameters.release_version >> monorepo_packages_version: << pipeline.parameters.release_monorepo_packages_version >> tag: << pipeline.parameters.release_tag >> @@ -91,7 +80,6 @@ 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 @@ -141,7 +129,6 @@ 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: diff --git a/scripts/releases-ci/prepare-package-for-release.js b/scripts/releases-ci/prepare-package-for-release.js deleted file mode 100755 index 80362844cd6c40..00000000000000 --- a/scripts/releases-ci/prepare-package-for-release.js +++ /dev/null @@ -1,154 +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 {RN_TESTER_DIR} = require('../consts'); -const {setReactNativeVersion} = require('../releases/set-rn-version'); -const {failIfTagExists} = require('../releases/utils/release-utils'); -const { - isReleaseBranch, - parseVersion, -} = require('../releases/utils/version-utils'); -const {execSync} = require('child_process'); -const {echo, exec, exit} = require('shelljs'); -const yargs = require('yargs'); - -/** - * This script prepares a release package to be pushed to npm - * It is triggered to run on CircleCI - * It will: - * * It updates the version in json/gradle files and makes sure they are consistent between each other (set-rn-version) - * * Updates podfile for RNTester - * * Commits changes and tags with the next version based off of last version tag. - * This in turn will trigger another CircleCI job to publish to npm - */ -async function main() { - const argv = yargs - .option('r', { - alias: 'remote', - default: 'origin', - }) - .option('v', { - alias: 'to-version', - type: 'string', - required: true, - }) - .option('l', { - alias: 'latest', - type: 'boolean', - default: false, - }) - .option('d', { - alias: 'dry-run', - type: 'boolean', - default: false, - }).argv; - - const branch = process.env.CIRCLE_BRANCH; - // $FlowFixMe[prop-missing] - const remote = argv.remote; - // $FlowFixMe[prop-missing] - const releaseVersion = argv.toVersion; - // $FlowFixMe[prop-missing] - const isLatest = argv.latest; - // $FlowFixMe[prop-missing] - const isDryRun = argv.dryRun; - - if (branch == null) { - throw new Error('process.env.CIRCLE_BRANCH is not set'); - } - - const buildType = isDryRun - ? 'dry-run' - : isReleaseBranch(branch) - ? 'release' - : 'nightly'; - - failIfTagExists(releaseVersion, buildType); - - if (branch && !isReleaseBranch(branch) && !isDryRun) { - console.error(`This needs to be on a release branch. On branch: ${branch}`); - exit(1); - } else if (!branch && !isDryRun) { - console.error('This needs to be on a release branch.'); - exit(1); - } - - const {version} = parseVersion(releaseVersion, buildType); - if (version == null) { - console.error(`Invalid version provided: ${releaseVersion}`); - exit(1); - } - - try { - await setReactNativeVersion(version, null, buildType); - } catch (e) { - echo(`Failed to set React Native version to ${version}`); - exit(1); - } - - // Release builds should commit the version bumps, and create tags. - try { - console.log('Updating RNTester Podfile.lock'); - execSync( - ` - bundle install; - bundle exec pod install; - `, - {cwd: RN_TESTER_DIR, stdio: 'inherit'}, - ); - } catch (e) { - console.error('Failed to update RNTester Podfile.lock.'); - console.error('Fix the issue, revert and try again.'); - - process.exitCode = 1; - return; - } - - echo(`Local checkout has been prepared for release version ${version}.`); - if (isDryRun) { - echo('Changes will not be committed because --dry-run was set to true.'); - exit(0); - } - - // Make commit [0.21.0-rc] Bump version numbers - if (exec(`git commit -a -m "[${version}] Bump version numbers"`).code) { - echo('failed to commit'); - exit(1); - } - - // Add tag v0.21.0-rc.1 - if (exec(`git tag -a v${version} -m "v${version}"`).code) { - echo( - `failed to tag the commit with v${version}, are you sure this release wasn't made earlier?`, - ); - echo('You may want to rollback the last commit'); - echo('git reset --hard HEAD~1'); - exit(1); - } - - // If `isLatest`, this git tag will also set npm release as `latest` - if (isLatest) { - exec('git tag -d latest'); - exec(`git push ${remote} :latest`); - - // This will be pushed with the `--follow-tags` - exec('git tag -a latest -m "latest"'); - } - - exec(`git push ${remote} ${branch} --follow-tags`); -} - -if (require.main === module) { - // eslint-disable-next-line no-void - void main(); -} diff --git a/scripts/releases-local/trigger-react-native-release.js b/scripts/releases-local/trigger-react-native-release.js index 8515f06c0f982e..fec627395f4319 100644 --- a/scripts/releases-local/trigger-react-native-release.js +++ b/scripts/releases-local/trigger-react-native-release.js @@ -11,8 +11,6 @@ 'use strict'; -const {REPO_ROOT} = require('../consts'); -const detectPackageUnreleasedChanges = require('../monorepo/bump-all-updated-packages/bump-utils.js'); const checkForGitChanges = require('../monorepo/check-for-git-changes'); const {failIfTagExists} = require('../releases/utils/release-utils'); const { @@ -23,7 +21,6 @@ const {exitIfNotOnGit, getBranchName} = require('../scm-utils'); const {getPackages} = require('../utils/monorepo'); const chalk = require('chalk'); const inquirer = require('inquirer'); -const path = require('path'); const request = require('request'); const {echo, exit} = require('shelljs'); const yargs = require('yargs'); @@ -53,12 +50,6 @@ let argv = yargs 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(), @@ -77,55 +68,6 @@ function exitIfNotOnReleaseBranch(branch /*: string */) { } } -const buildExecutor = - ( - packageAbsolutePath /*: string */, - packageRelativePathFromRoot /*: string */, - packageManifest /*: $FlowFixMe */, - ) => - async () => { - const {name: packageName} = packageManifest; - if (packageManifest.private) { - return; - } - if ( - detectPackageUnreleasedChanges( - packageRelativePathFromRoot, - packageName, - REPO_ROOT, - ) - ) { - // if I enter here, I want to throw an error upward - throw new Error( - `Package ${packageName} has unreleased changes. Please release it first.`, - ); - } - }; - -async function exitIfUnreleasedPackages() { - // use the other script to verify that there's no packages in the monorepo - // that have changes that haven't been released - - const packages = await getPackages({ - includeReactNative: false, - includePrivate: true, - }); - - for (const pkg of Object.values(packages)) { - const executor = buildExecutor( - pkg.path, - path.relative(REPO_ROOT, pkg.path), - pkg.packageJson, - ); - - await executor().catch(error => { - echo(chalk.red(error)); - // need to throw upward - throw error; - }); - } -} - /** * Get the next version that all workspace packages will be set to. * @@ -184,18 +126,6 @@ async function main() { exit(1); } - // $FlowFixMe[prop-missing] - const useNewWorkflow /*: boolean */ = argv.useNewWorkflow; - - // now check for unreleased packages - if (!useNewWorkflow) { - try { - await exitIfUnreleasedPackages(); - } catch (error) { - exit(1); - } - } - // $FlowFixMe[prop-missing] const token = argv.token; // $FlowFixMe[prop-missing] @@ -238,39 +168,29 @@ async function main() { return; } - let nextMonorepoPackagesVersion; - - if (useNewWorkflow) { - nextMonorepoPackagesVersion = await getNextMonorepoPackagesVersion(); + 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; - } + 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 - ? { - 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, - } - : { - release_version: version, - release_latest: latest, - run_release_workflow: true, - }; + const parameters = { + run_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', From 1dcd3546b9381da3c292558a3b8e82575e0794db Mon Sep 17 00:00:00 2001 From: Alex Hunt Date: Tue, 19 Mar 2024 05:09:08 -0700 Subject: [PATCH 2/2] Remove bump-all-updated-packages script (#43534) Summary: This is no longer used after switching to the new release workflow, which uses the newer and less error-prone `set-version` script. Changelog: [Internal] Differential Revision: D55027122 --- package.json | 1 - scripts/__tests__/npm-utils-test.js | 21 -- .../get-and-update-packages-fixtures.js | 174 ------------ .../__tests__/bump-package-version-test.js | 36 --- scripts/monorepo/align-package-versions.js | 135 --------- .../bump-package-version.js | 52 ---- .../bump-all-updated-packages/bump-utils.js | 49 ---- .../bump-all-updated-packages/index.js | 261 ------------------ scripts/monorepo/constants.js | 24 -- scripts/npm-utils.js | 32 --- .../releases-ci/publish-updated-packages.js | 2 +- 11 files changed, 1 insertion(+), 786 deletions(-) delete mode 100644 scripts/monorepo/__tests__/__fixtures__/get-and-update-packages-fixtures.js delete mode 100644 scripts/monorepo/__tests__/bump-package-version-test.js delete mode 100644 scripts/monorepo/align-package-versions.js delete mode 100644 scripts/monorepo/bump-all-updated-packages/bump-package-version.js delete mode 100644 scripts/monorepo/bump-all-updated-packages/bump-utils.js delete mode 100644 scripts/monorepo/bump-all-updated-packages/index.js delete mode 100644 scripts/monorepo/constants.js diff --git a/package.json b/package.json index 761a16cc7c2fce..5351aba4e1439d 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,6 @@ "android": "cd packages/rn-tester && npm run android", "build-android": "./gradlew :packages:react-native:ReactAndroid:build", "build": "node ./scripts/build/build.js", - "bump-all-updated-packages": "node ./scripts/monorepo/bump-all-updated-packages", "clang-format": "clang-format -i --glob=*/**/*.{h,cpp,m,mm}", "clean": "node ./scripts/build/clean.js", "flow-check": "flow check", diff --git a/scripts/__tests__/npm-utils-test.js b/scripts/__tests__/npm-utils-test.js index 0413bb54f5b6cc..b8291e8caa8a21 100644 --- a/scripts/__tests__/npm-utils-test.js +++ b/scripts/__tests__/npm-utils-test.js @@ -10,7 +10,6 @@ const { applyPackageVersions, getNpmInfo, - getPackageVersionStrByTag, getVersionsBySpec, publishPackage, } = require('../npm-utils'); @@ -73,26 +72,6 @@ describe('npm-utils', () => { }); }); - describe('getPackageVersionStrByTag', () => { - it('should return package version string', () => { - execMock.mockImplementationOnce(() => ({code: 0, stdout: '0.34.2 \n'})); - const versionStr = getPackageVersionStrByTag('my-package', 'next'); - expect(versionStr).toBe('0.34.2'); - }); - it('should throw error when invalid result', () => { - execMock.mockImplementationOnce(() => ({ - code: 1, - stderr: 'Some error message', - })); - - expect(() => { - getPackageVersionStrByTag('my-package', 'next'); - }).toThrow( - "Failed to run 'npm view my-package@next version'\nSome error message", - ); - }); - }); - describe('publishPackage', () => { it('should run publish command', () => { publishPackage( diff --git a/scripts/monorepo/__tests__/__fixtures__/get-and-update-packages-fixtures.js b/scripts/monorepo/__tests__/__fixtures__/get-and-update-packages-fixtures.js deleted file mode 100644 index 4fb2738c7e69c3..00000000000000 --- a/scripts/monorepo/__tests__/__fixtures__/get-and-update-packages-fixtures.js +++ /dev/null @@ -1,174 +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. - * - * @format - * @oncall react-native - */ - -const mockPackages = [ - { - packageManifest: { - name: '@react-native/packageA', - version: 'local-version', - dependencies: {}, - devDependencies: {}, - }, - packageAbsolutePath: '/some/place/packageA', - packageRelativePathFromRoot: './place/packageA', - }, - { - packageManifest: { - name: '@react-native/not_published', - version: 'local-version', - dependencies: {'@react-native/packageA': 'local-version'}, - }, - packageAbsolutePath: '/some/place/not_published', - packageRelativePathFromRoot: './place/not_published', - }, - { - packageManifest: { - name: '@react-native/packageB', - version: 'local-version', - dependencies: {'@react-native/packageA': 'local-version'}, - }, - packageAbsolutePath: '/some/place/packageB', - packageRelativePathFromRoot: './place/packageB', - }, - { - packageManifest: { - name: '@react-native/packageC', - version: 'local-version', - devDependencies: {'@react-native/packageE': 'local-version'}, - }, - packageAbsolutePath: '/some/place/packageC', - packageRelativePathFromRoot: './place/packageC', - }, - { - packageManifest: { - name: '@react-native/packageD', - version: 'local-version', - dependencies: { - '@react-native/packageA': 'local-version', - '@react-native/packageC': 'local-version', - }, - }, - packageAbsolutePath: '/some/place/packageD', - packageRelativePathFromRoot: './place/packageD', - }, - { - packageManifest: {name: '@react-native/packageE', version: 'local-version'}, - packageAbsolutePath: '/some/place/packageE', - packageRelativePathFromRoot: './place/packageE', - }, - { - packageManifest: { - name: '@react-native/packageF', - version: 'local-version', - dependencies: { - '@react-native/packageB': 'local-version', - }, - devDependencies: { - '@react-native/packageD': 'local-version', - }, - }, - packageAbsolutePath: '/some/place/packageF', - packageRelativePathFromRoot: './place/packageF', - }, - { - packageManifest: { - name: '@react-native/packageP', - version: 'local-version', - private: true, - dependencies: {}, - devDependencies: {}, - }, - packageAbsolutePath: '/some/place/packageP', - packageRelativePathFromRoot: './place/packageP', - }, - { - packageManifest: { - name: 'react-native', - version: 'local-version', - private: true, - dependencies: { - '@react-native/packageA': 'local-version', - '@react-native/packageB': 'local-version', - '@react-native/packageC': 'local-version', - }, - devDependencies: { - '@react-native/packageD': 'local-version', - '@react-native/packageE': 'local-version', - '@react-native/packageF': 'local-version', - }, - }, - packageAbsolutePath: '/some/place/react-native', - packageRelativePathFromRoot: './place/react-native', - }, -]; - -function expectedPackageA(newVersion) { - return { - name: '@react-native/packageA', - version: newVersion, - dependencies: {}, - devDependencies: {}, - }; -} - -function expectedPackageB(newVersion) { - return { - name: '@react-native/packageB', - version: newVersion, - dependencies: {'@react-native/packageA': newVersion}, - }; -} - -function expectedPackageC(newVersion) { - return { - name: '@react-native/packageC', - version: newVersion, - devDependencies: {'@react-native/packageE': newVersion}, - }; -} -function expectedPackageD(newVersion) { - return { - name: '@react-native/packageD', - version: newVersion, - dependencies: { - '@react-native/packageA': newVersion, - '@react-native/packageC': newVersion, - }, - }; -} -function expectedPackageE(newVersion) { - return {name: '@react-native/packageE', version: newVersion}; -} -function expectedPackageF(newVersion) { - return { - name: '@react-native/packageF', - version: newVersion, - dependencies: { - '@react-native/packageB': newVersion, - }, - devDependencies: { - '@react-native/packageD': newVersion, - }, - }; -} - -const expectedPackages = { - '@react-native/packageA': expectedPackageA, - '@react-native/packageB': expectedPackageB, - '@react-native/packageC': expectedPackageC, - '@react-native/packageD': expectedPackageD, - '@react-native/packageE': expectedPackageE, - '@react-native/packageF': expectedPackageF, -}; - -module.exports = { - mockPackages, - expectedPackages, -}; diff --git a/scripts/monorepo/__tests__/bump-package-version-test.js b/scripts/monorepo/__tests__/bump-package-version-test.js deleted file mode 100644 index 00dcccb7359d2e..00000000000000 --- a/scripts/monorepo/__tests__/bump-package-version-test.js +++ /dev/null @@ -1,36 +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. - * - * @format - */ - -const bumpPackageVersion = require('../bump-all-updated-packages/bump-package-version'); -const {writeFileSync} = require('fs'); -const path = require('path'); - -jest.mock('fs', () => ({ - writeFileSync: jest.fn(), - readFileSync: jest.fn(() => '{}'), -})); - -describe('bumpPackageVersionTest', () => { - it('updates patch version of the package', () => { - const mockedPackageLocation = '~/packages/assets'; - const mockedPackageManifest = { - name: '@react-native/test', - version: '1.2.3', - }; - - bumpPackageVersion(mockedPackageLocation, mockedPackageManifest); - - expect(writeFileSync).toHaveBeenCalledWith( - path.join(mockedPackageLocation, 'package.json'), - JSON.stringify({...mockedPackageManifest, version: '1.2.4'}, null, 2) + - '\n', - 'utf-8', - ); - }); -}); diff --git a/scripts/monorepo/align-package-versions.js b/scripts/monorepo/align-package-versions.js deleted file mode 100644 index b30d4088b3f9a3..00000000000000 --- a/scripts/monorepo/align-package-versions.js +++ /dev/null @@ -1,135 +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 - */ - -/*:: -import type {PackageJson} from '../utils/monorepo'; -*/ - -const {getPackages} = require('../utils/monorepo'); -const {readFileSync, writeFileSync} = require('fs'); -const path = require('path'); - -const ROOT_LOCATION = path.join(__dirname, '..', '..'); -const TEMPLATE_LOCATION = path.join( - ROOT_LOCATION, - 'packages', - 'react-native', - 'template', -); - -const readJSONFile = (pathToFile /*: string */) /*: PackageJson */ => - JSON.parse(readFileSync(pathToFile, 'utf-8')); - -const checkIfShouldUpdateDependencyPackageVersion = ( - consumerPackageAbsolutePath /*: string */, - updatedPackageName /*: string */, - updatedPackageVersion /*: string */, -) => { - const consumerPackageManifestPath = path.join( - consumerPackageAbsolutePath, - 'package.json', - ); - const consumerPackageManifest = readJSONFile(consumerPackageManifestPath); - - const dependencyVersion = - consumerPackageManifest.dependencies?.[updatedPackageName]; - - if (dependencyVersion && dependencyVersion !== '*') { - const updatedDependencyVersion = dependencyVersion.startsWith('^') - ? `^${updatedPackageVersion}` - : updatedPackageVersion; - - if (updatedDependencyVersion !== dependencyVersion) { - console.log( - `\uD83D\uDCA1 ${consumerPackageManifest.name} was updated: now using version ${updatedPackageVersion} of ${updatedPackageName}`, - ); - - const updatedPackageManifest = { - ...consumerPackageManifest, - dependencies: { - ...consumerPackageManifest.dependencies, - [updatedPackageName]: updatedDependencyVersion, - }, - }; - - writeFileSync( - consumerPackageManifestPath, - JSON.stringify(updatedPackageManifest, null, 2) + '\n', - 'utf-8', - ); - } - } - - const devDependencyVersion = - consumerPackageManifest.devDependencies?.[updatedPackageName]; - - if (devDependencyVersion && devDependencyVersion !== '*') { - const updatedDependencyVersion = devDependencyVersion.startsWith('^') - ? `^${updatedPackageVersion}` - : updatedPackageVersion; - - if (updatedDependencyVersion !== devDependencyVersion) { - console.log( - `\uD83D\uDCA1 ${consumerPackageManifest.name} was updated: now using version ${updatedPackageVersion} of ${updatedPackageName}`, - ); - - const updatedPackageManifest = { - ...consumerPackageManifest, - devDependencies: { - ...consumerPackageManifest.devDependencies, - [updatedPackageName]: updatedDependencyVersion, - }, - }; - - writeFileSync( - consumerPackageManifestPath, - JSON.stringify(updatedPackageManifest, null, 2) + '\n', - 'utf-8', - ); - } - } -}; - -async function alignPackageVersions() { - const allPackages = await getPackages({ - includeReactNative: true, - includePrivate: true, - }); - const packagesExcludingReactNative = Object.keys(allPackages).filter( - packageName => packageName !== 'react-native', - ); - - for (const packageName of packagesExcludingReactNative) { - const {packageJson: packageManifest} = allPackages[packageName]; - - checkIfShouldUpdateDependencyPackageVersion( - ROOT_LOCATION, - packageManifest.name, - packageManifest.version, - ); - - checkIfShouldUpdateDependencyPackageVersion( - TEMPLATE_LOCATION, - packageManifest.name, - packageManifest.version, - ); - - for (const {path: pathToPackage} of Object.values(allPackages)) { - checkIfShouldUpdateDependencyPackageVersion( - pathToPackage, - packageManifest.name, - packageManifest.version, - ); - } - } -} - -module.exports = alignPackageVersions; diff --git a/scripts/monorepo/bump-all-updated-packages/bump-package-version.js b/scripts/monorepo/bump-all-updated-packages/bump-package-version.js deleted file mode 100644 index d403eb9f94e712..00000000000000 --- a/scripts/monorepo/bump-all-updated-packages/bump-package-version.js +++ /dev/null @@ -1,52 +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. - * - * @format - */ - -const {writeFileSync} = require('fs'); -const path = require('path'); - -const getIncrementedVersion = (version, increment) => - version - .split('.') - .map((token, index) => { - const indexOfVersionToIncrement = increment === 'minor' ? 1 : 2; - - if (index === indexOfVersionToIncrement) { - return parseInt(token, 10) + 1; - } - - if (index > indexOfVersionToIncrement) { - return 0; - } - - return token; - }) - .join('.'); - -const bumpPackageVersion = ( - packageAbsolutePath, - packageManifest, - increment = 'patch', -) => { - const updatedVersion = getIncrementedVersion( - packageManifest.version, - increment, - ); - - // Not using simple `npm version patch` because it updates dependencies and yarn.lock file - writeFileSync( - path.join(packageAbsolutePath, 'package.json'), - JSON.stringify({...packageManifest, version: updatedVersion}, null, 2) + - '\n', - 'utf-8', - ); - - return updatedVersion; -}; - -module.exports = bumpPackageVersion; diff --git a/scripts/monorepo/bump-all-updated-packages/bump-utils.js b/scripts/monorepo/bump-all-updated-packages/bump-utils.js deleted file mode 100644 index 07c57e5313ab27..00000000000000 --- a/scripts/monorepo/bump-all-updated-packages/bump-utils.js +++ /dev/null @@ -1,49 +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. - * - * @format - */ - -const chalk = require('chalk'); -const {echo, exec} = require('shelljs'); - -const detectPackageUnreleasedChanges = ( - packageRelativePathFromRoot, - packageName, - ROOT_LOCATION, -) => { - const hashOfLastCommitInsidePackage = exec( - `git log -n 1 --format=format:%H -- ${packageRelativePathFromRoot}`, - {cwd: ROOT_LOCATION, silent: true}, - ).stdout.trim(); - - const hashOfLastCommitThatChangedVersion = exec( - `git log -G\\"version\\": --format=format:%H -n 1 -- ${packageRelativePathFromRoot}/package.json`, - {cwd: ROOT_LOCATION, silent: true}, - ).stdout.trim(); - - if (hashOfLastCommitInsidePackage === hashOfLastCommitThatChangedVersion) { - echo( - `\uD83D\uDD0E No changes for package ${chalk.green( - packageName, - )} since last version bump`, - ); - return false; - } else { - echo(`\uD83D\uDCA1 Found changes for ${chalk.yellow(packageName)}:`); - exec( - `git log --pretty=oneline ${hashOfLastCommitThatChangedVersion}..${hashOfLastCommitInsidePackage} ${packageRelativePathFromRoot}`, - { - cwd: ROOT_LOCATION, - }, - ); - echo(); - - return true; - } -}; - -module.exports = detectPackageUnreleasedChanges; diff --git a/scripts/monorepo/bump-all-updated-packages/index.js b/scripts/monorepo/bump-all-updated-packages/index.js deleted file mode 100644 index ae8bb555a6bd36..00000000000000 --- a/scripts/monorepo/bump-all-updated-packages/index.js +++ /dev/null @@ -1,261 +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 - */ - -const {REPO_ROOT} = require('../../consts'); -const {getPackageVersionStrByTag} = require('../../npm-utils'); -const { - isReleaseBranch, - parseVersion, -} = require('../../releases/utils/version-utils'); -const {getBranchName} = require('../../scm-utils'); -const {getPackages} = require('../../utils/monorepo'); -const alignPackageVersions = require('../align-package-versions'); -const checkForGitChanges = require('../check-for-git-changes'); -const { - COMMIT_WITH_CUSTOM_MESSAGE_CHOICE, - COMMIT_WITH_GENERIC_MESSAGE_CHOICE, - GENERIC_COMMIT_MESSAGE, - NO_COMMIT_CHOICE, - PUBLISH_PACKAGES_TAG, -} = require('../constants'); -const bumpPackageVersion = require('./bump-package-version'); -const detectPackageUnreleasedChanges = require('./bump-utils'); -const chalk = require('chalk'); -const {execSync} = require('child_process'); -const inquirer = require('inquirer'); -const path = require('path'); -const {echo, exec, exit} = require('shelljs'); - -const buildExecutor = - ( - packageAbsolutePath /*: string */, - packageRelativePathFromRoot /*: string */, - packageManifest /*: $FlowFixMe */, - ) => - async () => { - const {name: packageName} = packageManifest; - if (packageManifest.private) { - echo(`\u23ED Skipping private package ${chalk.dim(packageName)}`); - - return; - } - - if ( - !detectPackageUnreleasedChanges( - packageRelativePathFromRoot, - packageName, - REPO_ROOT, - ) - ) { - return; - } - - await inquirer - .prompt([ - { - type: 'list', - name: 'shouldBumpPackage', - message: `Do you want to bump ${packageName}?`, - choices: ['Yes', 'No'], - filter: val => val === 'Yes', - }, - ]) - .then(({shouldBumpPackage}) => { - if (!shouldBumpPackage) { - echo(`Skipping bump for ${packageName}`); - return; - } - - return inquirer - .prompt([ - { - type: 'list', - name: 'increment', - message: 'Which version you want to increment?', - choices: ['patch', 'minor'], - }, - ]) - .then(({increment}) => { - const updatedVersion = bumpPackageVersion( - packageAbsolutePath, - packageManifest, - increment, - ); - echo( - `\u2705 Successfully bumped ${chalk.green( - packageName, - )} to ${chalk.green(updatedVersion)}`, - ); - }); - }); - }; - -const main = async () => { - if (checkForGitChanges()) { - echo( - chalk.red( - 'Found uncommitted changes. Please commit or stash them before running this script', - ), - ); - exit(1); - } - - const packages = await getPackages({ - includeReactNative: false, - includePrivate: true, - }); - - for (const pkg of Object.values(packages)) { - const executor = buildExecutor( - pkg.path, - path.relative(REPO_ROOT, pkg.path), - pkg.packageJson, - ); - - await executor() - .catch(() => exit(1)) - .then(() => echo()); - } - - if (!checkForGitChanges()) { - echo('No changes have been made. Finishing the process...'); - exit(0); - } - - echo('Aligning new versions across monorepo...'); - await alignPackageVersions(); - echo(chalk.green('Done!\n')); - - // Figure out the npm dist-tags we want for all monorepo packages we're bumping - const branchName = getBranchName(); - const choices = []; - - if (branchName === 'main') { - choices.push({name: '"nightly"', value: 'nightly', checked: true}); - } else if (isReleaseBranch(branchName)) { - choices.push({ - name: `"${branchName}"`, - value: branchName, - checked: true, - }); - - const latestVersion = getPackageVersionStrByTag('react-native', 'latest'); - const {major, minor} = parseVersion(latestVersion, 'release'); - choices.push({ - name: '"latest"', - value: 'latest', - checked: `${major}.${minor}-stable` === branchName, - }); - } else { - echo( - 'You should be running `yarn bump-all-updated-packages` only from release or main branch', - ); - exit(1); - } - - const {tags} = await inquirer.prompt([ - { - type: 'checkbox', - name: 'tags', - message: 'Select suggested npm tags.', - choices, - required: true, - }, - ]); - - const {confirm} = await inquirer.prompt({ - type: 'confirm', - name: 'confirm', - message: `Confirm these tags for *ALL* packages being bumped: ${tags - .map(t => `"${t}"`) - .join()}`, - }); - - if (!confirm) { - echo('Exiting without commiting...'); - exit(0); - } - - const tagString = '&' + tags.join('&'); - - await inquirer - .prompt([ - { - type: 'list', - name: 'commitChoice', - message: 'Do you want to submit a commit with these changes?', - choices: [ - { - name: 'Yes, with generic message', - value: COMMIT_WITH_GENERIC_MESSAGE_CHOICE, - }, - { - name: 'Yes, with custom message', - value: COMMIT_WITH_CUSTOM_MESSAGE_CHOICE, - }, - { - name: 'No', - value: NO_COMMIT_CHOICE, - }, - ], - }, - ]) - .then(({commitChoice}) => { - switch (commitChoice) { - case NO_COMMIT_CHOICE: { - echo('Not submitting a commit, but keeping all changes'); - - break; - } - - case COMMIT_WITH_GENERIC_MESSAGE_CHOICE: { - exec(`git commit -am "${GENERIC_COMMIT_MESSAGE}${tagString}"`, { - cwd: REPO_ROOT, - silent: true, - }); - - break; - } - - case COMMIT_WITH_CUSTOM_MESSAGE_CHOICE: { - // exec from shelljs currently does not support interactive input - // https://github.com/shelljs/shelljs/wiki/FAQ#running-interactive-programs-with-exec - execSync('git commit -a', {cwd: REPO_ROOT, stdio: 'inherit'}); - - const enteredCommitMessage = exec('git log -n 1 --format=format:%B', { - cwd: REPO_ROOT, - silent: true, - }).stdout.trim(); - const commitMessageWithTag = - enteredCommitMessage + `\n\n${PUBLISH_PACKAGES_TAG}${tagString}`; - - exec(`git commit --amend -m "${commitMessageWithTag}"`, { - cwd: REPO_ROOT, - silent: true, - }); - - break; - } - - default: - throw new Error(''); - } - }) - .then(() => echo()); - - echo(chalk.green('Successfully finished the process of bumping packages')); - exit(0); -}; - -if (require.main === module) { - // eslint-disable-next-line no-void - void main(); -} diff --git a/scripts/monorepo/constants.js b/scripts/monorepo/constants.js deleted file mode 100644 index 8dd1f6c5fe87a9..00000000000000 --- a/scripts/monorepo/constants.js +++ /dev/null @@ -1,24 +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 strict-local - * @format - */ - -const PUBLISH_PACKAGES_TAG = '#publish-packages-to-npm'; -const GENERIC_COMMIT_MESSAGE = `bumped packages versions\n\n${PUBLISH_PACKAGES_TAG}`; - -const NO_COMMIT_CHOICE = 'NO_COMMIT'; -const COMMIT_WITH_GENERIC_MESSAGE_CHOICE = 'COMMIT_WITH_GENERIC_MESSAGE'; -const COMMIT_WITH_CUSTOM_MESSAGE_CHOICE = 'COMMIT_WITH_CUSTOM_MESSAGE'; - -module.exports = { - PUBLISH_PACKAGES_TAG, - GENERIC_COMMIT_MESSAGE, - NO_COMMIT_CHOICE, - COMMIT_WITH_GENERIC_MESSAGE_CHOICE, - COMMIT_WITH_CUSTOM_MESSAGE_CHOICE, -}; diff --git a/scripts/npm-utils.js b/scripts/npm-utils.js index 8886b08122c0d5..cdc9b6baabd438 100644 --- a/scripts/npm-utils.js +++ b/scripts/npm-utils.js @@ -149,35 +149,6 @@ function publishPackage( return exec(`npm publish${tagsFlag}${otpFlag}${accessFlag}`, options); } -function diffPackages( - packageSpecA /*: string */, - packageSpecB /*: string */, - options /*: ExecOptsSync */, -) /*: string */ { - const result = exec( - `npm diff --diff=${packageSpecA} --diff=${packageSpecB} --diff-name-only`, - options, - ); - - if (result.code !== 0) { - throw new Error( - `Failed to diff ${packageSpecA} and ${packageSpecB}\n${result.stderr}`, - ); - } - - return result.stdout; -} - -function pack(packagePath /*: string */) { - const result = exec('npm pack', { - cwd: packagePath, - }); - - if (result.code !== 0) { - throw new Error(result.stderr); - } -} - /** * `package` is an object form of package.json * `dependencies` is a map of dependency to version string @@ -280,9 +251,6 @@ function getVersionsBySpec( module.exports = { applyPackageVersions, getNpmInfo, - getPackageVersionStrByTag, getVersionsBySpec, publishPackage, - diffPackages, - pack, }; diff --git a/scripts/releases-ci/publish-updated-packages.js b/scripts/releases-ci/publish-updated-packages.js index 56b4bd61003f5f..ff5bf6c688dbe0 100644 --- a/scripts/releases-ci/publish-updated-packages.js +++ b/scripts/releases-ci/publish-updated-packages.js @@ -9,12 +9,12 @@ * @oncall react_native */ -const {PUBLISH_PACKAGES_TAG} = require('../monorepo/constants'); const {publishPackage} = require('../npm-utils'); const {getPackages} = require('../utils/monorepo'); const {parseArgs} = require('@pkgjs/parseargs'); const {execSync} = require('child_process'); +const PUBLISH_PACKAGES_TAG = '#publish-packages-to-npm'; const NPM_CONFIG_OTP = process.env.NPM_CONFIG_OTP; const config = {