@invarn/cibuild 1.7.0 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +1 -1
- package/dist/src/commands/build.d.ts +43 -0
- package/dist/src/commands/build.d.ts.map +1 -1
- package/dist/src/commands/build.js +6 -6
- package/dist/src/commands/build.test.d.ts +13 -0
- package/dist/src/commands/build.test.d.ts.map +1 -0
- package/dist/src/commands/build.test.js +59 -0
- package/dist/src/commands/init.d.ts +7 -0
- package/dist/src/commands/init.d.ts.map +1 -1
- package/dist/src/commands/init.js +1 -0
- package/dist/src/runner.d.ts +1 -1
- package/dist/src/runner.d.ts.map +1 -1
- package/dist/src/runner.js +19 -3
- package/dist/src/step-marker.d.ts +12 -0
- package/dist/src/step-marker.d.ts.map +1 -0
- package/dist/src/step-marker.js +29 -0
- package/dist/src/step-marker.test.d.ts +11 -0
- package/dist/src/step-marker.test.d.ts.map +1 -0
- package/dist/src/step-marker.test.js +45 -0
- package/dist/src/yaml/steps/xcode-destination.d.ts +47 -0
- package/dist/src/yaml/steps/xcode-destination.d.ts.map +1 -0
- package/dist/src/yaml/steps/xcode-destination.js +202 -0
- package/dist/src/yaml/steps/xcode-destination.test.d.ts +9 -0
- package/dist/src/yaml/steps/xcode-destination.test.d.ts.map +1 -0
- package/dist/src/yaml/steps/xcode-destination.test.js +227 -0
- package/dist/src/yaml/steps/xcode.d.ts +1 -1
- package/dist/src/yaml/steps/xcode.d.ts.map +1 -1
- package/dist/src/yaml/steps/xcode.js +31 -9
- package/package.json +1 -1
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the shared "auto destination" resolver.
|
|
3
|
+
*
|
|
4
|
+
* The resolver consumes the JSON `xcrun simctl list devices available --json`
|
|
5
|
+
* would produce on a macOS runner, and returns the canonical
|
|
6
|
+
* `platform=iOS Simulator,OS=<v>,name=<name>` string to feed to xcodebuild.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=xcode-destination.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xcode-destination.test.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/xcode-destination.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the shared "auto destination" resolver.
|
|
3
|
+
*
|
|
4
|
+
* The resolver consumes the JSON `xcrun simctl list devices available --json`
|
|
5
|
+
* would produce on a macOS runner, and returns the canonical
|
|
6
|
+
* `platform=iOS Simulator,OS=<v>,name=<name>` string to feed to xcodebuild.
|
|
7
|
+
*/
|
|
8
|
+
import { describe, test, expect } from '@jest/globals';
|
|
9
|
+
import { AutoDestinationError, resolveAutoDestinationFromSimctlJson, resolveDestinationInput, } from './xcode-destination.js';
|
|
10
|
+
import { XcodeBuildStepExecutor, XcodeTestStepExecutor, XcodeBuildForTestStepExecutor, XcodeTestWithoutBuildingStepExecutor, XcodeBuildForSimulatorStepExecutor, } from './xcode.js';
|
|
11
|
+
import { testConfig } from './test-config.js';
|
|
12
|
+
describe('resolveAutoDestinationFromSimctlJson', () => {
|
|
13
|
+
test('picks the newest iPhone in the highest iOS runtime', () => {
|
|
14
|
+
const simctl = {
|
|
15
|
+
devices: {
|
|
16
|
+
'com.apple.CoreSimulator.SimRuntime.iOS-18-0': [
|
|
17
|
+
{
|
|
18
|
+
name: 'iPhone 16',
|
|
19
|
+
isAvailable: true,
|
|
20
|
+
state: 'Shutdown',
|
|
21
|
+
udid: 'AAA',
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
const resolved = resolveAutoDestinationFromSimctlJson(JSON.stringify(simctl));
|
|
27
|
+
expect(resolved).toBe('platform=iOS Simulator,OS=18.0,name=iPhone 16');
|
|
28
|
+
});
|
|
29
|
+
test('higher iOS runtime wins (iOS 18.0 beats iOS 17.5), even if older runtime has newer model', () => {
|
|
30
|
+
const simctl = {
|
|
31
|
+
devices: {
|
|
32
|
+
'com.apple.CoreSimulator.SimRuntime.iOS-17-5': [
|
|
33
|
+
// Pretend iPhone 16 also shows up here — runtime version should still win.
|
|
34
|
+
{ name: 'iPhone 16', isAvailable: true, udid: 'old' },
|
|
35
|
+
],
|
|
36
|
+
'com.apple.CoreSimulator.SimRuntime.iOS-18-0': [
|
|
37
|
+
{ name: 'iPhone 15', isAvailable: true, udid: 'new' },
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
const resolved = resolveAutoDestinationFromSimctlJson(JSON.stringify(simctl));
|
|
42
|
+
expect(resolved).toBe('platform=iOS Simulator,OS=18.0,name=iPhone 15');
|
|
43
|
+
});
|
|
44
|
+
test('Pro Max wins over Pro and plain at same model number', () => {
|
|
45
|
+
const simctl = {
|
|
46
|
+
devices: {
|
|
47
|
+
'com.apple.CoreSimulator.SimRuntime.iOS-18-0': [
|
|
48
|
+
{ name: 'iPhone 16', isAvailable: true, udid: '1' },
|
|
49
|
+
{ name: 'iPhone 16 Pro', isAvailable: true, udid: '2' },
|
|
50
|
+
{ name: 'iPhone 16 Pro Max', isAvailable: true, udid: '3' },
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
const resolved = resolveAutoDestinationFromSimctlJson(JSON.stringify(simctl));
|
|
55
|
+
expect(resolved).toBe('platform=iOS Simulator,OS=18.0,name=iPhone 16 Pro Max');
|
|
56
|
+
});
|
|
57
|
+
test('Pro wins over plain when Pro Max is missing', () => {
|
|
58
|
+
const simctl = {
|
|
59
|
+
devices: {
|
|
60
|
+
'com.apple.CoreSimulator.SimRuntime.iOS-18-0': [
|
|
61
|
+
{ name: 'iPhone 16', isAvailable: true, udid: '1' },
|
|
62
|
+
{ name: 'iPhone 16 Pro', isAvailable: true, udid: '2' },
|
|
63
|
+
],
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
const resolved = resolveAutoDestinationFromSimctlJson(JSON.stringify(simctl));
|
|
67
|
+
expect(resolved).toBe('platform=iOS Simulator,OS=18.0,name=iPhone 16 Pro');
|
|
68
|
+
});
|
|
69
|
+
test('higher iPhone model number wins (iPhone 16 beats iPhone 15)', () => {
|
|
70
|
+
const simctl = {
|
|
71
|
+
devices: {
|
|
72
|
+
'com.apple.CoreSimulator.SimRuntime.iOS-18-0': [
|
|
73
|
+
{ name: 'iPhone 15', isAvailable: true, udid: '1' },
|
|
74
|
+
{ name: 'iPhone 16', isAvailable: true, udid: '2' },
|
|
75
|
+
{ name: 'iPhone 14', isAvailable: true, udid: '3' },
|
|
76
|
+
{ name: 'iPhone SE (3rd generation)', isAvailable: true, udid: '4' },
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
const resolved = resolveAutoDestinationFromSimctlJson(JSON.stringify(simctl));
|
|
81
|
+
expect(resolved).toBe('platform=iOS Simulator,OS=18.0,name=iPhone 16');
|
|
82
|
+
});
|
|
83
|
+
test('throws documented error when no iPhone simulator runtime is installed', () => {
|
|
84
|
+
const simctl = { devices: {} };
|
|
85
|
+
expect(() => resolveAutoDestinationFromSimctlJson(JSON.stringify(simctl))).toThrow(AutoDestinationError);
|
|
86
|
+
expect(() => resolveAutoDestinationFromSimctlJson(JSON.stringify(simctl))).toThrow(/no iPhone simulator runtimes are installed/);
|
|
87
|
+
});
|
|
88
|
+
test('throws documented error when iOS runtime has no iPhone devices (e.g. only iPads)', () => {
|
|
89
|
+
const simctl = {
|
|
90
|
+
devices: {
|
|
91
|
+
'com.apple.CoreSimulator.SimRuntime.iOS-18-0': [
|
|
92
|
+
{ name: 'iPad Pro (11-inch)', isAvailable: true, udid: '1' },
|
|
93
|
+
],
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
expect(() => resolveAutoDestinationFromSimctlJson(JSON.stringify(simctl))).toThrow(/no iPhone simulator runtimes are installed/);
|
|
97
|
+
});
|
|
98
|
+
test('throws documented error on unparseable JSON', () => {
|
|
99
|
+
expect(() => resolveAutoDestinationFromSimctlJson('not-json')).toThrow(/xcrun simctl returned no usable output/);
|
|
100
|
+
});
|
|
101
|
+
test('resolveDestinationInput passes literal destinations through verbatim', () => {
|
|
102
|
+
const literal = 'platform=iOS Simulator,name=iPhone 14,OS=17.5';
|
|
103
|
+
expect(resolveDestinationInput(literal)).toBe(literal);
|
|
104
|
+
});
|
|
105
|
+
test('resolveDestinationInput delegates to injected resolver only when value === "auto"', () => {
|
|
106
|
+
const fakeResolver = () => 'platform=iOS Simulator,OS=99.9,name=iPhone Fixture';
|
|
107
|
+
expect(resolveDestinationInput('auto', fakeResolver)).toBe('platform=iOS Simulator,OS=99.9,name=iPhone Fixture');
|
|
108
|
+
// Pass-through still wins when value is anything else, even if a resolver is provided.
|
|
109
|
+
expect(resolveDestinationInput('generic/platform=iOS', fakeResolver)).toBe('generic/platform=iOS');
|
|
110
|
+
});
|
|
111
|
+
test('ignores unavailable iPhones', () => {
|
|
112
|
+
const simctl = {
|
|
113
|
+
devices: {
|
|
114
|
+
'com.apple.CoreSimulator.SimRuntime.iOS-18-0': [
|
|
115
|
+
{ name: 'iPhone 16', isAvailable: false, udid: '1' },
|
|
116
|
+
{ name: 'iPhone 15', isAvailable: true, udid: '2' },
|
|
117
|
+
],
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
const resolved = resolveAutoDestinationFromSimctlJson(JSON.stringify(simctl));
|
|
121
|
+
expect(resolved).toBe('platform=iOS Simulator,OS=18.0,name=iPhone 15');
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
/**
|
|
125
|
+
* Each affected executor must (a) embed a literal destination unchanged and
|
|
126
|
+
* (b) add an `xcrun` validation requirement only when destination === "auto".
|
|
127
|
+
*
|
|
128
|
+
* The "auto" execute() path is not exercised here — it shells out to xcrun.
|
|
129
|
+
* The pure parser tests above cover its correctness; the manual smoke test in
|
|
130
|
+
* the spike's "done criteria" covers the end-to-end shell-out.
|
|
131
|
+
*/
|
|
132
|
+
describe('xcode-* executors — destination input wiring', () => {
|
|
133
|
+
const xcrunReq = (reqs) => reqs.find((r) => r.category === 'command' && r.name === 'xcrun');
|
|
134
|
+
describe('XcodeBuildStepExecutor', () => {
|
|
135
|
+
test('literal destination is embedded in the script unchanged', async () => {
|
|
136
|
+
const executor = new XcodeBuildStepExecutor();
|
|
137
|
+
const result = await executor.execute({
|
|
138
|
+
project_path: 'MyApp.xcodeproj',
|
|
139
|
+
scheme: 'MyApp',
|
|
140
|
+
destination: 'platform=iOS Simulator,name=iPhone 99,OS=99.0',
|
|
141
|
+
}, {}, testConfig);
|
|
142
|
+
expect(result.script).toContain('platform=iOS Simulator,name=iPhone 99,OS=99.0');
|
|
143
|
+
});
|
|
144
|
+
test('validation requires xcrun only when destination === "auto"', () => {
|
|
145
|
+
const executor = new XcodeBuildStepExecutor();
|
|
146
|
+
const autoReqs = executor.getValidationRequirements({ project_path: 'MyApp.xcodeproj', scheme: 'MyApp', destination: 'auto' }, {}, testConfig);
|
|
147
|
+
expect(xcrunReq(autoReqs)).toBeDefined();
|
|
148
|
+
const literalReqs = executor.getValidationRequirements({
|
|
149
|
+
project_path: 'MyApp.xcodeproj',
|
|
150
|
+
scheme: 'MyApp',
|
|
151
|
+
destination: 'platform=iOS Simulator,name=iPhone 16,OS=18.0',
|
|
152
|
+
}, {}, testConfig);
|
|
153
|
+
expect(xcrunReq(literalReqs)).toBeUndefined();
|
|
154
|
+
const defaultReqs = executor.getValidationRequirements({ project_path: 'MyApp.xcodeproj', scheme: 'MyApp' }, {}, testConfig);
|
|
155
|
+
expect(xcrunReq(defaultReqs)).toBeUndefined();
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
describe('XcodeTestStepExecutor', () => {
|
|
159
|
+
test('literal destination is embedded in the script unchanged', async () => {
|
|
160
|
+
const executor = new XcodeTestStepExecutor();
|
|
161
|
+
const result = await executor.execute({
|
|
162
|
+
project_path: 'MyApp.xcodeproj',
|
|
163
|
+
scheme: 'MyApp',
|
|
164
|
+
destination: 'platform=iOS Simulator,name=iPhone 99,OS=99.0',
|
|
165
|
+
}, {}, testConfig);
|
|
166
|
+
expect(result.script).toContain('platform=iOS Simulator,name=iPhone 99,OS=99.0');
|
|
167
|
+
});
|
|
168
|
+
test('validation requires xcrun only when destination === "auto"', () => {
|
|
169
|
+
const executor = new XcodeTestStepExecutor();
|
|
170
|
+
const autoReqs = executor.getValidationRequirements({ project_path: 'MyApp.xcodeproj', scheme: 'MyApp', destination: 'auto' }, {}, testConfig);
|
|
171
|
+
expect(xcrunReq(autoReqs)).toBeDefined();
|
|
172
|
+
const literalReqs = executor.getValidationRequirements({ project_path: 'MyApp.xcodeproj', scheme: 'MyApp' }, {}, testConfig);
|
|
173
|
+
expect(xcrunReq(literalReqs)).toBeUndefined();
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
describe('XcodeBuildForTestStepExecutor', () => {
|
|
177
|
+
test('literal destination is embedded in the script unchanged', async () => {
|
|
178
|
+
const executor = new XcodeBuildForTestStepExecutor();
|
|
179
|
+
const result = await executor.execute({
|
|
180
|
+
project_path: 'MyApp.xcodeproj',
|
|
181
|
+
scheme: 'MyApp',
|
|
182
|
+
destination: 'generic/platform=iOS Simulator',
|
|
183
|
+
}, {}, testConfig);
|
|
184
|
+
expect(result.script).toContain('generic/platform=iOS Simulator');
|
|
185
|
+
});
|
|
186
|
+
test('validation requires xcrun only when destination === "auto"', () => {
|
|
187
|
+
const executor = new XcodeBuildForTestStepExecutor();
|
|
188
|
+
const autoReqs = executor.getValidationRequirements({ project_path: 'MyApp.xcodeproj', scheme: 'MyApp', destination: 'auto' }, {}, testConfig);
|
|
189
|
+
expect(xcrunReq(autoReqs)).toBeDefined();
|
|
190
|
+
const literalReqs = executor.getValidationRequirements({ project_path: 'MyApp.xcodeproj', scheme: 'MyApp' }, {}, testConfig);
|
|
191
|
+
expect(xcrunReq(literalReqs)).toBeUndefined();
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
describe('XcodeTestWithoutBuildingStepExecutor', () => {
|
|
195
|
+
test('literal destination is embedded in the script unchanged', async () => {
|
|
196
|
+
const executor = new XcodeTestWithoutBuildingStepExecutor();
|
|
197
|
+
const result = await executor.execute({ destination: 'platform=iOS Simulator,name=iPhone 99,OS=99.0' }, {}, testConfig);
|
|
198
|
+
expect(result.script).toContain('platform=iOS Simulator,name=iPhone 99,OS=99.0');
|
|
199
|
+
});
|
|
200
|
+
test('validation requires xcrun only when destination === "auto"', () => {
|
|
201
|
+
const executor = new XcodeTestWithoutBuildingStepExecutor();
|
|
202
|
+
const autoReqs = executor.getValidationRequirements({ destination: 'auto' }, {}, testConfig);
|
|
203
|
+
expect(xcrunReq(autoReqs)).toBeDefined();
|
|
204
|
+
const literalReqs = executor.getValidationRequirements({}, {}, testConfig);
|
|
205
|
+
expect(xcrunReq(literalReqs)).toBeUndefined();
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
describe('XcodeBuildForSimulatorStepExecutor', () => {
|
|
209
|
+
test('literal destination is embedded in the script unchanged', async () => {
|
|
210
|
+
const executor = new XcodeBuildForSimulatorStepExecutor();
|
|
211
|
+
const result = await executor.execute({
|
|
212
|
+
project_path: 'MyApp.xcodeproj',
|
|
213
|
+
scheme: 'MyApp',
|
|
214
|
+
destination: 'generic/platform=watchOS Simulator',
|
|
215
|
+
}, {}, testConfig);
|
|
216
|
+
expect(result.script).toContain('generic/platform=watchOS Simulator');
|
|
217
|
+
});
|
|
218
|
+
test('validation requires xcrun only when destination === "auto"', () => {
|
|
219
|
+
const executor = new XcodeBuildForSimulatorStepExecutor();
|
|
220
|
+
const autoReqs = executor.getValidationRequirements({ project_path: 'MyApp.xcodeproj', scheme: 'MyApp', destination: 'auto' }, {}, testConfig);
|
|
221
|
+
expect(xcrunReq(autoReqs)).toBeDefined();
|
|
222
|
+
const literalReqs = executor.getValidationRequirements({ project_path: 'MyApp.xcodeproj', scheme: 'MyApp' }, {}, testConfig);
|
|
223
|
+
expect(xcrunReq(literalReqs)).toBeUndefined();
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
//# sourceMappingURL=xcode-destination.test.js.map
|
|
@@ -180,7 +180,7 @@ export interface XcodeTestWithoutBuildingInputs {
|
|
|
180
180
|
* Runs pre-compiled tests from an .xctestrun file.
|
|
181
181
|
*/
|
|
182
182
|
export declare class XcodeTestWithoutBuildingStepExecutor extends BaseStepExecutor {
|
|
183
|
-
getValidationRequirements(
|
|
183
|
+
getValidationRequirements(inputs: XcodeTestWithoutBuildingInputs, _env: Record<string, string>, _config: CIConfig): ValidationRequirement[];
|
|
184
184
|
getOutputs(): StepOutput[];
|
|
185
185
|
execute(inputs: XcodeTestWithoutBuildingInputs, _env: Record<string, string>, _config: CIConfig): Promise<StepDef>;
|
|
186
186
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"xcode.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/xcode.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"xcode.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/xcode.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { existsSync } from 'node:fs';
|
|
5
5
|
import { BaseStepExecutor } from './base.js';
|
|
6
|
+
import { resolveDestinationInput } from './xcode-destination.js';
|
|
6
7
|
/**
|
|
7
8
|
* Xcodebuild step executor
|
|
8
9
|
* Builds iOS/macOS projects using xcodebuild
|
|
@@ -19,6 +20,9 @@ export class XcodeBuildStepExecutor extends BaseStepExecutor {
|
|
|
19
20
|
if (inputs.project_path && !existsSync(inputs.project_path)) {
|
|
20
21
|
requirements.push(this.runtimeRequirement(inputs.project_path, 'Xcode project/workspace file', 'file', 'git-clone'));
|
|
21
22
|
}
|
|
23
|
+
if (inputs.destination === 'auto') {
|
|
24
|
+
requirements.push(this.requireCommand('xcrun', 'xcrun is required to resolve destination: auto via xcrun simctl', 'Install Xcode and run: xcode-select --install'));
|
|
25
|
+
}
|
|
22
26
|
return requirements;
|
|
23
27
|
}
|
|
24
28
|
async execute(inputs, env, config) {
|
|
@@ -33,8 +37,9 @@ export class XcodeBuildStepExecutor extends BaseStepExecutor {
|
|
|
33
37
|
const scheme = this.getRequiredInput(inputs, 'scheme', stepName);
|
|
34
38
|
// Get configuration - defaults to Release
|
|
35
39
|
const configuration = this.getInput(inputs, 'configuration', 'Release');
|
|
36
|
-
// Get destination - defaults to generic/platform=iOS
|
|
37
|
-
|
|
40
|
+
// Get destination - defaults to generic/platform=iOS.
|
|
41
|
+
// `auto` triggers runtime resolution via `xcrun simctl`.
|
|
42
|
+
const destination = resolveDestinationInput(this.getInput(inputs, 'destination', 'generic/platform=iOS'));
|
|
38
43
|
// Get output directory - defaults to build
|
|
39
44
|
const outputDir = this.getInput(inputs, 'output_dir', 'build');
|
|
40
45
|
// Get clean build flag
|
|
@@ -119,6 +124,9 @@ export class XcodeTestStepExecutor extends BaseStepExecutor {
|
|
|
119
124
|
if (inputs.project_path && !existsSync(inputs.project_path)) {
|
|
120
125
|
requirements.push(this.runtimeRequirement(inputs.project_path, 'Xcode project/workspace file', 'file', 'git-clone'));
|
|
121
126
|
}
|
|
127
|
+
if (inputs.destination === 'auto') {
|
|
128
|
+
requirements.push(this.requireCommand('xcrun', 'xcrun is required to resolve destination: auto via xcrun simctl', 'Install Xcode and run: xcode-select --install'));
|
|
129
|
+
}
|
|
122
130
|
return requirements;
|
|
123
131
|
}
|
|
124
132
|
async execute(inputs, env, config) {
|
|
@@ -131,8 +139,9 @@ export class XcodeTestStepExecutor extends BaseStepExecutor {
|
|
|
131
139
|
}
|
|
132
140
|
// Get scheme - required
|
|
133
141
|
const scheme = this.getRequiredInput(inputs, 'scheme', stepName);
|
|
134
|
-
// Get destination - defaults to platform=iOS Simulator
|
|
135
|
-
|
|
142
|
+
// Get destination - defaults to platform=iOS Simulator.
|
|
143
|
+
// `auto` triggers runtime resolution via `xcrun simctl`.
|
|
144
|
+
const destination = resolveDestinationInput(this.getInput(inputs, 'destination', 'platform=iOS Simulator,name=iPhone 14,OS=latest'));
|
|
136
145
|
// Get test plan - optional
|
|
137
146
|
const testPlan = this.getInput(inputs, 'test_plan', '');
|
|
138
147
|
// Get code coverage flag
|
|
@@ -740,6 +749,9 @@ export class XcodeBuildForTestStepExecutor extends BaseStepExecutor {
|
|
|
740
749
|
if (inputs.project_path && !existsSync(inputs.project_path)) {
|
|
741
750
|
requirements.push(this.runtimeRequirement(inputs.project_path, 'Xcode project/workspace file', 'file', 'git-clone'));
|
|
742
751
|
}
|
|
752
|
+
if (inputs.destination === 'auto') {
|
|
753
|
+
requirements.push(this.requireCommand('xcrun', 'xcrun is required to resolve destination: auto via xcrun simctl', 'Install Xcode and run: xcode-select --install'));
|
|
754
|
+
}
|
|
743
755
|
return requirements;
|
|
744
756
|
}
|
|
745
757
|
getOutputs() {
|
|
@@ -753,7 +765,8 @@ export class XcodeBuildForTestStepExecutor extends BaseStepExecutor {
|
|
|
753
765
|
const projectPath = this.getRequiredInput(inputs, 'project_path', stepName);
|
|
754
766
|
const scheme = this.getRequiredInput(inputs, 'scheme', stepName);
|
|
755
767
|
const configuration = this.getInput(inputs, 'configuration', 'Debug');
|
|
756
|
-
|
|
768
|
+
// `auto` triggers runtime resolution via `xcrun simctl`.
|
|
769
|
+
const destination = resolveDestinationInput(this.getInput(inputs, 'destination', 'generic/platform=iOS Simulator'));
|
|
757
770
|
const testPlan = this.getInput(inputs, 'test_plan', '');
|
|
758
771
|
const xcconfigContent = this.getInput(inputs, 'xcconfig_content', '');
|
|
759
772
|
const xcodebuildOptions = this.getInput(inputs, 'xcodebuild_options', '');
|
|
@@ -828,10 +841,14 @@ export class XcodeBuildForTestStepExecutor extends BaseStepExecutor {
|
|
|
828
841
|
* Runs pre-compiled tests from an .xctestrun file.
|
|
829
842
|
*/
|
|
830
843
|
export class XcodeTestWithoutBuildingStepExecutor extends BaseStepExecutor {
|
|
831
|
-
getValidationRequirements(
|
|
832
|
-
|
|
844
|
+
getValidationRequirements(inputs, _env, _config) {
|
|
845
|
+
const requirements = [
|
|
833
846
|
this.requireCommand('xcodebuild', 'Xcode Command Line Tools are required', 'Install Xcode, then run: xcode-select --install'),
|
|
834
847
|
];
|
|
848
|
+
if (inputs.destination === 'auto') {
|
|
849
|
+
requirements.push(this.requireCommand('xcrun', 'xcrun is required to resolve destination: auto via xcrun simctl', 'Install Xcode and run: xcode-select --install'));
|
|
850
|
+
}
|
|
851
|
+
return requirements;
|
|
835
852
|
}
|
|
836
853
|
getOutputs() {
|
|
837
854
|
return [
|
|
@@ -841,7 +858,8 @@ export class XcodeTestWithoutBuildingStepExecutor extends BaseStepExecutor {
|
|
|
841
858
|
async execute(inputs, _env, _config) {
|
|
842
859
|
const stepName = 'xcode-test-without-building';
|
|
843
860
|
const xctestrun = this.getInput(inputs, 'xctestrun', '$CIBUILD_XCTESTRUN_FILE_PATH');
|
|
844
|
-
|
|
861
|
+
// `auto` triggers runtime resolution via `xcrun simctl`.
|
|
862
|
+
const destination = resolveDestinationInput(this.getInput(inputs, 'destination', 'platform=iOS Simulator,name=iPhone 15,OS=latest'));
|
|
845
863
|
const onlyTesting = this.getInput(inputs, 'only_testing', '');
|
|
846
864
|
const skipTesting = this.getInput(inputs, 'skip_testing', '');
|
|
847
865
|
const repetitionMode = this.getInput(inputs, 'test_repetition_mode', 'none');
|
|
@@ -920,6 +938,9 @@ export class XcodeBuildForSimulatorStepExecutor extends BaseStepExecutor {
|
|
|
920
938
|
if (inputs.project_path && !existsSync(inputs.project_path)) {
|
|
921
939
|
requirements.push(this.runtimeRequirement(inputs.project_path, 'Xcode project/workspace file', 'file', 'git-clone'));
|
|
922
940
|
}
|
|
941
|
+
if (inputs.destination === 'auto') {
|
|
942
|
+
requirements.push(this.requireCommand('xcrun', 'xcrun is required to resolve destination: auto via xcrun simctl', 'Install Xcode and run: xcode-select --install'));
|
|
943
|
+
}
|
|
923
944
|
return requirements;
|
|
924
945
|
}
|
|
925
946
|
getOutputs() {
|
|
@@ -932,7 +953,8 @@ export class XcodeBuildForSimulatorStepExecutor extends BaseStepExecutor {
|
|
|
932
953
|
const projectPath = this.getRequiredInput(inputs, 'project_path', stepName);
|
|
933
954
|
const scheme = this.getRequiredInput(inputs, 'scheme', stepName);
|
|
934
955
|
const configuration = this.getInput(inputs, 'configuration', '');
|
|
935
|
-
|
|
956
|
+
// `auto` triggers runtime resolution via `xcrun simctl`.
|
|
957
|
+
const destination = resolveDestinationInput(this.getInput(inputs, 'destination', 'generic/platform=iOS Simulator'));
|
|
936
958
|
const performClean = this.getInput(inputs, 'perform_clean_action', 'no');
|
|
937
959
|
const xcconfigContent = this.getInput(inputs, 'xcconfig_content', 'CODE_SIGNING_ALLOWED=NO');
|
|
938
960
|
const xcodebuildOptions = this.getInput(inputs, 'xcodebuild_options', '');
|