Skip to content

Commit bd627e4

Browse files
authored
Fix global namespaced package detection with bun + add automatic package manager detection for ncu -g (#1514)
1 parent 38b4843 commit bd627e4

File tree

8 files changed

+129
-2
lines changed

8 files changed

+129
-2
lines changed

.ncurc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ module.exports = {
55
// https://github.com/tj/commander.js/pull/2312
66
'commander',
77
// breaking
8+
'@types/bun',
89
'@types/chai-as-promised',
910
'@types/node',
1011
'chai-as-promised',

package-lock.json

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
},
5959
"devDependencies": {
6060
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
61+
"@types/bun": "^1.2.10",
6162
"@types/chai": "^4.3.19",
6263
"@types/chai-as-promised": "^8.0.0",
6364
"@types/chai-string": "^1.4.5",

src/lib/determinePackageManager.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,22 @@ const packageManagerLockfileMap: Index<PackageManagerName> = {
1313
bun: 'bun',
1414
}
1515

16+
/**
17+
* Get the package manager being used to run the command.
18+
* When checking global packages, we need to do it this way since there is no
19+
* lockfile in the global directory.
20+
*/
21+
const getRunningPackageManager = (): PackageManagerName => {
22+
const userAgent = process.env.npm_config_user_agent ?? ''
23+
const execpath = process.env.npm_execpath ?? ''
24+
25+
if (userAgent.startsWith('yarn/') || execpath.includes('yarn')) return 'yarn'
26+
if (userAgent.startsWith('pnpm/') || execpath.includes('pnpm')) return 'pnpm'
27+
if (userAgent.startsWith('bun/') || typeof Bun !== 'undefined' || process.versions.bun) return 'bun'
28+
29+
return 'npm'
30+
}
31+
1632
/**
1733
* If the packageManager option was not provided, look at the lockfiles to
1834
* determine which package manager is being used.
@@ -23,7 +39,7 @@ const determinePackageManager = async (
2339
readdir: (_path: string) => Promise<string[]> = fs.readdir,
2440
): Promise<PackageManagerName> => {
2541
if (options.packageManager) return options.packageManager
26-
else if (options.global) return 'npm'
42+
else if (options.global) return getRunningPackageManager()
2743

2844
const lockfileName = (await findLockfile(options, readdir))?.filename
2945
return lockfileName ? packageManagerLockfileMap[lockfileName.split('.')[0]] : 'npm'

src/package-managers/bun.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ export const list = async (options: Options = {}): Promise<Index<string | undefi
6060
// When bun is spawned in the GitHub Actions environment, it outputs ANSI color. Unfortunately, it does not respect the `NO_COLOR` envirionment variable. Therefore, we have to manually strip ansi.
6161
const lines = stripAnsi(stdout).split('\n')
6262
const dependencies = keyValueBy(lines, line => {
63-
const match = line.match(/.* (.*?)@(.+)/)
63+
// The capturing group for the package name requires a + quantifier, otherwise namespaced packages like @angular/cli will not be captured correctly.
64+
const match = line.match(/.* (.+?)@(.+)/)
6465
if (match) {
6566
const [, name, version] = match
6667
return { [name]: version }

test/bun/bun.lockb

0 Bytes
Binary file not shown.

test/determinePackageManager.test.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,4 +164,72 @@ describe('determinePackageManager', () => {
164164
)
165165
packageManager.should.equal('npm')
166166
})
167+
168+
describe('global', () => {
169+
it('detects npm', async () => {
170+
const oldUserAgent = process.env.npm_config_user_agent
171+
const oldExecpath = process.env.npm_execpath
172+
173+
process.env.npm_config_user_agent = 'bun/1.2.10'
174+
process.env.npm_execpath = 'bun'
175+
process.versions.bun = '1.2.10'
176+
177+
const packageManager = await determinePackageManager({
178+
global: true,
179+
})
180+
packageManager.should.equal('bun')
181+
182+
process.env.npm_config_user_agent = oldUserAgent
183+
process.env.npm_execpath = oldExecpath
184+
process.versions.bun = ''
185+
})
186+
187+
it('detects yarn', async () => {
188+
const oldUserAgent = process.env.npm_config_user_agent
189+
const oldExecpath = process.env.npm_execpath
190+
191+
process.env.npm_config_user_agent = 'yarn/1.2.10'
192+
process.env.npm_execpath = 'yarn'
193+
194+
const packageManager = await determinePackageManager({
195+
global: true,
196+
})
197+
packageManager.should.equal('yarn')
198+
199+
process.env.npm_config_user_agent = oldUserAgent
200+
process.env.npm_execpath = oldExecpath
201+
})
202+
203+
it('detects pnpm', async () => {
204+
const oldUserAgent = process.env.npm_config_user_agent
205+
const oldExecpath = process.env.npm_execpath
206+
207+
process.env.npm_config_user_agent = 'pnpm/1.2.10'
208+
process.env.npm_execpath = 'pnpm'
209+
210+
const packageManager = await determinePackageManager({
211+
global: true,
212+
})
213+
packageManager.should.equal('pnpm')
214+
215+
process.env.npm_config_user_agent = oldUserAgent
216+
process.env.npm_execpath = oldExecpath
217+
})
218+
219+
it('defaults to npm', async () => {
220+
const oldUserAgent = process.env.npm_config_user_agent
221+
const oldExecpath = process.env.npm_execpath
222+
223+
process.env.npm_config_user_agent = ''
224+
process.env.npm_execpath = ''
225+
226+
const packageManager = await determinePackageManager({
227+
global: true,
228+
})
229+
packageManager.should.equal('npm')
230+
231+
process.env.npm_config_user_agent = oldUserAgent
232+
process.env.npm_execpath = oldExecpath
233+
})
234+
})
167235
})

test/test-data/doctor/fail/bun.lock

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"lockfileVersion": 1,
3+
"workspaces": {
4+
"": {
5+
"dependencies": {
6+
"emitter20": "2.0.0",
7+
"ncu-test-return-version": "~1.0.0",
8+
"ncu-test-v2": "~2.0.0",
9+
},
10+
},
11+
},
12+
"packages": {
13+
"emitter20": ["[email protected]", "", {}, "sha512-S6tIABrpAK6CJrZddTwMnLVWP4YUskGCW8jRtZ7OaA/Gdmm0Neg34RJGiUYWUq2RK2suvzZ5hFBg9350+CDuuA=="],
14+
15+
"ncu-test-return-version": ["[email protected]", "", {}, "sha512-xen4KcnzVAHxYIGDm1vyKJ6BOKGxATwrW7TMO9/Teg0IwQQ1EaiPi2lr16bqgPnT8odWcZHzdh4WiHsbCaMCqQ=="],
16+
17+
"ncu-test-v2": ["[email protected]", "", {}, "sha512-Jqu6DzpKkTrUdeL+VN/X4lz4IVDxkNAqVHmyJ+3uVcszqPlU8JMNTA2qeihzMcbd4pOiagKlJno7r+EO2WLmfw=="],
18+
}
19+
}

0 commit comments

Comments
 (0)