Files
fx/.github/workflows/binary-size.yml
T
Pranit c6b629ead8 Gate CI on Linux and run macOS only when a change needs it
- Run the full deterministic E2E suite on Linux in four shards on every pull request, plus the MCP conformance baseline, all against one shared build of fx.
- Run macOS arm64 unit tests and platform E2E files only when a change touches macOS-specific code, build.zig, macOS signing, or the native SDK addon, or carries the ci:macos label. Otherwise the macOS arm64 check passes without a macOS runner.
- Remove the four-platform Full CI workflow and the separate cross-target compile jobs.
- Smoke-test the Linux arm64, macOS x86_64, and macOS arm64 binaries in Binary Size, and reuse the base build for later pushes to the same pull request.
- Build the SDK WASM surfaces and Node-API addons once and share them across the SDK test jobs.
- Run PGSO on pull requests only when the PGSO pipeline changes, and keep release PGSO evidence for 90 days.
- Run the long-turn memory, libfx runtime, and live ACP jobs only on request.
- Limit libfx publishing to an archive check, an install smoke test, and a registry byte comparison.
- Add a warning when an E2E file passes only on retry.
- Remove the unused Prepare Release workflow and document the new CI rules.
2026-10-01 05:12:19 -04:00

201 lines
7.4 KiB
YAML

