Skip to content

Commit

Permalink
ci: binary size included in each release
Browse files Browse the repository at this point in the history
Part of: https://linear.app/customerio/issue/MBL-155/track-the-binary-size-of-our-ios-sdk-upon-every-release

Allowing us to see the binary size of each release of our SDK. This is done by generating binary size reports to local files. Then, these files are committed to git on each release. 

Testing criteria: 
To test this, I modified the deploy-sdk workflow to only generate the report files (skip running semantic-release and cocoapods). I then ran this workflow by creating a draft PR. 

Notes for reviewers:
* binny is complex to get working on Linux. I noticed that you either have to compile it from source or use outdated pre-made builds of it. Installing on mac is more sustainable long-term so I suggest we stick to running bloaty on mac, only, on the CI. 
* I noticed that I was beginning to copy and paste the same code over and over again for downloading the latest main branch build and generating the SDK size reports. For this commit, I opted to making these tasks re-usable by creating dedicated github actions to do these repetitive tasks. In a future PR, I plan to refactor the workflow files to all use these re-usable actions. That's out of scope for this commit. 

commit-id:b7178f40
  • Loading branch information
levibostian committed Apr 12, 2024
1 parent f9f3c06 commit bf56a21
Show file tree
Hide file tree
Showing 5 changed files with 192 additions and 1 deletion.
80 changes: 80 additions & 0 deletions .github/actions/generate-sdk-size-report/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
name: Generate SDK size reports
# We only need to use 1 sample app build to generate the SDK size diff report. Therefore, we are hard-coding APN-UIKit into this action.
description: Given a .xcarchive for the APN sample app, this action will generate all of the SDK size reports.

inputs:
apn-app-xcarchive-name:
description: 'The name of the .xcarchive located inside of Apps/APN-UIKit/build/ to generate reports for. Example: "App.xcarchive"'
type: string
required: true
generate-main-diff-report:
description: 'Whether to generate the SDK size diff report between the main branch and the PR branch. If you are running on a PR, set this to true'
type: boolean
required: true

# 3 separate SDK size reports may be generated by this action.
outputs:
sdk-size-report:
description: 'The SDK size report, as a string.'
value: ${{ steps.sdk-size-report.outputs.stdout }}
sdk-size-including-dependencies-report:
description: 'The SDK size report, as a string. This report includes dependencies as well as the SDK size.'
value: ${{ steps.sdk-size-including-dependencies-report.outputs.stdout }}
sdk-size-diff-report:
description: 'The SDK size report, as a string. This report is the size difference between passed in app and the last build on main branch. Only populated if generate-main-diff-report input variable is true.'
value: ${{ steps.sdk-size-diff-report.outputs.stdout }}

runs:
using: "composite"
steps:
- name: Set environment variables for convenience in future steps
shell: bash
# Use each of the set variables in future steps like: ${{ env.WORKING_DIRECTORY }}
run: echo "WORKING_DIRECTORY=Apps/APN-UIKit/build" >> $GITHUB_ENV

- name: Assert running on macOS runner. Bloaty requires some complex compilation to run on Linux. Therefore, this action only supports macOS runners.
shell: bash
run: test $RUNNER_OS = 'macOS'

- name: Install bloaty, in case it is not already
shell: bash
run: brew install bloaty || true # If it's already installed, this will fail without error

- name: Make the SDK size report
uses: mathiasvr/[email protected]
id: sdk-size-report
with:
run: |
bloaty --source-filter ".*(customerio-ios\/Sources).*" \
-d compileunits --debug-file=${{ env.WORKING_DIRECTORY }}/${{ inputs.apn-app-xcarchive-name }}/dSYMs/APN\ UIKit.app.dSYM/Contents/Resources/DWARF/APN\ UIKit \
${{ env.WORKING_DIRECTORY }}/${{ inputs.apn-app-xcarchive-name }}/Products/Applications/APN\ UIKit.app/APN\ UIKit \
-n 0
- name: Make the SDK size report, including dependencies
uses: mathiasvr/[email protected]
id: sdk-size-including-dependencies-report
with:
run: |
bloaty --source-filter ".*(customerio-ios\/Sources)|(SourcePackages\/checkouts).*" \
-d compileunits --debug-file=${{ env.WORKING_DIRECTORY }}/${{ inputs.apn-app-xcarchive-name }}/dSYMs/APN\ UIKit.app.dSYM/Contents/Resources/DWARF/APN\ UIKit \
${{ env.WORKING_DIRECTORY }}/${{ inputs.apn-app-xcarchive-name }}/Products/Applications/APN\ UIKit.app/APN\ UIKit \
-n 0
# We want to determine if the SDK's binary size will change after merging a PR.
# To do that, we take the latest sample app build from the main branch and compare it to the app passed into this action.

