Skip to content

fix(preprod): Parse dotted Apple build numbers instead of dropping them#645

Merged
trevor-e merged 4 commits into
mainfrom
telkins/fix-preprod-apple-build-number-parsing
Jul 9, 2026
Merged

fix(preprod): Parse dotted Apple build numbers instead of dropping them#645
trevor-e merged 4 commits into
mainfrom
telkins/fix-preprod-apple-build-number-parsing

Conversation

@trevor-e

@trevor-e trevor-e commented Jul 8, 2026

Copy link
Copy Markdown
Member

Summary

  • app_info.build (CFBundleVersion) is only guaranteed to be a plain integer for Android's versionCode. Apple allows up to three dot-separated non-negative integers (e.g. "1.2.3"), which the previous isdigit() check silently turned into None.
  • That broke Sentry's build_number tiebreaker used to sort/find the latest build within a version, and also made those artifacts non-installable on the Sentry side (worked around there separately).
  • Pack multi-component builds into a single sortable int by zero-padding each component to a fixed width; the existing plain-integer path (Android, and simple Apple builds) is unchanged.
  • Also send the raw, unparsed build string as build_number_raw so Sentry can store/display the exact value later without another launchpad deploy. Sentry currently ignores unrecognized fields, so this is safe to ship ahead of that follow-up work.
  • Adds unit tests for _parse_build_number (plain ints unchanged, dotted values packed and correctly ordered, malformed input falls back to None) and for _prepare_update_data's wiring of build_number/build_number_raw.

Known limitation (flagged in review): plain-integer build numbers stay small while packed dotted values are much larger, so if the same app_id/build_version ever has builds in both conventions, build_number alone doesn't reliably order them. This can't be resolved in launchpad — a single artifact update has no visibility into sibling artifacts' formats, and unifying the magnitude would break backward compatibility with every already-stored plain-integer build_number. The authoritative fix belongs in Sentry's tiebreak query once build_number_raw is available there (comparing the raw string directly for mixed-format cases), which is being scoped as a follow-up. Documented inline on _parse_build_number.

Test plan

  • make test-unit (3 pre-existing, unrelated failures in Android APK signing/Swift symbol tests — confirmed present without this change)
  • make check

app_info.build (CFBundleVersion) is only guaranteed to be a plain integer
for Android's versionCode. Apple allows up to three dot-separated
non-negative integers (e.g. "1.2.3"), which the previous isdigit()
check silently turned into None. That broke Sentry's build_number
tiebreaker for sorting/finding the latest build within a version, and
also made those artifacts non-installable on the Sentry side.

Pack multi-component builds into a single sortable int by zero-padding
each component to a fixed width, while leaving the existing
plain-integer path unchanged. Also send the raw, unparsed build string
alongside it as build_number_raw so Sentry can store/display the exact
value later without another launchpad deploy; Sentry currently ignores
unrecognized fields, so this is safe to ship ahead of that work.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@sentry

sentry Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

📲 Install Builds

iOS

🔗 App Name App ID Version Configuration
HackerNews com.emergetools.hackernews 3.8 (1) Release

Android

🔗 App Name App ID Version Configuration
Hacker News com.emergetools.hackernews 1.0.2 (13) Release

⚙️ launchpad-test-android Build Distribution Settings

Covers _parse_build_number directly (plain ints unchanged, dotted Apple
CFBundleVersion values packed and correctly ordered, malformed input
still falls back to None) and _prepare_update_data's wiring of
build_number/build_number_raw into the update payload.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Comment thread src/launchpad/artifact_processor.py Outdated
unchanged. Apple's CFBundleVersion also allows up to three dot-separated
non-negative integers (e.g. "1.2.3"); those are packed into a single int by
zero-padding each component to `component_width` digits, which preserves
correct ordering as long as no component reaches 10**component_width.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This field is stored as a BoundedBigInt in Sentry so it should be safe to pad like this.

component_width was a function parameter but nothing ever called
_parse_build_number with a non-default value — it's an implementation
detail of the packing scheme, not something callers should tune.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@trevor-e trevor-e marked this pull request as ready for review July 8, 2026 19:10

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want reviews to match your repository better? Bugbot Learning can learn team-specific rules from PR activity. A team admin can enable Learning in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit a08c7e0. Configure here.

Comment thread src/launchpad/artifact_processor.py
A reviewer correctly flagged that plain-integer build numbers stay
small while packed dotted values are much larger, so mixing both
conventions within the same app_id/build_version isn't reliably
ordered by this int alone.

This can't be fixed here: a single artifact update has no visibility
into sibling artifacts' formats, and unifying the magnitude would
break backward compatibility with every already-stored plain-integer
build_number. The authoritative fix belongs in Sentry's tiebreak
query, comparing the raw build string once build_number_raw is
available there, with this int remaining a fast common-case sort key.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
trevor-e added a commit to getsentry/sentry that referenced this pull request Jul 8, 2026
## Summary
- Launchpad will start packing multi-component Apple `CFBundleVersion`
values (e.g. `1.2.3`) into a large synthesized int for `build_number`
(getsentry/launchpad#645), which would otherwise show up as an odd,
unreadable number anywhere a build number is displayed.
- Adds `build_number_raw` — the original unparsed build string — so
those surfaces can show the real value instead. Stored in
`PreprodArtifactMobileAppInfo.extras` (no migration needed) and exposed
via `BuildDetailsAppInfo`.
- Safe to deploy ahead of the launchpad change: it's a no-op until
launchpad starts sending the field.
- Frontend changes to consume this are a separate follow-up PR.

## Test plan
- [x] New unit tests covering storage, the API response, and display
formatting
- [x] `prek` passing

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
@trevor-e trevor-e merged commit 173b85e into main Jul 9, 2026
27 checks passed
@trevor-e trevor-e deleted the telkins/fix-preprod-apple-build-number-parsing branch July 9, 2026 17:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants