Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## [Unreleased]

### Added

- Added `extraArgs` as a first-class session-default value. Repo config or runtime defaults can now carry common `xcodebuild` flags (for example `-skipPackagePluginValidation` or `-disableAutomaticPackageResolution`) so they don't need repeating on every build or test call. Per-call `extraArgs` replace matching configured flags or build settings and append after non-matching defaults, while an explicit empty array (`extraArgs: []`) clears the defaults for a single call. The session management tools show, set, sync, and clear `extraArgs` alongside the other defaults.

## [2.6.2]

### Fixed
Expand Down Expand Up @@ -683,4 +689,3 @@ Please note that the UI automation features are an early preview and currently i
- Basic support for building iOS and macOS applications



1 change: 1 addition & 0 deletions config.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ sessionDefaults:
preferXcodebuild: false
platform: 'iOS'
bundleId: 'io.sentry.myapp'
extraArgs: ['-skipPackagePluginValidation']
13 changes: 13 additions & 0 deletions schemas/structured-output/_defs/common.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,19 @@
}
}
]
},
"extraArgs": {
"anyOf": [
{
"const": null
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
}
},
"required": [
Expand Down
45 changes: 45 additions & 0 deletions src/cli/__tests__/session-defaults.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,49 @@ describe('CLI session defaults', () => {
},
});
});

it('appends explicit extraArgs after configured extraArgs', () => {
const merged = mergeCliSessionDefaults({
defaults: {
extraArgs: ['-skipPackagePluginValidation'],
},
explicitArgs: {
extraArgs: ['-quiet'],
},
});

expect(merged).toEqual({
extraArgs: ['-skipPackagePluginValidation', '-quiet'],
});
});

it('lets explicit destination extraArgs replace matching configured extraArgs', () => {
const merged = mergeCliSessionDefaults({
defaults: {
extraArgs: ['-quiet', '-skipMacroValidation', '-destination', 'id=x'],
},
explicitArgs: {
extraArgs: ['-quiet', '-destination', 'id=y'],
},
});

expect(merged).toEqual({
extraArgs: ['-skipMacroValidation', '-quiet', '-destination', 'id=y'],
});
});

it('allows an explicit empty extraArgs array to clear configured extraArgs', () => {
const merged = mergeCliSessionDefaults({
defaults: {
extraArgs: ['-skipPackagePluginValidation'],
},
explicitArgs: {
extraArgs: [],
},
});

expect(merged).toEqual({
extraArgs: [],
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,18 @@ describe('session-clear-defaults tool', () => {
expect(current.scheme).toBe('MyScheme');
});

it('should clear extraArgs when keys includes extraArgs', async () => {
sessionStore.setDefaults({ extraArgs: ['-skipPackagePluginValidation'] });

const result = await runLogic(() => sessionClearDefaultsLogic({ keys: ['extraArgs'] }));

expect(result.isError).toBeFalsy();

const current = sessionStore.getAll();
expect(current.extraArgs).toBeUndefined();
expect(current.scheme).toBe('MyScheme');
});

it('should clear all profiles only when all=true', async () => {
sessionStore.setActiveProfile('ios');
sessionStore.setDefaults({ scheme: 'IOS' });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,47 @@ describe('session-set-defaults tool', () => {
expect(parsed.sessionDefaults?.env).toEqual(envVars);
});

it('should store extraArgs as a string array default', async () => {
const extraArgs = ['-skipPackagePluginValidation', '-skipMacroValidation'];
const result = await runLogic(() => sessionSetDefaultsLogic({ extraArgs }, createContext()));

expect(result.isError).toBeFalsy();
expect(sessionStore.getAll().extraArgs).toEqual(extraArgs);
});

it('should persist extraArgs to config when persist is true', async () => {
const yaml = ['schemaVersion: 1', 'sessionDefaults: {}', ''].join('\n');

const writes: { path: string; content: string }[] = [];
const fs = createMockFileSystemExecutor({
existsSync: (targetPath: string) => targetPath === configPath,
readFile: async (targetPath: string) => {
if (targetPath !== configPath) {
throw new Error(`Unexpected readFile path: ${targetPath}`);
}
return yaml;
},
writeFile: async (targetPath: string, content: string) => {
writes.push({ path: targetPath, content });
},
});

await initConfigStore({ cwd, fs });

const extraArgs = ['-skipPackagePluginValidation'];
const result = await runLogic(() =>
sessionSetDefaultsLogic({ extraArgs, persist: true }, createContext()),
);

expect(result.isError).toBeFalsy();
expect(writes.length).toBe(1);

const parsed = parseYaml(writes[0].content) as {
sessionDefaults?: Record<string, unknown>;
};
expect(parsed.sessionDefaults?.extraArgs).toEqual(extraArgs);
});

it('should not persist when persist is true but no defaults were provided', async () => {
const writes: { path: string; content: string }[] = [];
const fs = createMockFileSystemExecutor({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,13 @@ describe('session-show-defaults tool', () => {
expect(result.isError).toBeFalsy();
expect(allText(result)).toContain('scheme: IOSScheme');
});

it('shows extraArgs defaults', async () => {
sessionStore.setDefaults({ extraArgs: ['-skipPackagePluginValidation'] });

const result = await callHandler(handler, {});
expect(result.isError).toBeFalsy();
expect(allText(result)).toContain('extraArgs: -skipPackagePluginValidation');
});
});
});
1 change: 1 addition & 0 deletions src/mcp/tools/session-management/session_clear_defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ function createSessionDefaultsProfile(profile: Record<string, unknown>): Session
platform: (profile.platform as string | undefined) ?? null,
bundleId: (profile.bundleId as string | undefined) ?? null,
env: (profile.env as Record<string, string> | undefined) ?? null,
extraArgs: (profile.extraArgs as string[] | undefined) ?? null,
};
}

Expand Down
1 change: 1 addition & 0 deletions src/mcp/tools/session-management/session_set_defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ function createSessionDefaultsProfile(defaults: SessionDefaults): SessionDefault
platform: defaults.platform ?? null,
bundleId: defaults.bundleId ?? null,
env: defaults.env ?? null,
extraArgs: defaults.extraArgs ?? null,
};
}

Expand Down
1 change: 1 addition & 0 deletions src/mcp/tools/session-management/session_show_defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ function createSessionDefaultsProfile(profile: Record<string, unknown>): Session
platform: (profile.platform as string | undefined) ?? null,
bundleId: (profile.bundleId as string | undefined) ?? null,
env: (profile.env as Record<string, string> | undefined) ?? null,
extraArgs: (profile.extraArgs as string[] | undefined) ?? null,
};
}

