Files
react-native/scripts/npm-utils.js
T
Luna Wei 05ec058ac5 Add print-packages as a command (#41959)
Summary:
Working on releases, I'm often looking for the name of our monorepo packages (as sometimes the name doesn't align with the directory) and also getting a list of the versions of everything, as well as if its private/public -- which I've interpreted to mean that we publish it or we don't. I thought this might be convenient to add.

## Changelog:
[Internal] - Add `print-packages` as a command to print our monorepo packages (including react-native)

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

Test Plan:
```
❯ yarn print-packages
yarn run v1.22.19
$ node ./scripts/monorepo/print
┌─────────┬─────────┬─────────────────────────────────────────┬────────────────┐
│ (index) │ Public? │                  Name                   │ Version (main) │
├─────────┼─────────┼─────────────────────────────────────────┼────────────────┤
│    0    │  ''   │     'react-native/assets-registry'     │    '0.74.0'    │
│    1    │  ''   │  'react-native/babel-plugin-codegen'   │    '0.74.0'    │
│    2    │  ''   │  'react-native/community-cli-plugin'   │    '0.74.0'    │
│    3    │  ''   │    'react-native/debugger-frontend'    │    '0.74.0'    │
│    4    │  ''   │     'react-native/dev-middleware'      │    '0.74.0'    │
│    5    │  ''   │      'react-native/eslint-config'      │    '0.74.0'    │
│    6    │  ''   │      'react-native/eslint-plugin'      │    '0.74.0'    │
│    7    │  ''   │   'react-native/eslint-plugin-specs'   │    '0.74.0'    │
│    8    │  ''   │ 'react-native/hermes-inspector-msggen' │    '0.72.0'    │
│    9    │  ''   │      'react-native/metro-config'       │    '0.74.0'    │
│   10    │  ''   │    'react-native/normalize-colors'     │    '0.74.1'    │
│   11    │  ''   │      'react-native/js-polyfills'       │    '0.74.0'    │
│   12    │  ''   │             'react-native'              │   '1000.0.0'   │
│   13    │  ''   │      'react-native/babel-preset'       │    '0.74.0'    │
│   14    │  ''   │ 'react-native/metro-babel-transformer' │    '0.74.0'    │
│   15    │  ''   │          'react-native/bots'           │    '0.0.0'     │
│   16    │  ''   │         'react-native/codegen'         │    '0.74.0'    │
│   17    │  ''   │ 'react-native/codegen-typescript-test' │    '0.0.1'     │
│   18    │  ''   │      'react-native/gradle-plugin'      │    '0.74.0'    │
│   19    │  ''   │         'react-native/tester'          │    '0.0.1'     │
│   20    │  ''   │       'react-native/tester-e2e'        │    '0.0.1'     │
│   21    │  ''   │    'react-native/typescript-config'    │    '0.74.0'    │
│   22    │  ''   │    'react-native/virtualized-lists'    │    '0.74.0'    │
└─────────┴─────────┴─────────────────────────────────────────┴────────────────┘
  Done in 0.55s.
```

Also added filter flag for private/public
```
❯ yarn print-packages --type private
yarn run v1.22.19
$ node ./scripts/monorepo/print --type private
┌─────────┬─────────┬─────────────────────────────────────────┬────────────────┐
│ (index) │ Public? │                  Name                   │ Version (main) │
├─────────┼─────────┼─────────────────────────────────────────┼────────────────┤
│    0    │  ''   │ 'react-native/hermes-inspector-msggen' │    '0.72.0'    │
│    1    │  ''   │          'react-native/bots'           │    '0.0.0'     │
│    2    │  ''   │ 'react-native/codegen-typescript-test' │    '0.0.1'     │
│    3    │  ''   │         'react-native/tester'          │    '0.0.1'     │
│    4    │  ''   │       'react-native/tester-e2e'        │    '0.0.1'     │
└─────────┴─────────┴─────────────────────────────────────────┴────────────────┘
  Done in 0.16s.
```

