Skip to content

feat(you): show the commit SHA in the version footer - #869

Open
bmc08gt wants to merge 3 commits into
mainfrom
feat/version-footer-commit-sha
Open

bmc08gt wants to merge 3 commits into
mainfrom
feat/version-footer-commit-sha

Conversation

@bmc08gt

@bmc08gt bmc08gt commented Sep 25, 2026 •

Copy link
Copy Markdown
Collaborator

The You screen footer's build number is Xcode Cloud's run counter (CFBundleVersion), so it maps to no commit without an App Store Connect lookup. The footer now shows the first 10 characters of the commit SHA on a second line, in every build, App Store and TestFlight included:

Version 2026.9.3 • Build 272
2acfecffeb • beta

This matches Android's footer from code-payments/code-android-app#1571. Line 2 ends with • development in a DEBUG build and • beta on TestFlight. An App Store build shows no track, so its line 2 is only the hash. A build with uncommitted changes shows 2acfecffeb*. With no commit, the footer falls back to the old single line.

How the SHA gets into the build

Scripts/write_commit_xcconfig writes GIT_COMMIT_SHA = <sha> to Configurations/commit.local.xcconfig, which is gitignored and optionally included by base.xcconfig. The Flipcash Info.plist exposes it as FCGitCommit, and AppMeta.commit reads it with the same unknown fallback as AppMeta.build.

The script runs from two places:

  • Xcode Cloud: the new ci_scripts/ci_pre_xcodebuild.sh calls it before every xcodebuild. It takes CI_COMMIT and never appends *, since package resolution and the generated Google plist can touch the clone's working tree.
  • Local builds: a second build pre-action on the Flipcash scheme, next to "Pull Secrets". It uses git rev-parse HEAD and appends * when git diff --quiet HEAD reports changes to tracked files, the same rule Android uses. Untracked files don't count. GoogleService-Info.plist is excluded because it's tracked but the "Generate Google" phase rewrites it from secrets on every build. On Xcode Cloud this pre-action also runs, but CI_COMMIT takes precedence there too.

I used a scheme pre-action rather than a Run Script phase for two reasons. Pre-actions run before build settings are resolved, so the value lands in the same build; a Run Script phase would always be one build behind. And under ENABLE_USER_SCRIPT_SANDBOXING, a Run Script phase can't read .git. A local build confirmed the built Info.plist had FCGitCommit set to the current SHA and CFBundleVersion still at 272.

The script never fails the build. If it can't find a 40-character SHA, it deletes any stale file and base.xcconfig falls back to unknown. A clone that never ran the script gets the same fallback.

CFBundleVersion is untouched, so SessionAuthenticator.requiresUpgrade and the server's minBuildNumber behave as before.

App changes

  • BuildCommit (FlipcashCore) parses the stamp and produces the 10-character label with the * marker. AppMeta.versionFooter assembles the two lines. BuildCommitTests covers the cut, the marker, unusable stamps, and each footer shape.
  • ReleaseTrack picks the track. TestFlight and the App Store run the same Release binary, so it reads StoreKit's AppTransaction environment: .sandbox means TestFlight. The You screen reads it once when it appears; if StoreKit can't answer, no track is shown. ReleaseTrackTests covers the mapping.
  • The footer tap still drives only the 10-tap beta unlock.
  • ErrorReporting.initialize() adds the raw stamp (including *) to Bugsnag's app metadata tab as commit.

CFBundleVersion is Xcode Cloud's run counter, so "Build 272" maps to no
commit without an App Store Connect lookup. The footer now reads
"Version 2026.9.3 • Build 272 • 2acfecffeb" in every build, matching the
Android change.

Scripts/write_commit_xcconfig writes GIT_COMMIT_SHA to a gitignored
Configurations/commit.local.xcconfig, which Info.plist exposes as
FCGitCommit. It runs from the Flipcash scheme's build pre-action and from
the new ci_scripts/ci_pre_xcodebuild.sh. On Xcode Cloud it takes CI_COMMIT
and never adds -dirty; locally it uses git rev-parse HEAD plus -dirty when
git status reports changes. base.xcconfig defaults the setting to
"unknown", so a clone that never ran the script still builds.

BuildCommit parses the stamp and owns the 10-character display. Tapping
the footer copies the full SHA and shows "Copied" through the existing
toast; the beta-unlock countdown still wins on its last taps. Bugsnag
events carry the raw stamp as app.commit.
@bmc08gt bmc08gt self-assigned this Sep 25, 2026
Android's footer changed in code-payments/code-android-app#1571, and the
two apps share one format:

    Version 2026.9.3 • Build 272
    2acfecffeb

- The commit moves to a second line, followed by " • <track>" when there
  is one. iOS has no release track yet, so its second line is the hash.
  Without a commit the footer is the old single line.
- A dirty build is marked "*" instead of "-dirty", and only changes to
  tracked files count, as on Android (git diff --quiet HEAD). The
  generated GoogleService-Info.plist is excluded because the Generate
  Google phase rewrites it on every build with secrets.
- Tap-to-copy is gone; the footer tap drives only the beta unlock count.
Line 2 of the footer now ends with ` • development` in a DEBUG build and
` • beta` on TestFlight, matching Android. App Store builds show no track.

TestFlight and the App Store run the same Release binary, so the track
comes from StoreKit's AppTransaction environment (`.sandbox` on
TestFlight), read once when the You screen appears. If StoreKit can't
answer, no track is shown.
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.

1 participant