Expand Down
1 change: 1 addition & 0 deletions src/mcp/tools/xcode-ide/sync_xcode_defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ function createSessionDefaultsProfile(profile: Record<string, unknown>): Session
platform: (profile.platform as string | undefined) ?? null,
bundleId: (profile.bundleId as string | undefined) ?? null,
env: (profile.env as Record<string, string> | undefined) ?? null,
extraArgs: (profile.extraArgs as string[] | undefined) ?? null,
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"preferXcodebuild": null,
"platform": null,
"bundleId": null,
"env": null
"env": null,
"extraArgs": null
}
},
"operation": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"preferXcodebuild": null,
"platform": null,
"bundleId": null,
"env": null
"env": null,
"extraArgs": null
}
},
"operation": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"preferXcodebuild": null,
"platform": null,
"bundleId": null,
"env": null
"env": null,
"extraArgs": null
}
},
"operation": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"preferXcodebuild": null,
"platform": null,
"bundleId": null,
"env": null
"env": null,
"extraArgs": null
}
},
"operation": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"preferXcodebuild": null,
"platform": null,
"bundleId": null,
"env": null
"env": null,
"extraArgs": null
},
"MyCustomProfile": {
"projectPath": null,
Expand All @@ -40,7 +41,8 @@
"preferXcodebuild": null,
"platform": null,
"bundleId": null,
"env": null
"env": null,
"extraArgs": null
}
},
"operation": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"preferXcodebuild": null,
"platform": null,
"bundleId": "io.sentry.calculatorapp",
"env": null
"env": null,
"extraArgs": null
},
"MyCustomProfile": {
"projectPath": null,
Expand All @@ -40,7 +41,8 @@
"preferXcodebuild": null,
"platform": null,
"bundleId": null,
"env": null
"env": null,
"extraArgs": null
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@
├ preferXcodebuild: (not set)
├ platform: (not set)
├ bundleId: (not set)
└ env: (not set)
├ env: (not set)
└ extraArgs: (not set)
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@
├ preferXcodebuild: (not set)
├ platform: (not set)
├ bundleId: (not set)
└ env: (not set)
├ env: (not set)
└ extraArgs: (not set)
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@
├ preferXcodebuild: (not set)
├ platform: (not set)
├ bundleId: (not set)
└ env: (not set)
├ env: (not set)
└ extraArgs: (not set)
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
├ preferXcodebuild: (not set)
├ platform: (not set)
├ bundleId: (not set)
└ env: (not set)
├ env: (not set)
└ extraArgs: (not set)

📁 MyCustomProfile
├ projectPath: (not set)
Expand All @@ -35,4 +36,5 @@
├ preferXcodebuild: (not set)
├ platform: (not set)
├ bundleId: (not set)
└ env: (not set)
├ env: (not set)
└ extraArgs: (not set)
1 change: 1 addition & 0 deletions src/types/domain-results.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ export interface SessionDefaultsProfile {
platform: string | null;
bundleId: string | null;
env: Record<string, string> | null;
extraArgs: string[] | null;
}
export interface BuildLikeSummary extends StatusSummary {
durationMs?: number;
Expand Down
5 changes: 5 additions & 0 deletions src/utils/__tests__/project-config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@ describe('project-config', () => {
' ios:',
' workspacePath: "~/Code/App.xcworkspace"',
' derivedDataPath: "~/.cache/dd"',
' extraArgs:',
' - "-skipPackagePluginValidation"',
'',
].join('\n');

Expand All @@ -231,6 +233,9 @@ describe('project-config', () => {
expect(result.config.sessionDefaultsProfiles?.ios?.derivedDataPath).toBe(
path.join(homedir(), '.cache/dd'),
);
expect(result.config.sessionDefaultsProfiles?.ios?.extraArgs).toEqual([
'-skipPackagePluginValidation',
]);
});

it('normalizes namespaced session defaults profiles and active profile', async () => {
Expand Down
Loading
Loading