diff --git a/.github/workflows/changelog-preview.yml b/.github/workflows/changelog-preview.yml new file mode 100644 index 00000000000..1ed1021302d --- /dev/null +++ b/.github/workflows/changelog-preview.yml @@ -0,0 +1,13 @@ +name: Changelog Preview +on: + pull_request: + types: + - opened + - synchronize + - reopened + - edited + - labeled +jobs: + changelog-preview: + uses: getsentry/craft/.github/workflows/changelog-preview.yml@v2 + secrets: inherit diff --git a/.github/workflows/release-upload-xcframework.yml b/.github/workflows/release-upload-xcframework.yml index 1c93802a81f..1d7f084cbb6 100644 --- a/.github/workflows/release-upload-xcframework.yml +++ b/.github/workflows/release-upload-xcframework.yml @@ -1,47 +1,29 @@ name: Upload XCFrameworks on: - push: - branches: - - release/** - + workflow_dispatch: + inputs: + version: + description: Version to release (or "auto") + required: false jobs: - # Craft uses the Git commit hash to query GitHub Actions for artifacts - # uploaded in a workflow run associated with that commit. - # - # To support this, we download the XCFramework already built and uploaded - # in release.yml (triggered via workflow_dispatch), and reupload it here. - # This associates it with the new commit in the release branch, which is - # created by getsentry/action-prepare-release in release.yml. - # - # This is necessary because Swift Package Manager requires a checksum for - # XCFrameworks, creating a chicken-and-egg problem: we need the XCFramework - # to generate the checksum, but we also need the checksum to update Package.swift. - # - # The sequence is: - # 1. Build the XCFrameworks in release.yml. - # 2. getsentry/action-prepare-release updates Package.swift with the checksum. - # 3. Upload the XCFrameworks again here so Craft can find it by commit. - upload-xcframeworks: + release: runs-on: ubuntu-latest + name: Release a new version steps: - - uses: actions/checkout@v6 - - - name: Get Release workflow run ID - run: echo "FRAMEWORK_RUN_ID=$(./scripts/xcframework-generated-run.sh)" >> $GITHUB_ENV - - - uses: actions/download-artifact@v7 - with: - name: xcframeworks.zip - path: XCFrameworkBuildPath/ - github-token: ${{ secrets.GITHUB_TOKEN }} - run-id: ${{ env.FRAMEWORK_RUN_ID }} - - - name: Archive XCFrameworks for Craft - uses: actions/upload-artifact@v6 - with: - # Craft uses the git commit hash of the release branch to download the release artifacts. - name: ${{ github.sha }} - if-no-files-found: error - overwrite: true - path: | - ${{github.workspace}}/XCFrameworkBuildPath/*.zip + - name: Get auth token + id: token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ vars.SENTRY_RELEASE_BOT_CLIENT_ID }} + private-key: ${{ secrets.SENTRY_RELEASE_BOT_PRIVATE_KEY }} + - uses: actions/checkout@v4 + with: + token: ${{ steps.token.outputs.token }} + fetch-depth: 0 + - name: Prepare release + uses: getsentry/craft@v2 + env: + GITHUB_TOKEN: ${{ steps.token.outputs.token }} + with: + version: ${{ inputs.version }} + path: '|' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5c2a95cfd64..ff76f82d1d0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,403 +1,37 @@ 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 + description: Version to release (or "auto") + required: false force: - description: Force a release even when there are release-blockers (optional) + description: Force a release even when there are release-blockers required: false merge_target: - description: Target branch to merge into. Uses the default branch as a fallback (optional) + description: Target branch to merge into 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. -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 - - 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 }} - steps: - - uses: actions/checkout@v6 - - name: Get changed files - id: changes - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 - 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@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) }} - - validate-xcframework: - name: Validate XCFramework - runs-on: macos-15 - 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' - steps: - - uses: actions/checkout@v6 - - uses: actions/download-artifact@v7 - with: - pattern: xcframework-${{github.sha}}-sentry-static - path: XCFrameworkBuildPath/ - - uses: actions/download-artifact@v7 - with: - pattern: xcframework-${{github.sha}}-sentry-swiftui - path: XCFrameworkBuildPath/ - - run: ./scripts/ci-select-xcode.sh 16.4 - - name: Unzip all XCFrameworks - run: | - find XCFrameworkBuildPath -name "*.xcframework.zip" -print0 | xargs -t0I @ unzip @ -d XCFrameworkBuildPath - - 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 - if: failure() - run: ./scripts/ci-diagnostics.sh - - # 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] - # 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@v6 - - uses: actions/download-artifact@v7 - 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 - - run: ./scripts/ci-select-xcode.sh 16.4 - - run: swift build - working-directory: Samples/macOS-SPM-CommandLine - - name: Run CI Diagnostics - if: failure() - run: ./scripts/ci-diagnostics.sh - - validate-spm-dynamic: - name: Validate SPM Dynamic - runs-on: macos-15 - 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' - steps: - - uses: actions/checkout@v6 - - uses: actions/download-artifact@v7 - 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 - - run: ./scripts/ci-select-xcode.sh 16.4 - - run: swift build - working-directory: Samples/SPM-Dynamic - - name: Run CI Diagnostics - if: failure() - run: ./scripts/ci-diagnostics.sh - - swift-build: - name: Build Swift Static - runs-on: macos-15 - 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' - steps: - - uses: actions/checkout@v6 - - uses: actions/download-artifact@v7 - 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 - - run: ./scripts/ci-select-xcode.sh 16.4 - - run: swift build --target SentrySwiftUI - - name: Run CI Diagnostics - if: failure() - run: ./scripts/ci-diagnostics.sh - - validate-spm-visionos: - name: Validate SPM Static visionOS - runs-on: macos-15 - 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' - steps: - - uses: actions/checkout@v6 - - uses: actions/download-artifact@v7 - 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 - - run: ./scripts/ci-select-xcode.sh 16.4 - - run: set -o pipefail &&xcodebuild build -scheme visionOS-SPM -sdk xros -destination 'generic/platform=xros' | tee raw-build-output-spm-visionOS.log | xcbeautify - working-directory: Samples/visionOS-SPM - - name: Run CI Diagnostics - if: failure() - run: ./scripts/ci-diagnostics.sh - - duplication-tests: - name: Test Sentry Duplication V4 # Up the version with every change to keep track of flaky tests - 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' - secrets: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - with: - fastlane_command: duplication_test - xcode_version: 16.4 - macos_version: macos-15 - needs_xcframework: true - - app-metrics: - name: Collect App Metrics - runs-on: macos-15 - needs: [files-changed, assemble-xcframework-variant] - # Run the job only for PRs with related changes (from contributors) or non-PR events. - if: github.event_name != 'pull_request' || (needs.files-changed.outputs.run_release_for_prs == 'true' && contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR", "CONTRIBUTOR"]'), github.event.pull_request.author_association)) - timeout-minutes: 20 - steps: - - name: Git checkout - uses: actions/checkout@v6 - - run: ./scripts/ci-select-xcode.sh 16.4 - - name: Setup Ruby - uses: ruby/setup-ruby@b90be12699fdfcbee4440c2bba85f6f460446bb0 # v1.279.0 - with: - bundler-cache: true - - uses: actions/cache@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/**') }} - - name: Build test app plain - if: steps.app-plain-cache.outputs['cache-hit'] != 'true' - run: bundle exec fastlane build_perf_test_app_plain - env: - APP_STORE_CONNECT_KEY_ID: ${{ secrets.APP_STORE_CONNECT_KEY_ID }} - APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }} - APP_STORE_CONNECT_KEY: ${{ secrets.APP_STORE_CONNECT_KEY }} - 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@v7 - 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 - env: - APP_STORE_CONNECT_KEY_ID: ${{ secrets.APP_STORE_CONNECT_KEY_ID }} - APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }} - APP_STORE_CONNECT_KEY: ${{ secrets.APP_STORE_CONNECT_KEY }} - 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 - uses: getsentry/action-app-sdk-overhead-metrics@5f2d99b8e5a7b833386524924d24320501099a44 - with: - config: Tests/Perf/metrics-test.yml - sauce-user: ${{ secrets.SAUCE_USERNAME }} - sauce-key: ${{ secrets.SAUCE_ACCESS_KEY }} - - name: Debug Xcode environment - if: ${{ failure() || cancelled() }} - run: ./scripts/ci-diagnostics.sh - - job_release: + 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, - ] - if: ${{ github.event_name == 'workflow_dispatch' }} - steps: - - name: Get auth token - id: token - uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1 - 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@v6 - with: - token: ${{ steps.token.outputs.token }} - fetch-depth: 0 - - - uses: actions/download-artifact@v7 - with: - pattern: xcframework-${{github.sha}}-* - merge-multiple: true - path: XCFrameworkBuildPath/ - - - name: Archive XCFrameworks for Craft - uses: actions/upload-artifact@v6 - 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/action-prepare-release@v1 - 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 - if: failure() - run: ./scripts/ci-diagnostics.sh - - release-required-check: - needs: - [ - files-changed, - build-xcframework-variant-slices, - assemble-xcframework-variant, - 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 + name: Release a new version + steps: + - name: Get auth token + id: token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ vars.SENTRY_RELEASE_BOT_CLIENT_ID }} + private-key: ${{ secrets.SENTRY_RELEASE_BOT_PRIVATE_KEY }} + - uses: actions/checkout@v4 + with: + token: ${{ steps.token.outputs.token }} + fetch-depth: 0 + - name: Prepare release + uses: getsentry/craft@v2 + env: + GITHUB_TOKEN: ${{ steps.token.outputs.token }} + with: + version: ${{ inputs.version }} + force: ${{ inputs.force }} + merge_target: ${{ inputs.merge_target }} + path: '|'