diff --git a/scripts/__tests__/npm-utils-test.js b/scripts/__tests__/npm-utils-test.js index f6da57d4961b23..adb3de08b69fe9 100644 --- a/scripts/__tests__/npm-utils-test.js +++ b/scripts/__tests__/npm-utils-test.js @@ -95,7 +95,7 @@ describe('npm-utils', () => { it('should run publish command', () => { publishPackage( 'path/to/my-package', - {tag: 'latest', otp: 'otp'}, + {tags: ['latest'], otp: 'otp'}, {silent: true, cwd: 'i/expect/this/to/be/overriden'}, ); expect(execMock).toHaveBeenCalledWith( @@ -105,12 +105,23 @@ describe('npm-utils', () => { }); it('should run publish command when no execOptions', () => { - publishPackage('path/to/my-package', {tag: 'latest', otp: 'otp'}); + publishPackage('path/to/my-package', {tags: ['latest'], otp: 'otp'}); expect(execMock).toHaveBeenCalledWith( 'npm publish --tag latest --otp otp', {cwd: 'path/to/my-package'}, ); }); + + it('should handle multiple tags', () => { + publishPackage('path/to/my-package', { + tags: ['next', '0.72-stable'], + otp: 'otp', + }); + expect(execMock).toHaveBeenCalledWith( + 'npm publish --tag next --tag 0.72-stable --otp otp', + {cwd: 'path/to/my-package'}, + ); + }); }); describe('getNpmInfo', () => { diff --git a/scripts/monorepo/__tests__/find-and-publish-all-bumped-packages-test.js b/scripts/monorepo/__tests__/find-and-publish-all-bumped-packages-test.js index 4890fb378a7d73..15c4c683d416eb 100644 --- a/scripts/monorepo/__tests__/find-and-publish-all-bumped-packages-test.js +++ b/scripts/monorepo/__tests__/find-and-publish-all-bumped-packages-test.js @@ -8,7 +8,10 @@ */ const {PUBLISH_PACKAGES_TAG} = require('../constants'); -const findAndPublishAllBumpedPackages = require('../find-and-publish-all-bumped-packages'); +const { + findAndPublishAllBumpedPackages, + getTagsFromCommitMessage, +} = require('../find-and-publish-all-bumped-packages'); const forEachPackage = require('../for-each-package'); const {spawnSync} = require('child_process'); @@ -42,3 +45,14 @@ describe('findAndPublishAllBumpedPackages', () => { ); }); }); + +describe('getTagsFromCommitMessage', () => { + it('should parse tags out', () => { + const commitMsg = `This may be any commit message before it like tag a \n\n${PUBLISH_PACKAGES_TAG}&tagA&tagB&tagA\n`; + expect(getTagsFromCommitMessage(commitMsg)).toEqual([ + 'tagA', + 'tagB', + 'tagA', + ]); + }); +}); diff --git a/scripts/monorepo/__tests__/get-and-update-packages-test.js b/scripts/monorepo/__tests__/get-and-update-packages-test.js index 6ccc21df78b8ec..44a51f5ad3cc26 100644 --- a/scripts/monorepo/__tests__/get-and-update-packages-test.js +++ b/scripts/monorepo/__tests__/get-and-update-packages-test.js @@ -88,7 +88,7 @@ describe('getAndUpdatePackages', () => { forEachPackageThatShouldBePublished(package => { expect(publishPackageMock).toHaveBeenCalledWith( package.packageAbsolutePath, - {otp: undefined, tag: 'nightly'}, + {otp: undefined, tags: ['nightly']}, ); }); @@ -154,7 +154,7 @@ describe('getAndUpdatePackages', () => { forEachPackageThatShouldBePublished(package => { expect(publishPackageMock).toHaveBeenCalledWith( package.packageAbsolutePath, - {otp: undefined, tag: 'prealpha'}, + {otp: undefined, tags: ['prealpha']}, ); }); diff --git a/scripts/monorepo/bump-all-updated-packages/index.js b/scripts/monorepo/bump-all-updated-packages/index.js index a04e043b5dd252..8ba2b1d486179c 100644 --- a/scripts/monorepo/bump-all-updated-packages/index.js +++ b/scripts/monorepo/bump-all-updated-packages/index.js @@ -7,6 +7,9 @@ * @format */ +const {getPackageVersionStrByTag} = require('../../npm-utils'); +const {getBranchName} = require('../../scm-utils'); +const {isReleaseBranch, parseVersion} = require('../../version-utils'); const alignPackageVersions = require('../align-package-versions'); const checkForGitChanges = require('../check-for-git-changes'); const { @@ -148,6 +151,58 @@ const main = async () => { 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([ { @@ -179,7 +234,7 @@ const main = async () => { } case COMMIT_WITH_GENERIC_MESSAGE_CHOICE: { - exec(`git commit -am "${GENERIC_COMMIT_MESSAGE}"`, { + exec(`git commit -am "${GENERIC_COMMIT_MESSAGE}${tagString}"`, { cwd: ROOT_LOCATION, silent: true, }); @@ -197,7 +252,7 @@ const main = async () => { silent: true, }).stdout.trim(); const commitMessageWithTag = - enteredCommitMessage + `\n\n${PUBLISH_PACKAGES_TAG}`; + enteredCommitMessage + `\n\n${PUBLISH_PACKAGES_TAG}${tagString}`; exec(`git commit --amend -m "${commitMessageWithTag}"`, { cwd: ROOT_LOCATION, diff --git a/scripts/monorepo/find-and-publish-all-bumped-packages.js b/scripts/monorepo/find-and-publish-all-bumped-packages.js index 17ffb58ed7f60b..5cec500e462410 100644 --- a/scripts/monorepo/find-and-publish-all-bumped-packages.js +++ b/scripts/monorepo/find-and-publish-all-bumped-packages.js @@ -16,6 +16,16 @@ const path = require('path'); const ROOT_LOCATION = path.join(__dirname, '..', '..'); const NPM_CONFIG_OTP = process.env.NPM_CONFIG_OTP; +function getTagsFromCommitMessage(msg) { + // ex message we're trying to parse tags out of + // `_some_message_here_${PUBLISH_PACKAGES_TAG}&tagA&tagB\n`; + return msg + .substring(msg.indexOf(PUBLISH_PACKAGES_TAG)) + .trim() + .split('&') + .slice(1); +} + const findAndPublishAllBumpedPackages = () => { console.log('Traversing all packages inside /packages...'); @@ -101,7 +111,12 @@ const findAndPublishAllBumpedPackages = () => { ); } - const result = publishPackage(packageAbsolutePath, {otp: NPM_CONFIG_OTP}); + const tags = getTagsFromCommitMessage(commitMessage); + + const result = publishPackage(packageAbsolutePath, { + tags, + otp: NPM_CONFIG_OTP, + }); if (result.code !== 0) { console.log( `\u274c Failed to publish version ${nextVersion} of ${packageManifest.name}. npm publish exited with code ${result.code}:`, @@ -120,4 +135,11 @@ const findAndPublishAllBumpedPackages = () => { process.exit(0); }; -findAndPublishAllBumpedPackages(); +if (require.main === module) { + findAndPublishAllBumpedPackages(); +} + +module.exports = { + findAndPublishAllBumpedPackages, + getTagsFromCommitMessage, +}; diff --git a/scripts/monorepo/get-and-update-packages.js b/scripts/monorepo/get-and-update-packages.js index 62446e984b3301..67b74e5383ef93 100644 --- a/scripts/monorepo/get-and-update-packages.js +++ b/scripts/monorepo/get-and-update-packages.js @@ -135,7 +135,7 @@ function publishPackages( const version = packageMetadata.packageJson.version; const result = publishPackage(packageAbsolutePath, { - tag: tag, + tags: [tag], otp: process.env.NPM_CONFIG_OTP, }); diff --git a/scripts/npm-utils.js b/scripts/npm-utils.js index 879ae65d11b52c..95e76a28134126 100644 --- a/scripts/npm-utils.js +++ b/scripts/npm-utils.js @@ -91,14 +91,14 @@ function getNpmInfo(buildType) { } function publishPackage(packagePath, packageOptions, execOptions) { - const {tag, otp} = packageOptions; - const tagFlag = tag ? ` --tag ${tag}` : ''; + const {otp, tags} = packageOptions; + const tagsFlag = tags ? tags.map(t => ` --tag ${t}`).join('') : ''; const otpFlag = otp ? ` --otp ${otp}` : ''; const options = execOptions ? {...execOptions, cwd: packagePath} : {cwd: packagePath}; - return exec(`npm publish${tagFlag}${otpFlag}`, options); + return exec(`npm publish${tagsFlag}${otpFlag}`, options); } function diffPackages(packageSpecA, packageSpecB, options) { diff --git a/scripts/publish-npm.js b/scripts/publish-npm.js index e8e710b2caf7b4..9051f207a9021d 100755 --- a/scripts/publish-npm.js +++ b/scripts/publish-npm.js @@ -96,7 +96,7 @@ function publishNpm(buildType) { const packagePath = path.join(__dirname, '..', 'packages', 'react-native'); const result = publishPackage(packagePath, { - tag, + tags: [tag], otp: process.env.NPM_CONFIG_OTP, });