Skip to content

[build-tools] report app and build version from final archive#3499

Open
kadikraman wants to merge 8 commits intomainfrom
kadikraman/report-actual-version
Open

[build-tools] report app and build version from final archive#3499
kadikraman wants to merge 8 commits intomainfrom
kadikraman/report-actual-version

Conversation

@kadikraman
Copy link
Contributor

Why

For projects that don't use CNG, the app version and build number can be evaluated dynamically in the native code. However we detect and save the value when the build is first created (so the actual resolved value is never shown).

Screenshot 2026-03-12 at 13 26 31

See https://exponent-internal.slack.com/archives/C02123T524U/p1772205677890089

How

After the build is finished, read the actual versions for app and build from the archive and updater the eas metadata.

Test Plan

Unit and integration tests.

Also tested locally when possible:

  • APK: aapt2 dump badging ~/Downloads/application-ba69caff-3ddd-45b3-b766-c74eed33aea3.apk  (& parse versionName / versionCode from output)
  • AAB: bundletool dump manifest --bundle ~/Downloads/application-083f9788-b177-4094-8f06-7b52eb2ef709.aab  (& parse versionName / versionCode from output)
  • IPA: use existing readIpaInfoAsync (NOT tested locally)
  • iOS Simulator app: plutil -convert xml1 -o - <path-to>.app/Info.plist | grep -A1 'CFBundleShortVersionString\|CFBundleVersion'
Screenshot 2026-03-12 at 16 14 11

@kadikraman kadikraman requested a review from sjchmiela March 12, 2026 16:18
@github-actions
Copy link

Subscribed to pull request

File Patterns Mentions
**/* @douglowder

Generated by CodeMention

@kadikraman kadikraman changed the title Kadikraman/report actual version [build-tools] report app and build version from final archive Mar 12, 2026
@codecov
Copy link

codecov bot commented Mar 12, 2026

Codecov Report

❌ Patch coverage is 63.55140% with 39 lines in your changes missing coverage. Please review.
✅ Project coverage is 53.60%. Comparing base (c51ac27) to head (3e90915).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
...tools/src/steps/functions/reportResolvedVersion.ts 64.29% 30 Missing ⚠️
packages/build-tools/src/builders/android.ts 33.34% 8 Missing ⚠️
packages/build-tools/src/utils/artifacts.ts 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3499      +/-   ##
==========================================
+ Coverage   53.56%   53.60%   +0.04%     
==========================================
  Files         815      816       +1     
  Lines       34566    34670     +104     
  Branches     7175     7198      +23     
==========================================
+ Hits        18513    18580      +67     
- Misses      15971    16009      +38     
+ Partials       82       81       -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

@sjchmiela sjchmiela left a comment

Choose a reason for hiding this comment

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

Also: you're rightly adding this to eas/build. This is not the only place that the build process is defined. There's also

await ctx.runBuildPhase(BuildPhase.UPLOAD_APPLICATION_ARCHIVE, async () => {
await uploadApplicationArchive(ctx, {
patternOrPath: resolveArtifactPath(ctx),
rootDir: ctx.getReactNativeProjectDirectory(),
logger: ctx.logger,
});
});
and
await ctx.runBuildPhase(BuildPhase.UPLOAD_APPLICATION_ARCHIVE, async () => {
await uploadApplicationArchive(ctx, {
patternOrPath: ctx.job.applicationArchivePath ?? 'android/app/build/outputs/**/*.{apk,aab}',
rootDir: ctx.getReactNativeProjectDirectory(),
logger: ctx.logger,
});
});
. Passing inputs/outputs around there should be easier since the orchestrating layer is just JS.

Comment on lines +65 to +70
const artifactPattern = iosJob.applicationArchivePath ?? 'ios/build/*.ipa';
const artifacts = await findArtifacts({
rootDir: workingDirectory,
patternOrPath: artifactPattern,
logger,
});
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of looking for artifacts again, could we use value from the previous step?

Right above these functions we usually do createFindAndUploadBuildArtifactsBuildFunction. We could add output to it that would point to the first (?) uploaded application archive. Then you would use that output as an input to this, sort of like we do in

callInputs: {
resolved_eas_update_runtime_version:
'${ steps.calculate_eas_update_runtime_version.resolved_eas_update_runtime_version }',
},
.

@github-actions
Copy link

❌ It looks like a changelog entry is missing for this PR. Add it manually to CHANGELOG.md.
⏩ If this PR doesn't require a changelog entry, such as if it's an internal change that doesn't affect the user experience, you can add the "no changelog" label to the PR.

@kadikraman kadikraman requested a review from sjchmiela March 13, 2026 11:15
Copy link
Contributor

@sjchmiela sjchmiela left a comment

Choose a reason for hiding this comment

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

nit: not sure if "report" is the right verb here? like… you usually report bugs… maybe "update" is better?

logger,
});

return applicationArchives[0];
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: let's return all archives and pick only the first one in the consumer?

Comment on lines +207 to +208
appVersion: appVersion ?? null,
appBuildVersion: appBuildVersion ?? null,
Copy link
Contributor

Choose a reason for hiding this comment

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

honest question — if appVersion is missing here, but it is present in a metadata, is this going to clear the appVersion or leave it as it is?

Comment on lines +180 to +181
appVersion?: string;
appBuildVersion?: string;
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
appVersion?: string;
appBuildVersion?: string;
appVersion: string | undefined;
appBuildVersion: string | undefined;

Less easy to forget

});
});

if (archivePath) {
Copy link
Contributor

Choose a reason for hiding this comment

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

We need it to be inside a build phase, otherwise if the users are oging to see "Unnamed build phase" logs which I've seen people complain about before. Maybe we can move it inside upload application archive?

});
});

if (archivePath) {
Copy link
Contributor

Choose a reason for hiding this comment

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

same

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