diff --git a/.github/actions/select-simulator/action.yml b/.github/actions/select-simulator/action.yml new file mode 100644 index 0000000..dcd3735 --- /dev/null +++ b/.github/actions/select-simulator/action.yml @@ -0,0 +1,30 @@ +name: Select iOS simulator +description: > + Finds the first available iPhone simulator, downloading the iOS platform + first if none is installed, and exposes its name as the `device` output. +outputs: + device: + description: The name of the selected iPhone simulator. + value: ${{ steps.select.outputs.device }} +runs: + using: composite + steps: + - id: select + shell: bash + run: | + set -euo pipefail + find_device() { + xcrun simctl list devices available --json \ + | jq -r '[.devices | to_entries[] | select(.key|test("iOS")) | .value[] | select(.isAvailable and (.name|startswith("iPhone")))][0].name // empty' + } + DEVICE=$(find_device) + if [ -z "$DEVICE" ]; then + sudo xcodebuild -downloadPlatform iOS + DEVICE=$(find_device) + fi + if [ -z "$DEVICE" ]; then + echo "::error::No available iPhone simulator found" >&2 + exit 1 + fi + echo "device=$DEVICE" >> "$GITHUB_OUTPUT" + echo "Using: $DEVICE" diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..8c676c4 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +# Keep the GitHub Actions used by the workflows up to date. The library has no +# package dependencies, so actions are the only ecosystem to watch. +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + groups: + actions: + patterns: + - "*" diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 7453743..0a6b256 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -15,6 +15,7 @@ jobs: deploy: name: Deploy to GitHub Pages runs-on: macos-26 + timeout-minutes: 30 permissions: contents: read pages: write diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1e2988c..a8de3ad 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,6 +6,9 @@ on: pull_request: workflow_dispatch: +permissions: + contents: read + concurrency: group: test-${{ github.ref }} cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} @@ -14,6 +17,7 @@ jobs: package: name: Package tests (iOS Simulator) runs-on: macos-26 + timeout-minutes: 45 steps: - uses: actions/checkout@v7 - name: Select Xcode @@ -26,13 +30,7 @@ jobs: swift --version - name: Select simulator id: sim - run: | - DEVICE=$(xcrun simctl list devices available --json \ - | jq -r '[.devices | to_entries[] | select(.key|test("iOS")) | .value[] | select(.isAvailable and (.name|startswith("iPhone")))][0].name // empty') - if [ -z "$DEVICE" ]; then sudo xcodebuild -downloadPlatform iOS; DEVICE=$(xcrun simctl list devices available --json | jq -r '[.devices|to_entries[]|select(.key|test("iOS"))|.value[]|select(.isAvailable and (.name|startswith("iPhone")))][0].name // empty'); fi - if [ -z "$DEVICE" ]; then echo "::error::No available iPhone simulator found" >&2; exit 1; fi - echo "device=$DEVICE" >> "$GITHUB_OUTPUT" - echo "Using: $DEVICE" + uses: ./.github/actions/select-simulator - name: Test run: | set -o pipefail @@ -41,11 +39,26 @@ jobs: xcodebuild test \ -scheme SwipeMenuViewController \ -destination "platform=iOS Simulator,name=${{ steps.sim.outputs.device }}" \ + -enableCodeCoverage YES \ + -resultBundlePath TestResults.xcresult \ CODE_SIGNING_ALLOWED=NO + - name: Report code coverage + run: | + set -euo pipefail + { + echo "### Code coverage" + echo "" + echo "| Target | Line coverage |" + echo "|---|---|" + # List the library targets only; the test bundle's own coverage is noise. + xcrun xccov view --report --json TestResults.xcresult \ + | jq -r '.targets[] | select(((.name | endswith(".xctest")) or (.name | endswith("Tests"))) | not) | "| \(.name) | \((.lineCoverage * 10000 | round) / 100)% |"' + } >> "$GITHUB_STEP_SUMMARY" example: name: Example app build runs-on: macos-26 + timeout-minutes: 45 steps: - uses: actions/checkout@v7 - name: Select Xcode @@ -68,13 +81,7 @@ jobs: run: xcodegen generate --spec Example/project.yml - name: Select simulator id: sim - run: | - DEVICE=$(xcrun simctl list devices available --json \ - | jq -r '[.devices | to_entries[] | select(.key|test("iOS")) | .value[] | select(.isAvailable and (.name|startswith("iPhone")))][0].name // empty') - if [ -z "$DEVICE" ]; then sudo xcodebuild -downloadPlatform iOS; DEVICE=$(xcrun simctl list devices available --json | jq -r '[.devices|to_entries[]|select(.key|test("iOS"))|.value[]|select(.isAvailable and (.name|startswith("iPhone")))][0].name // empty'); fi - if [ -z "$DEVICE" ]; then echo "::error::No available iPhone simulator found" >&2; exit 1; fi - echo "device=$DEVICE" >> "$GITHUB_OUTPUT" - echo "Using: $DEVICE" + uses: ./.github/actions/select-simulator - name: Build and test run: | set -o pipefail @@ -88,6 +95,7 @@ jobs: docc: name: Documentation build runs-on: macos-26 + timeout-minutes: 20 steps: - uses: actions/checkout@v7 - name: Select Xcode