diff --git a/.github/actions/prepare-simulator/action.yml b/.github/actions/prepare-simulator/action.yml new file mode 100644 index 0000000..2309341 --- /dev/null +++ b/.github/actions/prepare-simulator/action.yml @@ -0,0 +1,48 @@ +name: "Prepare simulator" +description: "Creates and boots a custom simulator" +inputs: + runtime: + description: "Runtime name" + required: true + device: + description: "Device name" + required: true +outputs: + destination-id: + description: "Destination simulator ID" + value: ${{ steps.simulator.outputs.destination-id }} +runs: + using: composite + steps: + - name: "Install runtime" + shell: bash + run: | + RUNTIME="${{ inputs.runtime }}" + if xcrun simctl list | grep "$RUNTIME" + then + echo "$RUNTIME is already installed."; + else + echo "::group::Available runtimes:" + xcodes runtimes + echo "::endgroup::" + sudo xcodes runtimes install "$RUNTIME" --keep-archive; + fi + + - name: "Create and boot simulator" + id: simulator + shell: bash + run: | + RUNTIME="${{ inputs.runtime }}" + DEVICE="${{ inputs.device }}" + + DEVICE_ID=$(xcrun simctl list devicetypes -j | jq -r ".devicetypes.[] | select(.name==\"$DEVICE\").identifier") + echo $DEVICE_ID + if [ $(echo $DEVICE_ID | wc -l) != 1 ] || [ "$DEVICE_ID" = "" ]; then echo "Invalid Device ID"; exit 1; fi + + RUNTIME_ID=$(xcrun simctl list runtimes -j | jq -r ".runtimes.[] | select(.name==\"$RUNTIME\").identifier") + echo $RUNTIME_ID + if [ $(echo $RUNTIME_ID | wc -l) != 1 ] || [ "$RUNTIME_ID" = "" ]; then echo "Invalid Runtime ID"; exit 1; fi + + DESTINATION_ID=$(xcrun simctl create "Custom: $DEVICE, $RUNTIME" $DEVICE_ID $RUNTIME_ID) + xcrun simctl boot $DESTINATION_ID + echo "destination-id=$(echo $DESTINATION_ID)" >> $GITHUB_OUTPUT diff --git a/.github/workflows/xcode.yml b/.github/workflows/xcode.yml new file mode 100644 index 0000000..ad0554e --- /dev/null +++ b/.github/workflows/xcode.yml @@ -0,0 +1,83 @@ +name: Xcode + +on: + pull_request: + push: + branches: [develop, release] + +jobs: + simulator: + name: "${{ matrix.scheme }}, Xcode ${{ matrix.env.xcode }}, ${{ matrix.env.runtime }}, ${{ matrix.env.device }}" + runs-on: macOS-26 + strategy: + fail-fast: false + matrix: + scheme: + - "Base16" + - "Base32" + env: + - xcode: 26.4 + runtime: "iOS 26.4" + device: "iPhone 17 Pro Max" + - xcode: 26.4 + runtime: "watchOS 26.4" + device: "Apple Watch Series 11 (46mm)" + - xcode: 26.4 + runtime: "tvOS 26.4" + device: "Apple TV 4K (3rd generation)" + - xcode: 26.4 + runtime: "visionOS 26.4" + device: "Apple Vision Pro" + steps: + - uses: actions/checkout@v6 + - name: "Select Xcode ${{ matrix.env.xcode }}" + uses: ./.github/actions/xcode-select + with: + version: ${{ matrix.env.xcode }} + - name: "Cache downloaded simulator runtimes" + uses: actions/cache@v5 + with: + path: ~/Downloads/*.dmg + key: Xcode ${{ matrix.env.xcode }}+${{ matrix.env.runtime }} + - name: "Prepare simulator" + id: prepare-simulator + uses: ./.github/actions/prepare-simulator + with: + runtime: ${{ matrix.env.runtime }} + device: ${{ matrix.env.device }} + - name: "Build and test" + run: xcodebuild test -scheme "${{ matrix.scheme }}" -destination "id=${{ steps.prepare-simulator.outputs.destination-id }}" + - uses: sersoft-gmbh/swift-coverage-action@v5 + with: + target-name-filter: ^Identifier$ + - uses: codecov/codecov-action@v6 + with: + token: ${{ secrets.CODECOV_TOKEN }} + fail_ci_if_error: true + + macos: + name: "${{ matrix.scheme }}, Xcode ${{ matrix.xcode }}, macOS 26" + runs-on: macOS-26 + strategy: + fail-fast: false + matrix: + scheme: + - "Base16" + - "Base32" + xcode: + - "26.4" + steps: + - uses: actions/checkout@v6 + - name: "Select Xcode ${{ matrix.xcode }}" + uses: ./.github/actions/xcode-select + with: + version: ${{ matrix.xcode }} + - name: "Build and test" + run: xcodebuild test -scheme "${{ matrix.scheme }}" -destination "name=My Mac" + - uses: sersoft-gmbh/swift-coverage-action@v5 + with: + target-name-filter: ^Identifier$ + - uses: codecov/codecov-action@v6 + with: + token: ${{ secrets.CODECOV_TOKEN }} + fail_ci_if_error: true