Skip to content

Commit

Permalink
Add print-packages as a command (#41959)
Browse files Browse the repository at this point in the history
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.

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

Pull Request resolved: #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
  • Loading branch information
lunaleaps committed Feb 4, 2024
1 parent f56bf1f commit 0d2c505
Show file tree
Hide file tree
Showing 4 changed files with 190 additions and 12 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"lint-java": "node ./scripts/lint-java.js",
"lint": "eslint .",
"prettier": "prettier --write \"./**/*.{js,md,yml,ts,tsx}\"",
"print-packages": "node ./scripts/monorepo/print",
"shellcheck": "./scripts/circleci/analyze_scripts.sh",
"start": "cd packages/rn-tester && npm run start",
"test-android": "./gradlew :packages:react-native:ReactAndroid:test",
Expand Down
46 changes: 46 additions & 0 deletions scripts/__tests__/npm-utils-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
const {
applyPackageVersions,
getPackageVersionStrByTag,
getVersionsBySpec,
publishPackage,
} = require('../npm-utils');

Expand Down Expand Up @@ -104,4 +105,49 @@ describe('npm-utils', () => {
);
});
});

describe('getVersionsBySpec', () => {
it('should return array when single version returned', () => {
execMock.mockImplementationOnce(() => ({code: 0, stdout: '"0.72.0" \n'}));

const versions = getVersionsBySpec('mypackage', '^0.72.0');
expect(versions).toEqual(['0.72.0']);
});

it('should return array of versions', () => {
execMock.mockImplementationOnce(() => ({
code: 0,
stdout: '[\n"0.73.0",\n"0.73.1"\n]\n',
}));

const versions = getVersionsBySpec('mypackage', '^0.73.0');
expect(versions).toEqual(['0.73.0', '0.73.1']);
});

it('should return error summary if E404', () => {
const error =
`npm ERR! code E404\n` +
`npm ERR! 404 No match found for version ^0.72.0\n` +
`npm ERR! 404\n` +
`npm ERR! 404 '@react-native/community-cli-plugin@^0.72.0' is not in this registry.\n` +
`npm ERR! 404\n` +
`npm ERR! 404 Note that you can also install from a\n` +
`npm ERR! 404 tarball, folder, http url, or git url.\n` +
`{\n` +
` "error": {\n` +
` "code": "E404",\n` +
` "summary": "No match found for version ^0.72.0",\n` +
` "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."\n` +
` }\n` +
`}\n`;
execMock.mockImplementationOnce(() => ({
code: 1,
stderr: error,
}));

expect(() => {
getVersionsBySpec('mypackage', '^0.72.0');
}).toThrow('No match found for version ^0.72.0');
});
});
});
80 changes: 80 additions & 0 deletions scripts/monorepo/print/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/**
* 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 {getVersionsBySpec} = require('../../npm-utils');
const forEachPackage = require('../for-each-package');
const {exit} = require('shelljs');
const yargs = require('yargs');

const {
argv: {type, minor},
} = yargs
.option('type', {
type: 'string',
describe: 'Choose which packages to list, default is all',
choices: ['all', 'public', 'private'],
default: 'all',
})
.option('minor', {
type: 'number',
describe:
'List latest version for specified minor. Ex. 72, 73. Note this will make a network request to npm',
default: 0,
})
.check(argv => {
if (argv.minor > 0 && argv.minor < 70) {
throw new Error('Invalid minor. No monorepo packages before 70');
}
return true;
})
.strict();

function reversePatchComp(semverA, semverB) {
const patchA = parseInt(semverA.split('.')[2], 10);
const patchB = parseInt(semverB.split('.')[2], 10);
return patchB - patchA;
}

const main = () => {
const data = [];
forEachPackage(
(_packageAbsolutePath, _packageRelativePathFromRoot, packageManifest) => {
const isPublic = !packageManifest.private;
if (
type === 'all' ||
(type === 'private' && !isPublic) ||
(type === 'public' && isPublic)
) {
const packageInfo = {
'Public?': isPublic ? '\u{2705}' : '\u{274C}',
Name: packageManifest.name,
'Version (main)': packageManifest.version,
};

if (isPublic && minor !== 0) {
try {
const versions = getVersionsBySpec(
packageManifest.name,
`^0.${minor}.0`,
).sort(reversePatchComp);
packageInfo[`Version (${minor})`] = versions[0];
} catch (e) {
packageInfo[`Version (${minor})`] = e.message;
}
}
data.push(packageInfo);
}
},
{includeReactNative: true},
);
console.table(data);
exit(0);
};

main();
75 changes: 63 additions & 12 deletions scripts/npm-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,18 +72,6 @@ function getNpmInfo(buildType) {
};
}

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();
}

function publishPackage(packagePath, packageOptions, execOptions) {
const {tag, otp} = packageOptions;
const tagFlag = tag ? ` --tag ${tag}` : '';
Expand Down Expand Up @@ -147,10 +135,73 @@ function applyPackageVersions(originalPackageJson, packageVersions) {
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,
Expand Down

0 comments on commit 0d2c505

Please sign in to comment.