Skip to content

Commit 0d2c505

Browse files
committed
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. [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
1 parent f56bf1f commit 0d2c505

File tree

4 files changed

+190
-12
lines changed

4 files changed

+190
-12
lines changed

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"lint-java": "node ./scripts/lint-java.js",
2626
"lint": "eslint .",
2727
"prettier": "prettier --write \"./**/*.{js,md,yml,ts,tsx}\"",
28+
"print-packages": "node ./scripts/monorepo/print",
2829
"shellcheck": "./scripts/circleci/analyze_scripts.sh",
2930
"start": "cd packages/rn-tester && npm run start",
3031
"test-android": "./gradlew :packages:react-native:ReactAndroid:test",

scripts/__tests__/npm-utils-test.js

+46
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
const {
1111
applyPackageVersions,
1212
getPackageVersionStrByTag,
13+
getVersionsBySpec,
1314
publishPackage,
1415
} = require('../npm-utils');
1516

@@ -104,4 +105,49 @@ describe('npm-utils', () => {
104105
);
105106
});
106107
});
108+
109+
describe('getVersionsBySpec', () => {
110+
it('should return array when single version returned', () => {
111+
execMock.mockImplementationOnce(() => ({code: 0, stdout: '"0.72.0" \n'}));
112+
113+
const versions = getVersionsBySpec('mypackage', '^0.72.0');
114+
expect(versions).toEqual(['0.72.0']);
115+
});
116+
117+
it('should return array of versions', () => {
118+
execMock.mockImplementationOnce(() => ({
119+
code: 0,
120+
stdout: '[\n"0.73.0",\n"0.73.1"\n]\n',
121+
}));
122+
123+
const versions = getVersionsBySpec('mypackage', '^0.73.0');
124+
expect(versions).toEqual(['0.73.0', '0.73.1']);
125+
});
126+
127+
it('should return error summary if E404', () => {
128+
const error =
129+
`npm ERR! code E404\n` +
130+
`npm ERR! 404 No match found for version ^0.72.0\n` +
131+
`npm ERR! 404\n` +
132+
`npm ERR! 404 '@react-native/community-cli-plugin@^0.72.0' is not in this registry.\n` +
133+
`npm ERR! 404\n` +
134+
`npm ERR! 404 Note that you can also install from a\n` +
135+
`npm ERR! 404 tarball, folder, http url, or git url.\n` +
136+
`{\n` +
137+
` "error": {\n` +
138+
` "code": "E404",\n` +
139+
` "summary": "No match found for version ^0.72.0",\n` +
140+
` "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` +
141+
` }\n` +
142+
`}\n`;
143+
execMock.mockImplementationOnce(() => ({
144+
code: 1,
145+
stderr: error,
146+
}));
147+
148+
expect(() => {
149+
getVersionsBySpec('mypackage', '^0.72.0');
150+
}).toThrow('No match found for version ^0.72.0');
151+
});
152+
});
107153
});

scripts/monorepo/print/index.js

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @format
8+
*/
9+
10+
const {getVersionsBySpec} = require('../../npm-utils');
11+
const forEachPackage = require('../for-each-package');
12+
const {exit} = require('shelljs');
13+
const yargs = require('yargs');
14+
15+
const {
16+
argv: {type, minor},
17+
} = yargs
18+
.option('type', {
19+
type: 'string',
20+
describe: 'Choose which packages to list, default is all',
21+
choices: ['all', 'public', 'private'],
22+
default: 'all',
23+
})
24+
.option('minor', {
25+
type: 'number',
26+
describe:
27+
'List latest version for specified minor. Ex. 72, 73. Note this will make a network request to npm',
28+
default: 0,
29+
})
30+
.check(argv => {
31+
if (argv.minor > 0 && argv.minor < 70) {
32+
throw new Error('Invalid minor. No monorepo packages before 70');
33+
}
34+
return true;
35+
})
36+
.strict();
37+
38+
function reversePatchComp(semverA, semverB) {
39+
const patchA = parseInt(semverA.split('.')[2], 10);
40+
const patchB = parseInt(semverB.split('.')[2], 10);
41+
return patchB - patchA;
42+
}
43+
44+
const main = () => {
45+
const data = [];
46+
forEachPackage(
47+
(_packageAbsolutePath, _packageRelativePathFromRoot, packageManifest) => {
48+
const isPublic = !packageManifest.private;
49+
if (
50+
type === 'all' ||
51+
(type === 'private' && !isPublic) ||
52+
(type === 'public' && isPublic)
53+
) {
54+
const packageInfo = {
55+
'Public?': isPublic ? '\u{2705}' : '\u{274C}',
56+
Name: packageManifest.name,
57+
'Version (main)': packageManifest.version,
58+
};
59+
60+
if (isPublic && minor !== 0) {
61+
try {
62+
const versions = getVersionsBySpec(
63+
packageManifest.name,
64+
`^0.${minor}.0`,
65+
).sort(reversePatchComp);
66+
packageInfo[`Version (${minor})`] = versions[0];
67+
} catch (e) {
68+
packageInfo[`Version (${minor})`] = e.message;
69+
}
70+
}
71+
data.push(packageInfo);
72+
}
73+
},
74+
{includeReactNative: true},
75+
);
76+
console.table(data);
77+
exit(0);
78+
};
79+
80+
main();

