Skip to content

Commit 43b7df5

Browse files
authored
chore(monorepo-tools): add a script for NPM token access tickets (#579)
1 parent 71e0a4d commit 43b7df5

File tree

7 files changed

+122
-3
lines changed

7 files changed

+122
-3
lines changed

package-lock.json

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@
3939
"test-changed": "lerna run test --stream --concurrency 1 --since origin/HEAD",
4040
"test-ci": "lerna run test-ci --concurrency 1",
4141
"test": "lerna run test --concurrency 1 --stream",
42-
"where": "node ./scripts/src/where.js"
42+
"where": "node ./scripts/src/where.js",
43+
"request-npm-token": "request-npm-token"
4344
},
4445
"dependencies": {
4546
"@mongodb-js/monorepo-tools": "^1.1.18"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/usr/bin/env node
2+
'use strict';
3+
require('../dist/request-npm-token.js');

packages/monorepo-tools/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
"precommit": "./bin/precommit.js",
2727
"depalign": "./bin/depalign.js",
2828
"monorepo-where": "./bin/where.js",
29-
"bump-monorepo-packages": "./bin/bump-packages.js"
29+
"bump-monorepo-packages": "./bin/bump-packages.js",
30+
"request-npm-token": "./bin/request-npm-token.js"
3031
},
3132
"scripts": {
3233
"bootstrap": "npm run compile",

packages/monorepo-tools/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ export * from './utils/update-package-json';
77
export * from './utils/with-progress';
88
export * from './utils/workspace-dependencies';
99
export * from './utils/get-packages-in-topological-order';
10+
export * from './utils/get-npm-token-list';
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#! /usr/bin/env node
2+
/* eslint-disable no-console */
3+
4+
/**
5+
* CLI command to get NPM token requirements for the current monorepo.
6+
*
7+
* Usage:
8+
* npm run request-npm-token
9+
*
10+
* This will output the scopes and packages that need to be included in NPM token permissions.
11+
*/
12+
13+
import { getNpmTokenList } from './utils/get-npm-token-list';
14+
15+
async function main() {
16+
try {
17+
const { scopes, packages } = await getNpmTokenList();
18+
19+
console.log(
20+
'Open an IAMSEC ticket with https://jira.mongodb.org/plugins/servlet/desk/portal/81/create/1380',
21+
);
22+
23+
console.log('Use the following description for the ticket:');
24+
console.log('--------------------------------');
25+
console.log('Hello,');
26+
console.log(
27+
'We need to update the NPM token for publishing our packages. The token needs Read/Write/Publish access to:\n',
28+
);
29+
30+
console.log('Following Scopes:');
31+
if (scopes.length > 0) {
32+
scopes.forEach((scope) => {
33+
console.log(scope);
34+
});
35+
} else {
36+
console.log('(none)');
37+
}
38+
39+
console.log('\nFollowing Packages:');
40+
if (packages.length > 0) {
41+
packages.forEach((pkg) => {
42+
console.log(pkg);
43+
});
44+
} else {
45+
console.log('(none)');
46+
}
47+
48+
console.log('');
49+
console.log('Please share it with our team lead: {TEAM LEADER NAME}');
50+
} catch (error) {
51+
console.error(
52+
'Error:',
53+
error instanceof Error ? error.message : String(error),
54+
);
55+
process.exit(1);
56+
}
57+
}
58+
59+
process.on('unhandledRejection', (err: Error) => {
60+
console.error();
61+
console.error(err?.stack || err?.message || err);
62+
process.exitCode = 1;
63+
});
64+
65+
main().catch((err) =>
66+
process.nextTick(() => {
67+
throw err;
68+
}),
69+
);
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { listAllPackages } from './list-all-packages';
2+
3+
export interface NpmTokenRequirements {
4+
scopes: string[];
5+
packages: string[];
6+
}
7+
8+
/**
9+
* Gets all package names and scopes from the current monorepo.
10+
* Returns scoped packages as scopes and unscoped packages as individual packages.
11+
*/
12+
export async function getNpmTokenList(): Promise<NpmTokenRequirements> {
13+
const allPackagesArr = [];
14+
for await (const { packageJson } of listAllPackages()) {
15+
// listAllPackages yields { name: string, ... }
16+
if (packageJson && typeof packageJson?.name === 'string') {
17+
allPackagesArr.push(packageJson.name);
18+
}
19+
}
20+
21+
// Separate scoped and unscoped packages
22+
const scopedPackages = allPackagesArr.filter(
23+
(pkg) => typeof pkg === 'string' && pkg.startsWith('@'),
24+
);
25+
const unscopedPackages = allPackagesArr.filter(
26+
(pkg) => typeof pkg === 'string' && !pkg.startsWith('@'),
27+
);
28+
29+
// Extract unique scopes from scoped packages
30+
const scopes = [
31+
...new Set(
32+
scopedPackages.map((pkg) => {
33+
const scope = pkg.split('/')[0];
34+
return `${scope}/*`;
35+
}),
36+
),
37+
].sort();
38+
39+
// Sort unscoped packages
40+
const packages = [...new Set(unscopedPackages)].sort();
41+
42+
return { scopes, packages };
43+
}

0 commit comments

Comments
 (0)