Skip to content

Commit 22c08b0

Browse files
authored
Add support for platform version range (#111)
* Add support for OS version range * Fix format * Update dist * Address code review comments * Fix index.ts * Specify os and Xcode versions in CI job
1 parent 3deab1d commit 22c08b0

File tree

7 files changed

+68
-19
lines changed

7 files changed

+68
-19
lines changed

.github/workflows/checks.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ jobs:
239239
requires: ${{ matrix.x.swift }}
240240

241241
xcode:
242-
name: ${{ matrix.platform }} (${{ matrix.action }}, ${{ matrix.xcode }}${{ matrix.codecov && ', cc' || ''}})
242+
name: ${{ matrix.platform }} (${{ matrix.action }}, ${{ matrix.xcode }}${{ matrix.codecov && ', cc' || ''}}${{ matrix.job-name-sufix }})
243243
runs-on: ${{ matrix.os || 'macos-12' }}
244244
needs: [verify-dist]
245245
strategy:
@@ -259,6 +259,11 @@ jobs:
259259
warnings-as-errors:
260260
- false
261261
include:
262+
- job-name-sufix: ', platform-version ^16'
263+
platform: iOS
264+
platform-version: ^16
265+
os: macos-14
266+
xcode: ^14
262267
- platform: mac-catalyst
263268
xcode: ^13
264269
codecov: false
@@ -275,6 +280,7 @@ jobs:
275280
- uses: ./
276281
with:
277282
platform: ${{ matrix.platform }}
283+
platform-version: ${{ matrix.platform-version }}
278284
xcode: ${{ matrix.xcode }}
279285
working-directory: fixtures/${{ matrix.platform }}
280286
code-coverage: ${{ matrix.codecov }}

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,25 @@ jobs:
7171
7272
> † check out https://devhints.io/semver for valid ranges
7373
74+
```yaml
75+
jobs:
76+
build:
77+
strategy:
78+
matrix:
79+
platform:
80+
- iOS
81+
platform-version:
82+
- ^15
83+
- ^16
84+
- ^17
85+
runs-on: macos-latest
86+
steps:
87+
- uses: mxcl/xcodebuild@v3
88+
with:
89+
platform-version: ${{ matrix.platform-version }}
90+
platform: ${{ matrix.platform }}
91+
```
92+
7493
```yaml
7594
jobs:
7695
build:

action.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ inputs:
1818
`mac-catalyst`
1919
Leave unset and `xcodebuild` decides itself.
2020
required: false
21+
platform-version:
22+
description: |
23+
A semantic version range, eg. ^15, ~16.1 or 17.4.1
24+
Leave unset for the latest available on the runner.
25+
required: false
2126
arch:
2227
description: |
2328
Either `arm64` `x86_64 `i386`

dist/index.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/index.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ async function main() {
3434

3535
const swiftPM = fs.existsSync('Package.swift')
3636
const platform = getPlatformInput('platform')
37+
const platformVersion = getRangeInput('platform-version')
3738
const arch = getArchInput('arch')
3839
const selected = await xcselect(
3940
getRangeInput('xcode'),
@@ -42,7 +43,7 @@ async function main() {
4243
const action = getAction(selected, platform)
4344
const configuration = getConfiguration()
4445
const warningsAsErrors = core.getBooleanInput('warnings-as-errors')
45-
const destination = await getDestination(selected, platform)
46+
const destination = await getDestination(selected, platform, platformVersion)
4647
const identity = getIdentity(core.getInput('code-sign-identity'), platform)
4748
const xcpretty = verbosity() == 'xcpretty'
4849
const workspace = core.getInput('workspace')

src/lib.ts

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -142,13 +142,18 @@ interface Devices {
142142
[key: string]: [
143143
{
144144
udid: string
145+
name: string
145146
}
146147
]
147148
}
148149
}
149150

150151
type DeviceType = 'watchOS' | 'tvOS' | 'iOS' | 'xrOS'
151-
type Destination = { [key: string]: string }
152+
type Destination = {
153+
id: string
154+
name: string | undefined
155+
version: SemVer
156+
}
152157

153158
interface Schemes {
154159
workspace?: {
@@ -193,7 +198,10 @@ function parseJSON<T>(input: string): T {
193198
}
194199
}
195200

196-
async function destinations(): Promise<Destination> {
201+
async function destination(
202+
deviceType: DeviceType,
203+
version?: Range
204+
): Promise<Destination | undefined> {
197205
const out = await exec('xcrun', [
198206
'simctl',
199207
'list',
@@ -203,22 +211,23 @@ async function destinations(): Promise<Destination> {
203211
])
204212
const devices = parseJSON<Devices>(out).devices
205213

206-
const rv: { [key: string]: { v: SemVer; id: string } } = {}
214+
// best match
215+
let bm: Destination | undefined
207216
for (const opaqueIdentifier in devices) {
208217
const device = (devices[opaqueIdentifier] ?? [])[0]
209218
if (!device) continue
210219
const [type, v] = parse(opaqueIdentifier)
211-
if (v && (!rv[type] || semver.lt(rv[type].v, v))) {
212-
rv[type] = { v, id: device.udid }
220+
if (
221+
v &&
222+
type === deviceType &&
223+
(!version || version.test(v)) &&
224+
(!bm || semver.lt(bm.version, v))
225+
) {
226+
bm = { id: device.udid, name: device.name, version: v }
213227
}
214228
}
215229

216-
return {
217-
tvOS: rv.tvOS?.id,
218-
watchOS: rv.watchOS?.id,
219-
iOS: rv.iOS?.id,
220-
visionOS: rv.xrOS?.id,
221-
}
230+
return bm
222231

223232
function parse(key: string): [DeviceType, SemVer?] {
224233
const [type, ...vv] = (key.split('.').pop() ?? '').split('-')
@@ -324,15 +333,24 @@ export function actionIsTestable(action?: string): boolean {
324333

325334
export async function getDestination(
326335
xcodeVersion: SemVer,
327-
platform?: Platform
336+
platform?: Platform,
337+
platformVersion?: Range
328338
): Promise<string[]> {
329339
switch (platform) {
330340
case 'iOS':
331341
case 'tvOS':
332342
case 'watchOS':
333343
case 'visionOS': {
334-
const id = (await destinations())[platform]
335-
return ['-destination', `id=${id}`]
344+
const deviceType: DeviceType = platform === 'visionOS' ? 'xrOS' : platform
345+
const dest = await destination(deviceType, platformVersion)
346+
if (!dest) {
347+
core.error(
348+
`Device not found (platform: ${platform}, version: ${platformVersion})`
349+
)
350+
return []
351+
}
352+
core.info(`Selected device: ${dest.name} (${dest.version})`)
353+
return ['-destination', `id=${dest.id}`]
336354
}
337355
case 'macOS':
338356
return ['-destination', `platform=macOS`]

0 commit comments

Comments
 (0)