Also added a npm query where you can see the latest published version of a minor
```
❯ yarn print-packages --type public --minor 72
yarn run v1.22.19
$ node ./scripts/monorepo/print --type public --minor 72
┌─────────┬─────────┬─────────────────────────────────────────┬────────────────┬──────────────────────────────────────┐
│ (index) │ Public? │                  Name                   │ Version (main) │             Version (72)             │
├─────────┼─────────┼─────────────────────────────────────────┼────────────────┼──────────────────────────────────────┤
│    0    │  ''   │     'react-native/assets-registry'     │    '0.74.0'    │               '0.72.0'               │
│    1    │  ''   │  'react-native/babel-plugin-codegen'   │    '0.74.0'    │               '0.72.3'               │
│    2    │  ''   │  'react-native/community-cli-plugin'   │    '0.74.0'    │ 'No match found for version ^0.72.0' │
│    3    │  ''   │    'react-native/debugger-frontend'    │    '0.74.0'    │ 'No match found for version ^0.72.0' │
│    4    │  ''   │     'react-native/dev-middleware'      │    '0.74.0'    │ 'No match found for version ^0.72.0' │
│    5    │  ''   │      'react-native/eslint-config'      │    '0.74.0'    │               '0.72.2'               │
│    6    │  ''   │      'react-native/eslint-plugin'      │    '0.74.0'    │               '0.72.0'               │
│    7    │  ''   │   'react-native/eslint-plugin-specs'   │    '0.74.0'    │               '0.72.4'               │
│    8    │  ''   │      'react-native/metro-config'       │    '0.74.0'    │              '0.72.11'               │
│    9    │  ''   │    'react-native/normalize-colors'     │    '0.74.1'    │               '0.72.0'               │
│   10    │  ''   │      'react-native/js-polyfills'       │    '0.74.0'    │               '0.72.1'               │
│   11    │  ''   │             'react-native'              │   '1000.0.0'   │               '0.72.8'               │
│   12    │  ''   │      'react-native/babel-preset'       │    '0.74.0'    │ 'No match found for version ^0.72.0' │
│   13    │  ''   │ 'react-native/metro-babel-transformer' │    '0.74.0'    │ 'No match found for version ^0.72.0' │
│   14    │  ''   │         'react-native/codegen'         │    '0.74.0'    │               '0.72.8'               │
│   15    │  ''   │      'react-native/gradle-plugin'      │    '0.74.0'    │              '0.72.11'               │
│   16    │  ''   │    'react-native/typescript-config'    │    '0.74.0'    │ 'No match found for version ^0.72.0' │
│   17    │  ''   │    'react-native/virtualized-lists'    │    '0.74.0'    │               '0.72.8'               │
└─────────┴─────────┴─────────────────────────────────────────┴────────────────┴──────────────────────────────────────┘
```

Reviewed By: cortinico

Differential Revision: D52347140

Pulled By: lunaleaps

fbshipit-source-id: 75811730e1afd5aae2d9fba4e437cd0d3d424a90
2024-01-02 11:46:03 -08:00

227 lines
6.2 KiB
JavaScript

