From e9a03c92a436f467ee158f25a32eccd781f93a23 Mon Sep 17 00:00:00 2001 From: Harshdeep Singh <6162866+harsh62@users.noreply.github.com> Date: Mon, 11 Aug 2025 05:07:17 -0400 Subject: [PATCH 1/4] chore: update Github action workflows chore: updating Github action workflows remove runtime check another update more updates update versions that are available for integration tests update versions add lowest as 18.4 test disabling parallel builds Revert "test disabling parallel builds" This reverts commit ce7eb6f99777f34e42d8018ed68f313dc5d8283d. try to use the webauthn approach remove --set testing another update Update index.mjs another update try another fix another update another try final update try install simulators if needed flow run download only for xcode 16 --- .../get_platform_parameters/action.yml | 70 +++++++++++++++---- .../install_simulators_if_needed/action.yml | 60 ++++++++++++++++ .../api-breaking-changes-detection.yml | 2 +- .github/workflows/api_digester_check.yml | 2 +- ...uild_minimum_supported_swift_platforms.yml | 2 +- .github/workflows/build_scheme.yml | 6 ++ .github/workflows/build_xcode_beta.yml | 44 ++++++++++++ .github/workflows/canary.yml | 23 +++--- .github/workflows/release_kickoff.yml | 2 +- .../LocalServer/index.mjs | 8 +-- .../PushNotificationGen2HostApp.xctestplan | 1 - .../PushNotificationHostApp.xcscheme | 2 +- .../PushNotificationWatchTests.xcscheme | 2 +- .../PushNotificationHostAppUITests.swift | 55 ++++++++++----- .../PushNotificationWatchTests.xctestplan | 1 - 15 files changed, 231 insertions(+), 49 deletions(-) create mode 100644 .github/composite_actions/install_simulators_if_needed/action.yml create mode 100644 .github/workflows/build_xcode_beta.yml diff --git a/.github/composite_actions/get_platform_parameters/action.yml b/.github/composite_actions/get_platform_parameters/action.yml index 55d1300511..bd222f8aef 100644 --- a/.github/composite_actions/get_platform_parameters/action.yml +++ b/.github/composite_actions/get_platform_parameters/action.yml @@ -5,7 +5,7 @@ inputs: required: true type: string xcode_version: - description: "The version of Xcode. Available aliases are 'latest' and 'minimum'" + description: "The version of Xcode. Available aliases are 'latest', 'minimum', and 'beta'" default: 'latest' type: string destination: @@ -41,8 +41,9 @@ runs: - id: get-xcode-version run: | - LATEST_XCODE_VERSION=16.2.0 - MINIMUM_XCODE_VERSION=16.1.0 + LATEST_XCODE_VERSION=16.4.0 + MINIMUM_XCODE_VERSION=16.0.0 + DEFAULT_BETA_XCODE_VERSION=26.0_beta INPUT_XCODE_VERSION=${{ inputs.xcode_version }} @@ -51,6 +52,17 @@ runs: XCODE_VERSION=$LATEST_XCODE_VERSION ;; minimum) XCODE_VERSION=$MINIMUM_XCODE_VERSION ;; + beta) + # Try to auto-detect installed Xcode 26 beta app name + DETECTED=$(ls -1 /Applications 2>/dev/null | grep -E '^Xcode_26.*\.app$' | head -n1 || true) + if [ -n "$DETECTED" ]; then + # strip prefix and suffix to get the version token used in the path template + # e.g., Xcode_26.0_beta.app -> 26.0_beta + XCODE_VERSION=$(echo "$DETECTED" | sed -E 's/^Xcode_//; s/\.app$//') + else + XCODE_VERSION=$DEFAULT_BETA_XCODE_VERSION + fi + ;; *) XCODE_VERSION=$INPUT_XCODE_VERSION ;; esac @@ -66,36 +78,68 @@ runs: case $INPUT_PLATFORM/$INPUT_XCODE_VERSION in iOS/latest) + DEVICE="iPhone 16 Pro Max" + OS_VERSION="18.5" + ;; + iOS/beta) DEVICE="iPhone 16" - OS_VERSION="18.2" + OS_VERSION="26.0" + ;; + iOS/minimum) + DEVICE="iPhone 16 Pro Max" + OS_VERSION="18.0" ;; iOS/*) - DEVICE="iPhone 15" - OS_VERSION="17.0.1" + DEVICE="iPhone 16 Pro Max" + OS_VERSION="18.5" ;; tvOS/latest) DEVICE="Apple TV 4K (3rd generation)" - OS_VERSION="18.2" + OS_VERSION="18.5" + ;; + tvOS/beta) + DEVICE="Apple TV 4K (3rd generation)" + OS_VERSION="26.0" + ;; + tvOS/minimum) + DEVICE="Apple TV 4K (3rd generation)" + OS_VERSION="18.0" ;; tvOS/*) DEVICE="Apple TV 4K (3rd generation)" - OS_VERSION="17.0" + OS_VERSION="18.5" ;; watchOS/latest) DEVICE="Apple Watch Series 10 (46mm)" - OS_VERSION="11.2" + OS_VERSION="11.5" + ;; + watchOS/beta) + DEVICE="Apple Watch Series 10 (46mm)" + OS_VERSION="26.0" + ;; + watchOS/minimum) + DEVICE="Apple Watch SE (44mm) (2nd generation)" + OS_VERSION="11.0" ;; watchOS/*) - DEVICE="Apple Watch Series 7 (45mm)" - OS_VERSION="10.0" + DEVICE="iPhone 16 Pro Max" + OS_VERSION="18.5" ;; visionOS/latest) DEVICE="Apple Vision Pro" - OS_VERSION="2.2" + OS_VERSION="2.5" + ;; + visionOS/beta) + DEVICE="Apple Vision Pro" + OS_VERSION="26.0" + ;; + visionOS/minimum) + DEVICE="Apple Vision Pro" + OS_VERSION="2.0" ;; visionOS/*) DEVICE="Apple Vision Pro" - OS_VERSION="1.0" + OS_VERSION="2.5" ;; esac diff --git a/.github/composite_actions/install_simulators_if_needed/action.yml b/.github/composite_actions/install_simulators_if_needed/action.yml new file mode 100644 index 0000000000..c8af3347b4 --- /dev/null +++ b/.github/composite_actions/install_simulators_if_needed/action.yml @@ -0,0 +1,60 @@ +name: 'Install Simulators if Needed' +description: 'Downloads and installs simulator runtimes for Xcode 16.0' + +inputs: + xcode_version: + description: 'The Xcode version being used' + required: true + type: string + platform: + description: 'The platform to install simulators for' + required: true + type: string + +runs: + using: "composite" + steps: + - name: Install Simulators for Xcode 16.0 + shell: bash + run: | + XCODE_VERSION="${{ inputs.xcode_version }}" + PLATFORM="${{ inputs.platform }}" + + # Only run for Xcode 16.0.0 + if [[ "$XCODE_VERSION" != "16.0.0" ]]; then + echo "Not Xcode 16.0.0 (current: $XCODE_VERSION), skipping simulator installation" + exit 0 + fi + + # Skip for macOS as it doesn't need simulators + if [[ "$PLATFORM" == "macOS" ]]; then + echo "macOS doesn't need simulator downloads" + exit 0 + fi + + echo "Installing simulators for $PLATFORM with Xcode 16.0.0..." + + # Show what's available before download + echo "Simulators before download:" + xcrun simctl list runtimes || true + + # Download the platform - this will get the appropriate version for Xcode 16.0 + echo "Downloading $PLATFORM platform for Xcode 16.0..." + case $PLATFORM in + iOS) + sudo xcodebuild -downloadPlatform iOS || echo "Failed to download iOS platform" + ;; + tvOS) + sudo xcodebuild -downloadPlatform tvOS || echo "Failed to download tvOS platform" + ;; + watchOS) + sudo xcodebuild -downloadPlatform watchOS || echo "Failed to download watchOS platform" + ;; + visionOS) + sudo xcodebuild -downloadPlatform visionOS || echo "Failed to download visionOS platform" + ;; + esac + + # Show what's available after download + echo "Simulators after download:" + xcrun simctl list runtimes || true \ No newline at end of file diff --git a/.github/workflows/api-breaking-changes-detection.yml b/.github/workflows/api-breaking-changes-detection.yml index e245f17866..e55023d9cf 100644 --- a/.github/workflows/api-breaking-changes-detection.yml +++ b/.github/workflows/api-breaking-changes-detection.yml @@ -10,7 +10,7 @@ permissions: jobs: build-and-check-api-breakage: name: Build and Check API Breakage - runs-on: macos-latest + runs-on: macos-15 steps: - name: Checkout repository diff --git a/.github/workflows/api_digester_check.yml b/.github/workflows/api_digester_check.yml index 4eaece17cf..0b82af5372 100644 --- a/.github/workflows/api_digester_check.yml +++ b/.github/workflows/api_digester_check.yml @@ -7,7 +7,7 @@ on: jobs: check-swift-api-digester: - runs-on: macos-latest + runs-on: macos-15 steps: - name: Checkout repository diff --git a/.github/workflows/build_minimum_supported_swift_platforms.yml b/.github/workflows/build_minimum_supported_swift_platforms.yml index 7f6052abfc..cde24c61cb 100644 --- a/.github/workflows/build_minimum_supported_swift_platforms.yml +++ b/.github/workflows/build_minimum_supported_swift_platforms.yml @@ -27,7 +27,7 @@ jobs: uses: ./.github/workflows/build_scheme.yml with: scheme: Amplify-Build - os-runner: 'macos-latest' + os-runner: 'macos-15' xcode-version: 'minimum' platform: ${{ matrix.platform }} save_build_cache: false diff --git a/.github/workflows/build_scheme.yml b/.github/workflows/build_scheme.yml index 4c66363d65..787a993a17 100644 --- a/.github/workflows/build_scheme.yml +++ b/.github/workflows/build_scheme.yml @@ -43,6 +43,12 @@ jobs: platform: ${{ inputs.platform }} xcode_version: ${{ inputs.xcode-version }} + - name: Install simulators if needed + uses: ./.github/composite_actions/install_simulators_if_needed + with: + xcode_version: ${{ steps.platform.outputs.xcode-version }} + platform: ${{ inputs.platform }} + - name: Attempt to use the dependencies cache id: dependencies-cache timeout-minutes: 4 diff --git a/.github/workflows/build_xcode_beta.yml b/.github/workflows/build_xcode_beta.yml new file mode 100644 index 0000000000..19ce18820e --- /dev/null +++ b/.github/workflows/build_xcode_beta.yml @@ -0,0 +1,44 @@ +name: Build with Xcode Beta | Amplify Swift + +on: + workflow_dispatch: + pull_request: + branches: + - main + push: + branches: + - main + +permissions: + contents: read + actions: write + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: ${{ github.ref_name != 'main' }} + +jobs: + build-amplify-with-xcode-beta: + name: Build Amplify Swift for ${{ matrix.platform }} + strategy: + fail-fast: false + matrix: + platform: [macOS] + + uses: ./.github/workflows/build_scheme.yml + with: + scheme: Amplify-Build + os-runner: 'macos-15' + xcode-version: 'beta' + platform: ${{ matrix.platform }} + save_build_cache: false + + confirm-pass: + runs-on: ubuntu-latest + name: Confirm Passing Build Steps + if: ${{ !cancelled() }} + needs: [build-amplify-with-xcode-beta] + env: + EXIT_CODE: ${{ contains(needs.*.result, 'failure') && 1 || 0 }} + steps: + - run: exit $EXIT_CODE diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index 1de1725fd1..8bbbca62f2 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -1,6 +1,7 @@ name: Canary Test on: + workflow_dispatch: schedule: - cron: '0 16 * * *' # Everyday 16:00 UTC @@ -15,14 +16,14 @@ jobs: strategy: matrix: include: - - os: macos-latest - xcode-version: 15.3.0 - device: iPhone 15 - version: 17.4 - - os: macos-latest - xcode-version: 15.0.1 - device: iPhone 14 - version: 17.0.1 + - os: macos-15 + xcode-version: '16.4.0' + device: 'iPhone 16 Pro Max' + version: '18.5' + - os: macos-15 + xcode-version: '16.0.0' + device: 'iPhone 16 Pro Max' + version: '18.0' name: Canary Test - Xcode ${{ matrix.xcode-version }} runs-on: ${{ matrix.os }} steps: @@ -50,6 +51,12 @@ jobs: sudo xcode-select -s "/Applications/Xcode_${{ matrix.xcode-version }}.app" xcodebuild -version + - name: Install simulators if needed + uses: ./.github/composite_actions/install_simulators_if_needed + with: + xcode_version: ${{ matrix.xcode-version }} + platform: iOS + - name: Run Tests - ${{ matrix.device }} with iOS ${{ matrix.version }} working-directory: ${{ github.workspace }}/canaries/example run: bundle exec fastlane scan --device "${{ matrix.device }}" --deployment_target_version "${{ matrix.version }}" diff --git a/.github/workflows/release_kickoff.yml b/.github/workflows/release_kickoff.yml index 76fc248335..4617e5f4fc 100644 --- a/.github/workflows/release_kickoff.yml +++ b/.github/workflows/release_kickoff.yml @@ -10,7 +10,7 @@ permissions: jobs: release: name: Release - runs-on: macos-latest + runs-on: ubuntu-latest steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1 diff --git a/AmplifyPlugins/Notifications/Push/Tests/PushNotificationHostApp/LocalServer/index.mjs b/AmplifyPlugins/Notifications/Push/Tests/PushNotificationHostApp/LocalServer/index.mjs index 7283e7c862..cf8f0eb090 100644 --- a/AmplifyPlugins/Notifications/Push/Tests/PushNotificationHostApp/LocalServer/index.mjs +++ b/AmplifyPlugins/Notifications/Push/Tests/PushNotificationHostApp/LocalServer/index.mjs @@ -46,7 +46,7 @@ app.post("/notifications", async (req, res) => { data: data ?? {} } try { - const cmd = `echo '${JSON.stringify(apns)}' | xcrun simctl --set testing push ${deviceId} ${bundleId} -` + const cmd = `echo '${JSON.stringify(apns)}' | xcrun simctl push ${deviceId} ${bundleId} -` await run(cmd) res.send("Done") } catch (error) { @@ -60,7 +60,7 @@ app.post('/uninstall', async (req, res) => { console.log("POST /uninstall ") const { deviceId } = req.body try { - const cmd = `xcrun simctl --set testing uninstall ${deviceId} ${bundleId}` + const cmd = `xcrun simctl uninstall ${deviceId} ${bundleId}` await run(cmd) res.send("Done") } catch (error) { @@ -73,7 +73,7 @@ app.post('/boot', async (req, res) => { console.log("POST /boot ") const { deviceId } = req.body try { - const cmd = `xcrun simctl --set testing bootstatus ${deviceId} -b` + const cmd = `xcrun simctl bootstatus ${deviceId} -b` await run(cmd) res.send("Done") } catch (error) { @@ -84,4 +84,4 @@ app.post('/boot', async (req, res) => { app.listen(9293, () => { console.log("Starting server") -}) +}) \ No newline at end of file diff --git a/AmplifyPlugins/Notifications/Push/Tests/PushNotificationHostApp/PushNotificationGen2HostApp.xctestplan b/AmplifyPlugins/Notifications/Push/Tests/PushNotificationHostApp/PushNotificationGen2HostApp.xctestplan index 8a1c6e72f2..4f89e013f5 100644 --- a/AmplifyPlugins/Notifications/Push/Tests/PushNotificationHostApp/PushNotificationGen2HostApp.xctestplan +++ b/AmplifyPlugins/Notifications/Push/Tests/PushNotificationHostApp/PushNotificationGen2HostApp.xctestplan @@ -23,7 +23,6 @@ }, "testTargets" : [ { - "parallelizable" : true, "target" : { "containerPath" : "container:PushNotificationHostApp.xcodeproj", "identifier" : "6084F1AB2967B87200434CBF", diff --git a/AmplifyPlugins/Notifications/Push/Tests/PushNotificationHostApp/PushNotificationHostApp.xcodeproj/xcshareddata/xcschemes/PushNotificationHostApp.xcscheme b/AmplifyPlugins/Notifications/Push/Tests/PushNotificationHostApp/PushNotificationHostApp.xcodeproj/xcshareddata/xcschemes/PushNotificationHostApp.xcscheme index 4aa810bccc..d1631e02d1 100644 --- a/AmplifyPlugins/Notifications/Push/Tests/PushNotificationHostApp/PushNotificationHostApp.xcodeproj/xcshareddata/xcschemes/PushNotificationHostApp.xcscheme +++ b/AmplifyPlugins/Notifications/Push/Tests/PushNotificationHostApp/PushNotificationHostApp.xcodeproj/xcshareddata/xcschemes/PushNotificationHostApp.xcscheme @@ -31,7 +31,7 @@ + parallelizable = "NO"> + parallelizable = "NO"> = 30 && + component.count <= 50 && + component.allSatisfy({ $0.isLetter || $0.isNumber || $0 == "-" }) { + return component + } + } + + // Last resort: try to extract from the full path using regex + let uuidPattern = "[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}" + if let regex = try? NSRegularExpression(pattern: uuidPattern), + let match = regex.firstMatch(in: bundlePath, range: NSRange(bundlePath.startIndex..., in: bundlePath)), + let range = Range(match.range, in: bundlePath) { + return String(bundlePath[range]) + } + + // If all else fails, provide detailed error information + fatalError("Could not extract device identifier from bundle path: \(bundlePath)\nPath components: \(paths)") }() @MainActor @@ -131,7 +154,7 @@ final class PushNotificationHostAppUITests: XCTestCase { journey: nil, deeplink: nil )), - deviceId: deviceIdentifier! + deviceId: deviceIdentifier )) let notification = notificationElement() @@ -169,7 +192,7 @@ final class PushNotificationHostAppUITests: XCTestCase { body: #function ), data: nil, - deviceId: deviceIdentifier! + deviceId: deviceIdentifier )) let notification = notificationElement() @@ -212,7 +235,7 @@ final class PushNotificationHostAppUITests: XCTestCase { journey: nil, deeplink: nil )), - deviceId: deviceIdentifier! + deviceId: deviceIdentifier )) let expectedEvent = anyElementContains(text: "Amplify.BasicAnalyticsEvent(name: \"_campaign.received_", scope: app) @@ -234,7 +257,7 @@ final class PushNotificationHostAppUITests: XCTestCase { body: #function ), data: nil, - deviceId: deviceIdentifier! + deviceId: deviceIdentifier )) let unexpectedEvent = anyElementContains(text: "Amplify.BasicAnalyticsEvent(name: \"_campaign.received_", scope: app) @@ -301,13 +324,13 @@ final class PushNotificationHostAppUITests: XCTestCase { } private func uninstallApp() async throws { - let request = LocalServer.uninstall(deviceIdentifier!).urlRequest + let request = LocalServer.uninstall(deviceIdentifier).urlRequest let (_, response) = try await URLSession.shared.data(for: request) XCTAssertTrue((response as! HTTPURLResponse).statusCode < 300, "Failed to uninstall the App") } private func bootDevice() async throws { - let request = LocalServer.boot(deviceIdentifier!).urlRequest + let request = LocalServer.boot(deviceIdentifier).urlRequest let (_, response) = try await URLSession.shared.data(for: request) XCTAssertTrue((response as! HTTPURLResponse).statusCode < 300, "Failed to boot the device") } diff --git a/AmplifyPlugins/Notifications/Push/Tests/PushNotificationHostApp/PushNotificationWatchTests.xctestplan b/AmplifyPlugins/Notifications/Push/Tests/PushNotificationHostApp/PushNotificationWatchTests.xctestplan index 8c24292cf1..5d791ae127 100644 --- a/AmplifyPlugins/Notifications/Push/Tests/PushNotificationHostApp/PushNotificationWatchTests.xctestplan +++ b/AmplifyPlugins/Notifications/Push/Tests/PushNotificationHostApp/PushNotificationWatchTests.xctestplan @@ -13,7 +13,6 @@ }, "testTargets" : [ { - "parallelizable" : true, "target" : { "containerPath" : "container:PushNotificationHostApp.xcodeproj", "identifier" : "6875F9882A3CD258001C9AAF", From 8aa3ca7df4d419af9c72a88605fce158a3de1925 Mon Sep 17 00:00:00 2001 From: Harshdeep Singh <6162866+harsh62@users.noreply.github.com> Date: Wed, 3 Sep 2025 12:25:59 -0400 Subject: [PATCH 2/4] list available content list --- .../install_simulators_if_needed/action.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/composite_actions/install_simulators_if_needed/action.yml b/.github/composite_actions/install_simulators_if_needed/action.yml index c8af3347b4..0ff2e90f50 100644 --- a/.github/composite_actions/install_simulators_if_needed/action.yml +++ b/.github/composite_actions/install_simulators_if_needed/action.yml @@ -38,8 +38,12 @@ runs: echo "Simulators before download:" xcrun simctl list runtimes || true - # Download the platform - this will get the appropriate version for Xcode 16.0 - echo "Downloading $PLATFORM platform for Xcode 16.0..." + # List available downloadable content first + echo "Checking available downloadable content..." + xcodebuild -downloadableContentList || true + + # Download the platform runtime for Xcode 16.0.0 + echo "Downloading $PLATFORM runtime for Xcode 16.0..." case $PLATFORM in iOS) sudo xcodebuild -downloadPlatform iOS || echo "Failed to download iOS platform" From a04a890d1f00f43eade15d085d161fa6972995b8 Mon Sep 17 00:00:00 2001 From: Harshdeep Singh <6162866+harsh62@users.noreply.github.com> Date: Wed, 3 Sep 2025 12:35:41 -0400 Subject: [PATCH 3/4] try selecting xcode before --- .../install_simulators_if_needed/action.yml | 12 ++++++++---- .github/workflows/canary.yml | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/composite_actions/install_simulators_if_needed/action.yml b/.github/composite_actions/install_simulators_if_needed/action.yml index 0ff2e90f50..efcdc0b902 100644 --- a/.github/composite_actions/install_simulators_if_needed/action.yml +++ b/.github/composite_actions/install_simulators_if_needed/action.yml @@ -34,14 +34,18 @@ runs: echo "Installing simulators for $PLATFORM with Xcode 16.0.0..." + # Ensure we're using Xcode 16.0.0 for simulator downloads + echo "Switching to Xcode 16.0.0..." + sudo xcode-select -switch /Applications/Xcode_16.0.0.app/Contents/Developer + + # Verify the switch worked + echo "Current Xcode version:" + xcodebuild -version + # Show what's available before download echo "Simulators before download:" xcrun simctl list runtimes || true - # List available downloadable content first - echo "Checking available downloadable content..." - xcodebuild -downloadableContentList || true - # Download the platform runtime for Xcode 16.0.0 echo "Downloading $PLATFORM runtime for Xcode 16.0..." case $PLATFORM in diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index a4415baf26..656f45119d 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -23,7 +23,7 @@ jobs: - os: macos-15 xcode-version: '16.0.0' device: 'iPhone 16 Pro Max' - version: '18.0' + version: '18.4' name: Canary Test - Xcode ${{ matrix.xcode-version }} runs-on: ${{ matrix.os }} steps: From bc854d61a81579d710b65029eedde3c94f57c4d3 Mon Sep 17 00:00:00 2001 From: Harshdeep Singh <6162866+harsh62@users.noreply.github.com> Date: Wed, 3 Sep 2025 12:48:52 -0400 Subject: [PATCH 4/4] Update canary.yml --- .github/workflows/canary.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index 656f45119d..a4415baf26 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -23,7 +23,7 @@ jobs: - os: macos-15 xcode-version: '16.0.0' device: 'iPhone 16 Pro Max' - version: '18.4' + version: '18.0' name: Canary Test - Xcode ${{ matrix.xcode-version }} runs-on: ${{ matrix.os }} steps: