fix(mobile): unblock release flow — Android Hermes entryFile + iOS fastlane Xcode 26#14394
Conversation
…ease When I added the Android gradle plugin path overrides for the hoisted node_modules in PR #14365, I also moved `react.root` to the monorepo root. That broke the React-Native Gradle plugin's entryFile lookup, which is anchored at `root` — it ended up searching for index.js at the monorepo root instead of packages/mobile/index.js. The Android release/production builds in run 26316494213 failed with: > Task :app:createBundleReleaseCandidateReleaseJsAndAssets FAILED - In plugin 'com.facebook.react' type 'com.facebook.react.tasks.BundleHermesCTask' property 'entryFile' specifies file '/home/runner/work/apps/apps/index.js' which doesn't exist. Restore the default `root = ../..` (packages/mobile) so entryFile resolves to packages/mobile/index.js. The other explicit overrides (reactNativeDir, codegenDir, cliFile) are absolute paths and still point at the hoisted node_modules — unaffected. Bump versions again so version-check fires the binary build jobs: - packages/mobile/package.json: 1.5.181 -> 1.5.182 - iOS Info.plist CFBundleShortVersionString: 1.1.194 -> 1.1.195 - Android versionName: 1.1.530 -> 1.1.531 Note: in the same run, both iOS jobs successfully archived (gym ~20min) but failed at the `pilot` TestFlight upload step with `undefined method 'each' for nil` in fastlane's itunes_transporter.rb — that's a separate fastlane error-reporting bug (fastlane#21455) masking the real Transporter error. Not addressed here; the iOS build itself works. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
|
Caution Review the following alerts detected in dependencies. According to your organization's Security Policy, you must resolve all "Block" alerts before proceeding. It is recommended to resolve "Warn" alerts too. Learn more about Socket for GitHub.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
The TestFlight upload step in the iOS RC + Prod builds crashes with fastlane_core/itunes_transporter.rb:266:in 'execute': [!] undefined method 'each' for nil (NoMethodError) The build itself succeeds (gym archives the IPA in ~20 min), then pilot calls altool, which fails — but fastlane crashes trying to log the failure, hiding the real upload error. Root cause: Xcode 26 changed altool's error prefix from "*** Error:" to "ERROR:". fastlane 2.225.0's ERROR_REGEX (`/\*\*\* Error:\s+(.+)/`) no longer matches, so `error_line_index = nil`. The fallback path then does `@all_lines[-20..-1].each`, but under Ruby 3.x the slice returns nil when the array has fewer than 20 elements (Ruby 3.0 changed Array#[] to no longer clamp out-of-range negative starts), so `.each` blows up on nil. Fixed upstream in fastlane: - 455bb5e1 (2.228.0): rewrites the displayer to iterate `@all_lines` directly, removing the broken slice - 744b01ce (2.230.0): updates ERROR_REGEX to also match "ERROR:" so Xcode 26 altool errors get parsed correctly Bump the Gemfile pin from 2.225.0 to 2.234.0 (latest at time of writing, includes both fixes). Lockfile updated to match. The Android Gemfile is already `>= 2.220.0` and locks at 2.231.1, so it's unaffected. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
b0de73c to
8f47f56
Compare
…14396) ## Summary Two real failures surfaced in [run 26319345276](https://github.com/AudiusProject/apps/actions/runs/26319345276) after the displayer fix in #14394 made fastlane log altool errors again. ### 1. iOS RC + Prod — Apple now requires iOS 26 SDK altool now returns: \`\`\` ERROR: Validation failed (409) SDK version issue. 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-3971-4158-b3c3-71eb1fcd6eb3) \`\`\` The \`macos-15\` runners ship Xcode 16.4 (iOS 18.5 SDK) by default — that's why gym archived fine but altool rejected the upload. Switch both iOS jobs to \`macos-26\` (Tahoe, GA), which has Xcode 26 as the only supported major. ### 2. Android RC + Prod — hermesc binary lookup also 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 \`\`\` #14394 restored \`react.root\` to its default (\`../.. = packages/mobile\`) to unblock the Hermes JS bundle's \`entryFile\` lookup. But the same gradle plugin uses \`root\` for hermesc detection too (\`PathUtils.kt#detectOSAwareHermesCommand\` → only checks \`root/node_modules/react-native/sdks/hermesc/...\`), and RN is hoisted to the monorepo \`node_modules\` so that path doesn't exist. Set \`react.hermesCommand\` explicitly to the hoisted prebuilt: \`\`\`groovy hermesCommand = "\$rootDir/../../../node_modules/react-native/sdks/hermesc/%OS-BIN%/hermesc" \`\`\` The \`%OS-BIN%\` placeholder is substituted by the plugin at runtime (linux64-bin / osx-bin / win64-bin). Verified all three subdirs exist in \`node_modules/react-native/sdks/hermesc/\` after \`npm ci\`. ### Housekeeping - \`packages/mobile/ios/Gemfile.lock\`: dependency line aligned to \`= 2.234.0\` to match the Gemfile pin from #14394. (The squash-merge of #14394 amended the Gemfile to a pin but kept the lock at the pre-pin \`>= 2.228.0\` constraint; CI was re-resolving every build.) - Versions bumped to re-fire the build matrix: - \`packages/mobile/package.json\`: \`1.5.182\` → \`1.5.183\` - iOS Info.plist \`CFBundleShortVersionString\`: \`1.1.195\` → \`1.1.196\` - Android \`versionName\`: \`1.1.531\` → \`1.1.532\` ## Test plan - [ ] Merge → version-check fires all 4 binary jobs - [ ] Android RC + Prod reach \`fastlane releaseCandidate\` / \`prod\` (no \`Couldn't determine Hermesc location\`) - [ ] iOS RC + Prod reach App Store Connect (no \`SDK version issue\` 409) - [ ] Slack notification fires from the success branch of each iOS / Android job 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Summary
Fixes both halves of the broken release run 26316494213 so a single re-release can ship both platforms.
1. Android RC + Prod — Hermes entryFile pointed at monorepo root
Both Android builds failed at the JS bundle task with:
```
A problem was found with the configuration of task ':app:createBundleReleaseCandidateReleaseJsAndAssets' (type 'BundleHermesCTask').
specifies file '/home/runner/work/apps/apps/index.js' which doesn't exist.
```
When I added the Android gradle path overrides for the hoisted node_modules in #14365, I also set `react.root = file("../../../../")` (monorepo root). The React-Native Gradle plugin anchors `entryFile` to `root` (`PathUtils.kt#detectEntryFile` → `File(reactRoot, "index.js")`), so it searched for `/home/runner/work/apps/apps/index.js` instead of `packages/mobile/index.js`.
Drop the `root` override and let it default to `../..` (= `packages/mobile`, where `index.js` lives). The explicit `reactNativeDir`, `codegenDir`, and `cliFile` overrides are absolute paths and continue to point at the hoisted node_modules.
2. iOS RC + Prod — fastlane crash on Xcode 26 altool errors
Both iOS jobs successfully archived the IPA (gym ~20 min) but died at the `pilot` TestFlight upload step with:
```
fastlane_core/itunes_transporter.rb:266:in 'execute':
undefined method 'each' for nil (NoMethodError)
```
Root cause is two upstream bugs interacting:
Both upstream bugs are fixed:
Bump the iOS Gemfile pin from `~> 2.225.0` to `2.234.0` (latest at time of writing, includes both fixes). `Gemfile.lock` updated to match. Android's Gemfile is already `>= 2.220.0` and locks at 2.231.1 — unaffected.
If altool itself has a real upload error remaining, it will at least surface in the logs after this lands; can be addressed in a follow-up.
3. Re-trigger the release flow
Test plan
🤖 Generated with Claude Code