/**
* 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
*/
'use strict';
const {
exitIfNotOnGit,
getCurrentCommit,
isTaggedLatest,
} = require('./scm-utils');
const {parseVersion} = require('./version-utils');
const {exec} = require('shelljs');
// Get `next` version from npm and +1 on the minor for `main` version
function getMainVersion() {
const versionStr = getPackageVersionStrByTag('react-native', 'next');
const {major, minor} = parseVersion(versionStr, 'release');
return `${major}.${parseInt(minor, 10) + 1}.0`;
}
function getNpmInfo(buildType) {
const currentCommit = getCurrentCommit();
const shortCommit = currentCommit.slice(0, 9);
if (buildType === 'dry-run') {
return {
version: `1000.0.0-${shortCommit}`,
tag: null, // We never end up publishing this
};
}
if (buildType === 'nightly') {
const mainVersion = getMainVersion();
const dateIdentifier = new Date()
.toISOString()
.slice(0, -14)
.replace(/[-]/g, '');
return {
version: `${mainVersion}-nightly-${dateIdentifier}-${shortCommit}`,
tag: 'nightly',
};
}
if (buildType === 'prealpha') {
const mainVersion = '0.0.0';
// Date in the format of YYYYMMDDHH.
// This is a progressive int that can track subsequent
// releases and it is smaller of 2^32-1.
// It is unlikely that we can trigger two prealpha in less
// than an hour given that nightlies take ~ 1 hr to complete.
const dateIdentifier = new Date()
.toISOString()
.slice(0, -10)
.replace(/[-T:]/g, '');
return {
version: `${mainVersion}-prealpha-${dateIdentifier}`,
tag: 'prealpha',
};
}
const {version, major, minor, prerelease} = parseVersion(
process.env.CIRCLE_TAG,
buildType,
);
// See if releaser indicated that this version should be tagged "latest"
// Set in `trigger-react-native-release`
const isLatest = exitIfNotOnGit(
() => isTaggedLatest(currentCommit),
'Not in git. We do not want to publish anything',
);
const releaseBranchTag = `${major}.${minor}-stable`;
// npm will automatically tag the version as `latest` if no tag is set when we publish
// To prevent this, use `releaseBranchTag` when we don't want that (ex. releasing a patch on older release)
const tag =
prerelease != null ? 'next' : isLatest ? 'latest' : releaseBranchTag;
return {
version,
tag,
};
}
function publishPackage(packagePath, packageOptions, execOptions) {
const {tag, otp} = packageOptions;
const tagFlag = tag ? ` --tag ${tag}` : '';
const otpFlag = otp ? ` --otp ${otp}` : '';
const options = execOptions
? {...execOptions, cwd: packagePath}
: {cwd: packagePath};
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);
}
}
/**
* `package` is an object form of package.json
* `dependencies` is a map of dependency to version string
*
* This replaces both dependencies and devDependencies in package.json
*/
function applyPackageVersions(originalPackageJson, packageVersions) {
const packageJson = {...originalPackageJson};
for (const name of Object.keys(packageVersions)) {
if (
packageJson.dependencies != null &&
packageJson.dependencies[name] != null
) {
packageJson.dependencies[name] = packageVersions[name];
}
if (
packageJson.devDependencies != null &&
packageJson.devDependencies[name] != null
) {
packageJson.devDependencies[name] = packageVersions[name];
}
}
return packageJson;
}
/**
* `packageName`: name of npm package
* `tag`: npm tag like `latest` or `next`
*
* This will fetch version of `packageName` with npm tag specified
*/
function getPackageVersionStrByTag(packageName, tag) {
const npmString = tag
? `npm view ${packageName}@${tag} version`
: `npm view ${packageName} version`;
const result = exec(npmString, {silent: true});
if (result.code) {
throw new Error(`Failed to get ${tag} version from npm\n${result.stderr}`);
}
return result.stdout.trim();
}
/**
* `packageName`: name of npm package
* `spec`: spec range ex. '^0.72.0'
*
* Return an array of versions of the specified spec range or throw an error
*/
function getVersionsBySpec(packageName, spec) {
const npmString = `npm view ${packageName}@'${spec}' version --json`;
const result = exec(npmString, {silent: true});
if (result.code) {
// Special handling if no such package spec exists
if (result.stderr.includes('npm ERR! code E404')) {
/**
* npm ERR! code E404
* npm ERR! 404 No match found for version ^0.72.0
* npm ERR! 404
* npm ERR! 404 '@react-native/community-cli-plugin@^0.72.0' is not in this registry.
* npm ERR! 404
* npm ERR! 404 Note that you can also install from a
* npm ERR! 404 tarball, folder, http url, or git url.
* {
* "error": {
* "code": "E404",
* "summary": "No match found for version ^0.72.0",
* "detail": "\n '@react-native/community-cli-plugin@^0.72.0' is not in this registry.\n\nNote that you can also install from a\ntarball, folder, http url, or git url."
* }
* }
*/
const error = JSON.parse(
result.stderr
.split('\n')
.filter(line => !line.includes('npm ERR'))
.join(''),
).error;
throw new Error(error.summary);
} else {
throw new Error(`Failed: ${npmString}`);
}
}
const versions = JSON.parse(result.stdout.trim());
return !Array.isArray(versions) ? [versions] : versions;
}
module.exports = {
applyPackageVersions,
getNpmInfo,
getPackageVersionStrByTag,
getVersionsBySpec,
publishPackage,
diffPackages,
pack,
};