Skip to content

Commit dd4e5c1

Browse files
Merge pull request #7555 from Shopify/bun-executes-npm-to-autoupgrade
Fix Windows auto-upgrade for local CLI installs
2 parents ced0ad4 + 5ce9ede commit dd4e5c1

2 files changed

Lines changed: 28 additions & 3 deletions

File tree

packages/cli-kit/src/public/node/is-global.test.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,23 @@ describe('currentProcessIsGlobal', () => {
8181
// Then
8282
expect(got).toBeFalsy()
8383
})
84+
85+
test('returns false on Windows when argv uses backslashes and projectDir uses forward slashes', () => {
86+
// Given - mimic the exact Windows shape:
87+
// projectDir comes from pathe -> normalized forward slashes
88+
// argv[1] is OS-native -> backslash separated
89+
const winProjectDir = 'C:/Users/me/project'
90+
const winArgv1 = 'C:\\Users\\me\\project\\node_modules\\@shopify\\cli\\bin\\run.js'
91+
vi.mocked(findPathUpSync).mockReturnValue(`${winProjectDir}/shopify.app.toml`)
92+
const argv = ['node', winArgv1, 'shopify']
93+
94+
// When
95+
const got = currentProcessIsGlobal(argv)
96+
97+
// Then - regression test for the path-separator bug that misclassified
98+
// Windows local installs as global, triggering an unwanted `npm install -g`.
99+
expect(got).toBeFalsy()
100+
})
84101
})
85102

86103
describe('inferPackageManagerForGlobalCLI', () => {

packages/cli-kit/src/public/node/is-global.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {cwd, dirname, joinPath, sniffForPath} from './path.js'
1+
import {cwd, dirname, isSubpath, joinPath, sniffForPath} from './path.js'
22
import {isUnitTest} from './context/local.js'
33
import {findPathUpSync, globSync} from './fs.js'
44
import {realpathSync} from 'fs'
@@ -27,9 +27,17 @@ export function currentProcessIsGlobal(argv = process.argv): boolean {
2727

2828
// From node docs: "The second element [of the array] will be the path to the JavaScript file being executed"
2929
const binDir = argv[1] ?? ''
30+
if (!binDir) {
31+
return true
32+
}
3033

31-
// If binDir starts with projectDir, then we are running a local CLI
32-
const isLocal = binDir.startsWith(projectDir.trim())
34+
// If binDir lives inside projectDir, we are running a local CLI.
35+
// Use isSubpath (pathe.relative under the hood) instead of a raw
36+
// string startsWith: projectDir flows through normalizePath and is
37+
// forward-slash on every platform, while argv[1] is OS-native, so on
38+
// Windows it arrives backslash-separated and a naive startsWith would
39+
// misclassify a local install as global.
40+
const isLocal = isSubpath(projectDir.trim(), binDir)
3341

3442
_isGlobal = !isLocal
3543
return _isGlobal

0 commit comments

Comments
 (0)