permissions:
contents: read
name: Binary Size
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:
concurrency:
group: binary-size-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
PROTOC_VERSION: "3.25.3"
SCCACHE_GHA_ENABLED: "true"
RUSTC_WRAPPER: "sccache"
CARGO_INCREMENTAL: "0"
CARGO_BLOAT_VERSION: "0.12.1"
CARGO_LLVM_LINES_VERSION: "0.4.46"
jobs:
binary-size-pr:
if: github.event_name == 'pull_request'
name: Binary Size (PR)
runs-on: ubuntu-latest
permissions:
contents: read
actions: read
pull-requests: write
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@master
with:
toolchain: nightly-2026-06-16
- name: Install tools (protoc, cargo-binstall)
uses: taiki-e/install-action@v2
with:
tool: protoc@${{ env.PROTOC_VERSION }},cargo-binstall
- name: Install cargo-bloat and cargo-llvm-lines
run: >
cargo binstall --no-confirm
cargo-bloat@${{ env.CARGO_BLOAT_VERSION }}
cargo-llvm-lines@${{ env.CARGO_LLVM_LINES_VERSION }}
- name: Setup sccache
uses: mozilla-actions/sccache-action@v0.0.10
- name: Cache Rust build (registry + target)
uses: Swatinem/rust-cache@v2
with:
prefix-key: ${{ runner.os }}-cargo-binary-size
cache-targets: "true"
- name: Install ALSA dev headers
run: sudo apt-get update && sudo apt-get install -y libasound2-dev
- name: Measure binary size
run: python3 scripts/ci/measure_binary_size.py --out-dir size-out
- name: Upload size artifacts
uses: actions/upload-artifact@v4
with:
name: size-metrics
path: size-out/
retention-days: 90
- name: Download baseline from latest main run
id: baseline
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# --event push: a fork PR from a branch named "main" also matches
# --branch main, and its artifact must not become the baseline.
run_id=$(gh run list --workflow binary-size.yml --branch main \
--event push --status success --limit 1 --json databaseId \
--jq '.[0].databaseId' || true)
if [ -n "$run_id" ] && [ "$run_id" != "null" ]; then
if gh run download "$run_id" --name size-metrics --dir base-out; then
echo "dir=base-out" >> "$GITHUB_OUTPUT"
else
echo "Baseline artifact missing or expired on run $run_id"
fi
else
echo "No successful Binary Size run on main yet"
fi
- name: Compare against gh-pages series
continue-on-error: true
uses: benchmark-action/github-action-benchmark@v1
with:
name: "whatsapp-rust binary size"
tool: "customSmallerIsBetter"
output-file-path: size-out/size-metrics.json
github-token: ${{ secrets.GITHUB_TOKEN }}
auto-push: false
save-data-file: false
benchmark-data-dir-path: dev/binary-size
summary-always: true
- name: Check size-increase-ok label
id: override
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
allow=$(gh api \
"repos/${{ github.repository }}/issues/${PR_NUMBER}/labels" \
--jq 'map(.name) | index("size-increase-ok") != null')
echo "allow=$allow" >> "$GITHUB_OUTPUT"
- name: Generate report and evaluate gate
env:
BASE_DIR: ${{ steps.baseline.outputs.dir }}
ALLOW_SIZE_INCREASE: ${{ steps.override.outputs.allow }}
run: |
python3 scripts/ci/binary_size_report.py --head size-out \
${BASE_DIR:+--base "$BASE_DIR"} --out-dir size-out
cat size-out/report.md >> "$GITHUB_STEP_SUMMARY"
- name: Post sticky PR comment
if: github.event.pull_request.head.repo.full_name == github.repository
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
marker='<!-- binary-size-report -->'
cid=$(gh api "repos/${{ github.repository }}/issues/${PR_NUMBER}/comments" \
--paginate \
--jq ".[] | select(.body | startswith(\"$marker\")) | .id" | head -n1)
if [ -n "$cid" ]; then
gh api -X PATCH "repos/${{ github.repository }}/issues/comments/${cid}" \
-F body=@size-out/report.md
else
gh api -X POST "repos/${{ github.repository }}/issues/${PR_NUMBER}/comments" \
-F body=@size-out/report.md
fi
- name: Enforce size budget
run: |
status=$(head -n1 size-out/gate.txt)
if [ "$status" = "FAIL" ]; then
echo "::error::Binary size budget exceeded — see the job summary or PR comment. If the increase is expected, add the size-increase-ok label."
exit 1
fi
echo "Gate status: $status"
binary-size-push:
if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main')
name: Binary Size (push)
runs-on: ubuntu-latest
permissions:
contents: write
deployments: write
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@master
with:
toolchain: nightly-2026-06-16
- name: Install tools (protoc, cargo-binstall)
uses: taiki-e/install-action@v2
with:
tool: protoc@${{ env.PROTOC_VERSION }},cargo-binstall
- name: Install cargo-bloat and cargo-llvm-lines
run: >
cargo binstall --no-confirm
cargo-bloat@${{ env.CARGO_BLOAT_VERSION }}
cargo-llvm-lines@${{ env.CARGO_LLVM_LINES_VERSION }}
- name: Setup sccache
uses: mozilla-actions/sccache-action@v0.0.10
- name: Cache Rust build (registry + target)
uses: Swatinem/rust-cache@v2
with:
prefix-key: ${{ runner.os }}-cargo-binary-size
cache-targets: "true"
- name: Install ALSA dev headers
run: sudo apt-get update && sudo apt-get install -y libasound2-dev
- name: Measure binary size
run: python3 scripts/ci/measure_binary_size.py --out-dir size-out
- name: Upload size artifacts
uses: actions/upload-artifact@v4
with:
name: size-metrics
path: size-out/
retention-days: 90
- name: Store series on gh-pages
uses: benchmark-action/github-action-benchmark@v1
with:
name: "whatsapp-rust binary size"
tool: "customSmallerIsBetter"
output-file-path: size-out/size-metrics.json
github-token: ${{ secrets.GITHUB_TOKEN }}
auto-push: true
benchmark-data-dir-path: dev/binary-size
max-items-in-chart: 200
alert-threshold: "102%"
comment-on-alert: true
fail-on-alert: false
summary-always: true