diff --git a/scripts/releases/set-version/__tests__/set-version-test.js b/scripts/releases/set-version/__tests__/set-version-test.js index 9e7369ff947..f294146a9a0 100644 --- a/scripts/releases/set-version/__tests__/set-version-test.js +++ b/scripts/releases/set-version/__tests__/set-version-test.js @@ -14,6 +14,12 @@ const path = require('path'); jest.mock('../../../consts', () => ({ REPO_ROOT: path.join(__dirname, '__fixtures__'), PACKAGES_DIR: path.join(__dirname, '__fixtures__', 'packages'), + REACT_NATIVE_PACKAGE_DIR: path.join( + __dirname, + '__fixtures__', + 'packages', + 'react-native', + ), })); let customWriteFileExpect = null; diff --git a/scripts/releases/set-version/index.js b/scripts/releases/set-version/index.js index 209f0647124..0373e316138 100644 --- a/scripts/releases/set-version/index.js +++ b/scripts/releases/set-version/index.js @@ -11,124 +11,92 @@ 'use strict'; -const forEachPackage = require('../../monorepo/for-each-package'); +/*:: +import type {PackageJson} from '../utils/monorepo'; +*/ + +const {REACT_NATIVE_PACKAGE_DIR} = require('../../consts'); const {updateGradleFile, updateSourceFiles} = require('../set-rn-version'); +const {getPackages} = require('../utils/monorepo'); const {parseVersion} = require('../utils/version-utils'); -const {promises: fs, readFileSync} = require('fs'); +const {promises: fs} = require('fs'); const path = require('path'); const yargs = require('yargs'); -function getPublicPackages() { - // eslint-disable-next-line func-call-spacing - const packages = new Set /*::*/(); - forEachPackage( - (_, __, packageJson) => { - if (packageJson.private !== true) { - packages.add(packageJson.name); - } +const TEMPLATE_DIR = path.join(REACT_NATIVE_PACKAGE_DIR, 'template'); + +async function updatePackages( + version /*: string */, + skipReactNativeVersion /*: boolean */, +) { + const packages = await getPackages({ + includePrivate: false, + includeReactNative: true, + }); + const newPackageVersions = Object.fromEntries( + Object.keys(packages).map(packageName => [packageName, version]), + ); + const templatePackageJson /*: PackageJson */ = JSON.parse( + await fs.readFile(path.join(TEMPLATE_DIR, 'package.json'), 'utf-8'), + ); + const packagesToUpdate = [ + ...Object.values(packages), + { + path: TEMPLATE_DIR, + packageJson: templatePackageJson, }, - {includeReactNative: true}, + ]; + + await Promise.all( + packagesToUpdate.map(({path: packagePath, packageJson}) => + updatePackageJson( + packagePath, + packageJson, + newPackageVersions, + skipReactNativeVersion, + ), + ), ); - return packages; } -function updatePackages( - version /*: string */, - skipReactNativeVersion /*: ?boolean */, -) { - const publicPackages = getPublicPackages(); - const writes = []; +async function updatePackageJson( + packagePath /*: string */, + packageJson /*: PackageJson */, + newPackageVersions /*: $ReadOnly<{[string]: string}> */, + skipReactNativeVersion /*: boolean */, +) /*: Promise */ { + const packageName = packageJson.name; - forEachPackage( - (packageAbsolutePath, _, packageJson) => { - if (packageJson.private === true) { - return; + if ( + packageName in newPackageVersions && + (!skipReactNativeVersion || packageName !== 'react-native') + ) { + packageJson.version = newPackageVersions[packageName]; + } + + for (const dependencyField of ['dependencies', 'devDependencies']) { + const deps = packageJson[dependencyField]; + + if (deps == null) { + continue; + } + + for (const dependency of Object.keys(deps)) { + if (dependency === 'react-native' && skipReactNativeVersion) { + continue; } - if ( - packageJson.name === 'react-native' && - skipReactNativeVersion === true - ) { - // Don't set react-native's version if skipReactNativeVersion - // but still update its dependencies - } else { - packageJson.version = version; + if (dependency in newPackageVersions) { + deps[dependency] = newPackageVersions[dependency]; } + } + } - if (packageJson.dependencies != null) { - for (const dependency of Object.keys(packageJson.dependencies)) { - if (publicPackages.has(dependency)) { - packageJson.dependencies[dependency] = version; - } - } - } - - if (packageJson.devDependencies != null) { - for (const devDependency of Object.keys(packageJson.devDependencies)) { - if (publicPackages.has(devDependency)) { - packageJson.devDependencies[devDependency] = version; - } - } - } - - writes.push( - fs.writeFile( - path.join(packageAbsolutePath, 'package.json'), - JSON.stringify(packageJson, null, 2) + '\n', - 'utf-8', - ), - ); - - // Update template package.json - if (packageJson.name === 'react-native') { - const templatePackageJsonPath = path.join( - packageAbsolutePath, - 'template', - 'package.json', - ); - const templatePackageJson = JSON.parse( - readFileSync(templatePackageJsonPath).toString(), - ); - if (templatePackageJson.dependencies != null) { - for (const dependency of Object.keys( - templatePackageJson.dependencies, - )) { - if ( - dependency === 'react-native' && - skipReactNativeVersion === true - ) { - // Skip updating react-native version in template package.json - continue; - } - - if (publicPackages.has(dependency)) { - templatePackageJson.dependencies[dependency] = version; - } - } - } - - if (templatePackageJson.devDependencies != null) { - for (const devDependency of Object.keys( - templatePackageJson.devDependencies, - )) { - if (publicPackages.has(devDependency)) { - templatePackageJson.devDependencies[devDependency] = version; - } - } - } - writes.push( - fs.writeFile( - templatePackageJsonPath, - JSON.stringify(templatePackageJson, null, 2) + '\n', - 'utf-8', - ), - ); - } - }, - {includeReactNative: true}, + return fs.writeFile( + path.join(packagePath, 'package.json'), + JSON.stringify(packageJson, null, 2) + '\n', + 'utf-8', ); - - return Promise.all(writes); } /** @@ -146,14 +114,15 @@ function updatePackages( */ async function setVersion( version /*: string */, - skipReactNativeVersion /*: ?boolean */, + skipReactNativeVersion /*: boolean */ = false, ) { const parsedVersion = parseVersion(version); - if (skipReactNativeVersion !== true) { + if (!skipReactNativeVersion) { await updateSourceFiles(parsedVersion); await updateGradleFile(parsedVersion.version); } + await updatePackages(parsedVersion.version, skipReactNativeVersion); } @@ -172,6 +141,7 @@ if (require.main === module) { .option('skip-react-native-version', { description: "Don't update the version of the react-native package", type: 'boolean', + default: false, }) .parseSync(); setVersion(toVersion, !!skipReactNativeVersion).then( diff --git a/scripts/releases/utils/monorepo.js b/scripts/releases/utils/monorepo.js index a488e15d06e..4908f951e8e 100644 --- a/scripts/releases/utils/monorepo.js +++ b/scripts/releases/utils/monorepo.js @@ -19,10 +19,10 @@ const WORKSPACES_CONFIG = 'packages/*'; /*:: export type PackageJson = { name: string, - private?: boolean, version: string, - dependencies: Record, - devDependencies: Record, + private?: boolean, + dependencies?: Record, + devDependencies?: Record, ... }; @@ -31,17 +31,19 @@ type PackagesFilter = $ReadOnly<{ includePrivate?: boolean, }>; +export type PackageInfo = { + // The name of the package + name: string, + + // The absolute path to the package + path: string, + + // The parsed package.json contents + packageJson: PackageJson, +}; + type ProjectInfo = { - [packageName: string]: { - // The name of the package - name: string, - - // The absolute path to the package - path: string, - - // The parsed package.json contents - packageJson: PackageJson, - }, + [packageName: string]: PackageInfo, }; */