name: Binary Size
on:
pull_request:
concurrency:
group: binary-size-${{ github.event.pull_request.number }}
cancel-in-progress: true
permissions:
contents: read
jobs:
compare:
name: ReleaseSafe delta (${{ matrix.name }})
runs-on: ${{ matrix.runner }}
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
include:
- name: linux-x86_64
target: x86_64-linux
runner: ubuntu-24.04
section_format: elf
expected_file: "ELF 64-bit LSB.*x86-64"
- name: linux-aarch64
target: aarch64-linux
runner: ubuntu-24.04-arm
section_format: elf
expected_file: "ELF 64-bit LSB.*ARM aarch64"
- name: macos-x86_64
target: x86_64-macos
runner: macos-15-intel
section_format: macho
expected_file: "Mach-O 64-bit executable x86_64"
- name: macos-aarch64
target: aarch64-macos
runner: macos-15
section_format: macho
expected_file: "Mach-O 64-bit executable arm64"
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.sha }}
EXPECTED_FILE: ${{ matrix.expected_file }}
SECTION_FORMAT: ${{ matrix.section_format }}
TARGET: ${{ matrix.target }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Zig
uses: mlugg/setup-zig@v2
with:
version: "0.16.0"
use-cache: false
- name: Test size reporter
run: python3 -m unittest scripts.tests.test_binary_size -v
- name: Build pull request binary
shell: bash
run: |
set -euo pipefail
evidence_dir="$RUNNER_TEMP/fx-binary-size-evidence"
mkdir -p "$evidence_dir"
test "$(git rev-parse HEAD)" = "$HEAD_SHA"
zig build \
-Dtarget=${{ matrix.target }} \
-Doptimize=ReleaseSafe \
--cache-dir "$RUNNER_TEMP/fx-head-cache" \
--global-cache-dir "$RUNNER_TEMP/fx-global-cache"
cp zig-out/bin/fx "$evidence_dir/head-fx"
file "$evidence_dir/head-fx" > "$evidence_dir/head-file.txt"
cat "$evidence_dir/head-file.txt"
grep -Eq "$EXPECTED_FILE" "$evidence_dir/head-file.txt"
if [ "$SECTION_FORMAT" = "macho" ]; then
size -m "$evidence_dir/head-fx" > "$evidence_dir/head-sections.txt"
else
size -A -d "$evidence_dir/head-fx" > "$evidence_dir/head-sections.txt"
fi
cat "$evidence_dir/head-sections.txt"
# Linux x86_64 gets the same smoke test in CI. The other platforms run
# nowhere else on a pull request, so this is where a broken binary shows up.
- name: Smoke test native binary
if: matrix.name != 'linux-x86_64'
env:
AI_GATEWAY_API_KEY: ""
VERCEL_OIDC_TOKEN: ""
run: scripts/smoke-binary.sh "$RUNNER_TEMP/fx-binary-size-evidence/head-fx"
- name: Restore base binary
id: base-cache
uses: actions/cache/restore@v4
with:
path: ${{ runner.temp }}/fx-binary-size-base-bin
key: binary-size-base-v1-${{ matrix.target }}-zig-0.16.0-${{ env.BASE_SHA }}
- name: Build base binary
if: steps.base-cache.outputs.cache-hit != 'true'
shell: bash
run: |
set -euo pipefail
base_worktree="$RUNNER_TEMP/fx-binary-size-base"
cleanup() {
git worktree remove --force "$base_worktree" >/dev/null 2>&1 || true
}
trap cleanup EXIT INT TERM
git worktree add --detach "$base_worktree" "$BASE_SHA"
test "$(git -C "$base_worktree" rev-parse HEAD)" = "$BASE_SHA"
(
cd "$base_worktree"
zig build \
-Dtarget=${{ matrix.target }} \
-Doptimize=ReleaseSafe \
--cache-dir "$RUNNER_TEMP/fx-base-cache" \
--global-cache-dir "$RUNNER_TEMP/fx-global-cache"
)
mkdir -p "$RUNNER_TEMP/fx-binary-size-base-bin"
cp "$base_worktree/zig-out/bin/fx" "$RUNNER_TEMP/fx-binary-size-base-bin/fx"
- name: Save base binary
if: steps.base-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: ${{ runner.temp }}/fx-binary-size-base-bin
key: binary-size-base-v1-${{ matrix.target }}-zig-0.16.0-${{ env.BASE_SHA }}
- name: Measure base binary
shell: bash
run: |
set -euo pipefail
evidence_dir="$RUNNER_TEMP/fx-binary-size-evidence"
cp "$RUNNER_TEMP/fx-binary-size-base-bin/fx" "$evidence_dir/base-fx"
file "$evidence_dir/base-fx" > "$evidence_dir/base-file.txt"
cat "$evidence_dir/base-file.txt"
grep -Eq "$EXPECTED_FILE" "$evidence_dir/base-file.txt"
if [ "$SECTION_FORMAT" = "macho" ]; then
size -m "$evidence_dir/base-fx" > "$evidence_dir/base-sections.txt"
else
size -A -d "$evidence_dir/base-fx" > "$evidence_dir/base-sections.txt"
fi
cat "$evidence_dir/base-sections.txt"
- name: Compare binary sizes
id: size
shell: bash
run: |
set -euo pipefail
evidence_dir="$RUNNER_TEMP/fx-binary-size-evidence"
python3 -m scripts.binary_size \
--base-binary "$evidence_dir/base-fx" \
--head-binary "$evidence_dir/head-fx" \
--base-sections "$evidence_dir/base-sections.txt" \
--head-sections "$evidence_dir/head-sections.txt" \
--base-sha "$BASE_SHA" \
--head-sha "$HEAD_SHA" \
--target "$TARGET" \
--warning-bytes 52429 \
--output-json "$evidence_dir/report.json" \
--output-markdown "$evidence_dir/report.md" \
--github-output "$GITHUB_OUTPUT"
cat "$evidence_dir/report.md" >> "$GITHUB_STEP_SUMMARY"
- name: Annotate notable growth
if: steps.size.outputs.warning == 'true'
env:
DELTA_BYTES: ${{ steps.size.outputs.delta_bytes }}
run: |
printf '%s\n' \
"::warning title=Binary size increase::${TARGET} ReleaseSafe grew by ${DELTA_BYTES} bytes; inspect the retained section report."
- name: Upload size evidence
if: always()
uses: actions/upload-artifact@v4
with:
name: binary-size-evidence-${{ matrix.name }}-${{ github.event.pull_request.number }}
path: |
${{ runner.temp }}/fx-binary-size-evidence/report.json
${{ runner.temp }}/fx-binary-size-evidence/report.md
${{ runner.temp }}/fx-binary-size-evidence/base-file.txt
${{ runner.temp }}/fx-binary-size-evidence/head-file.txt
${{ runner.temp }}/fx-binary-size-evidence/base-sections.txt
${{ runner.temp }}/fx-binary-size-evidence/head-sections.txt
if-no-files-found: warn
retention-days: 30
- name: Upload binaries for investigation
if: steps.size.outputs.warning == 'true'
uses: actions/upload-artifact@v4
with:
name: binary-size-binaries-${{ matrix.name }}-${{ github.event.pull_request.number }}
path: |
${{ runner.temp }}/fx-binary-size-evidence/base-fx
${{ runner.temp }}/fx-binary-size-evidence/head-fx
compression-level: 0
retention-days: 7