|
1 | 1 | import { spawnSync } from 'node:child_process'; |
2 | | -import { mkdirSync, writeFileSync } from 'node:fs'; |
| 2 | +import { mkdirSync, symlinkSync, writeFileSync } from 'node:fs'; |
3 | 3 | import path from 'node:path'; |
4 | 4 | import { expect, test } from 'rstack/test'; |
5 | 5 | import { createHookFiles } from '../../src/setup/hooks.ts'; |
@@ -28,16 +28,33 @@ test('generates the dispatcher and all client-side Git hook shims', () => { |
28 | 28 | expect(new Set(Object.values(shims)).size).toBe(1); |
29 | 29 | }); |
30 | 30 |
|
| 31 | +test.runIf(process.platform === 'win32')('converts Windows Node paths', () => { |
| 32 | + const { runner } = createHookFiles(String.raw`C:\Program Files\nodejs\node.exe`); |
| 33 | + |
| 34 | + expect(runner).toContain("node_fallback='/c/Program Files/nodejs/node.exe'"); |
| 35 | +}); |
| 36 | + |
| 37 | +test.runIf(process.platform !== 'win32')('preserves backslashes in POSIX Node paths', () => { |
| 38 | + const nodeExecutable = String.raw`/opt/node\24/bin/node`; |
| 39 | + const { runner } = createHookFiles(nodeExecutable); |
| 40 | + |
| 41 | + expect(runner).toContain(`node_fallback='${nodeExecutable}'`); |
| 42 | +}); |
| 43 | + |
31 | 44 | test.runIf(process.platform !== 'win32')('runs generated hooks', () => { |
32 | 45 | withDirectory((directory) => { |
33 | | - const hooksDirectory = path.join(directory, 'hooks with spaces'); |
| 46 | + const hooksDirectory = path.join(directory, "hooks with ' quotes"); |
34 | 47 | const generatedDirectory = path.join(hooksDirectory, '_'); |
35 | 48 | const generatedHook = path.join(generatedDirectory, 'pre-commit'); |
36 | 49 | const userHook = path.join(hooksDirectory, 'pre-commit'); |
37 | | - const files = createHookFiles(); |
| 50 | + const fallbackNode = path.join(hooksDirectory, 'node'); |
| 51 | + const configDirectory = path.join(directory, 'runtime config'); |
| 52 | + const runtimeDirectory = path.join(configDirectory, 'rstack'); |
| 53 | + const init = path.join(runtimeDirectory, 'hooks-init.sh'); |
| 54 | + const files = createHookFiles(fallbackNode); |
38 | 55 | const env: NodeJS.ProcessEnv = { |
39 | 56 | ...process.env, |
40 | | - XDG_CONFIG_HOME: path.join(directory, 'config'), |
| 57 | + XDG_CONFIG_HOME: configDirectory, |
41 | 58 | }; |
42 | 59 |
|
43 | 60 | mkdirSync(generatedDirectory, { recursive: true }); |
@@ -71,5 +88,20 @@ printf 'unreachable\\n' |
71 | 88 |
|
72 | 89 | expect(errexitResult.status).toBe(1); |
73 | 90 | expect(errexitResult.stdout).toBe('Rstack - pre-commit hook failed (code 1)\n'); |
| 91 | + |
| 92 | + mkdirSync(runtimeDirectory, { recursive: true }); |
| 93 | + writeFileSync(init, `export PATH="${runtimeDirectory}"\n`); |
| 94 | + writeFileSync(userHook, 'command -v node\n'); |
| 95 | + symlinkSync('/bin/sh', path.join(runtimeDirectory, 'sh')); |
| 96 | + symlinkSync('/bin/sh', fallbackNode); |
| 97 | + |
| 98 | + const fallbackResult = spawnSync('sh', [generatedHook], { encoding: 'utf8', env }); |
| 99 | + expect(fallbackResult.stdout).toBe(`${fallbackNode}\n`); |
| 100 | + |
| 101 | + const activeNode = path.join(runtimeDirectory, 'node'); |
| 102 | + symlinkSync('/bin/sh', activeNode); |
| 103 | + |
| 104 | + const activeResult = spawnSync('sh', [generatedHook], { encoding: 'utf8', env }); |
| 105 | + expect(activeResult.stdout).toBe(`${activeNode}\n`); |
74 | 106 | }); |
75 | 107 | }); |
0 commit comments