diff --git a/.github/file-filters.yml b/.github/file-filters.yml index 186bba5caf..1fe162372e 100644 --- a/.github/file-filters.yml +++ b/.github/file-filters.yml @@ -172,6 +172,28 @@ run_lint_clang_formatting_for_prs: &run_lint_clang_formatting_for_prs - "Makefile" - "Brewfile*" +# Same ObjC/C/C++ source patterns as run_lint_clang_formatting_for_prs; omits clang-format-only paths. +run_sentrycrash_import_ratchet_for_prs: + - "**/*.h" + - "**/*.hpp" + - "**/*.c" + - "**/*.cpp" + - "**/*.m" + - "**/*.mm" + + # GH Actions + - ".github/workflows/lint-sentrycrash-imports.yml" + - ".github/file-filters.yml" + + # Scripts + - "scripts/check-sentrycrash-imports.sh" + - "scripts/ci-diagnostics.sh" + - "scripts/ci-utils.sh" + + # Build configuration + - "Makefile" + - "Brewfile*" + run_objc_conversion_analysis_for_prs: &run_objc_conversion_analysis_for_prs - "SwiftConversion/**" diff --git a/.github/workflows/fast-pr-checks.yml b/.github/workflows/fast-pr-checks.yml index bef598692f..c79e5e32a7 100644 --- a/.github/workflows/fast-pr-checks.yml +++ b/.github/workflows/fast-pr-checks.yml @@ -58,7 +58,11 @@ jobs: run_on_cirrus_labs: true fast-checks-required: - needs: [files-changed, fast-xcframework-slices, fast-unit-tests] + needs: [ + files-changed, + fast-xcframework-slices, + fast-unit-tests, + ] name: Fast PR Checks if: always() runs-on: ubuntu-latest diff --git a/.github/workflows/lint-sentrycrash-imports.yml b/.github/workflows/lint-sentrycrash-imports.yml new file mode 100644 index 0000000000..1f8bdfafd5 --- /dev/null +++ b/.github/workflows/lint-sentrycrash-imports.yml @@ -0,0 +1,59 @@ +name: Lint SentryCrash Imports + +on: + push: + branches: + - main + - v8.x + + pull_request: + +# Concurrency configuration: +# - We use workflow-specific concurrency groups to prevent multiple lint runs on the same code, +# as linting checks are deterministic and don't require parallel validation. +# - For pull requests, we cancel in-progress runs when new commits are pushed since only the +# latest linting matters for merge decisions. +# - For main branch pushes, we never cancel to ensure the ratchet runs for every push. +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +jobs: + files-changed: + name: Detect File Changes + runs-on: ubuntu-latest + outputs: + run_sentrycrash_import_ratchet_for_prs: ${{ steps.changes.outputs.run_sentrycrash_import_ratchet_for_prs }} + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - name: Get changed files + id: changes + uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1 + with: + token: ${{ github.token }} + filters: .github/file-filters.yml + + check-imports: + name: Check SentryCrash Imports + if: github.event_name != 'pull_request' || needs.files-changed.outputs.run_sentrycrash_import_ratchet_for_prs == 'true' + needs: files-changed + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - name: Check SentryCrash import count + run: ./scripts/check-sentrycrash-imports.sh + + - name: Run CI Diagnostics + if: failure() + run: ./scripts/ci-diagnostics.sh + + lint_sentrycrash_imports-required-check: + needs: [files-changed, check-imports] + name: Lint SentryCrash Imports + if: always() + runs-on: ubuntu-latest + steps: + - name: Check for failures + if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') + run: | + echo "One of the SentryCrash import ratchet jobs has failed." && exit 1 diff --git a/Makefile b/Makefile index bd39d9057d..cf88f252e0 100644 --- a/Makefile +++ b/Makefile @@ -95,6 +95,14 @@ update-versions: check-versions: ./scripts/check-tooling-versions.sh +## Check SentryCrash imports +# +# CI ratchet that ensures the number of direct SentryCrash header imports +# from SDK source files does not increase beyond the established baseline. +.PHONY: check-sentrycrash-imports +check-sentrycrash-imports: + @./scripts/check-sentrycrash-imports.sh + # ============================================================================ # BUILDING # ============================================================================ diff --git a/scripts/check-sentrycrash-imports.sh b/scripts/check-sentrycrash-imports.sh new file mode 100755 index 0000000000..fce9bf83ee --- /dev/null +++ b/scripts/check-sentrycrash-imports.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +# CI ratchet: ensures SentryCrash import count doesn't increase in SDK sources. +# Decrease MAX_IMPORTS as phases eliminate imports. Never increase it. + +set -euo pipefail + +# Source CI utilities for proper logging +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=./ci-utils.sh disable=SC1091 +source "$SCRIPT_DIR/ci-utils.sh" + +# Baseline count of #import / #include lines referencing SentryCrash in Sources/Sentry +# and Sources/Swift only (not Sources/SentryCrash). Pattern allows whitespace after '#' +# so indented directives under #if are counted; matches #include and #import. +MAX_IMPORTS=85 + +count=$(grep -rnE '#[[:space:]]*(import|include).*SentryCrash' Sources/Sentry Sources/Swift \ + --include='*.m' --include='*.h' --include='*.c' --include='*.mm' --include='*.cpp' \ + | wc -l | tr -d ' ') + +if [ "$count" -gt "$MAX_IMPORTS" ]; then + log_error "SentryCrash import count increased from $MAX_IMPORTS to $count" + log_error "New #import / #include of SentryCrash from SDK files is not allowed." + log_error "Use the SentryCrashReporter protocol instead." + echo "" + log_notice "Offending imports:" + grep -rnE '#[[:space:]]*(import|include).*SentryCrash' Sources/Sentry Sources/Swift \ + --include='*.m' --include='*.h' --include='*.c' --include='*.mm' --include='*.cpp' + exit 1 +fi + +log_notice "SentryCrash import ratchet: $count / $MAX_IMPORTS (OK)"