- name: Download latest main sample app build to generate SDK size diff report
if: ${{ inputs.generate-main-diff-report }} == true
id: download-latest-main-build
uses: ./.github/actions/main-sample-app-build

- name: Generate SDK binary diff report between main branch and current branch
if: ${{ steps.download-latest-main-build.outputs.apn-app-xcarchive-path != '' }}
id: sdk-size-diff-report
uses: mathiasvr/[email protected]
with:
run: |
bloaty --source-filter ".*(customerio-ios\/Sources).*" -d compileunits \
--debug-file="${{ steps.download-latest-main-build.outputs.apn-app-xcarchive-path }}/dSYMs/APN UIKit.app.dSYM/Contents/Resources/DWARF/APN UIKit" \
--debug-file="${{ env.WORKING_DIRECTORY }}/${{ inputs.apn-app-xcarchive-name }}/dSYMs/APN UIKit.app.dSYM/Contents/Resources/DWARF/APN UIKit" \
"${{ env.WORKING_DIRECTORY }}/${{ inputs.apn-app-xcarchive-name }}/Products/Applications/APN UIKit.app/APN UIKit" -- "${{ steps.download-latest-main-build.outputs.apn-app-xcarchive-path }}/Products/Applications/APN UIKit.app/APN UIKit"
69 changes: 69 additions & 0 deletions .github/actions/main-sample-app-build/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
name: Get or save latest main branch sample app build
description: Use to either save or get the latest sample app build for the APN sample app, from the main branch. The build is used to generate the SDK size diff reports.

inputs:
# If you want to save a new build, pass in this input. If you want to get the latest build, leave this input out.
set-latest-main-build:
description: 'The name of the xcarchive for the APN sample app to save. Example: "App.xcarchive"'
type: string
required: false
default: ''

outputs:
apn-app-xcarchive-path:
description: 'The full relative path to the xcarchive for the APN sample app. Example: "Apps/APN-UIKit/build/MainBranchApp.xcarchive"'
value: ${{ steps.set-action-outputs.outputs.apn-app-xcarchive-path }}
apn-app-xcarchive-name:
description: 'The name of the xcarchive for the APN sample app. Example: "MainBranchApp.xcarchive"'
value: ${{ steps.set-action-outputs.outputs.apn-app-xcarchive-name }}

runs:
using: "composite"
steps:
- name: Setting environment variables for convenience in future steps
shell: bash
# Use each of the set variables in future steps like: ${{ env.APN_SAMPLE_APP_BUILD_PATH }}
run: |
echo "APN_SAMPLE_APP_BUILD_PATH=Apps/APN-UIKit/build" >> $GITHUB_ENV
echo "BUILD_FILE_NAME=MainBranchApp.xcarchive" >> $GITHUB_ENV
echo "CACHE_KEY_BASE=APN-UIKit-build-main-" >> $GITHUB_ENV
- name: Download latest main sample app build to compare against
if: ${{ inputs.set-latest-main-build == '' }}
uses: actions/cache/restore@v4
with:
# The key input is required for this action to run. But whatever value we pass in, it will not work for our use case. Therefore, this value is a placeholder value.
# The restore-keys param is what will download the latest cache version for us.
key: this-is-a-placeholder-because-value-required-by-action
path: ${{ env.APN_SAMPLE_APP_BUILD_PATH }}/${{ env.BUILD_FILE_NAME }} # the path where the build will be restored to
# The restore key is what will download the latest cache entry for us.
#
# How it works: "If there are multiple partial matches for a restore key, the action returns the most recently created cache."
# https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#matching-a-cache-key
restore-keys: |
${{ env.CACHE_KEY_BASE }}
# It's easiest if the latest main build always has the same name that easily identifies it.
# Therefore, we take the input build and copy it to have the name that we expect to upload.
- name: If saving a new build, create copy that we will save.
if: ${{ inputs.set-latest-main-build != '' }}
working-directory: ${{ env.APN_SAMPLE_APP_BUILD_PATH }}
shell: bash
run: |
cp -r ${{ inputs.set-latest-main-build }} ${{ env.BUILD_FILE_NAME }}
- name: Save latest main sample app build
if: ${{ inputs.set-latest-main-build != '' }}
uses: actions/cache/save@v4
with:
# the key must be unique. caches are immutable so the key must always be unique.
# https://github.com/actions/cache/blob/main/tips-and-workarounds.md#update-a-cache
key: ${{ env.CACHE_KEY_BASE }}${{ github.run_id }}
path: ${{ env.APN_SAMPLE_APP_BUILD_PATH }}/${{ env.BUILD_FILE_NAME }}

