Skip to content

Commit

Permalink
Add support for bumping packages on main after release cut
Browse files Browse the repository at this point in the history
Summary:
Changelog: [Internal] - Add support to `set-version` that we can bump the monorepo packages on main

This should be used after we cut a release branch. The release crew should then run

`yarn set-version 0.next.0-main --skip-react-native-version`

This makes sure we don't update `react-native` on main branch and keep it at 1000.0.0

This essentially replaces:
`yarn bump-all-updated-packages --release-branch-cutoff`
in this step: https://reactnative.dev/contributing/release-branch-cut-and-rc0#12-bump-minor-version-of-all-monorepo-packages-in-main

The reason for this change is to consolidate all the places where we update the version to one place, set-version.

Currently we do this in many fragmented places
* bump-all-updated-packages
* set-rn-version
* get-and-update-packages (deleted in the prev diff)

In the future, I want to get rid of `skip-react-native-version` but we'll need to remove the `1000.0.0` nomenclature. This unblocks us to just use this script for now.

Differential Revision: D53648688
  • Loading branch information
lunaleaps authored and facebook-github-bot committed Feb 11, 2024
1 parent d149c77 commit f566d59
Show file tree
Hide file tree
Showing 6 changed files with 175 additions and 21 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"print-packages": "node ./scripts/monorepo/print",
"shellcheck": "./scripts/circleci/analyze_scripts.sh",
"start": "cd packages/rn-tester && npm run start",
"set-version": "node ./scripts/releases/set-version",
"test-android": "./gradlew :packages:react-native:ReactAndroid:test",
"test-ci": "jest --maxWorkers=2 --ci --reporters=\"default\" --reporters=\"jest-junit\"",
"test-e2e-local-clean": "node ./scripts/release-testing/test-e2e-local-clean.js",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-native",
"version": "0.0.0",
"version": "1000.0.0",
"description": "fake react native package",
"dependencies": {
"@monorepo/pkg-a": "0.0.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"dependencies": {
"react": "18.2.0",
"react-native": "0.0.0"
"react-native": "1000.0.0"
},
"devDependencies": {
"@monorepo/pkg-a": "0.0.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -596,3 +596,81 @@ exports[`setVersion updates monorepo for stable version: packages/react-native/t
}
"
`;
exports[`setVersion updates monorepo on main after release cut: packages/monorepo-pkg-a/package.json 1`] = `
"{
\\"name\\": \\"@monorepo/pkg-a\\",
\\"version\\": \\"0.82.0-main\\",
\\"description\\": \\"@monorepo/pkg-a\\",
\\"dependencies\\": {
\\"@monorepo/pkg-b\\": \\"0.82.0-main\\",
\\"@monorepo/other\\": \\"0.0.1\\"
},
\\"devDependencies\\": {
\\"@monorepo/pkg-c\\": \\"0.82.0-main\\"
}
}
"
`;
exports[`setVersion updates monorepo on main after release cut: packages/monorepo-pkg-b/package.json 1`] = `
"{
\\"name\\": \\"@monorepo/pkg-b\\",
\\"version\\": \\"0.82.0-main\\",
\\"description\\": \\"@monorepo/pkg-b\\",
\\"dependencies\\": {
\\"@monorepo/pkg-c\\": \\"0.82.0-main\\",
\\"metro-config\\": \\"^0.80.3\\",
\\"metro-runtime\\": \\"^0.80.3\\"
}
}
"
`;
exports[`setVersion updates monorepo on main after release cut: packages/monorepo-pkg-c/package.json 1`] = `
"{
\\"name\\": \\"@monorepo/pkg-c\\",
\\"version\\": \\"0.82.0-main\\",
\\"description\\": \\"@monorepo/pkg-c\\",
\\"dependencies\\": {
\\"metro-config\\": \\"^0.80.3\\",
\\"metro-runtime\\": \\"^0.80.3\\"
}
}
"
`;
exports[`setVersion updates monorepo on main after release cut: packages/react-native/package.json 1`] = `
"{
\\"name\\": \\"react-native\\",
\\"version\\": \\"1000.0.0\\",
\\"description\\": \\"fake react native package\\",
\\"dependencies\\": {
\\"@monorepo/pkg-a\\": \\"0.82.0-main\\",
\\"@monorepo/pkg-b\\": \\"0.82.0-main\\",
\\"@monorepo/pkg-c\\": \\"0.82.0-main\\",
\\"metro-config\\": \\"^0.80.3\\",
\\"metro-runtime\\": \\"^0.80.3\\"
}
}
"
`;
exports[`setVersion updates monorepo on main after release cut: packages/react-native/template/package.json 1`] = `
"{
\\"name\\": \\"react-native-test-template\\",
\\"version\\": \\"0.0.1\\",
\\"private\\": true,
\\"dependencies\\": {
\\"react\\": \\"18.2.0\\",
\\"react-native\\": \\"1000.0.0\\"
},
\\"devDependencies\\": {
\\"@monorepo/pkg-a\\": \\"0.82.0-main\\",
\\"@monorepo/pkg-c\\": \\"0.82.0-main\\",
\\"@types/react\\": \\"^18.2.6\\",
\\"@types/react-test-renderer\\": \\"^18.0.0\\"
}
}
"
`;
59 changes: 50 additions & 9 deletions scripts/releases/set-version/__tests__/set-version-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,26 @@
const setVersion = require('../index');
const path = require('path');

let customWriteFileExpect = null;
const writeFileMock = jest.fn().mockImplementation((filePath, content) => {
if (customWriteFileExpect != null) {
customWriteFileExpect(filePath, content);
}

expect(content).toMatchSnapshot(
// Make snapshot names resilient to platform path sep differences
path
.relative(path.join(__dirname, '__fixtures__'), filePath)
.split(path.sep)
.join('/'),
);
});

describe('setVersion', () => {
beforeEach(() => {
jest.clearAllMocks();
});

beforeAll(() => {
jest.mock('path', () => {
// $FlowIgnore[underconstrained-implicit-instantiation]
Expand All @@ -30,15 +49,7 @@ describe('setVersion', () => {
...originalFs,
promises: {
...originalFs.promises,
writeFile: (filePath, content) => {
expect(content).toMatchSnapshot(
// Make snapshot names resilient to platform path sep differences
path
.relative(path.join(__dirname, '__fixtures__'), filePath)
.split(path.sep)
.join('/'),
);
},
writeFile: writeFileMock,
},
};
});
Expand All @@ -56,6 +67,36 @@ describe('setVersion', () => {
await setVersion('0.81.0-nightly-29282302-abcd1234');
});

test('updates monorepo on main after release cut', async () => {
customWriteFileExpect = (filePath /*: string */, content /*: string */) => {
const reactNativePath = path.join('react-native', 'package.json');
if (filePath.endsWith(reactNativePath)) {
expect(JSON.parse(content).version).toBe('1000.0.0');
}
const templatePath = path.join(
'react-native',
'template',
'package.json',
);
if (filePath.endsWith(templatePath)) {
expect(JSON.parse(content).dependencies['react-native']).toBe(
'1000.0.0',
);
}
};

await setVersion('0.82.0-main', true);

// Make sure we don't update any react-native source or build files
writeFileMock.mock.calls.forEach(([filePath, content]) => {
if (!filePath.endsWith('package.json')) {
throw new Error(
`set-version should not update any react-native source or build files. Updated ${filePath}`,
);
}
});
});

afterAll(() => {
jest.unmock('path');
jest.unmock('fs');
Expand Down
54 changes: 44 additions & 10 deletions scripts/releases/set-version/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ function getPublicPackages() {
return packages;
}

function updatePackages(version /*: string */) {
function updatePackages(
version /*: string */,
skipReactNativeVersion /*: ?boolean */,
) {
const publicPackages = getPublicPackages();
const writes = [];

Expand All @@ -42,7 +45,15 @@ function updatePackages(version /*: string */) {
return;
}

packageJson.version = version;
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 (packageJson.dependencies != null) {
for (const dependency of Object.keys(packageJson.dependencies)) {
Expand Down Expand Up @@ -82,6 +93,14 @@ function updatePackages(version /*: string */) {
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;
}
Expand Down Expand Up @@ -112,24 +131,35 @@ function updatePackages(version /*: string */) {
return Promise.all(writes);
}

async function setVersion(version /*: string */) {
async function setVersion(
version /*: string */,
skipReactNativeVersion /*: ?boolean */,
) {
const parsedVersion = parseVersion(version);

await updateSourceFiles(parsedVersion);
await updateGradleFile(parsedVersion.version);
await updatePackages(parsedVersion.version);
if (skipReactNativeVersion !== true) {
await updateSourceFiles(parsedVersion);
await updateGradleFile(parsedVersion.version);
}
await updatePackages(parsedVersion.version, skipReactNativeVersion);
}

/*
Sets a singular version for the entire monorepo (including `react-native` package)
Sets a singular version for the entire monorepo.
Set `skipReactNativeVersion` to true when we don't want to update the version of react-native.
The use-case is when we update versions on `main` after a release cut. The version of react-native
stays 1000.0.0.
This script does the following:
* Update all public npm packages under `<root>/packages` to specified version
* Update all npm dependencies of a `<root>/packages` package to specified version
* Update npm dependencies of the template app (`packages/react-native/template`) to specified version
* Update `packages/react-native` native source and build files to specified version
* Update `packages/react-native` native source and build files to specified version if relevant
*/

if (require.main === module) {
const {toVersion} = yargs(process.argv.slice(2))
const {toVersion, skipReactNativeVersion} = yargs(process.argv.slice(2))
.command(
'$0 <to-version>',
'Update all monorepo packages to <to-version>',
Expand All @@ -140,8 +170,12 @@ if (require.main === module) {
required: true,
}),
)
.option('skip-react-native-version', {
description: "Don't update the version of the react-native package",
type: 'boolean',
})
.parseSync();
setVersion(toVersion).then(
setVersion(toVersion, !!skipReactNativeVersion).then(
() => process.exit(0),
error => {
console.error(`Failed to set version ${toVersion}\n`, error);
Expand Down

0 comments on commit f566d59

Please sign in to comment.