Integrating Into CI

Uploading from CI

With Emerge's CI integration, you can configure automated comparisons (PR Comments / Status Checks) to show in your VCS, making it easy for everyone in your organization to be aware of your performance metrics.

For CI builds to work, we require additional metadata to be included with the upload that describes where the build was generated. Following a standard Git Flow setup, this would typically be:

  • Base build: a build from the main or master branch
  • Head build: a build from a development branch, like a Pull Request

We recommend configuring this in two steps:

  1. Create a PR to configure uploading a base build. Once this PR is merged, it will upload a base build which future pull requests can use as a base.
  2. Create a second PR to configure uploading head builds. Uploading head builds is most commonly done from CI that is run on each pull request.

πŸ“˜

The Emerge Fastlane Plugin (iOS) and Emerge Gradle Plugin (Android) make it easy to integrate Emerge into your CI pipeline. If your team doesn't use Fastlane or Gradle, you also have the option to use our REST API directly.

Metadata fields

The following metadata fields need to be included with your uploads in CI:

FieldRequired
filenameYes (both)
branchYes (both)
shaYes (both)
repoNameYes (both)
tagNo (defaults to release if not provided)
prNumberOnly for head builds
baseShaOnly for head builds
previousShaNo, but encouraged for all builds (required for certain features)

Tags

tag is an optional parameter that defaults to release if not provided when uploading. We recommend changing this value for head builds (eg using pull_request) and setting it to default for builds of your default branch.

You can set this value to anything you'd like. For example, you might want to track sizes per device architecture using x86_64 and arm64 tags.

SHA and base SHA

The sha and baseSha parameters are used to provide Emerge information about the position of your build within your version control system structure. Both values should be sent using the SHA's long form. If you send a shortened SHA value this may result in errors.

The sha field should be the commit SHA that your upload was built from. This represents the HEAD position for the build, whether the build is on main or a branch.

The baseSha field is used specifically for branch builds. This field represents the point in your git tree that your branch was created from, allowing Emerge to identify all the changes on a branch. The baseSha should remain the same for all builds on a branch, unless the branch is rebased.

Previous SHA

The previousSha parameter is just like the sha param, but for the commit before the current one (in git terms: HEAD^).

It similarly should be sent using the SHA's long form.

We use this value to stitch together a historical relationship across your uploads, without needing code access in your repository. This field enables new features like Snapshot History which allow you to conveniently see changes over time!

Testing the Integration

On a build, you can see the status of your integration by clicking Actions (top-right of screen) > Emerge Metadata > Test Git Integration

Which builds should be uploaded?

For reliable PR diffs, we recommend uploading a branch build after pushing to a PR and when PRs are merged back to your default branch, i.e. main or master. Builds from your default branch act as base builds for comparison against branch builds.

It's also important to only compare builds generated from the same (or very similar) build configuration. For example, comparing a debug build against a release build will show unexpected results.

🚧

Unique apps per SHA

Emerge will compare uploads by SHA then appId (packageName on Android, bundleId on iOS) to ensure accuracy. It’s important to make sure there aren’t multiple uploads from the same commit SHA with the same appId, as this could result in inaccurate comparisons.

For example, if you upload a debug and release build on each commit, one should be com.company.app.debug and the other should be com.company.app. Otherwise, the release build could be compared against the debug build, resulting in incorrect comparisons.

If your build system does not have separate appIds, you can use the parameter appIdSuffix for iOS uploads (which is an option in the fastlane action) and applicationIdSuffix for Android apps.

iOS

Test builds

Test builds for running unit tests in CI are created by the xcodebuild test command and generally use the Debug configuration and target the simulator architecture.

Emerge supports processing these builds with the caveat that the app size and performance may be inaccurate for what your user will see due to skipped compiler optimizations and the target architecture format. Comparisons will still be accurate and allow you to find unexpected size increases, potential savings, and unused code.

Archive builds

Archive builds are created by xcodebuild archive and are the most accurate representations of app size. These can be used to track size over time or generate PR diffs.

If your app supports iOS 10 or earlier you'll be building multiple architectures when submitting to the App Store. To save time when building for Emerge you can optionally disable the 32-bit architecture since only one CPU slice is needed to measure app size.

Android

Debug builds

Debug builds are created by using debug Gradle build variants.

Emerge supports processing these builds with the caveat that the app size and performance may be inaccurate for what your user will see. For example, Proguard/R8 code optimizations are disabled by default for debug builds. It's also likely that the shrinkResources Gradle configuration is disabled. Comparisons will still be accurate and allow you to find unexpected size increases, potential savings, and unused code.

Release builds

Release builds are created by using release Gradle build variants.

We recommend uploading release builds with Proguard/R8 optimizations enabled, as well as shrinkResources turned on.

AAB vs APK

Emerge supports both .aab and .apk formats, however, diffs must be between builds of the same format.

We recommend uploading AAB builds as they are now required for new apps (as of August 2021). For AAB builds, Emerge will analyze the outputted APKs Google Play would serve for your AAB on a Pixel 5 running Android 11.

Special notes for cross-platform Monorepos

Monorepos, specifically those that contain both iOS and Android projects, introduce some complexity into CI uploads.

Emerge relies on a base build being present for size, performance, and snapshot checks. If you open a pull request with commit SHA bar against base commit SHA foo, we first need to find the Emerge build associated with commit foo. For a Monorepo setup, this can present a challenge if the base commit for the pull request did not trigger a build for the respective platform, e.g. an iOS pull request was branched from an Android commit.

To ensure every code change has a base to compare against, make sure to upload both iOS and Android builds as part of the main branch push. In a GitHub workflow, this looks like:

name: Emerge Android upload

on:
  push:
    branches: [ main ]
    # Notice we only specify a path for pull_request events, not pushes to main
  pull_request:
    branches: [ main ]
    paths: [android/**]

Doing so for your CI system will ensure that no matter the platform a pull request targets, there always will be both an iOS and Android base build present to compare against.