- name: Set action output values
id: set-action-outputs
shell: bash
run: |
echo "apn-app-xcarchive-path=$(echo ${{ env.APN_SAMPLE_APP_BUILD_PATH }}/${{ env.BUILD_FILE_NAME }})" >> $GITHUB_OUTPUT
echo "apn-app-xcarchive-name=$(echo ${{ env.BUILD_FILE_NAME }})" >> $GITHUB_OUTPUT
39 changes: 39 additions & 0 deletions .github/workflows/deploy-sdk.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,32 @@ permissions:
contents: write # access to push the git tag

jobs:
# We can only generate SDK size reports on macOS and we prefer to run deployments on Linux because macOS resources are limited.
# Therefore, generating SDK reports is a separate job that runs before deployment.
generate-sdk-size-report:
name: Generate SDK size report to attach to the release
runs-on: macos-14
# In order to pass data from 1 action to another, you use outputs.
# These are the generated reports that the deployment action depends on.
outputs:
sdk-size-report: ${{ steps.generate-sdk-size-report.outputs.sdk-size-report }}
sdk-size-including-dependencies-report: ${{ steps.generate-sdk-size-report.outputs.sdk-size-including-dependencies-report }}
steps:
- uses: actions/checkout@v4

- name: Download the latest main sample app build to generate SDK size diff report
id: main-sample-app-build
uses: ./.github/actions/main-sample-app-build

- uses: ./.github/actions/generate-sdk-size-report
id: generate-sdk-size-report
with:
apn-app-xcarchive-name: ${{ steps.main-sample-app-build.outputs.apn-app-xcarchive-name }}
generate-main-diff-report: false

deploy-git-tag:
name: Deploy git tag
needs: [generate-sdk-size-report]
runs-on: ubuntu-latest
outputs:
new_release_git_head: ${{ steps.semantic-release.outputs.new_release_git_head }}
Expand All @@ -31,6 +55,21 @@ jobs:
# uses: kenji-miyake/setup-sd@v1
uses: levibostian/setup-sd@add-file-extension # Using fork until upstream Action has bug fixed in it.

# We want to track the SDK binary size for each release.
# The reports is pushed by semantic-release action below by including files listed in the `assets` array in the `.releaserc` file.
- name: Write SDK size reports to file to include in the release
run: |
mkdir -p reports
echo "${{ needs.generate-sdk-size-report.outputs.sdk-size-report }}" > reports/sdk-binary-size.txt
echo "${{ needs.generate-sdk-size-report.outputs.sdk-size-including-dependencies-report }}" > reports/sdk-binary-size-including-dependencies.txt
echo "Verifying the reports got written to the file system. If the files are not empty, they were generated successfully..."
echo "SDK binary size report:"
head reports/sdk-binary-size.txt
echo "SDK binary size including dependencies report:"
head reports/sdk-binary-size-including-dependencies.txt

# Semantic-release tool is used to:
# 1. Determine the next semantic version for the software during deployment.
# For example, if the last deployment you made was version 1.3.5 and you are releasing a new feature
Expand Down
2 changes: 1 addition & 1 deletion .releaserc.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"changelogFile": "CHANGELOG.md"
}],
["@semantic-release/git", {
"assets": ["CHANGELOG.md", "Sources/Common/Version.swift", "*.podspec"],
"assets": ["CHANGELOG.md", "Sources/Common/Version.swift", "*.podspec", "reports/*"],
"message": "chore: prepare for ${nextRelease.version}\n\n${nextRelease.notes}"
}],
["@semantic-release/github", {
Expand Down
3 changes: 3 additions & 0 deletions reports/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Reports

**Important:** All files that are inside of this directory will be committed into the GitHub repository on every deployment. See our CI deployment scripts to learn more.

0 comments on commit bf56a21

Please sign in to comment.