Skip to content

Commit 8b9f001

Browse files
committed
fix(xcodemake): Avoid global cwd mutation during build setup
Run xcodemake with per-process cwd instead of process.chdir to prevent cross-request working-directory races in concurrent execution. Add regression tests to verify executeXcodemakeCommand leaves process cwd unchanged and forwards cwd to the command executor. Refs #206
1 parent 5ec993b commit 8b9f001

2 files changed

Lines changed: 50 additions & 4 deletions

File tree

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { beforeEach, describe, expect, it, vi } from 'vitest';
2+
3+
const { executorMock } = vi.hoisted(() => ({
4+
executorMock: vi.fn(),
5+
}));
6+
7+
vi.mock('../command.ts', () => ({
8+
getDefaultCommandExecutor: () => executorMock,
9+
}));
10+
11+
import { executeXcodemakeCommand } from '../xcodemake.ts';
12+
13+
describe('executeXcodemakeCommand', () => {
14+
beforeEach(() => {
15+
executorMock.mockReset();
16+
});
17+
18+
it('runs xcodemake using child-process cwd without mutating process cwd', async () => {
19+
const projectDir = '/tmp/project';
20+
const originalCwd = process.cwd();
21+
executorMock.mockResolvedValue({ success: true, output: 'ok' });
22+
23+
await executeXcodemakeCommand(
24+
projectDir,
25+
['-scheme', 'App', '-project', '/tmp/project/App.xcodeproj'],
26+
'Build',
27+
);
28+
29+
expect(executorMock).toHaveBeenCalledWith(
30+
['xcodemake', '-scheme', 'App', '-project', 'App.xcodeproj'],
31+
'Build',
32+
false,
33+
{ cwd: projectDir },
34+
);
35+
expect(process.cwd()).toBe(originalCwd);
36+
});
37+
38+
it('does not mutate process cwd when command execution fails', async () => {
39+
const projectDir = '/tmp/project';
40+
const originalCwd = process.cwd();
41+
executorMock.mockRejectedValue(new Error('xcodemake failed'));
42+
43+
await expect(executeXcodemakeCommand(projectDir, ['-scheme', 'App'], 'Build')).rejects.toThrow(
44+
'xcodemake failed',
45+
);
46+
47+
expect(process.cwd()).toBe(originalCwd);
48+
});
49+
});

src/utils/xcodemake.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -206,9 +206,6 @@ export async function executeXcodemakeCommand(
206206
buildArgs: string[],
207207
logPrefix: string,
208208
): Promise<CommandResponse> {
209-
// Change directory to project directory, this is needed for xcodemake to work
210-
process.chdir(projectDir);
211-
212209
const xcodemakeCommand = [getXcodemakeCommand(), ...buildArgs];
213210

214211
// Remove projectDir from arguments if present at the start
@@ -220,7 +217,7 @@ export async function executeXcodemakeCommand(
220217
return arg;
221218
});
222219

223-
return getDefaultCommandExecutor()(command, logPrefix);
220+
return getDefaultCommandExecutor()(command, logPrefix, false, { cwd: projectDir });
224221
}
225222

226223
/**

0 commit comments

Comments
 (0)