Skip to content

Release 8487b35181fae97b1e3143367c7f8e32d3f61a61 #10181

Release 8487b35181fae97b1e3143367c7f8e32d3f61a61

Release 8487b35181fae97b1e3143367c7f8e32d3f61a61 #10181

Workflow file for this run

name: Release
run-name: Release ${{ github.event.inputs.version || github.sha }}
on:
push:
branches:
- main
- v8.x
pull_request:
types: [opened, synchronize, reopened, labeled]
workflow_dispatch:
inputs:
version:
description: Version to release
required: true
force:
description: Force a release even when there are release-blockers (optional)
required: false
merge_target:
description: Target branch to merge into. Uses the default branch as a fallback (optional)
required: false
# Concurrency configuration:
# - We use workflow-specific concurrency groups to prevent multiple release builds from running
# simultaneously, which could lead to race conditions in artifact generation and storage.
# - For pull requests, we cancel in-progress runs when testing release workflow changes since
# only the latest version needs validation before merging.
# - For main branch pushes (actual releases), we never cancel runs to ensure every release
# process completes fully, as partial releases could corrupt our distribution pipeline.
# - For workflow_dispatch events (manual releases), each run gets a unique group using run_id
# to prevent manual releases from canceling each other, allowing multiple concurrent releases.
concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'workflow_dispatch' && format('{0}-{1}', github.ref, github.run_id) || 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
files-changed:
name: Detect File Changes
runs-on: ubuntu-latest
needs: ready-to-merge-gate
outputs:
run_release_for_prs: ${{ steps.changes.outputs.run_release_for_prs }}
is_dependabot: ${{ github.actor == 'dependabot[bot]' }}
is_fork: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository }}
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- name: Get changed files
id: changes
uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
with:
token: ${{ github.token }}
filters: .github/file-filters.yml
setup-matrix:
runs-on: ubuntu-latest
if: github.event_name != 'pull_request' || needs.files-changed.outputs.run_release_for_prs == 'true'
needs: files-changed
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- name: Setup matrix combinations
id: setup-matrix-combinations
run: |
./scripts/generate_release_matrix.sh
env:
EVENT_NAME: ${{ github.event_name }}
outputs:
slices: ${{ steps.setup-matrix-combinations.outputs.slices }}
variants: ${{ steps.setup-matrix-combinations.outputs.variants }}
sdk-list-array: ${{ steps.setup-matrix-combinations.outputs.sdk-list-array }}
sdk-list-string: ${{ steps.setup-matrix-combinations.outputs.sdk-list-string }}
build-xcframework-variant-slices:
name: Build XCFramework Slices
# Run the job only for PRs with related changes or non-PR events.
if: github.event_name != 'pull_request' || needs.files-changed.outputs.run_release_for_prs == 'true'
needs: [files-changed, setup-matrix]
uses: ./.github/workflows/build-xcframework-variant-slices.yml
with:
name: ${{matrix.variant.name}}
suffix: ${{matrix.variant.suffix}}
macho-type: ${{matrix.variant.macho-type}}
configuration-suffix: ${{matrix.variant.configuration-suffix}}
variant-id: ${{matrix.variant.id}}
release-version: ${{ github.event.inputs.version }}
sdk-list: ${{ needs.setup-matrix.outputs.sdk-list-array }}
strategy:
matrix:
variant: ${{ fromJson(needs.setup-matrix.outputs.slices) }}
assemble-xcframework-variant:
needs: [files-changed, build-xcframework-variant-slices, setup-matrix]
# Run the job only for PRs with related changes or non-PR events.
if: github.event_name != 'pull_request' || needs.files-changed.outputs.run_release_for_prs == 'true'
name: Assemble XCFramework Variant
uses: ./.github/workflows/assemble-xcframework-variant.yml
secrets: inherit
with:
scheme: ${{matrix.variant.scheme}}
suffix: ${{matrix.variant.suffix}}
configuration-suffix: ${{matrix.variant.configuration-suffix}}
variant-id: ${{matrix.variant.id}}
# Only sign the XCFramework on releases
signed: ${{ github.event_name != 'pull_request' }}
release-version: ${{ github.event.inputs.version }}
excluded-archs: ${{matrix.variant.excluded-archs}}
override-name: ${{matrix.variant.override-name}}
sdks: ${{ needs.setup-matrix.outputs.sdk-list-string }}
strategy:
matrix:
variant: ${{ fromJson(needs.setup-matrix.outputs.variants) }}
build-sentryobjc-slices:
name: Build SentryObjC Slices
if: github.event_name != 'pull_request' || needs.files-changed.outputs.run_release_for_prs == 'true'
needs: [files-changed, setup-matrix]
uses: ./.github/workflows/build-sentryobjc-slices.yml
with:
release-version: ${{ github.event.inputs.version }}
sdk-list: ${{ needs.setup-matrix.outputs.sdk-list-array }}
assemble-sentryobjc-static-xcframework:
name: Assemble SentryObjC Static XCFramework
if: github.event_name != 'pull_request' || needs.files-changed.outputs.run_release_for_prs == 'true'
needs: [files-changed, build-sentryobjc-slices, setup-matrix]
uses: ./.github/workflows/assemble-sentryobjc-static-xcframework.yml
secrets: inherit
with:
signed: ${{ github.event_name != 'pull_request' }}
release-version: ${{ github.event.inputs.version }}
sdks: ${{ needs.setup-matrix.outputs.sdk-list-string }}
assemble-sentryobjc-dynamic-xcframework:
name: Assemble SentryObjC Dynamic XCFramework
if: github.event_name != 'pull_request' || needs.files-changed.outputs.run_release_for_prs == 'true'
needs: [files-changed, build-sentryobjc-slices, setup-matrix]
uses: ./.github/workflows/assemble-sentryobjc-dynamic-xcframework.yml
secrets: inherit
with:
signed: ${{ github.event_name != 'pull_request' }}
release-version: ${{ github.event.inputs.version }}
sdks: ${{ needs.setup-matrix.outputs.sdk-list-string }}
validate-xcframework:
name: Validate XCFramework
runs-on: macos-15
needs:
[
files-changed,
assemble-xcframework-variant,
assemble-sentryobjc-static-xcframework,
assemble-sentryobjc-dynamic-xcframework,
]
# Run the job only for PRs with related changes or non-PR events.
if: github.event_name != 'pull_request' || needs.files-changed.outputs.run_release_for_prs == 'true'
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
pattern: xcframework-${{github.sha}}-*
merge-multiple: true
path: XCFrameworkBuildPath/
- name: Setup Xcode
uses: ./.github/actions/setup-xcode
with:
version: "16"
- name: Unzip all XCFrameworks
run: |
find XCFrameworkBuildPath -name "*.xcframework.zip" -print0 | xargs -t0I @ unzip @ -d XCFrameworkBuildPath
- name: Validate all XCFrameworks
shell: bash
run: |
set -euo pipefail
found=0
while IFS= read -r -d '' xcframework; do
found=1
./scripts/validate-xcframework-format.sh "$xcframework"
./scripts/validate-xcframework-architectures.sh --xcframework "$xcframework"
./scripts/validate-xcframework-symbols.sh --xcframework "$xcframework"
done < <(find XCFrameworkBuildPath -name "*.xcframework" -type d -print0)
if [ "$found" -eq 0 ]; then
echo "No XCFrameworks found to validate." >&2
exit 1
fi
- name: Strip expectedSignature attributes from XCFramework project
if: ${{ github.event_name == 'pull_request' }}
run: make strip-xcframework-expected-signature
- run: make build-xcframework-sample
- name: Run CI Diagnostics
uses: ./.github/actions/ci-diagnostics
if: failure()
# Use github.event.pull_request.head.sha instead of github.sha when available as
# the github.sha is be the pre merge commit id for PRs.
# See https://github.community/t/github-sha-isnt-the-value-expected/17903/17906.
validate-spm:
name: Validate SPM Static
runs-on: macos-15
needs: [
files-changed,
assemble-xcframework-variant,
assemble-sentryobjc-static-xcframework,
assemble-sentryobjc-dynamic-xcframework,
]
# Run the job only for PRs with related changes or non-PR events.
if: github.event_name != 'pull_request' || needs.files-changed.outputs.run_release_for_prs == 'true'
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
pattern: xcframework-${{github.sha}}-*
merge-multiple: true
- name: Prepare Package.swift
shell: bash
run: |
./scripts/prepare-package.sh \
--package-file Package.swift \
--is-pr "${{ github.event_name == 'pull_request' }}" \
--change-path true
./scripts/prepare-package.sh \
--package-file Package@swift-6.1.swift \
--is-pr "${{ github.event_name == 'pull_request' }}" \
--change-path true
./scripts/prepare-package.sh \
--package-file Package@swift-6.2.swift \
--is-pr "${{ github.event_name == 'pull_request' }}" \
--change-path true
- name: Setup Xcode
uses: ./.github/actions/setup-xcode
with:
version: "16"
- run: swift build
working-directory: Samples/macOS-SPM-CommandLine
- name: Run CI Diagnostics
uses: ./.github/actions/ci-diagnostics
if: failure()
validate-spm-dynamic:
name: Validate SPM Dynamic
runs-on: macos-15
needs: [
files-changed,
assemble-xcframework-variant,
assemble-sentryobjc-static-xcframework,
assemble-sentryobjc-dynamic-xcframework,
]
# Run the job only for PRs with related changes or non-PR events.
if: github.event_name != 'pull_request' || needs.files-changed.outputs.run_release_for_prs == 'true'
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
pattern: xcframework-${{github.sha}}-*
merge-multiple: true
- name: Prepare Package.swift
shell: bash
run: |
./scripts/prepare-package.sh \
--package-file Package.swift \
--is-pr "${{ github.event_name == 'pull_request' }}" \
--change-path true
./scripts/prepare-package.sh \
--package-file Package@swift-6.1.swift \
--is-pr "${{ github.event_name == 'pull_request' }}" \
--change-path true
./scripts/prepare-package.sh \
--package-file Package@swift-6.2.swift \
--is-pr "${{ github.event_name == 'pull_request' }}" \
--change-path true
- name: Setup Xcode
uses: ./.github/actions/setup-xcode
with:
version: "16"
- run: swift build
working-directory: Samples/SPM-Dynamic
- name: Run CI Diagnostics
uses: ./.github/actions/ci-diagnostics
if: failure()
swift-build:
name: Build Swift Static
runs-on: macos-15
needs: [
files-changed,
assemble-xcframework-variant,
assemble-sentryobjc-static-xcframework,
assemble-sentryobjc-dynamic-xcframework,
]
# Run the job only for PRs with related changes or non-PR events.
if: github.event_name != 'pull_request' || needs.files-changed.outputs.run_release_for_prs == 'true'
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
pattern: xcframework-${{github.sha}}-*
merge-multiple: true
- name: Prepare Package.swift
shell: bash
run: |
./scripts/prepare-package.sh \
--package-file Package.swift \
--is-pr "${{ github.event_name == 'pull_request' }}" \
--change-path true
./scripts/prepare-package.sh \
--package-file Package@swift-6.1.swift \
--is-pr "${{ github.event_name == 'pull_request' }}" \
--change-path true
./scripts/prepare-package.sh \
--package-file Package@swift-6.2.swift \
--is-pr "${{ github.event_name == 'pull_request' }}" \
--change-path true
- name: Setup Xcode
uses: ./.github/actions/setup-xcode
with:
version: "16"
- run: swift build --target SentrySwiftUI
- name: Run CI Diagnostics
uses: ./.github/actions/ci-diagnostics
if: failure()
validate-spm-visionos:
name: Validate SPM Static visionOS
runs-on: macos-15
needs: [
files-changed,
assemble-xcframework-variant,
assemble-sentryobjc-static-xcframework,
assemble-sentryobjc-dynamic-xcframework,
]
# Run the job only for PRs with related changes or non-PR events.
if: github.event_name != 'pull_request' || needs.files-changed.outputs.run_release_for_prs == 'true'
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
pattern: xcframework-${{github.sha}}-*
merge-multiple: true
- name: Prepare Package.swift
shell: bash
run: |
./scripts/prepare-package.sh \
--package-file Package.swift \
--is-pr "${{ github.event_name == 'pull_request' }}" \
--change-path true
./scripts/prepare-package.sh \
--package-file Package@swift-6.1.swift \
--is-pr "${{ github.event_name == 'pull_request' }}" \
--change-path true
./scripts/prepare-package.sh \
--package-file Package@swift-6.2.swift \
--is-pr "${{ github.event_name == 'pull_request' }}" \
--change-path true
- name: Setup Xcode
uses: ./.github/actions/setup-xcode
with:
version: "16"
- run: set -o pipefail && NSUnbufferedIO=YES xcodebuild build -scheme visionOS-SPM -sdk xros -destination 'generic/platform=xros' | tee raw-build-output-spm-visionOS.log | xcbeautify --preserve-unbeautified
working-directory: Samples/visionOS-SPM
- name: Run CI Diagnostics
uses: ./.github/actions/ci-diagnostics
if: failure()
duplication-tests:
name: Test Sentry Duplication V4 on ${{matrix.runner_provider}}
uses: ./.github/workflows/ui-tests-common.yml
needs: [files-changed, assemble-xcframework-variant]
# Run the job only for PRs with related changes or non-PR events.
if: github.event_name != 'pull_request' || needs.files-changed.outputs.run_release_for_prs == 'true'
with:
fastlane_command: duplication_test
xcode_version: "16"
macos_version: sequoia
needs_xcframework: true
platform: macOS
runner_provider: ${{matrix.runner_provider}}
strategy:
matrix:
runner_provider: ["cirrus", "bitrise"]
app-metrics:
name: Collect App Metrics
runs-on: macos-15
needs: [files-changed, assemble-xcframework-variant]
# Run for PRs with related changes (including dependabot) or non-PR events. Skip fork PRs (no secrets available).
if: |
github.event_name != 'pull_request' || (
needs.files-changed.outputs.run_release_for_prs == 'true' &&
needs.files-changed.outputs.is_fork != 'true' && (
contains(
fromJson('["OWNER", "MEMBER", "COLLABORATOR", "CONTRIBUTOR"]'),
github.event.pull_request.author_association
) ||
needs.files-changed.outputs.is_dependabot == 'true')
)
timeout-minutes: 20
steps:
- name: Git checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- name: Setup Xcode
uses: ./.github/actions/setup-xcode
with:
version: "16"
- name: Setup Ruby
uses: ruby/setup-ruby@89f90524b88a01fe6e0b732220432cc6142926af # v1.313.0
with:
bundler-cache: true
- uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
id: app-plain-cache
with:
path: Tests/Perf/test-app-plain.ipa
key: ${{ github.workflow }}-${{ github.job }}-appplain-${{ hashFiles('fastlane/Fastfile', 'Tests/Perf/test-app-plain/**') }}
# When running the workflows for dependabot PRs, we need to skip code signing, because the code signing secrets are not available for dependabot PRs.
# We still want to run as much of the full workflow as possible, to verify the behaviour.
- name: Build test app plain
if: steps.app-plain-cache.outputs['cache-hit'] != 'true'
run: |
bundle exec fastlane build_perf_test_app_plain \
skip_codesigning:${{ needs.files-changed.outputs.is_dependabot == 'true' }}
env:
FASTLANE_KEYCHAIN_PASSWORD: ${{ secrets.FASTLANE_KEYCHAIN_PASSWORD }}
MATCH_GIT_PRIVATE_KEY: ${{ secrets.MATCH_GIT_PRIVATE_KEY }}
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
MATCH_USERNAME: ${{ secrets.MATCH_USERNAME }}
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
pattern: xcframework-${{github.sha}}-sentry-dynamic
path: XCFrameworkBuildPath/
- run: find XCFrameworkBuildPath -name "Sentry-Dynamic.xcframework.zip" -print0 | xargs -t0I @ unzip @ -d XCFrameworkBuildPath
- name: Build test app with sentry
run: |
bundle exec fastlane build_perf_test_app_sentry \
skip_codesigning:${{ needs.files-changed.outputs.is_dependabot == 'true' }}
env:
FASTLANE_KEYCHAIN_PASSWORD: ${{ secrets.FASTLANE_KEYCHAIN_PASSWORD }}
MATCH_GIT_PRIVATE_KEY: ${{ secrets.MATCH_GIT_PRIVATE_KEY }}
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
MATCH_USERNAME: ${{ secrets.MATCH_USERNAME }}
- name: Collect app metrics
if: needs.files-changed.outputs.is_dependabot != 'true'
uses: getsentry/action-app-sdk-overhead-metrics@44fb5489ac4ac252c87d84811972dc93a1e490b8
with:
config: Tests/Perf/metrics-test.yml
sauce-user: ${{ secrets.SAUCE_USERNAME }}
sauce-key: ${{ secrets.SAUCE_ACCESS_KEY }}
- name: App metrics collection skipped
if: needs.files-changed.outputs.is_dependabot == 'true'
run: |
echo "::warning::App metrics collection was SKIPPED ON PURPOSE for dependabot PR. Code signing secrets are not available for dependabot PRs."
- name: Run CI Diagnostics
uses: ./.github/actions/ci-diagnostics
if: ${{ failure() || cancelled() }}
job_release:
runs-on: ubuntu-latest
name: "Release New Version"
needs:
[
files-changed,
validate-xcframework,
validate-spm,
validate-spm-dynamic,
swift-build,
duplication-tests,
app-metrics,
assemble-sentryobjc-static-xcframework,
assemble-sentryobjc-dynamic-xcframework,
]
if: ${{ github.event_name == 'workflow_dispatch' }}
steps:
- name: Get auth token
id: token
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
app-id: ${{ vars.SENTRY_RELEASE_BOT_CLIENT_ID }}
private-key: ${{ secrets.SENTRY_RELEASE_BOT_PRIVATE_KEY }}
- name: Check out current commit (${{ github.sha }})
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
token: ${{ steps.token.outputs.token }}
fetch-depth: 0
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
pattern: xcframework-${{github.sha}}-*
merge-multiple: true
path: XCFrameworkBuildPath/
- name: Archive XCFrameworks for Craft
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: xcframeworks.zip
if-no-files-found: error
overwrite: true
path: |
${{github.workspace}}/XCFrameworkBuildPath/*.zip
# update-package-sha.sh uses this env variable to update Package.swift.
# During release Craft calls bump.sh that uses update-package-sha.sh.
- run: export GITHUB_RUN_ID="$GITHUB_RUN_ID"
env:
GITHUB_RUN_ID: ${{ github.run_id }}
- name: Prepare release
uses: getsentry/craft@acdb88019720182caf57293360d7cdc8db9e75ac # v2
env:
GITHUB_TOKEN: ${{ steps.token.outputs.token }}
with:
version: ${{ github.event.inputs.version }}
force: ${{ github.event.inputs.force }}
merge_target: ${{ github.event.inputs.merge_target }}
- name: Run CI Diagnostics
uses: ./.github/actions/ci-diagnostics
if: failure()
release-required-check:
needs:
[
files-changed,
build-xcframework-variant-slices,
assemble-xcframework-variant,
build-sentryobjc-slices,
assemble-sentryobjc-static-xcframework,
assemble-sentryobjc-dynamic-xcframework,
validate-xcframework,
validate-spm,
validate-spm-dynamic,
swift-build,
duplication-tests,
app-metrics,
ready-to-merge-gate,
]
name: Release
# 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 release check jobs has failed." && exit 1