Skip to content

chore: Add try? linter for tests and fix current cases #18989

chore: Add try? linter for tests and fix current cases

chore: Add try? linter for tests and fix current cases #18989

Workflow file for this run

name: Test
on:
push:
branches:
- main
- v8.x
- release/**
pull_request:
types: [opened, synchronize, reopened, labeled]
# Concurrency configuration:
# - We use workflow-specific concurrency groups to allow independent test runs across different workflows
# while preventing multiple runs of the same test suite on the same branch/commit.
# - For pull requests, we cancel in-progress runs when new commits are pushed to save CI resources
# and provide faster feedback on the latest changes.
# - For main branch pushes and scheduled runs, we never cancel in-progress runs to ensure the complete
# test suite always finishes, maintaining the integrity of our main branch quality gates.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
ready-to-merge-gate:
name: Ready-to-merge gate
uses: ./.github/workflows/ready-to-merge-workflow.yml
# This job detects if the PR contains changes that require running unit tests.
# If yes, the job will output a flag that will be used by the next job to run the unit tests.
# If no, the job will output a flag that will be used by the next job to skip running the unit tests.
# At the end of this workflow, we run a check that validates that either all unit tests passed or were
# called unit-tests-required-check.
files-changed:
name: Detect File Changes
runs-on: ubuntu-latest
needs: ready-to-merge-gate
# Map a step output to a job output
outputs:
run_unit_tests_for_prs: ${{ steps.changes.outputs.run_unit_tests_for_prs }}
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
- name: Get changed files
id: changes
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
with:
token: ${{ github.token }}
filters: .github/file-filters.yml
build-test-server:
name: Build test server
if: github.event_name != 'pull_request' || needs.files-changed.outputs.run_unit_tests_for_prs == 'true'
needs: files-changed
runs-on: macos-15
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
- name: Cache for Test Server
id: cache_test_server
uses: actions/cache@v5
with:
path: ./test-server/.build
key: test-server-${{ hashFiles('./test-server') }}-universal
restore-keys: |
test-server-${{ hashFiles('./test-server') }}-universal
test-server-
- name: Build Test Server for Intel CPU
if: steps.cache_test_server.outputs.cache-hit != 'true'
working-directory: test-server
run: >-
swift build -c release --triple x86_64-apple-macosx 2>&1 | tee test-server-build-intel.log
- name: Build Test Server for M1 CPU
if: steps.cache_test_server.outputs.cache-hit != 'true'
working-directory: test-server
run: >-
swift build -c release --arch arm64 2>&1 | tee test-server-build-arm64.log
- name: Combine Test Server
working-directory: test-server
run: >-
lipo -create -output test-server-exec $(swift build --show-bin-path -c release --triple arm64-apple-macosx)/Run $(swift build --show-bin-path -c release --triple x86_64-apple-macosx)/Run
- name: Archiving DerivedData
uses: actions/upload-artifact@v6
with:
name: test-server
path: |
./test-server/test-server-exec
- name: Archiving Raw Test Logs
uses: actions/upload-artifact@v6
if: ${{ failure() || cancelled() }}
with:
name: test-server-build-log
path: |
test-server-build-intel.log
test-server-build-arm64.log
- name: Run CI Diagnostics
if: failure()
run: ./scripts/ci-diagnostics.sh
distribution-tests:
name: Distribution Tests
runs-on: macos-15
# Don't run this on release branches, cause the SPM Package.swift points to the unreleased versions.
# Also, skip when PR changes don't require running tests to save CI time.
if: startsWith(github.ref, 'refs/heads/release/') == false && (github.event_name != 'pull_request' || needs.files-changed.outputs.run_unit_tests_for_prs == 'true')
needs: files-changed
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
- name: Prepare Package.swift
shell: bash
run: |
./scripts/prepare-package.sh \
--package-file Package.swift \
--is-pr "${{ github.event_name == 'pull_request' }}" \
--remove-duplicate true \
--change-path false \
--remove-binary-targets true
- name: Ensure required runtime is loaded
# Ideally we will not need this, but CI sometimes is failing to load some runtimes, this will ensure they are loaded
timeout-minutes: 5 # 5 minutes timeout
env:
OS_VERSION: "18.5"
PLATFORM: "iOS"
run: ./scripts/ci-ensure-runtime-loaded.sh --os-version "$OS_VERSION" --platform "$PLATFORM"
- run: rm -r Sentry.xcodeproj && rm -r Sentry.xcworkspace
- run: set -o pipefail && NSUnbufferedIO=YES SKIP_BINARIES=1 xcodebuild test -scheme Sentry-Package -sdk iphonesimulator -destination 'platform=iOS Simulator,OS=18.5,name=iPhone 16 Pro' | tee raw-test-output-distribution.log | xcbeautify --preserve-unbeautified
shell: sh
- name: Upload Distribution Test Logs
uses: actions/upload-artifact@v6
if: ${{ failure() || cancelled() }}
with:
name: raw-test-output-distribution
path: |
raw-test-output-distribution.log
# This matrix runs only the unit tests requiring the test server.
# We do this to speed up the other unit test jobs and to avoid running the
# test server with potential side effects in GH actions for all unit tests.
# We don't run this matrix for all different OS versions, because the chances
# of a bug solely on a specific OS version is minimal.
unit-tests-with-test-server:
name: Unit with Test Server ${{matrix.name}}
runs-on: ${{matrix.runs-on}}
timeout-minutes: 20
needs: build-test-server
strategy:
fail-fast: false
matrix:
include:
# Running the tests with simulators is incredibly flaky. Our assumption is that simulators might have difficulties
# with communicating with the test server in CI.
# We are going to add these back in https://github.com/getsentry/sentry-cocoa/issues/6361
- name: macOS 15
runs-on:
["ghcr.io/cirruslabs/macos-runner:sequoia", "runner_group_id:10"]
platform: "macOS"
xcode: "16.4"
test-destination-os: "15.0"
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
- uses: actions/download-artifact@v7
with:
name: test-server
- name: Start Test Server
run: ./scripts/start-test-server.sh
- run: ./scripts/ci-select-xcode.sh ${{matrix.xcode}}
# Note: We don't install Slather or gather code coverage for this job because it only runs
# the SentryTestServerTests target, which contains minimal tests that don't significantly
# contribute to overall code coverage metrics. The main unit-tests job handles comprehensive
# code coverage reporting.
# We split building and running tests in two steps so we know how long running the tests takes.
- name: Build tests
id: build_tests
run: |
./scripts/sentry-xcodebuild.sh \
--platform ${{matrix.platform}} \
--os ${{matrix.test-destination-os}} \
--ref ${{ github.ref_name }} \
--command build-for-testing \
--configuration TestCI \
--scheme Sentry \
--test-plan Sentry_TestServer
- name: Run tests
run: |
./scripts/sentry-xcodebuild.sh \
--platform ${{matrix.platform}} \
--os ${{matrix.test-destination-os}} \
--ref ${{ github.ref_name }} \
--command test-without-building \
--configuration TestCI \
--scheme Sentry \
--test-plan Sentry_TestServer
- name: Archiving DerivedData Logs
uses: actions/upload-artifact@v6
if: steps.build_tests.outcome == 'failure'
with:
name: derived-data-test-server-${{matrix.platform}}-xcode-${{matrix.xcode}}
path: |
/Users/runner/Library/Developer/Xcode/DerivedData/**/Logs/**
- name: Archiving Raw Logs
uses: actions/upload-artifact@v6
if: ${{ failure() || cancelled() }}
with:
name: raw-output-test-server-${{matrix.platform}}-xcode-${{matrix.xcode}}
path: |
raw-build-output.log
raw-build-for-testing-output.log
raw-test-output.log
- name: Archiving Crash Logs
uses: actions/upload-artifact@v6
if: ${{ failure() || cancelled() }}
with:
name: crash-logs-test-server-${{matrix.platform}}-xcode-${{matrix.xcode}}
path: |
~/Library/Logs/DiagnosticReports/**
- name: Run CI Diagnostics
if: ${{ failure() || cancelled() }}
run: ./scripts/ci-diagnostics.sh
- name: Store screenshot
uses: ./.github/actions/capture-screenshot
if: ${{ failure() || cancelled() }}
with:
suffix: ${{ matrix.platform }}-xcode-${{ matrix.xcode }}
unit-tests:
name: Unit ${{matrix.name}}
needs: files-changed
uses: ./.github/workflows/unit-test-common.yml
secrets: inherit
with:
name: ${{matrix.name}}
runs-on: ${{ matrix.runs-on }}
should_skip: ${{github.event_name == 'pull_request' && needs.files-changed.outputs.run_unit_tests_for_prs != 'true'}}
xcode: ${{matrix.xcode}}
platform: ${{matrix.platform}}
test-destination-os: ${{matrix.test-destination-os || 'latest'}}
timeout: ${{matrix.timeout || 20}}
device: ${{matrix.device || ''}}
scheme: ${{matrix.scheme || 'Sentry'}}
run_on_cirrus_labs: true # We always run tests on Cirrus Labs
strategy:
fail-fast: false
matrix:
# Can't run tests on watchOS because XCTest is not available
include:
# We are running tests on iOS 17 and later, as there were OS-internal changes introduced in succeeding versions.
# iOS 17
- name: iOS 17 Sentry
runs-on: sequoia
xcode: "16.4"
test-destination-os: "17.5"
platform: "iOS"
device: "iPhone 15 Pro"
scheme: "Sentry"
# iOS 18
- name: iOS 18 Sentry
runs-on: sequoia
xcode: "16.4"
test-destination-os: "18.5"
platform: "iOS"
device: "iPhone 16 Pro"
scheme: "Sentry"
# iOS 26
- name: iOS 26 Sentry
runs-on: tahoe
xcode: "26.1.1"
test-destination-os: "26.1"
platform: "iOS"
device: "iPhone 17 Pro"
scheme: "Sentry"
# We don't run the unit tests on macOS 13 cause we run them on all on GH actions available iOS versions.
# The chance of missing a bug solely on tvOS 16 that doesn't occur on iOS, macOS 12 or macOS 14 is minimal.
# We are running tests on macOS 14 and later, as there were OS-internal changes introduced in succeeding versions.
# macOS 14
- name: macOS 14 Sentry
runs-on: sonoma
xcode: "16.1"
test-destination-os: "latest"
platform: "macOS"
scheme: "Sentry"
# macOS 15
- name: macOS 15 Sentry
runs-on: sequoia
xcode: "16.4"
test-destination-os: "latest"
platform: "macOS"
scheme: "Sentry"
# macOS 26
- name: macOS 26 Sentry
runs-on: tahoe
xcode: "26.1.1"
test-destination-os: "26.1"
platform: "macOS"
scheme: "Sentry"
# Catalyst. We test the latest version, as the risk something breaking on Catalyst and not
# on an older iOS or macOS version is low.
# In addition we are running tests on macOS 14, as there were OS-internal changes introduced in succeeding versions.
- name: Catalyst 14 Sentry
runs-on: sonoma
xcode: "16.1"
test-destination-os: "latest"
platform: "Catalyst"
scheme: "Sentry"
- name: Catalyst 15 Sentry
runs-on: sequoia
xcode: "16.4"
test-destination-os: "latest"
platform: "Catalyst"
scheme: "Sentry"
## We don't run unit tests on macCatalyst 26 yet because of https://github.com/getsentry/sentry-cocoa/issues/6165.
# We don't run the unit tests on tvOS 16 cause we run them on all on GH actions available iOS versions.
# The chance of missing a bug solely on tvOS 16 that doesn't occur on iOS, tvOS 15 or tvOS 16 is minimal.
# We are running tests on tvOS 17 and latest, as there were OS-internal changes introduced in succeeding versions.
# tvOS 17
- name: tvOS 17 Sentry
runs-on: sequoia
xcode: "16.4"
test-destination-os: "17.5"
platform: "tvOS"
scheme: "Sentry"
# iOS 17 - SwiftUI
- name: iOS 17 SentrySwiftUI
runs-on: sequoia
xcode: "16.4"
test-destination-os: "17.5"
platform: "iOS"
device: "iPhone 15 Pro"
scheme: "SentrySwiftUI"
# tvOS 18
- name: tvOS 18 Sentry
runs-on: sequoia
xcode: "16.4"
test-destination-os: "18.5"
platform: "tvOS"
scheme: "Sentry"
# tvOS 26
- name: tvOS 26 Sentry
runs-on: tahoe
xcode: "26.1.1"
test-destination-os: "26.1"
platform: "tvOS"
device: "Apple TV"
scheme: "Sentry"
# visionOS 26
- name: visionOS 26 Sentry
runs-on: tahoe
xcode: "26.1.1"
test-destination-os: "26.1"
platform: "visionOS"
scheme: "Sentry"
device: "Apple Vision Pro"
timeout: 30
# This will be replaced once #6945 is merged.
swiftlog-integration-unit-tests:
name: SentrySwiftLog Unit Tests
if: startsWith(github.ref, 'refs/heads/release/') == false && (github.event_name != 'pull_request' || needs.files-changed.outputs.run_unit_tests_for_prs == 'true')
needs: files-changed
runs-on: ["ghcr.io/cirruslabs/macos-runner:sequoia", "runner_group_id:10"]
steps:
- uses: actions/checkout@v6
- name: Select Xcode
run: ./scripts/ci-select-xcode.sh 16.4
- name: Setup local sentry-cocoa dependency
working-directory: 3rd-party-integrations/SentrySwiftLog
run: swift package edit sentry-cocoa --path ../..
- name: Run SwiftLog tests
working-directory: 3rd-party-integrations/SentrySwiftLog
run: swift test
- name: Archiving Raw Logs
uses: actions/upload-artifact@v6
if: ${{ failure() || cancelled() }}
with:
name: raw-output-swiftlog-integration
path: |
3rd-party-integrations/SentrySwiftLog/.build/**/*.log
- name: Run CI Diagnostics
if: failure()
run: ./scripts/ci-diagnostics.sh
# This will be replaced once #6945 is merged.
swiftybeaver-integration-unit-tests:
name: SentrySwiftyBeaver Unit Tests
if: startsWith(github.ref, 'refs/heads/release/') == false && (github.event_name != 'pull_request' || needs.files-changed.outputs.run_unit_tests_for_prs == 'true')
needs: files-changed
runs-on: ["ghcr.io/cirruslabs/macos-runner:sequoia", "runner_group_id:10"]
steps:
- uses: actions/checkout@v6
- name: Select Xcode
run: ./scripts/ci-select-xcode.sh 16.4
- name: Setup local sentry-cocoa dependency
working-directory: 3rd-party-integrations/SentrySwiftyBeaver
run: swift package edit sentry-cocoa --path ../..
- name: Run SwiftyBeaver tests
working-directory: 3rd-party-integrations/SentrySwiftyBeaver
run: swift test
- name: Archiving Raw Logs
uses: actions/upload-artifact@v6
if: ${{ failure() || cancelled() }}
with:
name: raw-output-swiftybeaver-integration
path: |
3rd-party-integrations/SentrySwiftyBeaver/.build/**/*.log
- name: Run CI Diagnostics
if: failure()
run: ./scripts/ci-diagnostics.sh
# This will be replaced once #6945 is merged.
cocoalumberjack-integration-unit-tests:
name: SentryCocoaLumberjack Unit Tests
if: startsWith(github.ref, 'refs/heads/release/') == false && (github.event_name != 'pull_request' || needs.files-changed.outputs.run_unit_tests_for_prs == 'true')
needs: files-changed
runs-on: ["ghcr.io/cirruslabs/macos-runner:sequoia", "runner_group_id:10"]
steps:
- uses: actions/checkout@v6
- name: Select Xcode
run: ./scripts/ci-select-xcode.sh 16.4
- name: Setup local sentry-cocoa dependency
working-directory: 3rd-party-integrations/SentryCocoaLumberjack
run: swift package edit sentry-cocoa --path ../..
- name: Run CocoaLumberjack tests
working-directory: 3rd-party-integrations/SentryCocoaLumberjack
run: swift test
- name: Archiving Raw Logs
uses: actions/upload-artifact@v6
if: ${{ failure() || cancelled() }}
with:
name: raw-output-cocoalumberjack-integration
path: |
3rd-party-integrations/SentryCocoaLumberjack/.build/**/*.log
- name: Run CI Diagnostics
if: failure()
run: ./scripts/ci-diagnostics.sh
# This will be replaced once #6945 is merged.
pulse-integration-unit-tests:
name: SentryPulse Unit Tests
if: startsWith(github.ref, 'refs/heads/release/') == false && (github.event_name != 'pull_request' || needs.files-changed.outputs.run_unit_tests_for_prs == 'true')
needs: files-changed
runs-on: ["ghcr.io/cirruslabs/macos-runner:sequoia", "runner_group_id:10"]
steps:
- uses: actions/checkout@v6
- name: Select Xcode
run: ./scripts/ci-select-xcode.sh 16.4
- name: Setup local sentry-cocoa dependency
working-directory: 3rd-party-integrations/SentryPulse
run: swift package edit sentry-cocoa --path ../..
- name: Run Pulse tests
working-directory: 3rd-party-integrations/SentryPulse
run: swift test
- name: Archiving Raw Logs
uses: actions/upload-artifact@v6
if: ${{ failure() || cancelled() }}
with:
name: raw-output-pulse-integration
path: |
3rd-party-integrations/SentryPulse/.build/**/*.log
- name: Run CI Diagnostics
if: failure()
run: ./scripts/ci-diagnostics.sh
# This check validates that either all unit tests passed or were skipped, which allows us
# to make unit tests a required check with only running the unit tests when required.
# So, we don't have to run unit tests, for example, for Changelog or ReadMe changes.
unit-tests-required-check:
needs:
[
files-changed,
build-test-server,
distribution-tests,
unit-tests,
swiftlog-integration-unit-tests,
swiftybeaver-integration-unit-tests,
cocoalumberjack-integration-unit-tests,
pulse-integration-unit-tests,
ready-to-merge-gate,
unit-tests-with-test-server,
]
name: Unit Tests
# This is necessary since a failed/skipped dependent job would cause this job to be skipped
if: always()
runs-on: ubuntu-latest
steps:
# If any jobs we depend on fails gets cancelled or times out, this job will fail.
# Skipped jobs are not considered failures.
- name: Check for failures
if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')
run: |
echo "One of the unit test jobs has failed." && exit 1