Skip to content

Commit 29b1e33

Browse files
Merge pull request #124 from blacksky-algorithms/fix/ci-ota-nightly
2 parents 4f5dcb3 + 23cf529 commit 29b1e33

8 files changed

Lines changed: 514 additions & 444 deletions

.github/workflows/build-submit-ios.yml

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -168,21 +168,28 @@ jobs:
168168
echo ""
169169
echo "Build dir contents:"
170170
ls -la "$BUILD_DIR"
171+
# Export the discovered paths rather than hardcoding a product name.
172+
# The Xcode scheme is "Blacksky" in this fork, so the artifacts are
173+
# Blacksky.ipa / Blacksky.app.dSYM.zip — downstream steps must use the
174+
# paths we actually found, not a fixed "Bluesky.ipa".
175+
DSYM_PATH="$(find ios-build -type f -name '*.app.dSYM.zip' -print -quit)"
171176
echo "BUILD_DIR=$BUILD_DIR" >> $GITHUB_ENV
177+
echo "IPA_PATH=$IPA_PATH" >> $GITHUB_ENV
178+
echo "DSYM_PATH=$DSYM_PATH" >> $GITHUB_ENV
172179
else
173180
echo "Archive file not found!"
174181
exit 1
175182
fi
176183
177184
- name: 🚀 Deploy
178-
run: pnpm eas submit -p ios --non-interactive --path "$BUILD_DIR/Bluesky.ipa"
185+
run: pnpm eas submit -p ios --non-interactive --path "$IPA_PATH"
179186

180187
- name: 🪲 Upload dSYM to Sentry
181188
run: >
182189
SENTRY_ORG=blacksky-algorithms
183190
SENTRY_PROJECT=social-app
184191
SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}
185-
pnpm sentry-cli debug-files upload "$BUILD_DIR/Bluesky.app.dSYM.zip" --include-sources
192+
pnpm sentry-cli debug-files upload "$DSYM_PATH" --include-sources
186193
187194
- name: 📚 Get version from package.json
188195
id: get-build-info
@@ -197,7 +204,7 @@ jobs:
197204
id: ipa-build-number
198205
run: |
199206
plist_dir="$(mktemp -d)"
200-
unzip -o -q "$BUILD_DIR/Bluesky.ipa" 'Payload/*.app/Info.plist' -d "$plist_dir"
207+
unzip -o -q "$IPA_PATH" 'Payload/*.app/Info.plist' -d "$plist_dir"
201208
plist="$(find "$plist_dir" -name Info.plist -print -quit)"
202209
build_number="$(/usr/libexec/PlistBuddy -c 'Print CFBundleVersion' "$plist")"
203210
rm -rf "$plist_dir"

.github/workflows/bundle-deploy-eas-update.yml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -276,21 +276,28 @@ jobs:
276276
echo ""
277277
echo "Build dir contents:"
278278
ls -la "$BUILD_DIR"
279+
# Export the discovered paths rather than hardcoding a product name.
280+
# The Xcode scheme is "Blacksky" in this fork, so the artifacts are
281+
# Blacksky.ipa / Blacksky.app.dSYM.zip — downstream steps must use the
282+
# paths we actually found, not a fixed "Bluesky.ipa".
283+
DSYM_PATH="$(find ios-build -type f -name '*.app.dSYM.zip' -print -quit)"
279284
echo "BUILD_DIR=$BUILD_DIR" >> $GITHUB_ENV
285+
echo "IPA_PATH=$IPA_PATH" >> $GITHUB_ENV
286+
echo "DSYM_PATH=$DSYM_PATH" >> $GITHUB_ENV
280287
else
281288
echo "Archive file not found!"
282289
exit 1
283290
fi
284291
285292
- name: 🚀 Deploy
286-
run: pnpm eas submit -p ios --non-interactive --path "$BUILD_DIR/Bluesky.ipa"
293+
run: pnpm eas submit -p ios --non-interactive --path "$IPA_PATH"
287294

288295
- name: 🪲 Upload dSYM to Sentry
289296
run: >
290297
SENTRY_ORG=blacksky-algorithms
291298
SENTRY_PROJECT=social-app
292299
SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}
293-
pnpm sentry-cli debug-files upload "$BUILD_DIR/Bluesky.app.dSYM.zip" --include-sources
300+
pnpm sentry-cli debug-files upload "$DSYM_PATH" --include-sources
294301
295302
- name: ⬇️ Restore Cache
296303
id: get-base-commit

