mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Publish nightly monorepo packages (#37556)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/37556 Changelog: [Internal] Before making this change, we need to publish `nightly` versions of all existing monorepo dependencies. Reviewed By: hoxyq Differential Revision: D46117197 fbshipit-source-id: bcf6364e068579e63ca19e8161dcd32de4353e56
This commit is contained in:
committed by
Facebook GitHub Bot
parent
e25c6632a2
commit
fd9e295bef
@@ -32,7 +32,8 @@ jest
|
||||
.mock('./../release-utils', () => ({
|
||||
generateAndroidArtifacts: jest.fn(),
|
||||
publishAndroidArtifactsToMaven: publishAndroidArtifactsToMavenMock,
|
||||
}));
|
||||
}))
|
||||
.mock('../monorepo/publish-nightly-for-each-changed-package');
|
||||
|
||||
const date = new Date('2023-04-20T23:52:39.543Z');
|
||||
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* 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 publishNightlyForEachChangedPackage = require('../publish-nightly-for-each-changed-package');
|
||||
|
||||
const mockPackages = [
|
||||
{
|
||||
packageManifest: {name: 'packageA', version: 'local-version'},
|
||||
packageAbsolutePath: '/some/place/packageA',
|
||||
packageRelativePathFromRoot: './place/packageA',
|
||||
},
|
||||
];
|
||||
|
||||
const execMock = jest.fn();
|
||||
const writeFileSyncMock = jest.fn();
|
||||
const diffPackagesMock = jest.fn();
|
||||
const publishPackageMock = jest.fn();
|
||||
|
||||
jest
|
||||
.mock('shelljs', () => ({
|
||||
exec: execMock,
|
||||
rm: jest.fn(),
|
||||
}))
|
||||
.mock('fs', () => ({
|
||||
writeFileSync: writeFileSyncMock,
|
||||
}))
|
||||
.mock('../for-each-package', () => callback => {
|
||||
mockPackages.forEach(
|
||||
({packageManifest, packageAbsolutePath, packageRelativePathFromRoot}) =>
|
||||
callback(
|
||||
packageAbsolutePath,
|
||||
packageRelativePathFromRoot,
|
||||
packageManifest,
|
||||
),
|
||||
);
|
||||
})
|
||||
.mock('../../scm-utils', () => ({
|
||||
restore: jest.fn(),
|
||||
}))
|
||||
.mock('../../npm-utils', () => ({
|
||||
getPackageVersionStrByTag: () => 'published-nightly-version',
|
||||
diffPackages: diffPackagesMock,
|
||||
publishPackage: publishPackageMock,
|
||||
pack: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('publishNightlyForEachChangedPackage', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('publishes because there are changes', () => {
|
||||
const nightlyVersion = '0.73.0-nightly-202108-shortcommit';
|
||||
publishPackageMock.mockImplementationOnce(() => ({code: 0}));
|
||||
diffPackagesMock.mockImplementationOnce(() => 'some-file-name.js\n');
|
||||
|
||||
publishNightlyForEachChangedPackage(nightlyVersion);
|
||||
|
||||
// ensure we set the version of the last published nightly (for diffing)
|
||||
expect(writeFileSyncMock.mock.calls[0][1]).toBe(
|
||||
'{\n "name": "packageA",\n "version": "published-nightly-version"\n}\n',
|
||||
);
|
||||
|
||||
expect(diffPackagesMock).toBeCalledWith(
|
||||
'packageA@nightly',
|
||||
'packageA-published-nightly-version.tgz',
|
||||
{
|
||||
cwd: '/some/place/packageA',
|
||||
},
|
||||
);
|
||||
|
||||
// when determining that we DO want to publish, ensure we update the version to the provded nightly version we want to use
|
||||
expect(writeFileSyncMock.mock.calls[1][1]).toBe(
|
||||
`{\n "name": "packageA",\n "version": "${nightlyVersion}"\n}\n`,
|
||||
);
|
||||
|
||||
expect(publishPackageMock).toBeCalled();
|
||||
});
|
||||
|
||||
it('doesnt publish because no changes', () => {
|
||||
const nightlyVersion = '0.73.0-nightly-202108-shortcommit';
|
||||
diffPackagesMock.mockImplementationOnce(() => '\n');
|
||||
|
||||
publishNightlyForEachChangedPackage(nightlyVersion);
|
||||
|
||||
expect(writeFileSyncMock.mock.calls[0][1]).toBe(
|
||||
'{\n "name": "packageA",\n "version": "published-nightly-version"\n}\n',
|
||||
);
|
||||
|
||||
// in this test, we expect there to be no differences between last published nightly and local
|
||||
// so we never update the version and we don't publish
|
||||
expect(writeFileSyncMock.mock.calls.length).toBe(1);
|
||||
expect(publishPackageMock).not.toBeCalled();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,135 @@
|
||||
/**
|
||||
* 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 forEachPackage = require('./for-each-package');
|
||||
const {rm} = require('shelljs');
|
||||
const {
|
||||
getPackageVersionStrByTag,
|
||||
diffPackages,
|
||||
publishPackage,
|
||||
pack,
|
||||
} = require('../npm-utils');
|
||||
const {restore} = require('../scm-utils');
|
||||
const path = require('path');
|
||||
const {writeFileSync} = require('fs');
|
||||
|
||||
function hasChanges(
|
||||
currentNightlyVersion,
|
||||
packageManifest,
|
||||
packageAbsolutePath,
|
||||
) {
|
||||
// Set local package to same nightly version so diff is comparable
|
||||
writeFileSync(
|
||||
path.join(packageAbsolutePath, 'package.json'),
|
||||
JSON.stringify(
|
||||
{...packageManifest, version: currentNightlyVersion},
|
||||
null,
|
||||
2,
|
||||
) + '\n',
|
||||
'utf-8',
|
||||
);
|
||||
|
||||
// prepare local package
|
||||
pack(packageAbsolutePath);
|
||||
|
||||
// ex. react-native-codegen-0.73.0-nightly-20230530-730ca3540.tgz
|
||||
const localTarballName = `${packageManifest.name
|
||||
.replace('@', '')
|
||||
.replace('/', '-')}-${currentNightlyVersion}.tgz`;
|
||||
|
||||
// npm diff --diff=<package-name>@nightly --diff=. --diff-name-only
|
||||
const diff = diffPackages(
|
||||
`${packageManifest.name}@nightly`,
|
||||
localTarballName,
|
||||
{
|
||||
cwd: packageAbsolutePath,
|
||||
},
|
||||
);
|
||||
|
||||
// delete tarball and restore package.json changes
|
||||
rm({cwd: packageAbsolutePath}, localTarballName);
|
||||
restore(packageAbsolutePath);
|
||||
|
||||
return diff.trim().length !== 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish nightlies for monorepo packages that changed since last publish.
|
||||
* This is called by `react-native`'s nightly job.
|
||||
*
|
||||
* Note: This does not publish `package/react-native`'s nightly. That is handled in `publish-npm`.
|
||||
*/
|
||||
function publishNightlyForEachChangedPackage(nightlyVersion) {
|
||||
forEachPackage(
|
||||
(packageAbsolutePath, packageRelativePathFromRoot, packageManifest) => {
|
||||
if (packageManifest.private) {
|
||||
console.log(`\u23ED Skipping private package ${packageManifest.name}`);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
let lastPublishedNightlyVersion;
|
||||
let shouldPublishNightly = false;
|
||||
console.log(
|
||||
`\n---- Attempting to publish nightly for ${packageManifest.name}`,
|
||||
);
|
||||
try {
|
||||
lastPublishedNightlyVersion = getPackageVersionStrByTag(
|
||||
packageManifest.name,
|
||||
'nightly',
|
||||
);
|
||||
shouldPublishNightly = hasChanges(
|
||||
lastPublishedNightlyVersion,
|
||||
packageManifest,
|
||||
packageAbsolutePath,
|
||||
);
|
||||
} catch (e) {
|
||||
console.error(
|
||||
`Unable to verify if ${packageManifest.name} has changes due to error:`,
|
||||
);
|
||||
console.error(e.message);
|
||||
console.log(`\u23ED Skipping package ${packageManifest.name}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!shouldPublishNightly) {
|
||||
console.log(
|
||||
`Detected no changes in ${packageManifest.name}@nightly since last publish. Skipping.`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the local package to the updated nightly version
|
||||
writeFileSync(
|
||||
path.join(packageAbsolutePath, 'package.json'),
|
||||
JSON.stringify({...packageManifest, version: nightlyVersion}, null, 2) +
|
||||
'\n',
|
||||
'utf-8',
|
||||
);
|
||||
|
||||
const result = publishPackage(packageAbsolutePath, {
|
||||
tag: 'nightly',
|
||||
otp: process.env.NPM_CONFIG_OTP,
|
||||
});
|
||||
if (result.code !== 0) {
|
||||
console.log(
|
||||
`\u274c Failed to publish version ${nightlyVersion} of ${packageManifest.name}. npm publish exited with code ${result.code}:`,
|
||||
);
|
||||
console.error(result.stderr);
|
||||
} else {
|
||||
console.log(
|
||||
`\u2705 Successfully published new version of ${packageManifest.name}`,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = publishNightlyForEachChangedPackage;
|
||||
+29
-2
@@ -12,10 +12,10 @@
|
||||
const {exec} = require('shelljs');
|
||||
|
||||
function getPackageVersionStrByTag(packageName, tag) {
|
||||
const result = exec(`npm view ${packageName}@${tag} version`);
|
||||
const result = exec(`npm view ${packageName}@${tag} version`, {silent: true});
|
||||
|
||||
if (result.code) {
|
||||
throw `Failed to get ${tag} version from npm\n${result.stderr}`;
|
||||
throw new Error(`Failed to get ${tag} version from npm\n${result.stderr}`);
|
||||
}
|
||||
return result.stdout.trim();
|
||||
}
|
||||
@@ -31,7 +31,34 @@ function publishPackage(packagePath, packageOptions, execOptions) {
|
||||
return exec(`npm publish${tagFlag}${otpFlag}`, options);
|
||||
}
|
||||
|
||||
function diffPackages(packageSpecA, packageSpecB, options) {
|
||||
const result = exec(
|
||||
`npm diff --diff=${packageSpecA} --diff=${packageSpecB} --diff-name-only`,
|
||||
options,
|
||||
);
|
||||
|
||||
if (result.code) {
|
||||
throw new Error(
|
||||
`Failed to diff ${packageSpecA} and ${packageSpecB}\n${result.stderr}`,
|
||||
);
|
||||
}
|
||||
|
||||
return result.stdout;
|
||||
}
|
||||
|
||||
function pack(packagePath) {
|
||||
const result = exec('npm pack', {
|
||||
cwd: packagePath,
|
||||
});
|
||||
|
||||
if (result.code !== 0) {
|
||||
throw new Error(result.stderr);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getPackageVersionStrByTag,
|
||||
publishPackage,
|
||||
diffPackages,
|
||||
pack,
|
||||
};
|
||||
|
||||
@@ -17,6 +17,7 @@ const {
|
||||
getCurrentCommit,
|
||||
isTaggedLatest,
|
||||
} = require('./scm-utils');
|
||||
const publishNightlyForEachChangedPackage = require('./monorepo/publish-nightly-for-each-changed-package');
|
||||
const {
|
||||
generateAndroidArtifacts,
|
||||
publishAndroidArtifactsToMaven,
|
||||
@@ -136,6 +137,7 @@ function publishNpm(buildType) {
|
||||
// Set version number in various files (package.json, gradle.properties etc)
|
||||
// For non-nightly, non-dry-run, CircleCI job `prepare_package_for_release` does this
|
||||
if (buildType === 'nightly' || buildType === 'dry-run') {
|
||||
// Sets the version for package/react-native
|
||||
if (
|
||||
exec(
|
||||
`node scripts/set-rn-version.js --to-version ${version} --build-type ${buildType}`,
|
||||
@@ -146,6 +148,11 @@ function publishNpm(buildType) {
|
||||
}
|
||||
}
|
||||
|
||||
// set and publish the relevant monorepo packages
|
||||
if (buildType === 'nightly') {
|
||||
publishNightlyForEachChangedPackage(version);
|
||||
}
|
||||
|
||||
generateAndroidArtifacts(version);
|
||||
|
||||
// Write version number to the build folder
|
||||
@@ -166,6 +173,7 @@ function publishNpm(buildType) {
|
||||
tag,
|
||||
otp: process.env.NPM_CONFIG_OTP,
|
||||
});
|
||||
|
||||
if (result.code) {
|
||||
echo('Failed to publish package to npm');
|
||||
return exit(1);
|
||||
|
||||
@@ -85,6 +85,19 @@ function revertFiles(filePaths, tmpFolder) {
|
||||
}
|
||||
}
|
||||
|
||||
// git restore for local path
|
||||
function restore(repoPath) {
|
||||
const result = exec('git restore .', {
|
||||
cwd: repoPath,
|
||||
});
|
||||
|
||||
if (result.code !== 0) {
|
||||
throw new Error(result.stderr);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
exitIfNotOnGit,
|
||||
getCurrentCommit,
|
||||
@@ -92,4 +105,5 @@ module.exports = {
|
||||
isTaggedLatest,
|
||||
revertFiles,
|
||||
saveFiles,
|
||||
restore,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user