From 355fefb10979bd3a6bacd20fb5d0b8efd7011ece Mon Sep 17 00:00:00 2001 From: amishabenramani Date: Sat, 26 Sep 2026 00:05:09 +0200 Subject: [PATCH] fix: repair PNPM_HOME registry type --- .../path-extender-windows.spec.ts | 52 +++++++++++++++++-- .../path-extender-windows.ts | 22 +++++--- 2 files changed, 64 insertions(+), 10 deletions(-) diff --git a/os/env/path-extender-windows/path-extender-windows.spec.ts b/os/env/path-extender-windows/path-extender-windows.spec.ts index 0d9763f..af30d6a 100644 --- a/os/env/path-extender-windows/path-extender-windows.spec.ts +++ b/os/env/path-extender-windows/path-extender-windows.spec.ts @@ -325,7 +325,7 @@ HKEY_CURRENT_USER\\Environment expect(report).toStrictEqual([ { variable: 'PNPM_HOME', - action: 'skipped', + action: 'updated', oldValue: pnpmHomeDirNormalized, newValue: pnpmHomeDirNormalized, }, @@ -337,9 +337,53 @@ HKEY_CURRENT_USER\\Environment }, ]) expect(execa).toHaveBeenNthCalledWith(3, 'reg', ['query', regKey], { windowsHide: false }) - expect(execa).toHaveBeenNthCalledWith(4, 'reg', ['add', regKey, '/v', 'Path', '/t', 'REG_EXPAND_SZ', '/d', `%PNPM_HOME%;${currentPathInRegistry}`, '/f'], { windowsHide: false }) - expect(execa).toHaveBeenNthCalledWith(5, 'setx', ['REFRESH_ENV_VARS', '1'], { windowsHide: false }) - expect(execa).toHaveBeenNthCalledWith(6, 'reg', ['delete' ,regKey, '/v', 'REFRESH_ENV_VARS', '/f'], { windowsHide: false }) + expect(execa).toHaveBeenNthCalledWith(4, 'reg', ['add', regKey, '/v', 'PNPM_HOME', '/t', 'REG_SZ', '/d', pnpmHomeDirNormalized, '/f'], { windowsHide: false }) + expect(execa).toHaveBeenNthCalledWith(5, 'reg', ['add', regKey, '/v', 'Path', '/t', 'REG_EXPAND_SZ', '/d', `%PNPM_HOME%;${currentPathInRegistry}`, '/f'], { windowsHide: false }) + expect(execa).toHaveBeenNthCalledWith(6, 'setx', ['REFRESH_ENV_VARS', '1'], { windowsHide: false }) + expect(execa).toHaveBeenNthCalledWith(7, 'reg', ['delete' ,regKey, '/v', 'REFRESH_ENV_VARS', '/f'], { windowsHide: false }) +}) + +test('PNPM_HOME with the correct registry type is left unchanged', async () => { + const pnpmHomeDir = tempDir(false) + const pnpmHomeDirNormalized = path.normalize(pnpmHomeDir) + const currentPathInRegistry = '%PNPM_HOME%;C:\Windows' + execa['mockResolvedValueOnce']({ + failed: false, + stdout: 'Active code page: 437', + }).mockResolvedValueOnce({ + failed: false, + stdout: '', + }).mockResolvedValueOnce({ + failed: false, + stdout: '\nHKEY_CURRENT_USER\\Environment\n PNPM_HOME REG_SZ ' + pnpmHomeDirNormalized + '\n Path REG_EXPAND_SZ ' + currentPathInRegistry + '\n', + }).mockResolvedValueOnce({ + failed: false, + stdout: '', + }).mockResolvedValueOnce({ + failed: false, + stdout: '', + }).mockResolvedValueOnce({ + failed: false, + stdout: '', + }) + + const report = await addDirToWindowsEnvPath(pnpmHomeDir, { proxyVarName: 'PNPM_HOME' }) + + expect(report).toStrictEqual([ + { + variable: 'PNPM_HOME', + action: 'skipped', + oldValue: pnpmHomeDirNormalized, + newValue: pnpmHomeDirNormalized, + }, + { + variable: 'Path', + action: 'skipped', + oldValue: currentPathInRegistry, + newValue: currentPathInRegistry, + }, + ]) + expect(execa).not.toHaveBeenCalledWith('reg', expect.arrayContaining(['add']), { windowsHide: false }) }) test('setup throws an error if PNPM_HOME is already set to a different directory', async () => { diff --git a/os/env/path-extender-windows/path-extender-windows.ts b/os/env/path-extender-windows/path-extender-windows.ts index af761bd..c222378 100644 --- a/os/env/path-extender-windows/path-extender-windows.ts +++ b/os/env/path-extender-windows/path-extender-windows.ts @@ -90,16 +90,19 @@ async function updateEnvVariable ( overwrite: boolean } ): Promise { - const currentValue = await getEnvValueFromRegistry(registryOutput, name) + const current = await getEnvValueFromRegistryWithType(registryOutput, name) + const currentValue = current?.data if (currentValue && !opts.overwrite) { if (currentValue !== value) { throw new BadEnvVariableError({ envName: name, currentValue, wantedValue: value }) } - return { variable: name, action: 'skipped', oldValue: currentValue, newValue: value } - } else { - await setEnvVarInRegistry(name, value, { expandableString: opts.expandableString }) - return { variable: name, action: 'updated', oldValue: currentValue as string, newValue: value } + const wantedType = opts.expandableString ? 'REG_EXPAND_SZ' : 'REG_SZ' + if (current.type === wantedType) { + return { variable: name, action: 'skipped', oldValue: currentValue, newValue: value } + } } + await setEnvVarInRegistry(name, value, { expandableString: opts.expandableString }) + return { variable: name, action: 'updated', oldValue: currentValue as string, newValue: value } } async function addToPath (registryOutput: string, addedDir: string, position: AddingPosition = 'start'): Promise { @@ -136,9 +139,16 @@ async function getRegistryOutput (): Promise { } async function getEnvValueFromRegistry (registryOutput: string, envVarName: string): Promise { + return (await getEnvValueFromRegistryWithType(registryOutput, envVarName))?.data +} + +async function getEnvValueFromRegistryWithType ( + registryOutput: string, + envVarName: string +): Promise { const regexp = new RegExp(`^ {4}(?${envVarName}) {4}(?\\w+) {4}(?.*)$`, 'gim') const match = Array.from(matchAll(registryOutput, regexp))[0] as IEnvironmentValueMatch - return match?.groups.data + return match?.groups } async function setEnvVarInRegistry (