.github/workflows/nightly-update-source-languages.yaml

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,21 +27,14 @@ jobs:
2727
cache: pnpm
2828
- name: pnpm install
2929
run: pnpm install --frozen-lockfile
30+
# We run extraction purely to catch strings that fail to compile/render, not
31+
# to sync translations. Blacksky has no Crowdin subscription, so the previous
32+
# "Push source lang to Crowdin" step always failed on an empty api_token. It
33+
# has been removed; the extract + auto-commit of messages.po is the useful part.
3034
- name: Extract language strings
3135
run: pnpm intl:extract
3236
- name: Create commit
3337
uses: stefanzweifel/git-auto-commit-action@04702edda442b2e678b25b537cec683a1493fcb9 # v7.1.0
3438
with:
3539
commit_message: Nightly source-language update
3640
file_pattern: ./src/locale/locales/en/messages.po
37-
- name: Push source lang to Crowdin
38-
uses: crowdin/github-action@52aa776766211d83d975df51f3b9c53c2f8ba35f # v2.16.3
39-
with:
40-
upload_sources: true
41-
upload_sources_args: "-b main"
42-
upload_translations: false
43-
push_translations: false
44-
push_sources: false
45-
create_pull_request: false
46-
env:
47-
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}

app.config.js

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ module.exports = function (_config) {
2121
const IS_TESTFLIGHT = process.env.EXPO_PUBLIC_ENV === 'testflight'
2222
const IS_PRODUCTION = process.env.EXPO_PUBLIC_ENV === 'production'
2323
const IS_DEV = !IS_TESTFLIGHT && !IS_PRODUCTION
24+
// True only when building on EAS (EAS sets EAS_BUILD=true / EAS_BUILD_PLATFORM).
25+
// Used to scope OTA update code signing to EAS builds so local dev doesn't
26+
// require the production update-signing private key.
27+
const IS_EAS_BUILD =
28+
process.env.EAS_BUILD === 'true' || !!process.env.EAS_BUILD_PLATFORM
2429

2530
const ASSOCIATED_DOMAINS = [
2631
'applinks:blacksky.community',
@@ -224,11 +229,20 @@ module.exports = function (_config) {
224229
url: 'https://updates.blacksky.community/manifest',
225230
enabled: true,
226231
fallbackToCacheTimeout: 30000,
227-
codeSigningCertificate: './code-signing/certificate.pem',
228-
codeSigningMetadata: {
229-
keyid: 'main',
230-
alg: 'rsa-v1_5-sha256',
231-
},
232+
// OTA manifest code signing is only applied on EAS builds (which have the
233+
// private key as a managed secret). Local dev builds omit it so developers
234+
// don't need the production update-signing key just to serve a dev
235+
// manifest from Metro (`expo start` otherwise errors: "Must specify
236+
// --private-key-path ...").
237+
...(IS_EAS_BUILD
238+
? {
239+
codeSigningCertificate: './code-signing/certificate.pem',
240+
codeSigningMetadata: {
241+
keyid: 'main',
242+
alg: 'rsa-v1_5-sha256',
243+
},
244+
}
245+
: {}),
232246
checkAutomatically: 'NEVER',
233247
// Enables Updates.setUpdateURLAndRequestHeadersOverride at runtime, which
234248
// is how non-production builds retarget to a pull-request-<n> channel for

patches/react-native@0.81.5.patch

Lines changed: 96 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,46 @@
1+
diff --git a/React/Base/Surface/RCTSurface.mm b/React/Base/Surface/RCTSurface.mm
2+
index 14f88de1f3ddadc39ca53c9e8944d7d2eeb60268..cee524b67823be6e4d10adb882a88e3bcb38efd4 100644
3+
--- a/React/Base/Surface/RCTSurface.mm
4+
+++ b/React/Base/Surface/RCTSurface.mm
5+
@@ -465,7 +465,7 @@
6+
// right after the semaphore signals.
7+
8+
// Atomic variant of `_waitingForMountingStageOnMainQueue = YES;`
9+
- atomic_fetch_or(&_waitingForMountingStageOnMainQueue, 1);
10+
+ atomic_exchange(&_waitingForMountingStageOnMainQueue, 1);
11+
}
12+
13+
dispatch_semaphore_t semaphore;
14+
@@ -488,7 +488,7 @@
15+
auto timeoutOccurred = dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, timeout * NSEC_PER_SEC));
16+
17+
// Atomic equivalent of `_waitingForMountingStageOnMainQueue = NO;`.
18+
- atomic_fetch_and(&_waitingForMountingStageOnMainQueue, 0);
19+
+ atomic_exchange(&_waitingForMountingStageOnMainQueue, 0);
20+
21+
if (!timeoutOccurred) {
22+
// Balancing the semaphore.
23+
@@ -546,7 +546,7 @@
24+
{
25+
if (atomic_load(&_waitingForMountingStageOnMainQueue) && (self.stage & RCTSurfaceStageSurfaceDidInitialLayout)) {
26+
// Atomic equivalent of `_waitingForMountingStageOnMainQueue = NO;`.
27+
- atomic_fetch_and(&_waitingForMountingStageOnMainQueue, 0);
28+
+ atomic_exchange(&_waitingForMountingStageOnMainQueue, 0);
29+
30+
{
31+
std::lock_guard<std::mutex> lock(_mutex);
32+
diff --git a/React/DevSupport/RCTPackagerConnection.mm b/React/DevSupport/RCTPackagerConnection.mm
33+
index 39419d60e1203673e9cafb71c6932a6b9200bf18..b252a4976f7ad3b430d97c2bc94b781dd93dbd0a 100644
34+
--- a/React/DevSupport/RCTPackagerConnection.mm
35+
+++ b/React/DevSupport/RCTPackagerConnection.mm
36+
@@ -9,6 +9,7 @@
37+
38+
#import <objc/runtime.h>
39+
#import <algorithm>
40+
+#import <mutex>
41+
#import <vector>
42+
43+
#import <React/RCTAssert.h>
144
diff --git a/React/Fabric/Mounting/ComponentViews/ScrollView/RCTPullToRefreshViewComponentView.h b/React/Fabric/Mounting/ComponentViews/ScrollView/RCTPullToRefreshViewComponentView.h
245
index 914a2494a57923fbf185644b7e2bb8aca8848e56..0deac55f22350f5e8377d8963fb1c2434bf6abfd 100644
346
--- a/React/Fabric/Mounting/ComponentViews/ScrollView/RCTPullToRefreshViewComponentView.h
@@ -15,7 +58,7 @@ diff --git a/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewCompon
1558
index 1494fd225aff1fa0429e917404d6b4ca5fc961c5..df643f5c844ad2e684de5161528eba17f4a188d0 100644
1659
--- a/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm
1760
+++ b/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm
18-
@@ -1038,6 +1038,11 @@ - (void)_adjustForMaintainVisibleContentPosition
61+
@@ -1038,6 +1038,11 @@ static inline UIViewAnimationOptions animationOptionsWithCurve(UIViewAnimationCu
1962
}
2063
}
2164

@@ -27,6 +70,28 @@ index 1494fd225aff1fa0429e917404d6b4ca5fc961c5..df643f5c844ad2e684de5161528eba17
2770
@end
2871

2972
Class<RCTComponentViewProtocol> RCTScrollViewCls(void)
73+
diff --git a/React/Profiler/RCTProfile.m b/React/Profiler/RCTProfile.m
74+
index 994e8ad6c107cb87274200849c204dee48e1f565..287b93403adb8554b2952f21bc56f1d02999636e 100644
75+
--- a/React/Profiler/RCTProfile.m
76+
+++ b/React/Profiler/RCTProfile.m
77+
@@ -445,7 +445,7 @@ BOOL RCTProfileIsProfiling(void)
78+
void RCTProfileInit(RCTBridge *bridge)
79+
{
80+
// TODO: enable assert JS thread from any file (and assert here)
81+
- BOOL wasProfiling = atomic_fetch_or(&RCTProfileProfiling, 1);
82+
+ BOOL wasProfiling = atomic_exchange(&RCTProfileProfiling, 1);
83+
if (wasProfiling) {
84+
return;
85+
}
86+
@@ -492,7 +492,7 @@ void RCTProfileInit(RCTBridge *bridge)
87+
void RCTProfileEnd(RCTBridge *bridge, void (^callback)(NSString *))
88+
{
89+
// assert JavaScript thread here again
90+
- BOOL wasProfiling = atomic_fetch_and(&RCTProfileProfiling, 0);
91+
+ BOOL wasProfiling = atomic_exchange(&RCTProfileProfiling, 0);
92+
if (!wasProfiling) {
93+
return;
94+
}
3095
diff --git a/React/Views/RefreshControl/RCTRefreshControl.h b/React/Views/RefreshControl/RCTRefreshControl.h
3196
index e9b330fa7c29c42653a3b0191d0f8a1b13b2d3de..ec5f58c887bfd949f1279ef1c31352e0b465e9ec 100644
3297
--- a/React/Views/RefreshControl/RCTRefreshControl.h
@@ -44,15 +109,15 @@ diff --git a/React/Views/RefreshControl/RCTRefreshControl.m b/React/Views/Refres
44109
index 53bfd04703502d5b8e932c47a528bb03cd79d330..ff1b1ed5e060bcf0d91528c6d3c2c5c8acf24967 100644
45110
--- a/React/Views/RefreshControl/RCTRefreshControl.m
46111
+++ b/React/Views/RefreshControl/RCTRefreshControl.m
47-
@@ -23,6 +23,7 @@ @implementation RCTRefreshControl {
112+
@@ -23,6 +23,7 @@
48113
UIColor *_titleColor;
49114
CGFloat _progressViewOffset;
50115
BOOL _hasMovedToWindow;
51116
+ UIColor *_customTintColor;
52117
}
53118

54119
- (instancetype)init
55-
@@ -58,6 +59,12 @@ - (void)layoutSubviews
120+
@@ -58,6 +59,12 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder)
56121
_isInitialRender = false;
57122
}
58123

@@ -65,7 +130,7 @@ index 53bfd04703502d5b8e932c47a528bb03cd79d330..ff1b1ed5e060bcf0d91528c6d3c2c5c8
65130
- (void)didMoveToWindow
66131
{
67132
[super didMoveToWindow];
68-
@@ -221,4 +228,50 @@ - (void)refreshControlValueChanged
133+
@@ -221,4 +228,50 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder)
69134
}
70135
}
71136

@@ -120,7 +185,7 @@ diff --git a/React/Views/RefreshControl/RCTRefreshControlManager.m b/React/Views
120185
index 40aaf9c51ebda9fedb1d1db2e9aacec84b4c39c8..1c60164b69762997b3369b46609a07768a06bad3 100644
121186
--- a/React/Views/RefreshControl/RCTRefreshControlManager.m
122187
+++ b/React/Views/RefreshControl/RCTRefreshControlManager.m
123-
@@ -22,11 +22,12 @@ - (UIView *)view
188+
@@ -22,11 +22,12 @@ RCT_EXPORT_MODULE()
124189

125190
RCT_EXPORT_VIEW_PROPERTY(onRefresh, RCTDirectEventBlock)
126191
RCT_EXPORT_VIEW_PROPERTY(refreshing, BOOL)
@@ -150,6 +215,32 @@ index 8b6571698fc5dd091a0d8980a33bb40295faf305..27c97bfeb6f13907c89f1d85f2bb8b8a
150215
reactChoreographer.postFrameCallback(ReactChoreographer.CallbackType.IDLE_EVENT, this)
151216
}
152217
}
218+
diff --git a/ReactCommon/hermes/inspector-modern/chrome/HermesRuntimeAgentDelegate.cpp b/ReactCommon/hermes/inspector-modern/chrome/HermesRuntimeAgentDelegate.cpp
219+
index 66a91c91c6463e133342d33aa054e750bb32c047..021084bffe1b2e9f0ca4e7932dca2ea25904ffd7 100644
220+
--- a/ReactCommon/hermes/inspector-modern/chrome/HermesRuntimeAgentDelegate.cpp
221+
+++ b/ReactCommon/hermes/inspector-modern/chrome/HermesRuntimeAgentDelegate.cpp
222+
@@ -111,6 +111,8 @@ HermesRuntimeAgentDelegate::HermesRuntimeAgentDelegate(
223+
runtimeTargetDelegate,
224+
std::move(runtimeExecutor))) {}
225+
226+
+HermesRuntimeAgentDelegate::~HermesRuntimeAgentDelegate() = default;
227+
+
228+
bool HermesRuntimeAgentDelegate::handleRequest(
229+
const cdp::PreparsedRequest& req) {
230+
return impl_->handleRequest(req);
231+
diff --git a/ReactCommon/hermes/inspector-modern/chrome/HermesRuntimeAgentDelegate.h b/ReactCommon/hermes/inspector-modern/chrome/HermesRuntimeAgentDelegate.h
232+
index d38e86358ca2266de08bedcb4629a7ca9ada8ac6..735802995e4bf51a3bc45b3a38a99098a60b915a 100644
233+
--- a/ReactCommon/hermes/inspector-modern/chrome/HermesRuntimeAgentDelegate.h
234+
+++ b/ReactCommon/hermes/inspector-modern/chrome/HermesRuntimeAgentDelegate.h
235+
@@ -56,6 +56,8 @@ class HermesRuntimeAgentDelegate : public RuntimeAgentDelegate {
236+
HermesRuntimeTargetDelegate& runtimeTargetDelegate,
237+
RuntimeExecutor runtimeExecutor);
238+
239+
+ ~HermesRuntimeAgentDelegate() override;
240+
+
241+
/**
242+
* Handle a CDP request. The response will be sent over the provided
243+
* \c FrontendChannel synchronously or asynchronously.
153244
diff --git a/third-party-podspecs/fmt.podspec b/third-party-podspecs/fmt.podspec
154245
index 2f38990e226c13f483aaf1b986302d4094243814..9b02e481e290299be20a6f09c42056ff51695e9b 100644
155246
--- a/third-party-podspecs/fmt.podspec
@@ -166,56 +257,3 @@ index 2f38990e226c13f483aaf1b986302d4094243814..9b02e481e290299be20a6f09c42056ff
166257
+ perl -i -pe 's/^# define FMT_USE_CONSTEVAL 1$/# define FMT_USE_CONSTEVAL 0/' include/fmt/base.h
167258
+ SCRIPT
168259
end
169-
diff --git a/React/Base/Surface/RCTSurface.mm b/React/Base/Surface/RCTSurface.mm
170-
index 14f88de035f7657cb267cb834b28c8f108595775..cee524bca80cf86517fb21af413f937b815275f6 100644
171-
--- a/React/Base/Surface/RCTSurface.mm
172-
+++ b/React/Base/Surface/RCTSurface.mm
173-
@@ -465,7 +465,7 @@ - (BOOL)synchronouslyWaitForStage:(RCTSurfaceStage)stage timeout:(NSTimeInterval
174-
// right after the semaphore signals.
175-
176-
// Atomic variant of `_waitingForMountingStageOnMainQueue = YES;`
177-
- atomic_fetch_or(&_waitingForMountingStageOnMainQueue, 1);
178-
+ atomic_exchange(&_waitingForMountingStageOnMainQueue, 1);
179-
}
180-
181-
dispatch_semaphore_t semaphore;
182-
@@ -488,7 +488,7 @@ - (BOOL)synchronouslyWaitForStage:(RCTSurfaceStage)stage timeout:(NSTimeInterval
183-
auto timeoutOccurred = dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, timeout * NSEC_PER_SEC));
184-
185-
// Atomic equivalent of `_waitingForMountingStageOnMainQueue = NO;`.
186-
- atomic_fetch_and(&_waitingForMountingStageOnMainQueue, 0);
187-
+ atomic_exchange(&_waitingForMountingStageOnMainQueue, 0);
188-
189-
if (!timeoutOccurred) {
190-
// Balancing the semaphore.
191-
@@ -546,7 +546,7 @@ - (void)_mountRootViewIfNeeded
192-
{
193-
if (atomic_load(&_waitingForMountingStageOnMainQueue) && (self.stage & RCTSurfaceStageSurfaceDidInitialLayout)) {
194-
// Atomic equivalent of `_waitingForMountingStageOnMainQueue = NO;`.
195-
- atomic_fetch_and(&_waitingForMountingStageOnMainQueue, 0);
196-
+ atomic_exchange(&_waitingForMountingStageOnMainQueue, 0);
197-
198-
{
199-
std::lock_guard<std::mutex> lock(_mutex);
200-
diff --git a/React/Profiler/RCTProfile.m b/React/Profiler/RCTProfile.m
201-
index 994e8ad65b6299f5b2898ce67b64cb4a8d03a7f4..287b9344c48279f00684f5ca552cc6b1ed6b7fac 100644
202-
--- a/React/Profiler/RCTProfile.m
203-
+++ b/React/Profiler/RCTProfile.m
204-
@@ -445,7 +445,7 @@ BOOL RCTProfileIsProfiling(void)
205-
void RCTProfileInit(RCTBridge *bridge)
206-
{
207-
// TODO: enable assert JS thread from any file (and assert here)
208-
- BOOL wasProfiling = atomic_fetch_or(&RCTProfileProfiling, 1);
209-
+ BOOL wasProfiling = atomic_exchange(&RCTProfileProfiling, 1);
210-
if (wasProfiling) {
211-
return;
212-
}
213-
@@ -492,7 +492,7 @@ void RCTProfileInit(RCTBridge *bridge)
214-
void RCTProfileEnd(RCTBridge *bridge, void (^callback)(NSString *))
215-
{
216-
// assert JavaScript thread here again
217-
- BOOL wasProfiling = atomic_fetch_and(&RCTProfileProfiling, 0);
218-
+ BOOL wasProfiling = atomic_exchange(&RCTProfileProfiling, 0);
219-
if (!wasProfiling) {
220-
return;
221-
}

0 commit comments

Comments
 (0)