Skip to content

fix(mobile): patch fmt 11.0.2 for Xcode 26 + make Android S3 archive non-fatal#14403

Merged
raymondjacobson merged 6 commits into
mainfrom
rj-mobile-release-retry-5
May 27, 2026
Merged

fix(mobile): patch fmt 11.0.2 for Xcode 26 + make Android S3 archive non-fatal#14403
raymondjacobson merged 6 commits into
mainfrom
rj-mobile-release-retry-5

Conversation

@raymondjacobson
Copy link
Copy Markdown
Member

@raymondjacobson raymondjacobson commented May 26, 2026

Summary

Follow-ups from run 26471836695. The previous PR (#14397) worked end-to-end where it mattered — Android gradle build went green in 8m 30s (track-player 4.1.2 + hermesc fix) and iOS made it deep into archive. Two real blockers remain.

1. iOS — fmt 11.0.2 ignores `-DFMT_USE_CONSTEVAL=0`

#14397 added `FMT_USE_CONSTEVAL=0` to the `fmt` target's `GCC_PREPROCESSOR_DEFINITIONS`. It didn't take effect because fmt 11.0.2 does not guard its detection block with `#ifndef FMT_USE_CONSTEVAL`:

```cpp
// include/fmt/base.h — fmt 11.0.2
// Detect consteval, ...
#if !defined(__cpp_lib_is_constant_evaluated)

define FMT_USE_CONSTEVAL 0

#elif FMT_CPLUSPLUS < 201709L

define FMT_USE_CONSTEVAL 0

... (several branches, none under #ifndef FMT_USE_CONSTEVAL)
#elif defined(__cpp_consteval)

define FMT_USE_CONSTEVAL 1

```

The elif chain unconditionally `#define`s the macro, clobbering my `-D`. fmt 11.2.0+ adds the missing `#ifndef` guard (fmtlib/fmt#4477); RN `0.83-stable` got the fmt 12.1.0 backport in facebook/react-native#56225 — but no equivalent backport exists for 0.79-stable yet.

Switch to patching the source. The detection chain already has an Apple-specific carve-out:

```cpp
#elif defined(apple_build_version) && apple_build_version < 14000029L

define FMT_USE_CONSTEVAL 0 // consteval is broken in Apple clang < 14.

```

Drop the `< 14000029L` clause via a Podfile post_install `gsub` so consteval is disabled for all Apple Clang builds, including Xcode 26's Apple Clang 17. fmt falls back to `constexpr` — the same code path that worked pre-Xcode-14.

2. Android — orphaned CodePush-era S3 sync, removed

Android RC + Prod gradle builds succeeded. Both then failed at the post-build artifact archive in `Fastfile:102`:

```
sh("aws s3 sync packages/mobile/android/app/build/outputs s3://audius-mobile-releasecandidate/android --delete")
fatal error: NoSuchBucket — The specified bucket does not exist
```

History trace:

  • #2913 (Mar 2023, "OTA Updates CI Flow") introduced this sync alongside `codepushDeployment = …` variables. It uploaded `app/build/outputs/` to per-channel S3 buckets (`audius-mobile`, `audius-mobile-releasecandidate`, `audius-mobile-staging-releasecandidate`, `audius-mobile-staging`) so the original CodePush OTA service could pull updates.
  • #11708 (May 2025, "Remove code-push") deleted CodePush itself but left this S3 sync orphaned in the Fastfile.
  • The current OTA pipeline (`Mobile OTA Release` jobs in `mobile.yml`) talks to a separate backend at `download.audius.co/mobile-ota` via `npx code-push release` from `packages/mobile/` — it does not read from these S3 buckets.
  • The buckets themselves have been turned down (returning `NoSuchBucket`), confirming no consumer remains.

Remove the dead code:

  • `packages/mobile/android/fastlane/Fastfile`: drop the `sudo pip install awscli` step, the `aws s3 sync` step, and the four `remoteDirectory = '…'` assignments that only fed it.
  • `.github/workflows/mobile.yml`: drop `Configure AWS credentials` from `Android Release Candidate Build & Upload` and `Android Production Build & Upload` — its only consumer was the removed sync. The OTA jobs still configure their own AWS credentials.

3. Re-trigger the release flow

  • `packages/mobile/package.json`: `1.5.184` → `1.5.185`
  • iOS `Info.plist` `CFBundleShortVersionString`: `1.1.197` → `1.1.198`
  • Android `versionName`: `1.1.533` → `1.1.534`

Test plan

  • Merge → version-check fires all 4 binary jobs
  • iOS RC + Prod compile `fmt` cleanly under Xcode 26 (look for "Patched Pods/fmt/include/fmt/base.h" in pod-install logs) and reach `pilot`
  • Android RC + Prod reach `upload_to_play_store` directly after gradle build (no AWS / S3 step in between)

🤖 Generated with Claude Code

raymondjacobson and others added 4 commits May 22, 2026 18:39
Two real failures surfaced in run 26319345276 after the displayer fix
in #14394 made fastlane log altool errors again:

### iOS RC + Prod — Apple now requires iOS 26 SDK

altool 409 Validation failed:

  This app was built with the iOS 18.5 SDK. All iOS and iPadOS apps
  must be built with the iOS 26 SDK or later, included in Xcode 26
  or later, in order to be uploaded to App Store Connect or submitted
  for distribution. (ID: 287c542e-…)

The `macos-15` runners default to Xcode 16.4 (iOS 18.5 SDK). Switch
both iOS upload jobs to `macos-26` (Tahoe, GA), which has Xcode 26
as the only supported major.

### Android RC + Prod — hermesc location anchored at the wrong root

  Couldn't determine Hermesc location. Please set `react.hermesCommand`
  to the path of the hermesc binary file.
  node_modules/react-native/sdks/hermesc/%OS-BIN%/hermesc

The previous PR restored `react.root` to its default
(`../..` = `packages/mobile`) to fix the Hermes JS bundle's entryFile
lookup. The same plugin uses `root` to detect the prebuilt hermesc
binary (PathUtils.kt#detectOSAwareHermesCommand) and only checks
`root/node_modules/react-native/sdks/hermesc/...`. Since RN is
hoisted to the monorepo node_modules, that lookup fails.

Set `react.hermesCommand` explicitly to the hoisted prebuilt path:

  $rootDir/../../../node_modules/react-native/sdks/hermesc/%OS-BIN%/hermesc

The `%OS-BIN%` placeholder is substituted at runtime by the plugin
to `linux64-bin` / `osx-bin` / `win64-bin` as appropriate. Verified
those bin directories exist in node_modules/react-native/sdks/hermesc/
in this branch.

### Housekeeping

- `Gemfile.lock` dependency line aligned to `= 2.234.0` to match the
  Gemfile pin from #14394 (the squash-merge left the lock at the
  pre-pin `>= 2.228.0` constraint).
- Bump versions to re-fire the build matrix:
  `1.5.182 -> 1.5.183`, iOS `1.1.195 -> 1.1.196`, Android `1.1.531
  -> 1.1.532`.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
After #14396 the Hermesc + Xcode 26 runner fixes both worked. The
binary build matrix now actually compiles, and surfaced two remaining
upstream-library incompatibilities with React Native 0.79 + Xcode 26.

### Android RC + Prod — react-native-track-player onBind signature

Kotlin compile failed on the bundled `react-native-track-player`:

  e: .../trackplayer/service/MusicService.kt:764:5
     'onBind' overrides nothing.

RN 0.79's HeadlessJsTaskService now declares:
  override fun onBind(intent: Intent): IBinder? = null
                            ^^^^^^         ^^^^^^^^^^

react-native-track-player 4.0.1 still has the old signature:
  override fun onBind(intent: Intent?): IBinder
                            ^^^^^^^         ^^^^^^^

Kotlin parameter types must match the override exactly (return types
can be covariant, parameter types cannot). 4.1.2 already matches
RN 0.79's signature, so bumping the dep is the fix.

  packages/mobile/package.json: 4.0.1 -> 4.1.2
  package-lock.json regenerated.

### iOS RC + Prod — fmt consteval error under Xcode 26 / Apple Clang

xcodebuild archive failed on the fmt Pod:

  Pods/fmt/include/fmt/format-inl.h:59: error: call to consteval
  function 'fmt::basic_format_string<...>' is not a constant expression
     59 |   fmt::format_to(it, FMT_STRING("{}{}"), message, SEP);

RN 0.79 pins fmt 11.0.2 via third-party-podspecs/fmt.podspec. Apple
Clang in Xcode 26 enforces stricter consteval evaluation than the
version 11.0.2 was written against. Fixed upstream in fmt 11.1+ (RN
0.80 picks up the newer fmt); for 0.79 the workaround is to define
FMT_USE_CONSTEVAL=0 on the fmt target, falling back to the constexpr
implementation.

Add a Podfile post_install hook that injects the define for the fmt
target only. CI's existing `bundle exec pod install` step will pick
up the change without lockfile churn.

### Re-trigger the release flow
- packages/mobile/package.json: 1.5.183 -> 1.5.184
- iOS Info.plist CFBundleShortVersionString: 1.1.196 -> 1.1.197
- Android versionName: 1.1.532 -> 1.1.533

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ry-4

# Conflicts:
#	packages/mobile/android/app/build.gradle
#	packages/mobile/ios/AudiusReactNative/Info.plist
#	packages/mobile/package.json
…non-fatal

Two follow-ups from run 26471836695. The previous PR (#14397) bumped
react-native-track-player to 4.1.2 and pinned the hermesc path — both
worked end-to-end (Android gradle build went green in 8m 30s, iOS
made it deep into archive). Two real blockers remain:

### iOS — fmt 11.0.2 ignores -DFMT_USE_CONSTEVAL=0

My previous attempt added FMT_USE_CONSTEVAL=0 to the fmt target's
GCC_PREPROCESSOR_DEFINITIONS. It didn't take effect because fmt 11.0.2
does NOT guard its FMT_USE_CONSTEVAL detection block with
`#ifndef FMT_USE_CONSTEVAL`. The `#if !defined(__cpp_lib_is_constant_evaluated)`
elif chain in include/fmt/base.h unconditionally redefines the macro,
clobbering the -D flag. (fmt 11.2.0+ adds the ifndef guard;
fmtlib/fmt#4477 / RN PR #56225 backports fmt 12.1.0 to 0.83-stable.)

Switch to patching the source instead. The detection chain already
has an Apple-specific carve-out:

  #elif defined(__apple_build_version__) && __apple_build_version__ < 14000029L
  #  define FMT_USE_CONSTEVAL 0  // consteval is broken in Apple clang < 14.

Drop the `< 14000029L` clause via Podfile post_install so consteval
is disabled for ALL Apple Clang builds, including Xcode 26's
Apple Clang 17. fmt falls back to constexpr (same code path that
was used pre-Xcode-14), which compiles cleanly.

### Android — aws s3 archive is best-effort

Android gradle build succeeded; both jobs (RC + Prod) failed at the
post-build artifact archive:

  fatal error: An error occurred (NoSuchBucket) when calling the
  ListObjectsV2 operation: The specified bucket does not exist

Buckets s3://audius-mobile and s3://audius-mobile-releasecandidate
do not exist in us-east-1 (or the CI credentials no longer have
access). The S3 sync is a side-archive of `app/build/outputs/` and
is not required for shipping to the Play Store via
`upload_to_play_store` (which runs immediately after).

Append `|| true` to the sync command so a missing/inaccessible bucket
doesn't fail the lane. If the side-archive is actually needed,
restoring it is a separate (ops) follow-up.

### Re-trigger the release flow
- packages/mobile/package.json:           1.5.184 -> 1.5.185
- iOS Info.plist CFBundleShortVersionString: 1.1.197 -> 1.1.198
- Android versionName:                     1.1.533 -> 1.1.534

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 26, 2026

⚠️ No Changeset found

Latest commit: 86845f2

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

raymondjacobson and others added 2 commits May 27, 2026 11:24
The S3 sync at android/fastlane/Fastfile lines 101-102 was introduced
in #2913 (Mar 2023, "OTA Updates CI Flow") as the artifact-archive
step that fed the original CodePush OTA backend. CodePush itself was
removed in #11708 (May 2025, "Remove code-push") but this step was
left orphaned. The current OTA pipeline (Mobile OTA Release jobs in
mobile.yml) talks to a separate OTA backend at download.audius.co/
mobile-ota via `npx code-push release` from packages/mobile/ — it
does not read from these S3 buckets.

The buckets s3://audius-mobile{,-releasecandidate,-staging,-staging-
releasecandidate} have already been turned down (run 26471836695
fails with NoSuchBucket), confirming no consumer remains.

Remove the dead code instead of papering over with `|| true`:
- android/fastlane/Fastfile:
  - drop `sudo pip install awscli` step
  - drop `aws s3 sync … s3://…/android --delete` step
  - drop the four `remoteDirectory = '…'` assignments (only used
    by the removed sync)
- .github/workflows/mobile.yml:
  - drop `Configure AWS credentials` from `Android Release Candidate
    Build & Upload` and `Android Production Build & Upload` (only
    consumer was the now-removed sync). OTA jobs still configure
    their own AWS credentials.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ry-5

# Conflicts:
#	packages/mobile/android/app/build.gradle
#	packages/mobile/ios/AudiusReactNative/Info.plist
#	packages/mobile/ios/Podfile
#	packages/mobile/package.json
@gitguardian
Copy link
Copy Markdown

gitguardian Bot commented May 27, 2026

⚠️ GitGuardian has uncovered 1 secret following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

🔎 Detected hardcoded secret in your pull request
GitGuardian id GitGuardian status Secret Commit Filename
9412812 Triggered Generic Password 86845f2 .github/workflows/identity.yml View secret
🛠 Guidelines to remediate hardcoded secrets
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secret safely. Learn here the best practices.
  3. Revoke and rotate this secret.
  4. If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.

To avoid such incidents in the future consider


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

@raymondjacobson raymondjacobson merged commit 808090a into main May 27, 2026
3 checks passed
@raymondjacobson raymondjacobson deleted the rj-mobile-release-retry-5 branch May 27, 2026 18:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant