Add Flow, add positive test case for monorepo publish step (#42936)

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

Changelog: [Internal]

Reviewed By: cipolleschi

Differential Revision: D53607809

fbshipit-source-id: 990826fda5538af9a13e3f24978295a2f3b0c8c3
This commit is contained in:
Alex Hunt
2024-02-12 04:42:27 -08:00
committed by Facebook GitHub Bot
parent 7e3e7684b1
commit b25be6687e
2 changed files with 79 additions and 18 deletions
@@ -4,7 +4,9 @@
* 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
* @oncall react_native
*/
const {PUBLISH_PACKAGES_TAG} = require('../constants');
@@ -12,18 +14,21 @@ const {
findAndPublishAllBumpedPackages,
getTagsFromCommitMessage,
} = require('../find-and-publish-all-bumped-packages');
const forEachPackage = require('../for-each-package');
const {spawnSync} = require('child_process');
jest.mock('child_process', () => ({spawnSync: jest.fn()}));
jest.mock('../for-each-package', () => jest.fn());
const spawnSync = jest.fn();
const forEachPackage = jest.fn();
const execMock = jest.fn();
jest.mock('child_process', () => ({spawnSync}));
jest.mock('shelljs', () => ({exec: execMock}));
jest.mock('../for-each-package', () => forEachPackage);
describe('findAndPublishAllBumpedPackages', () => {
beforeEach(() => {
// Silence logs.
jest.spyOn(console, 'log').mockImplementation(() => {});
});
it('throws an error if updated version is not 0.x.y', () => {
test('should throw an error if updated version is not 0.x.y', async () => {
const mockedPackageNewVersion = '1.0.0';
forEachPackage.mockImplementationOnce(callback => {
@@ -40,10 +45,64 @@ describe('findAndPublishAllBumpedPackages', () => {
stdout: `This is my commit message\n\n${PUBLISH_PACKAGES_TAG}`,
}));
expect(() => findAndPublishAllBumpedPackages()).toThrow(
await expect(findAndPublishAllBumpedPackages()).rejects.toThrow(
`Package version expected to be 0.x.y, but received ${mockedPackageNewVersion}`,
);
});
test('should publish all changed packages', async () => {
forEachPackage.mockImplementationOnce(callback => {
callback('absolute/path/to/package-a', 'to/package-a', {
version: '0.72.1',
});
callback('absolute/path/to/package-b', 'to/package-b', {
version: '0.72.1',
});
callback('absolute/path/to/package-c', 'to/package-b', {
version: '0.72.0',
});
});
spawnSync.mockImplementationOnce(() => ({
stdout: `- "version": "0.72.0"\n+ "version": "0.72.1"\n`,
}));
spawnSync.mockImplementationOnce(() => ({
stdout: `This is my commit message\n\n${PUBLISH_PACKAGES_TAG}`,
}));
spawnSync.mockImplementationOnce(() => ({
stdout: `- "version": "0.72.0"\n+ "version": "0.72.1"\n`,
}));
spawnSync.mockImplementationOnce(() => ({
stdout: `This is my commit message\n\n${PUBLISH_PACKAGES_TAG}`,
}));
spawnSync.mockImplementationOnce(() => ({
stdout: '\n',
}));
spawnSync.mockImplementationOnce(() => ({
stdout: `This is my commit message\n\n${PUBLISH_PACKAGES_TAG}`,
}));
execMock.mockImplementation(() => ({code: 0}));
await findAndPublishAllBumpedPackages();
expect(execMock.mock.calls).toMatchInlineSnapshot(`
Array [
Array [
"npm publish",
Object {
"cwd": "absolute/path/to/package-a",
},
],
Array [
"npm publish",
Object {
"cwd": "absolute/path/to/package-b",
},
],
]
`);
});
});
describe('getTagsFromCommitMessage', () => {
@@ -4,7 +4,9 @@
* 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
* @oncall react_native
*/
const {publishPackage} = require('../npm-utils');
@@ -16,7 +18,7 @@ const path = require('path');
const ROOT_LOCATION = path.join(__dirname, '..', '..');
const NPM_CONFIG_OTP = process.env.NPM_CONFIG_OTP;
function getTagsFromCommitMessage(msg) {
function getTagsFromCommitMessage(msg /*: string */) /*: Array<string> */ {
// ex message we're trying to parse tags out of
// `_some_message_here_${PUBLISH_PACKAGES_TAG}&tagA&tagB\n`;
return msg
@@ -26,12 +28,12 @@ function getTagsFromCommitMessage(msg) {
.slice(1);
}
const findAndPublishAllBumpedPackages = () => {
async function findAndPublishAllBumpedPackages() {
console.log('Traversing all packages inside /packages...');
forEachPackage(
(packageAbsolutePath, packageRelativePathFromRoot, packageManifest) => {
if (packageManifest.private) {
if (packageManifest.private === true) {
console.log(`\u23ED Skipping private package ${packageManifest.name}`);
return;
@@ -58,9 +60,9 @@ const findAndPublishAllBumpedPackages = () => {
process.exit(1);
}
const previousVersionPatternMatches = diff.match(
/- {2}"version": "([0-9]+.[0-9]+.[0-9]+)"/,
);
const previousVersionPatternMatches = diff
.toString()
.match(/- {2}"version": "([0-9]+.[0-9]+.[0-9]+)"/);
if (!previousVersionPatternMatches) {
console.log(`\uD83D\uDD0E No version bump for ${packageManifest.name}`);
@@ -68,7 +70,7 @@ const findAndPublishAllBumpedPackages = () => {
return;
}
const {stdout: commitMessage, stderr: commitMessageStderr} = spawnSync(
const {stdout, stderr: commitMessageStderr} = spawnSync(
'git',
[
'log',
@@ -79,6 +81,7 @@ const findAndPublishAllBumpedPackages = () => {
],
{cwd: ROOT_LOCATION, shell: true, stdio: 'pipe', encoding: 'utf-8'},
);
const commitMessage = stdout.toString();
if (commitMessageStderr) {
console.log(
@@ -131,12 +134,11 @@ const findAndPublishAllBumpedPackages = () => {
}
},
);
process.exit(0);
};
}
if (require.main === module) {
findAndPublishAllBumpedPackages();
// eslint-disable-next-line no-void
void findAndPublishAllBumpedPackages();
}
module.exports = {