scripts/npm-utils.js

+63-12
Original file line numberDiff line numberDiff line change
@@ -72,18 +72,6 @@ function getNpmInfo(buildType) {
7272
};
7373
}
7474

75-
function getPackageVersionStrByTag(packageName, tag) {
76-
const npmString = tag
77-
? `npm view ${packageName}@${tag} version`
78-
: `npm view ${packageName} version`;
79-
const result = exec(npmString, {silent: true});
80-
81-
if (result.code) {
82-
throw new Error(`Failed to get ${tag} version from npm\n${result.stderr}`);
83-
}
84-
return result.stdout.trim();
85-
}
86-
8775
function publishPackage(packagePath, packageOptions, execOptions) {
8876
const {tag, otp} = packageOptions;
8977
const tagFlag = tag ? ` --tag ${tag}` : '';
@@ -147,10 +135,73 @@ function applyPackageVersions(originalPackageJson, packageVersions) {
147135
return packageJson;
148136
}
149137

138+
/**
139+
* `packageName`: name of npm package
140+
* `tag`: npm tag like `latest` or `next`
141+
*
142+
* This will fetch version of `packageName` with npm tag specified
143+
*/
144+
function getPackageVersionStrByTag(packageName, tag) {
145+
const npmString = tag
146+
? `npm view ${packageName}@${tag} version`
147+
: `npm view ${packageName} version`;
148+
const result = exec(npmString, {silent: true});
149+
150+
if (result.code) {
151+
throw new Error(`Failed to get ${tag} version from npm\n${result.stderr}`);
152+
}
153+
return result.stdout.trim();
154+
}
155+
156+
/**
157+
* `packageName`: name of npm package
158+
* `spec`: spec range ex. '^0.72.0'
159+
*
160+
* Return an array of versions of the specified spec range or throw an error
161+
*/
162+
function getVersionsBySpec(packageName, spec) {
163+
const npmString = `npm view ${packageName}@'${spec}' version --json`;
164+
const result = exec(npmString, {silent: true});
165+
166+
if (result.code) {
167+
// Special handling if no such package spec exists
168+
if (result.stderr.includes('npm ERR! code E404')) {
169+
/**
170+
* npm ERR! code E404
171+
* npm ERR! 404 No match found for version ^0.72.0
172+
* npm ERR! 404
173+
* npm ERR! 404 '@react-native/community-cli-plugin@^0.72.0' is not in this registry.
174+
* npm ERR! 404
175+
* npm ERR! 404 Note that you can also install from a
176+
* npm ERR! 404 tarball, folder, http url, or git url.
177+
* {
178+
* "error": {
179+
* "code": "E404",
180+
* "summary": "No match found for version ^0.72.0",
181+
* "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."
182+
* }
183+
* }
184+
*/
185+
const error = JSON.parse(
186+
result.stderr
187+
.split('\n')
188+
.filter(line => !line.includes('npm ERR'))
189+
.join(''),
190+
).error;
191+
throw new Error(error.summary);
192+
} else {
193+
throw new Error(`Failed: ${npmString}`);
194+
}
195+
}
196+
const versions = JSON.parse(result.stdout.trim());
197+
return !Array.isArray(versions) ? [versions] : versions;
198+
}
199+
150200
module.exports = {
151201
applyPackageVersions,
152202
getNpmInfo,
153203
getPackageVersionStrByTag,
204+
getVersionsBySpec,
154205
publishPackage,
155206
diffPackages,
156207
pack,

0 commit comments

Comments
 (0)