Repository navigation
225 lines (197 loc) · 9.51 KB
/
Copy pathspm-application.yml
File metadata and controls
225 lines (197 loc) · 9.51 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
name: SwiftPM Application
# Builds a fresh React Native app that consumes the SDK through React Native's
# Swift Package Manager autolinking instead of CocoaPods. The app is generated
# per run rather than committed: the SwiftPM path only works on a plain
# template, because `react-native spm` stops on any autolinked dependency that
# ships no `Package.swift`, and most community libraries still don't.
on:
push:
branches:
- main
- release/**
pull_request:
types: [opened, synchronize, reopened, labeled]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
env:
# The first React Native version with the SwiftPM integration. Bump it
# together with the `Package.swift` platform requirement.
RN_VERSION: "0.87.1"
APP_NAME: SpmTestApp
APP_PATH: spm-app
jobs:
ready-to-merge-gate:
name: Ready-to-merge gate
uses: ./.github/workflows/ready-to-merge-workflow.yml
with:
is-pr: ${{ github.event_name == 'pull_request' }}
labels: ${{ toJson(github.event.pull_request.labels) }}
diff_check:
needs: [ready-to-merge-gate]
uses: ./.github/workflows/skip-ci.yml
detect-changes:
needs: [ready-to-merge-gate]
uses: ./.github/workflows/detect-changes.yml
with:
caller_event_name: ${{ github.event_name }}
caller_ref: ${{ github.ref }}
build-ios:
name: swiftpm ios ${{ matrix.build-type }}
runs-on: macos-26-xlarge
needs: [diff_check, detect-changes]
if: ${{ needs.diff_check.outputs.skip_ci != 'true' && needs.detect-changes.outputs.needs_ios == 'true' }}
strategy:
fail-fast: false
matrix:
build-type: ["dev", "production"]
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Enable Corepack
run: corepack enable
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
with:
package-manager-cache: false
node-version: 22
cache: "yarn"
cache-dependency-path: yarn.lock
- name: Install SDK Dependencies
run: yarn install
- name: Build SDK
run: yarn build
- name: Pack SDK
# Packs both workspaces with `yarn pack`, which replaces the
# `workspace:` ranges with concrete versions. `npm pack` leaves them in
# place and the install then fails.
run: yarn build:tarball
- name: Create React Native App
working-directory: ${{ runner.temp }}
run: |
npx --yes @react-native-community/cli@latest init "$APP_NAME" \
--directory "$APP_PATH" \
--version "$RN_VERSION" \
--skip-git-init \
--install-pods false
- name: Install SDK in App
working-directory: ${{ runner.temp }}/${{ env.APP_PATH }}
# Install both tarballs together so the `@sentry/expo-upload-sourcemaps`
# cross-dependency resolves locally. On a release branch the bumped
# version is not on the registry yet, and a fetch would fail with
# ETARGET — the same reason `buildandtest.yml` installs both.
run: |
set -e
CORE_TARBALL=$(find "$GITHUB_WORKSPACE/packages/core" -name 'sentry-react-native-*.tgz' -print -quit)
EXPO_TARBALL=$(find "$GITHUB_WORKSPACE/packages/expo-upload-sourcemaps" -name 'sentry-expo-upload-sourcemaps-*.tgz' -print -quit)
[ -n "$CORE_TARBALL" ] || { echo "::error::core tarball not found"; exit 1; }
[ -n "$EXPO_TARBALL" ] || { echo "::error::expo-upload-sourcemaps tarball not found"; exit 1; }
npm install "$EXPO_TARBALL" "$CORE_TARBALL"
- name: Set Up SwiftPM
working-directory: ${{ runner.temp }}/${{ env.APP_PATH }}/ios
# `--deintegrate` removes the template's CocoaPods integration first.
# A missing `Package.swift` in any autolinked dependency exits 2 here,
# which is the regression this job is meant to catch.
run: npx react-native spm add --deintegrate
- name: Build iOS App
working-directory: ${{ runner.temp }}/${{ env.APP_PATH }}/ios
env:
# Fix for Xcode 26+ with MetalToolchain: use default Xcode toolchain to avoid
# missing Swift compatibility libraries (swiftCompatibility56, etc.)
# See: https://github.com/actions/runner-images/issues/13135
TOOLCHAINS: com.apple.dt.toolchain.XcodeDefault
run: |
[[ "${{ matrix.build-type }}" == "production" ]] && export CONFIG='Release' || export CONFIG='Debug'
xcodebuild \
-project "$APP_NAME.xcodeproj" \
-scheme "$APP_NAME" \
-configuration "$CONFIG" \
-sdk iphonesimulator \
-destination 'generic/platform=iOS Simulator' \
-derivedDataPath build \
CODE_SIGNING_ALLOWED=NO \
build
- name: Verify SDK Is Linked
working-directory: ${{ runner.temp }}/${{ env.APP_PATH }}/ios
# A silent autolinking regression still produces a green build, so
# assert that a class from each layer reached the app. Both markers are
# Objective-C class names, which the linker keeps in the binary for
# every class it links — unlike, say, the sentry-cocoa package name,
# which appears only incidentally.
run: |
[[ "${{ matrix.build-type }}" == "production" ]] && export CONFIG='Release' || export CONFIG='Debug'
app="build/Build/Products/$CONFIG-iphonesimulator/$APP_NAME.app"
# Debug builds put the code in a separate dylib, Release builds do not.
binary="$app/$APP_NAME"
[[ -f "$app/$APP_NAME.debug.dylib" ]] && binary="$app/$APP_NAME.debug.dylib"
echo "Inspecting $binary"
if ! strings -a "$binary" | grep -q 'RNSentryReplayMask'; then
echo "RNSentry is missing from the app binary."
exit 1
fi
if ! strings -a "$binary" | grep -q 'SentryOptions'; then
echo "sentry-cocoa is missing from the app binary."
exit 1
fi
echo "The app binary contains both RNSentry and sentry-cocoa."
- name: Verify Sentry Categories Survived The Link
working-directory: ${{ runner.temp }}/${{ env.APP_PATH }}/ios
# A class symbol reaching the binary does not prove its categories did.
# sentry-cocoa ships object files that hold nothing but a category
# (`SentryReplayNetworkDetails+Capture`, `Options+Dictionary`,
# `SentryNSNotificationCenterWrapper`), so nothing references them and
# the linker drops them from the static archive unless it is
# force-loaded — the selectors then fail at runtime with "unrecognized
# selector" (#6609, Apple QA1490). `RNSentry.podspec` solves this with
# `-force_load`; SwiftPM has no equivalent, so assert the outcome here.
run: |
[[ "${{ matrix.build-type }}" == "production" ]] && export CONFIG='Release' || export CONFIG='Debug'
app="build/Build/Products/$CONFIG-iphonesimulator/$APP_NAME.app"
binary="$app/$APP_NAME"
[[ -f "$app/$APP_NAME.debug.dylib" ]] && binary="$app/$APP_NAME.debug.dylib"
# Selector defined only inside a category-only object file.
canary='setRequestWithSize:bodyData:contentType:allHeaders:configuredHeaders:'
# Not finding the archive means this check can no longer see what it
# is asserting about, so fail rather than pass silently.
archive=$(find build -type f -path '*Sentry.framework/Sentry' | head -1)
if [ -z "$archive" ]; then
echo "::error::Sentry.framework not found under build/; this check can no longer verify anything."
exit 1
fi
# A renamed selector is different: the canary is stale, not the link.
# Warn to update it rather than report a false dead-strip.
if ! strings -a "$archive" | grep -qF "$canary"; then
echo "::warning::Canary selector not found in sentry-cocoa; update it for this version."
exit 0
fi
if strings -a "$binary" | grep -qF "$canary"; then
echo "Category-only objects survived the link."
else
echo "::error::Sentry ObjC categories were dead-stripped from the app binary."
exit 1
fi
- name: Archive iOS App
if: ${{ matrix.build-type == 'production' }}
working-directory: ${{ runner.temp }}/${{ env.APP_PATH }}/ios
env:
TOOLCHAINS: com.apple.dt.toolchain.XcodeDefault
# Only the archive step collects xcframework signatures into
# `Signatures/`. Two copies of the Sentry signature fail it.
run: |
xcodebuild \
-project "$APP_NAME.xcodeproj" \
-scheme "$APP_NAME" \
-configuration Release \
-destination 'generic/platform=iOS' \
-derivedDataPath build \
-archivePath "build/$APP_NAME.xcarchive" \
CODE_SIGNING_ALLOWED=NO \
archive
archive="build/$APP_NAME.xcarchive"
if [ ! -f "$archive/Products/Applications/$APP_NAME.app/$APP_NAME" ]; then
echo "::error::The archive does not contain the app binary."
exit 1
fi
if [ ! -f "$archive/Signatures/Sentry.xcframework-ios.signature" ]; then
echo "::error::The archive does not contain the Sentry.xcframework signature."
exit 1
fi
echo "The archive contains the app and the Sentry.xcframework signature."